diff --git a/ChangeLog b/ChangeLog index d25300be9..fe9188e68 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2007-07-27 Wolfgang Sourdeau + * UI/MailerUI/UIxMailEditor.m ([UIxMailEditor -saveAction]): added + code to save the attached filenames with the filename returned by + the web server as well as their mime types. + * UI/MailPartViewers/UIxMailPartMessageViewer.m ([UIxMailPartMessageViewer -fromAddresses]) ([UIxMailPartMessageViewer -toAddresses]) ([UIxMailPartMessageViewer -ccAddresses]): new methods returning diff --git a/UI/MailerUI/Toolbars/SOGoDraftObject.toolbar b/UI/MailerUI/Toolbars/SOGoDraftObject.toolbar index d8bba1f0a..6355b0a0e 100644 --- a/UI/MailerUI/Toolbars/SOGoDraftObject.toolbar +++ b/UI/MailerUI/Toolbars/SOGoDraftObject.toolbar @@ -2,7 +2,7 @@ ( /* first group */ { link = "#"; isSafe = NO; - onclick = "clickedEditorSend(this);return false;"; + onclick = "return clickedEditorSend(this);"; image = "tb-compose-send-flat-24x24.png"; cssClass = "tbicon_send"; label = "Send"; }, @@ -13,13 +13,13 @@ label = "Contacts"; }, { link = "#"; isSafe = NO; - onclick = "clickedEditorAttach(this)"; + onclick = "return clickedEditorAttach(this)"; image = "tb-compose-attach-flat-24x24.png"; cssClass = "tbicon_attach"; label = "Attach"; }, { link = "#"; isSafe = NO; - onclick = "clickedEditorSave(this);return false;"; + onclick = "return clickedEditorSave(this);"; image = "tb-mail-file-flat-24x24.png"; cssClass = "tbicon_save"; label = "Save"; }, diff --git a/UI/MailerUI/UIxMailEditor.m b/UI/MailerUI/UIxMailEditor.m index 6b530be21..ffae1214b 100644 --- a/UI/MailerUI/UIxMailEditor.m +++ b/UI/MailerUI/UIxMailEditor.m @@ -25,14 +25,17 @@ #import #import -#import -#import #import #import #import #import #import #import +#import +#import +#import +#import +#import #import #import @@ -77,12 +80,13 @@ static BOOL useLocationBasedSentFolder = NO; static NSDictionary *internetMailHeaders = nil; static NSArray *infoKeys = nil; -+ (void)initialize { ++ (void) initialize +{ NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; infoKeys = [[NSArray alloc] initWithObjects: @"subject", @"text", @"to", @"cc", @"bcc", - @"from", @"replyTo", + @"from", @"replyTo", nil]; keepMailTmpFile = [ud boolForKey:@"SOGoMailEditorKeepTmpFile"]; @@ -95,18 +99,18 @@ static NSArray *infoKeys = nil; /* Internet mail settings */ showInternetMarker = [ud boolForKey:@"SOGoShowInternetMarker"]; - if (!showInternetMarker) { + if (!showInternetMarker) NSLog(@"Note: visual Internet marker on mail editor disabled " @"(SOGoShowInternetMarker)"); - } internetMailHeaders = [[ud dictionaryForKey:@"SOGoInternetMailHeaders"] copy]; - NSLog(@"Note: specified %d headers for mails send via the Internet.", + NSLog (@"Note: specified %d headers for mails send via the Internet.", [internetMailHeaders count]); } -- (void)dealloc { +- (void) dealloc +{ [sentFolder release]; [fromEMails release]; [from release]; @@ -123,68 +127,94 @@ static NSArray *infoKeys = nil; /* accessors */ -- (void)setFrom:(NSString *)_value { +- (void) setFrom: (NSString *) _value +{ ASSIGNCOPY(from, _value); } -- (NSString *)from { + +- (NSString *) from +{ if (![from isNotEmpty]) return [[[self context] activeUser] primaryEmail]; + return from; } -- (void)setReplyTo:(NSString *)_ignore { +- (void) setReplyTo: (NSString *) _ignore +{ } -- (NSString *)replyTo { + +- (NSString *) replyTo +{ /* we are here for future extensibility */ return @""; } -- (void)setSubject:(NSString *)_value { +- (void) setSubject: (NSString *) _value +{ ASSIGNCOPY(subject, _value); } -- (NSString *)subject { + +- (NSString *) subject +{ return subject ? subject : @""; } -- (void)setText:(NSString *)_value { +- (void) setText: (NSString *) _value +{ ASSIGNCOPY(text, _value); } -- (NSString *)text { + +- (NSString *) text +{ return [text isNotNull] ? text : @""; } -- (void)setTo:(NSArray *)_value { +- (void) setTo: (NSArray *)_value +{ ASSIGNCOPY(to, _value); } -- (NSArray *)to { + +- (NSArray *) to +{ return [to isNotNull] ? to : [NSArray array]; } -- (void)setCc:(NSArray *)_value { +- (void) setCc: (NSArray *) _value +{ ASSIGNCOPY(cc, _value); } -- (NSArray *)cc { + +- (NSArray *) cc +{ return [cc isNotNull] ? cc : [NSArray array]; } -- (void)setBcc:(NSArray *)_value { +- (void) setBcc: (NSArray *) _value +{ ASSIGNCOPY(bcc, _value); } -- (NSArray *)bcc { + +- (NSArray *) bcc +{ return [bcc isNotNull] ? bcc : [NSArray array]; } -- (BOOL)hasOneOrMoreRecipients { +- (BOOL) hasOneOrMoreRecipients +{ if ([[self to] count] > 0) return YES; if ([[self cc] count] > 0) return YES; if ([[self bcc] count] > 0) return YES; return NO; } -- (void)setAttachmentName:(NSString *)_attachmentName { +- (void) setAttachmentName: (NSString *) _attachmentName +{ ASSIGN(attachmentName, _attachmentName); } -- (NSString *)attachmentName { + +- (NSString *) attachmentName +{ return attachmentName; } @@ -403,23 +433,96 @@ static NSArray *infoKeys = nil; /* actions */ -- (BOOL)_saveFormInfo { - NSDictionary *info; - - if ((info = [self storeInfo]) != nil) { - NSException *error; - - if ((error = [[self clientObject] storeInfo:info]) != nil) { - [self errorWithFormat:@"failed to store draft: %@", error]; - // TODO: improve error handling - return NO; +- (NSDictionary *) _scanAttachmentFilenamesInRequest: (id) httpBody +{ + NSMutableDictionary *filenames; + NSDictionary *attachment; + NSArray *parts; + unsigned int count, max; + NGMimeBodyPart *part; + NGMimeContentDispositionHeaderField *header; + NSString *mimeType; + + parts = [httpBody parts]; + max = [parts count]; + filenames = [NSMutableDictionary dictionaryWithCapacity: max]; + + for (count = 0; count < max; count++) + { + part = [parts objectAtIndex: count]; + header = [part headerForKey: @"content-disposition"]; + mimeType = [[part headerForKey: @"content-type"] stringValue]; + attachment = [NSDictionary dictionaryWithObjectsAndKeys: + [header filename], @"filename", + mimeType, @"mime-type", nil]; + [filenames setObject: attachment + forKey: [header name]]; } - } + + return filenames; +} + +- (BOOL) _saveAttachments +{ + WORequest *request; + NSEnumerator *allKeys; + NSString *key; + BOOL success; + NSDictionary *filenames; + id httpBody; + SOGoDraftObject *co; + + success = YES; + request = [context request]; + + httpBody = [[request httpRequest] body]; + filenames = [self _scanAttachmentFilenamesInRequest: httpBody]; + + co = [self clientObject]; + allKeys = [[request formValueKeys] objectEnumerator]; + key = [allKeys nextObject]; + while (key && success) + { + if ([key hasPrefix: @"attachment"]) + success + = (![co saveAttachment: (NSData *) [request formValueForKey: key] + withMetadata: [filenames objectForKey: key]]); + key = [allKeys nextObject]; + } + + return success; +} + +- (BOOL) _saveFormInfo +{ + NSDictionary *info; + NSException *error; + BOOL success; + + success = YES; + + if ([self _saveAttachments]) + { + info = [self storeInfo]; + if (info) + { + error = [[self clientObject] storeInfo:info]; + if (error) + { + [self errorWithFormat:@"failed to store draft: %@", error]; + // TODO: improve error handling + success = NO; + } + } + } + else + success = NO; // TODO: wrap content - return YES; + return success; } + - (id)failedToSaveFormResponse { // TODO: improve error handling return [NSException exceptionWithHTTPStatus:500 /* server error */ @@ -443,23 +546,8 @@ static NSArray *infoKeys = nil; return [[self attachmentNames] count] > 0 ? YES : NO; } -- (NSString *)initialLeftsideStyle { - if ([self hasAttachments]) - return @"width: 67%"; - return @"width: 100%"; -} - -- (NSString *)initialRightsideStyle { - if ([self hasAttachments]) - return @"display: block"; - return @"display: none"; -} - -- (id)defaultAction { - return [self redirectToLocation:@"edit"]; -} - -- (id)editAction { +- (id) defaultAction +{ #if 0 [self logWithFormat:@"edit action, load content from: %@", [self clientObject]]; diff --git a/UI/Templates/MailerUI/UIxMailEditor.wox b/UI/Templates/MailerUI/UIxMailEditor.wox index 709379cff..af0ff5b21 100644 --- a/UI/Templates/MailerUI/UIxMailEditor.wox +++ b/UI/Templates/MailerUI/UIxMailEditor.wox @@ -9,16 +9,27 @@ className="UIxPageFrame" title="panelTitle" const:popup="YES"> -
+ + +
-
-
-
-
+
    + +
: 0) { + alert(labels.error_validationfailed.decodeEntities() + ":\n" + + errortext.decodeEntities()); + return false; + } + return true; +} + +function clickedEditorSend(sender) { + if (!validateEditorInput(sender)) + return false; + + document.pageform.action = "send"; + document.pageform.submit(); + + window.alert("cocou"); + + return false; +} + +function clickedEditorAttach(sender) { + var area = $("attachmentsArea"); + + area.setStyle({ display: "block" }); + + var inputs = area.getElementsByTagName("input"); + var attachmentName = "attachment" + inputs.length; + var newAttachment = createElement("input", attachmentName, + "currentAttachment", null, + { type: "file", + name: attachmentName }, + area); + Event.observe(newAttachment, "change", + onAttachmentChange.bindAsEventListener(newAttachment)); + + return false; +} + +function onAddAttachment() { + var area = $("attachmentsArea"); + var inputs = area.getElementsByTagName("input"); + var attachmentName = "attachment" + inputs.length; + var newAttachment = createElement("input", attachmentName, + "currentAttachment", null, + { type: "file", + name: attachmentName }, + area); + Event.observe(newAttachment, "change", + onAttachmentChange.bindAsEventListener(newAttachment)); +} + +function onAttachmentChange(event) { + if (this.value == "") + this.parentNode.removeChild(this); + else { + this.addClassName("attachment"); + this.removeClassName("currentAttachment"); + var list = $("attachments"); + createAttachment(this, list); + } +} + +function createAttachment(node, list) { + var attachment = createElement("li", null, null, { node: node }, null, list); + createElement("img", null, null, { src: ResourcesURL + "/attachment.gif" }, + null, attachment); + Event.observe(attachment, "click", onRowClick); + + var filename = node.value; + var separator; + if (navigator.appVersion.indexOf("Windows") > -1) + separator = "\\"; + else + separator = "/"; + var fileArray = filename.split(separator); + var attachmentName = document.createTextNode(fileArray[fileArray.length-1]); + attachment.appendChild(attachmentName); +} + +function clickedEditorSave(sender) { + document.pageform.action = "save"; + document.pageform.submit(); + refreshOpener(); + + return false; +} + +function clickedEditorDelete(sender) { + document.pageform.action = "delete"; + document.pageform.submit(); + refreshOpener(); + window.close(); + + return false; +} + +function initMailEditor() { + var list = $("attachments"); + $(list).attachMenu("attachmentsMenu"); + var elements = list.childNodesWithTag("li"); + for (var i = 0; i < elements.length; i++) + Event.observe(elements[i], "click", + onRowClick.bindAsEventListener(elements[i])); +} + +function getMenus() { + return { "attachmentsMenu": new Array(null, onRemoveAttachments, + onSelectAllAttachments, + "-", + onAddAttachment, null) }; +} + +function onRemoveAttachments() { + var list = $("attachments"); + var nodes = list.getSelectedNodes(); + for (var i = nodes.length-1; i > -1; i--) { + var input = $(nodes[i]).node; + if (input) { + input.parentNode.removeChild(input); + list.removeChild(nodes[i]); + } + else + window.alert("Server attachments not handled"); + } +} + +function onSelectAllAttachments() { + var list = $("attachments"); + var nodes = list.childNodesWithTag("li"); + for (var i = 0; i < nodes.length; i++) + nodes[i].select(); +} + +window.addEventListener("load", initMailEditor, false);