From d228e96a78d0ae73e1fb9058b9c875301d4e9cb0 Mon Sep 17 00:00:00 2001 From: C Robert Date: Tue, 30 Sep 2008 13:42:48 +0000 Subject: [PATCH] See ChangeLog Monotone-Parent: da4549a652b63b86055b1d36eb59d91375871786 Monotone-Revision: 694484559aed659a4395cabbbbf946966b25ff4e Monotone-Author: crobert@inverse.ca Monotone-Date: 2008-09-30T13:42:48 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 16 +++ SoObjects/Mailer/SOGoDraftsFolder.m | 11 +- SoObjects/Mailer/SOGoMailFolder.h | 5 + SoObjects/Mailer/SOGoMailFolder.m | 134 +++++++++++++++++++-- UI/MailerUI/UIxMailFolderActions.h | 1 + UI/MailerUI/UIxMailFolderActions.m | 27 +++++ UI/MailerUI/product.plist | 5 + UI/Templates/MailerUI/UIxMailMainFrame.wox | 1 + UI/WebServerResources/UIxMailEditor.js | 2 +- 9 files changed, 179 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1fff3ae3f..9e3a17a64 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2008-09-30 Cyril Robert + + * SoObjects/Mailer/SOGoDraftsFolder.m + Moved userSpoolFolderPath method to SOGoMailFolder.m + * SoObjects/Mailer/SOGoMailFolder.h + * SoObjects/Mailer/SOGoMailFolder.m + Added userSpoolFolderPath from SOGoDraftsFolder + Added archiveUIDs method to create an archive from email uids + * UI/MailerUI/UIxMailFolderActions.h + * UI/MailerUI/UIxMailFolderActions.m + Added saveMessagesAction method to handle the /saveMessages call + * UI/MailerUI/product.plist + Added a definition for saveMessages + + + 2008-09-28 Ludovic Marcotte * Modified the following files: diff --git a/SoObjects/Mailer/SOGoDraftsFolder.m b/SoObjects/Mailer/SOGoDraftsFolder.m index f305c2169..47078e920 100644 --- a/SoObjects/Mailer/SOGoDraftsFolder.m +++ b/SoObjects/Mailer/SOGoDraftsFolder.m @@ -47,7 +47,7 @@ static unsigned int newCount; ud = [NSUserDefaults standardUserDefaults]; spoolFolder = [ud stringForKey:@"SOGoMailSpoolPath"]; if (![spoolFolder length]) - spoolFolder = @"/tmp/"; + spoolFolder = @"/tmp/"; [spoolFolder retain]; NSLog(@"Note: using SOGo mail spool folder: %@", spoolFolder); @@ -102,14 +102,5 @@ static unsigned int newCount; return YES; } -- (NSString *) userSpoolFolderPath -{ - NSString *login; - - login = [[context activeUser] login]; - - return [NSString stringWithFormat: @"%@/%@", - spoolFolder, login]; -} @end diff --git a/SoObjects/Mailer/SOGoMailFolder.h b/SoObjects/Mailer/SOGoMailFolder.h index 839a36084..eba89a3fa 100644 --- a/SoObjects/Mailer/SOGoMailFolder.h +++ b/SoObjects/Mailer/SOGoMailFolder.h @@ -24,6 +24,7 @@ #include #import +#import /* SOGoMailFolder @@ -55,6 +56,7 @@ typedef enum { /* messages */ - (NSException *) deleteUIDs: (NSArray *) uids inContext: (id) context; +- (WOResponse *) archiveUIDs: (NSArray *) uids inContext: (id) context; - (NSArray *) fetchUIDsMatchingQualifier: (id)_q sortOrdering: (id) _so; - (NSArray *) fetchUIDs: (NSArray *) _uids parts: (NSArray *) _parts; @@ -81,6 +83,9 @@ typedef enum { - (NSArray *) allFolderPaths; - (NSArray *) allFolderURLs; +- (NSString *) userSpoolFolderPath; +- (BOOL) ensureSpoolFolderPath; + @end @interface SOGoSpecialMailFolder : SOGoMailFolder diff --git a/SoObjects/Mailer/SOGoMailFolder.m b/SoObjects/Mailer/SOGoMailFolder.m index 6925e92d5..952d0bbae 100644 --- a/SoObjects/Mailer/SOGoMailFolder.m +++ b/SoObjects/Mailer/SOGoMailFolder.m @@ -23,13 +23,16 @@ #import #import #import +#import #import #import +#import #import #import #import #import +#import #import #import @@ -51,6 +54,8 @@ static BOOL aclUsernamesAreQuoted = NO; /* http://www.tools.ietf.org/wg/imapext/draft-ietf-imapext-acl/ */ static BOOL aclConformsToIMAPExt = NO; +static NSString *spoolFolder = nil; + @interface NGImap4Connection (PrivateMethods) - (NSString *) imap4FolderNameForURL: (NSURL *) url; @@ -65,19 +70,29 @@ static BOOL aclConformsToIMAPExt = NO; NSString *aclStyleStr; if (aclStyle == undefined) - { - ud = [NSUserDefaults standardUserDefaults]; - aclStyleStr = [ud stringForKey: @"SOGoIMAPAclStyle"]; - if ([aclStyleStr isEqualToString: @"rfc2086"]) - aclStyle = rfc2086; - else - aclStyle = rfc4314; + { + ud = [NSUserDefaults standardUserDefaults]; + aclStyleStr = [ud stringForKey: @"SOGoIMAPAclStyle"]; + if ([aclStyleStr isEqualToString: @"rfc2086"]) + aclStyle = rfc2086; + else + aclStyle = rfc4314; - aclUsernamesAreQuoted - = [ud boolForKey: @"SOGoIMAPAclUsernamesAreQuoted"]; - aclConformsToIMAPExt - = [ud boolForKey: @"SOGoIMAPAclConformsToIMAPExt"]; - } + aclUsernamesAreQuoted + = [ud boolForKey: @"SOGoIMAPAclUsernamesAreQuoted"]; + aclConformsToIMAPExt + = [ud boolForKey: @"SOGoIMAPAclConformsToIMAPExt"]; + } + + if (!spoolFolder) + { + spoolFolder = [ud stringForKey:@"SOGoMailSpoolPath"]; + if (![spoolFolder length]) + spoolFolder = @"/tmp/"; + [spoolFolder retain]; + + NSLog(@"Note: using SOGo mail spool folder: %@", spoolFolder); + } } + (SOGoIMAPAclStyle) imapAclStyle @@ -302,6 +317,82 @@ static BOOL aclConformsToIMAPExt = NO; return error; } +- (WOResponse *) archiveUIDs: (NSArray *) uids + inContext: (id) localContext +{ + NSException *error; + NSFileManager *fm; + NSString *spoolPath, *fileName; + NSDictionary *msgs; + NSArray *messages; + NSData *content, *zipContent; + NSTask *zipTask; + NSMutableArray *zipTaskArguments; + WOResponse *response; + int i; + + spoolPath = [self userSpoolFolderPath]; + if ( ![self ensureSpoolFolderPath] ) { + error = [NSException exceptionWithHTTPStatus: 500 + reason: @"spoolFolderPath doesn't exist"]; + return (WOResponse *)error; + } + + fm = [NSFileManager defaultManager]; + if ( ![fm fileExistsAtPath: @"/usr/bin/zip"] ) { + error = [NSException exceptionWithHTTPStatus: 500 + reason: @"zip not available"]; + return (WOResponse *)error; + } + + zipTask = [[NSTask alloc] init]; + [zipTask setCurrentDirectoryPath: spoolPath]; + [zipTask setLaunchPath: @"/usr/bin/zip"]; + + zipTaskArguments = [NSMutableArray arrayWithObjects: nil]; + [zipTaskArguments addObject: @"SavedMessages.zip"]; + + msgs = (NSDictionary *)[self fetchUIDs: uids + parts: [NSArray arrayWithObject: @"RFC822"]]; + messages = [[msgs objectForKey: @"fetch"] retain]; + + for (i = 0; i < [messages count]; i++) { + content = [[messages objectAtIndex: i] objectForKey: @"message"]; + + [content writeToFile: + [NSString stringWithFormat:@"%@/%d.eml", spoolPath, [uids objectAtIndex: i]] + atomically: YES]; + + [zipTaskArguments addObject: + [NSString stringWithFormat:@"%d.eml", [uids objectAtIndex: i]]]; + } + + [zipTask setArguments: zipTaskArguments]; + [zipTask launch]; + [zipTask waitUntilExit]; + + [zipTask release]; + + zipContent = [[NSData alloc] initWithContentsOfFile: + [NSString stringWithFormat: @"%@/SavedMessages.zip", spoolPath]]; + + for(i = 0; i < [zipTaskArguments count]; i++) { + fileName = [zipTaskArguments objectAtIndex: i]; + [fm removeFileAtPath: + [NSString stringWithFormat: @"%@/%@", spoolPath, fileName] handler: nil]; + } + + response = [[WOResponse alloc] init]; + [response autorelease]; + [response setHeader: @"application/zip" forKey:@"content-type"]; + [response setHeader: @"attachment;filename=SavedMessages.zip" forKey: @"Content-Disposition"]; + [response setContent: zipContent]; + + [zipContent release]; + + return response; +} + - (NSArray *) fetchUIDsMatchingQualifier: (id) _q sortOrdering: (id) _so { @@ -891,6 +982,25 @@ static BOOL aclConformsToIMAPExt = NO; return [userURL absoluteString]; } +- (NSString *) userSpoolFolderPath +{ + NSString *login; + + login = [[context activeUser] login]; + + return [NSString stringWithFormat: @"%@/%@", + spoolFolder, login]; +} + +- (BOOL) ensureSpoolFolderPath +{ + NSFileManager *fm; + + fm = [NSFileManager defaultManager]; + + return ([fm createDirectoriesAtPath: [self userSpoolFolderPath] attributes:nil]); +} + @end /* SOGoMailFolder */ @implementation SOGoSpecialMailFolder diff --git a/UI/MailerUI/UIxMailFolderActions.h b/UI/MailerUI/UIxMailFolderActions.h index 51e3dc669..594bff8c9 100644 --- a/UI/MailerUI/UIxMailFolderActions.h +++ b/UI/MailerUI/UIxMailFolderActions.h @@ -33,6 +33,7 @@ - (WOResponse *) renameFolderAction; - (WOResponse *) deleteFolderAction; - (WOResponse *) deleteMessagesAction; +- (WOResponse *) saveMessagesAction; - (WOResponse *) expungeAction; - (WOResponse *) emptyTrashAction; - (WOResponse *) subscribeAction; diff --git a/UI/MailerUI/UIxMailFolderActions.m b/UI/MailerUI/UIxMailFolderActions.m index 6e7f2b020..c7237b0d5 100644 --- a/UI/MailerUI/UIxMailFolderActions.m +++ b/UI/MailerUI/UIxMailFolderActions.m @@ -209,6 +209,33 @@ return response; } +- (WOResponse *) saveMessagesAction +{ + SOGoMailFolder *co; + WOResponse *response; + NSArray *uids; + NSString *value; + + co = [self clientObject]; + value = [[context request] formValueForKey: @"uid"]; + response = nil; + + if ([value length] > 0) + { + uids = [value componentsSeparatedByString: @","]; + response = [co archiveUIDs: uids inContext: context]; + if (!response) + response = [self responseWith204]; + } + else + { + response = [self responseWithStatus: 500]; + [response appendContentString: @"Missing 'uid' parameter."]; + } + + return response; +} + - (WOResponse *) _setFolderPurpose: (NSString *) purpose { SOGoMailFolder *co; diff --git a/UI/MailerUI/product.plist b/UI/MailerUI/product.plist index 0bc397b63..f759eea14 100644 --- a/UI/MailerUI/product.plist +++ b/UI/MailerUI/product.plist @@ -141,6 +141,11 @@ actionClass = "UIxMailFolderActions"; actionName = "deleteMessages"; }; + saveMessages = { + protectedBy = "View"; + actionClass = "UIxMailFolderActions"; + actionName = "saveMessages"; + }; setAsDraftsFolder = { protectedBy = "View"; actionClass = "UIxMailFolderActions"; diff --git a/UI/Templates/MailerUI/UIxMailMainFrame.wox b/UI/Templates/MailerUI/UIxMailMainFrame.wox index fafe9f69f..63f5c1cb7 100644 --- a/UI/Templates/MailerUI/UIxMailMainFrame.wox +++ b/UI/Templates/MailerUI/UIxMailMainFrame.wox @@ -124,6 +124,7 @@
  • +
  • diff --git a/UI/WebServerResources/UIxMailEditor.js b/UI/WebServerResources/UIxMailEditor.js index a0cab55a0..8080c1340 100644 --- a/UI/WebServerResources/UIxMailEditor.js +++ b/UI/WebServerResources/UIxMailEditor.js @@ -539,7 +539,7 @@ function initMailEditor() { var sigLimit = textContent.lastIndexOf("--"); if (sigLimit > -1) signatureLength = (textContent.length - sigLimit); - if ( userDefaults["SignaturePlacement"] != "above" ) { + if ( userDefaults["ReplyPlacement"] != "above" ) { textarea.scrollTop = textarea.scrollHeight; } textarea.observe("focus", onTextFirstFocus);