2007-07-27 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ * UI/MailerUI/UIxMailForwardAction.m ([UIxMailForwardAction
+ -forwardAction]): adapted to the new saveAttachment:withMetadata:
+ method (see below).
+
+ * 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
+ the corresponding fields separated with a ", " (if needed).
+
+ * SoObjects/Mailer/SOGoDraftObject.m ([SOGoDraftObject
+ -saveAttachment:_attachwithMetadata:metadata]): new method
+ replacing -saveAttachment:withName: and which takes a dictionary
+ as parameter with the filename and the mime type of the
+ attachment.
+ The mimetype is then saved in a hidden text file.
+ ([SOGoDraftObject -contentTypeForAttachmentWithName:]): if exists,
+ take the mime type from the hidden text file related to the
+ attachment.
+
* SoObjects/Contacts/SOGoContactGCSFolder.m ()
([SOGoContactGCSFolder
-lookupContactsWithFilter:filtersortBy:sortKeyordering:sortOrdering]):
- (NSArray *)fetchAttachmentNames;
- (BOOL)isValidAttachmentName:(NSString *)_name;
-- (NSException *)saveAttachment:(NSData *)_attach withName:(NSString *)_name;
+- (NSException *) saveAttachment: (NSData *)_attach
+ withMetadata: (NSDictionary *) metadata;
- (NSException *)deleteAttachmentWithName:(NSString *)_name;
/* NGMime representations */
reason:@"Invalid attachment name!"];
}
-- (NSException *)saveAttachment:(NSData *)_attach withName:(NSString *)_name {
- NSString *p;
+- (NSException *) saveAttachment: (NSData *) _attach
+ withMetadata: (NSDictionary *) metadata
+{
+ NSString *p, *name, *mimeType;
if (![_attach isNotNull]) {
return [NSException exceptionWithHTTPStatus:400 /* Bad Request */
return [NSException exceptionWithHTTPStatus:500 /* Server Error */
reason:@"Could not create folder for draft!"];
}
- if (![self isValidAttachmentName:_name])
- return [self invalidAttachmentNameError:_name];
+ name = [metadata objectForKey: @"filename"];
+ if (![self isValidAttachmentName: name])
+ return [self invalidAttachmentNameError: name];
- p = [self pathToAttachmentWithName:_name];
- if (![_attach writeToFile:p atomically:YES]) {
- return [NSException exceptionWithHTTPStatus:500 /* Server Error */
- reason:@"Could not write attachment to draft!"];
- }
+ p = [self pathToAttachmentWithName: name];
+ if (![_attach writeToFile: p atomically: YES])
+ {
+ return [NSException exceptionWithHTTPStatus:500 /* Server Error */
+ reason:@"Could not write attachment to draft!"];
+ }
+
+ mimeType = [metadata objectForKey: @"mime-type"];
+ if ([mimeType length] > 0)
+ {
+ p = [self pathToAttachmentWithName:
+ [NSString stringWithFormat: @".%@.mime", name]];
+ if (![[mimeType dataUsingEncoding: NSUTF8StringEncoding]
+ writeToFile: p atomically: YES])
+ {
+ return [NSException exceptionWithHTTPStatus:500 /* Server Error */
+ reason:@"Could not write attachment to draft!"];
+ }
+ }
return nil; /* everything OK */
}
}
- (NSString *)contentTypeForAttachmentWithName:(NSString *)_name {
- NSString *s;
+ NSString *s, *p;
+ NSData *mimeData;
- s = [self mimeTypeForExtension:[_name pathExtension]];
- if ([_name length] > 0)
- s = [s stringByAppendingFormat:@"; name=\"%@\"", _name];
+ p = [self pathToAttachmentWithName:
+ [NSString stringWithFormat: @".%@.mime", _name]];
+ mimeData = [NSData dataWithContentsOfFile: p];
+ if (mimeData)
+ {
+ s = [[NSString alloc] initWithData: mimeData
+ encoding: NSUTF8StringEncoding];
+ [s autorelease];
+ }
+ else
+ {
+ s = [self mimeTypeForExtension:[_name pathExtension]];
+ if ([_name length] > 0)
+ s = [s stringByAppendingFormat:@"; name=\"%@\"", _name];
+ }
return s;
}
+
- (NSString *)contentDispositionForAttachmentWithName:(NSString *)_name {
NSString *type;
NSString *cdtype;
OGo is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public
- License along with OGo; see the file COPYING. If not, write to the
+ License along with OGo; see the file COPYING. If not, write to the
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
-#include "UIxMailPartViewer.h"
+#import <NGImap4/NGImap4Envelope.h>
+#import <NGImap4/NGImap4EnvelopeAddress.h>
+
+#import <UI/MailerUI/WOContext+UIxMailer.h>
+#import "UIxMailRenderingContext.h"
+
+#import "UIxMailPartViewer.h"
/*
UIxMailPartMessageViewer
- Show message/rfc822 mail parts. Note that the IMAP4 server already returns a
- proper body structure of the message.
-
- Relevant body-info keys:
- to/sender/from/cc/bcc/in-reply-to/reply-to - array of addr-dicts
- type/subtype - message/RFC822
- size
- subject
- parameterList - dict (eg 'name')
- messageId
- date
- encoding - 7BIT
- bodyLines - 83
- bodyId - (empty string?)
- description - (empty string?, content-description?)
-
- body - a body structure?
-
- Addr-Dict:
- hostName / mailboxName / personalName / sourceRoute
+ Show message/rfc822 mail parts. Note that the IMAP4 server already returns a
+ proper body structure of the message.
+
+ Relevant body-info keys:
+ to/sender/from/cc/bcc/in-reply-to/reply-to - array of addr-dicts
+ type/subtype - message/RFC822
+ size
+ subject
+ parameterList - dict (eg 'name')
+ messageId
+ date
+ encoding - 7BIT
+ bodyLines - 83
+ bodyId - (empty string?)
+ description - (empty string?, content-description?)
+
+ body - a body structure?
+
+ Addr-Dict:
+ hostName / mailboxName / personalName / sourceRoute
*/
@class NGImap4Envelope;
@interface UIxMailPartMessageViewer : UIxMailPartViewer
{
NGImap4Envelope *envelope;
- id currentAddress;
}
@end
-#include <UI/MailerUI/WOContext+UIxMailer.h>
-#include "UIxMailRenderingContext.h"
-#include <NGImap4/NGImap4Envelope.h>
-#include <NGImap4/NGImap4EnvelopeAddress.h>
-#include "common.h"
-
@implementation UIxMailPartMessageViewer
-- (void)dealloc {
- [self->currentAddress release];
- [self->envelope release];
+- (void) dealloc
+{
+ [envelope release];
[super dealloc];
}
/* cache maintenance */
-- (void)resetBodyInfoCaches {
+- (void) resetBodyInfoCaches
+{
[super resetBodyInfoCaches];
- [self->envelope release]; self->envelope = nil;
- [self->currentAddress release]; self->currentAddress = nil;
-}
-
-/* notifications */
-
-- (void)sleep {
- [self->currentAddress release]; self->currentAddress = nil;
- [super sleep];
-}
-
-/* accessors */
-
-- (void)setCurrentAddress:(id)_addr {
- ASSIGN(self->currentAddress, _addr);
-}
-- (id)currentAddress {
- return self->currentAddress;
+ [envelope release]; envelope = nil;
}
/* nested body structure */
-- (id)contentInfo {
+- (id) contentInfo
+{
return [[self bodyInfo] valueForKey:@"body"];
}
-- (id)contentPartPath {
+- (id) contentPartPath
+{
/*
Path processing is a bit weird in the context of message/rfc822. If we have
a multipart, the multipart itself has no own identifier! Instead the
children of the multipart are directly mapped into the message namespace.
-
+
If the message has just a plain content, ids seems to be as expected (that
is, its just a "1").
*/
- NSArray *pp;
+ NSArray *pp;
NSString *mt;
-
+
mt = [[[self contentInfo] valueForKey:@"type"] lowercaseString];
if ([mt isEqualToString:@"multipart"])
return [self partPath];
-
+
pp = [self partPath];
- return [pp count] > 0
- ? [pp arrayByAddingObject:@"1"]
- : [NSArray arrayWithObject:@"1"];
+ return (([pp count] > 0)
+ ? [pp arrayByAddingObject: @"1"]
+ : [NSArray arrayWithObject: @"1"]);
}
-- (id)contentViewerComponent {
- id info;
-
- info = [self contentInfo];
- return [[[self context] mailRenderingContext] viewerForBodyInfo:info];
+- (id) contentViewerComponent
+{
+ UIxMailRenderingContext *mailContext;
+
+ mailContext = [[self context] mailRenderingContext];
+
+ return [mailContext viewerForBodyInfo: [self contentInfo]];
}
/* generating envelope */
-- (NGImap4Envelope *)envelope {
- if (self->envelope == nil) {
- self->envelope = [[NGImap4Envelope alloc] initWithBodyStructureInfo:
- [self bodyInfo]];
- }
- return self->envelope;
+- (NGImap4Envelope *) envelope
+{
+ if (!envelope)
+ envelope = [[NGImap4Envelope alloc] initWithBodyStructureInfo:
+ [self bodyInfo]];
+
+ return envelope;
+}
+
+- (NSString *) formattedComponents: (NSArray *) components
+{
+ NSMutableArray *formattedComponents;
+ unsigned int count, max;
+ NSString *component;
+
+ max = [components count];
+ formattedComponents = [NSMutableArray arrayWithCapacity: max];
+ for (count = 0; count < max; count++)
+ {
+ component = [[components objectAtIndex: count] email];
+ [formattedComponents addObject: component];
+ }
+
+ return [formattedComponents componentsJoinedByString: @", "];
+}
+
+- (NSString *) fromAddresses
+{
+ NSArray *from;
+
+ from = [[self envelope] from];
+
+ return [self formattedComponents: from];
+}
+
+- (NSString *) toAddresses
+{
+ NSArray *to;
+
+ to = [[self envelope] to];
+
+ return [self formattedComponents: to];
+}
+
+- (NSString *) ccAddresses
+{
+ NSArray *cc;
+
+ cc = [[self envelope] cc];
+
+ return [self formattedComponents: cc];
}
/* links to recipients */
-- (NSString *)linkToEnvelopeAddress:(NGImap4EnvelopeAddress *)_address {
+- (NSString *) linkToEnvelopeAddress: (NGImap4EnvelopeAddress *) _address
+{
// TODO: make some web-link, eg open a new compose panel?
return [@"mailto:" stringByAppendingString:[_address baseEMail]];
}
-- (NSString *)currentAddressLink {
- return [self linkToEnvelopeAddress:[self currentAddress]];
-}
-
@end /* UIxMailPartMessageViewer */
( /* 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"; },
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"; },
#import <Foundation/NSUserDefaults.h>
#import <NGObjWeb/WORequest.h>
-#import <NGMail/NGMimeMessage.h>
-#import <NGMail/NGMimeMessageGenerator.h>
#import <NGObjWeb/SoSubContext.h>
#import <NGObjWeb/NSException+HTTP.h>
#import <NGExtensions/NSNull+misc.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSString+misc.h>
#import <NGExtensions/NSException+misc.h>
+#import <NGMail/NGMimeMessage.h>
+#import <NGMail/NGMimeMessageGenerator.h>
+#import <NGMime/NGMimeBodyPart.h>
+#import <NGMime/NGMimeHeaderFields.h>
+#import <NGMime/NGMimeMultipartBody.h>
#import <SoObjects/Mailer/SOGoDraftObject.h>
#import <SoObjects/Mailer/SOGoMailFolder.h>
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"];
/* 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];
/* 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;
}
/* actions */
-- (BOOL)_saveFormInfo {
+- (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;
-
- 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;
+ 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 */
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]];
nil];
if ((error = [newDraft storeInfo:info]) != nil)
return error;
-
+
/* attach message */
// TODO: use subject for filename?
- error = [newDraft saveAttachment:content withName:@"forward.mail"];
+// error = [newDraft saveAttachment:content withName:@"forward.mail"];
+ attachment = [NSDictionary dictionaryWithObjectsAndKeys:
+ @"forward.mail", @"filename",
+ @"message/rfc822", @"mime-type",
+ nil];
+ error = [newDraft saveAttachment: content
+ withMetadata: attachment];
if (error != nil)
return error;
<?xml version="1.0" standalone="yes"?>
+<!DOCTYPE div>
<div xmlns="http://www.w3.org/1999/xhtml"
- xmlns:var="http://www.skyrix.com/od/binding"
- xmlns:label="OGo:label"
- class="linked_attachment_frame"
->
+ xmlns:var="http://www.skyrix.com/od/binding"
+ xmlns:label="OGo:label"
+ class="linked_attachment_frame">
<div class="linked_attachment_body">
-
- <!-- TODO: the table is a DUP to UIxMailView, own component? -->
- <table class="mailer_fieldtable">
- <tr class="mailer_fieldrow">
- <td class="mailer_fieldname" ><var:string label:value="Subject"/>:</td>
- <td class="mailer_subjectfieldvalue">
- <var:string value="envelope.subject"
- formatter="context.mailSubjectFormatter"/>
-<!--
- <a var:href="pathToAttachment"
- var:title="filenameForDisplay"
- >(<var:string label:value="download" />)</a>
--->
- </td>
- </tr>
- <tr class="mailer_fieldrow">
- <td class="mailer_fieldname" ><var:string label:value="From"/>:</td>
- <td class="mailer_fieldvalue">
- <!-- compose link? -->
- <var:foreach list="envelope.from" item="currentAddress">
- <a var:href="currentAddressLink">
- <var:string value="currentAddress"
- formatter="context.mailEnvelopeFullAddressFormatter" /></a>
- </var:foreach>
- </td>
- </tr>
- <tr class="mailer_fieldrow">
- <td class="mailer_fieldname" ><var:string label:value="Date"/>:</td>
- <td class="mailer_fieldvalue">
- <var:string value="envelope.date"
- formatter="context.mailDateFormatter"/>
- </td>
- </tr>
-
- <tr class="mailer_fieldrow">
- <td class="mailer_fieldname" ><var:string label:value="To"/>:</td>
- <td class="mailer_fieldvalue">
- <!-- compose link? -->
- <var:foreach list="envelope.to" item="currentAddress">
- <a var:href="currentAddressLink">
- <var:string value="currentAddress"
- formatter="context.mailEnvelopeFullAddressFormatter" /></a>
- </var:foreach>
- </td>
- </tr>
- <var:if condition="envelope.hasCC">
- <tr class="mailer_fieldrow">
- <td class="mailer_fieldname" ><var:string label:value="CC"/>:</td>
- <td class="mailer_fieldvalue">
- <!-- compose link? -->
- <var:foreach list="envelope.cc" item="currentAddress">
- <a var:href="currentAddressLink">
- <var:string value="currentAddress"
- formatter="context.mailEnvelopeFullAddressFormatter" /></a>
- <br /> <!-- TODO: better to use li+CSS -->
- </var:foreach>
- </td>
- </tr>
- </var:if>
- </table>
-
- <div class="mailer_mailcontent">
- <var:component value="contentViewerComponent"
- bodyInfo="contentInfo"
- partPath="contentPartPath" />
- </div>
-
-<!-- debug
+ <hr/>
+ <!-- TODO: the table is a DUP to UIxMailView, own component? -->
+ <div class="bodyFields">
+ <span class="fieldName"><var:string label:value="Subject"/>:</span>
+ <var:string value="envelope.subject"
+ formatter="context.mailSubjectFormatter"/><br/>
+ <span class="fieldName"><var:string label:value="From"/>:</span>
+ <var:string value="fromAddresses"/><br/>
+ <span class="fieldName"><var:string label:value="Date"/>:</span>
+ <var:string value="envelope.date"
+ formatter="context.mailDateFormatter"/><br/>
+ <div class="bodyAdditionalFields">
+ <span class="fieldName"><var:string label:value="To"/>:</span>
+ <var:string value="toAddresses"/><br/>
+ <var:if condition="envelope.hasCC">
+ <span class="fieldName"><var:string label:value="CC"/>:</span>
+ <var:string value="ccAddresses"/>
+ </var:if>
+ </div>
+ </div>
+
+ <div class="bodyMailContent">
+ <var:component value="contentViewerComponent"
+ bodyInfo="contentInfo"
+ partPath="contentPartPath" />
+ </div>
+
+ <!-- debug
<pre><var:string value="envelope"/></pre>
<pre><var:string value="bodyInfo.body"/></pre>
--->
+ -->
</div>
</div>
className="UIxPageFrame"
title="panelTitle"
const:popup="YES">
- <form name="pageform">
+ <div class="menu" id="attachmentsMenu">
+ <ul>
+ <li><var:string label:value="Open"/></li>
+ <li><var:string label:value="Delete" /></li>
+ <li><var:string label:value="Select All" /></li>
+ <li><!-- separator --></li>
+ <li><var:string label:value="Attach File(s)..." /></li>
+ <li><var:string label:value="Attach Web Page..." /></li>
+ </ul>
+ </div>
+
+ <form name="pageform" enctype="multipart/form-data">
<div id="headerArea">
<div id="attachmentsArea">
<var:string label:value="Attachments:" />
- <div id="compose_attachments_list"
- onclick="clickedEditorAttach(this);"
- ><var:foreach list="attachmentNames" item="attachmentName">
- <var:string value="attachmentName" /><br />
- </var:foreach>
- </div>
+ <ul id="attachments">
+ <var:foreach list="attachmentNames" item="attachmentName"
+ ><img rsrc:img="attachment.gif"
+ /><var:string value="attachmentName"
+ /></var:foreach>
+ </ul>
</div>
<span class="headerField"><var:string label:value="From" />:</span>
<var:popup const:name="from"
+++ /dev/null
-<?xml version='1.0' standalone='yes'?>
-<html xmlns="http://www.w3.org/1999/xhtml"
- xmlns:var="http://www.skyrix.com/od/binding"
- xmlns:const="http://www.skyrix.com/od/constant"
- xmlns:rsrc="OGo:url"
- xmlns:label="OGo:label"
->
- <head>
- <title>Attach ...</title>
-
- <meta name="description" content="SOGo Web Interface"/>
- <meta name="author" content="SKYRIX Software AG"/>
- <meta name="robots" content="stop"/>
-
- <script rsrc:src="generic.js"> <!-- space required --></script>
- <script rsrc:src="UIxMailEditorAttach.js" > <!-- space required --></script>
-
- <link type="text/css" rel="stylesheet" rsrc:href="uix.css"/>
- <link type="text/css" rel="stylesheet" rsrc:href="mailer.css"/>
- <link href="mailto:info@skyrix.com" rev="made"/>
- </head>
-
- <body id="attachment_body"
- style="background-color: #D4D0C8;"
- onload="updateAttachmentListInEditorWindow(this);"
- >
- <form name="pageform" href="attach" _wosid="NO"
- method="POST" enctype="multipart/form-data"
- id="attachment_form"
- >
- <div id="attachment_upload">
- <table border="0" width="98%">
- <tr>
- <td class="attachment_uplabel">File:</td>
- <td><input type="file" name="file1"
- var:filePath="filePath1"
- var:data="fileData1" /></td>
- </tr>
- <tr>
- <td class="attachment_uplabel">File:</td>
- <td><input type="file" name="file2"
- var:filePath="filePath2"
- var:data="fileData2" /></td>
- </tr>
- <tr>
- <td class="attachment_uplabel">File:</td>
- <td><input type="file" name="file3"
- var:filePath="filePath3"
- var:data="fileData3" /></td>
- </tr>
- <tr>
- <td></td>
- <td>
- <input type="submit"
- name="submit"
- value="attach"
- />
- <input type="reset" value="close"
- onclick="window.close()" />
- </td>
- </tr>
- </table>
- </div>
-
- <div id="attachment_list">
- <div style="padding: 4px;">
- <var:if condition="hasAttachments">
- <div class="embedwhite_out">
- <div class="embedwhite_in">
- <table border="0" width="100%" cellspacing="0" cellpadding="1">
- <tr class="tableview">
- <td class="tbtv_headercell">
- Attachments
- </td>
- <td class="tbtv_headercell" width="10%">
- <entity name="nbsp" />
- </td>
- </tr>
-
- <var:foreach list="attachmentNames" item="attachmentName">
- <tr class="tableview">
- <td><var:string value="attachmentName" /></td>
- <td>
- <a href="deleteAttachment"
- var:_attachmentName="attachmentName"
- >delete</a>
- </td>
- </tr>
- </var:foreach>
- </table>
- </div>
- </div>
- </var:if>
- </div>
- <span id="attachmentList"
- style="display: none;"
- ><var:foreach list="attachmentNames" item="attachmentName"><var:string value="attachmentName" />/</var:foreach></span>
- </div>
- </form>
- </body>
-</html>
padding-left: 6px;
}
-table.titletable
+TABLE.titletable
{
height: 24px;
vertical-align: middle;
padding-left: 6px;
}
-table.titletable td.titlecell SELECT
+TABLE.titletable td.titlecell SELECT
{
display: -moz-popup;
border-top: 1px solid #fff;
*/
}
-div.mailer_readicon
+DIV.mailer_readicon
{
/* TODO: use Thunderbird icon */
background-image: url(icon_read.gif);
background-position: 0px 4px;
}
-div.mailer_readicon a
+DIV.mailer_readicon a
{
width: 17px;
height: 17px;
display: block;
}
-div.mailerUnreadIcon
+DIV.mailerUnreadIcon
{
/* TODO: use Thunderbird icon */
background-image: url(icon_unread.gif);
background-position: 0px 4px;
}
-div.mailer_unreadicon a
+DIV.mailer_unreadicon a
{
width: 17px;
height: 17px;
/* fields (key/value UI), eg used in mail viewer */
-table.mailer_fieldtable
+TABLE.mailer_fieldtable
{
top: 0px;
left: 0px;
padding-top: .5em;
overflow-y: auto;
overflow-x: hidden;
- height: 6.5em;
+ height: 7.5em;
border-bottom: 1px solid #808080;
background: #d4d0c8;
}
-div.mailer_mailcontent
+DIV.mailer_mailcontent
{
background-color: #fff;
position: absolute;
padding: .5em;
- margin-top: .5em;
- top: 10em;
+ top: 7.5em;
overflow: auto;
left: 0px;
right: 0px;
bottom: 0px;
}
-DIV#messageContent div.mailer_mailcontent
-{
- top: 6em;
-}
-
td.mailer_fieldname
{
white-space: nowrap;
/* attachment link viewer */
-div.linked_attachment_frame
-{
- background-color: #dcdad5;
- padding: 4px;
-}
+DIV.linked_attachment_frame
+{ border: 0px; }
-div.linked_attachment_body
-{
- padding: 4px;
- border-width: 1px;
- border-style: solid;
- border-top-color: white;
- border-left-color: white;
- border-bottom-color: #808080;
- border-right-color: #808080;
-}
+DIV.linked_attachment_body
+{ border: 0px; }
-div.linked_attachment_meta
+DIV.linked_attachment_meta
{
color: #444444;
font-style: italic;
padding: 2px;
}
-table.linked_attachment_meta
+TABLE.linked_attachment_meta
{
color: #444444;
font-style: italic;
}
+DIV.bodyFields
+{
+ background: #efefef;
+ font-family: serif;
+ margin: 0.5em;
+}
+
+DIV.bodyFields SPAN.fieldName
+{ font-weight: bold; }
+
+DIV.bodyAdditionalFields
+{
+ background: #d4d0c8;
+}
+
DIV[datatype~="additional"] > A.node > SPAN.nodeName
{ color: #777;
font-style: italic; }
return true;
}
-/* mail editor */
-
-function validateEditorInput(sender) {
- var errortext = "";
- var field;
-
- field = document.pageform.subject;
- if (field.value == "")
- errortext = errortext + labels.error_missingsubject + "\n";
-
- if (!UIxRecipientSelectorHasRecipients())
- errortext = errortext + labels.error_missingrecipients + "\n";
-
- if (errortext.length > 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();
- // if everything is ok, close the window
- return true;
-}
-
-function clickedEditorAttach(sender) {
- var urlstr;
-
- urlstr = "viewAttachments";
- window.open(urlstr, "SOGo_attach",
- "width=320,height=320,resizable=1,scrollbars=1,toolbar=0," +
- "location=0,directories=0,status=0,menubar=0,copyhistory=0");
- return false; /* stop following the link */
-}
-
-function clickedEditorSave(sender) {
- document.pageform.action = "save";
- document.pageform.submit();
- refreshOpener();
- return true;
-}
-
-function clickedEditorDelete(sender) {
- document.pageform.action = "delete";
- document.pageform.submit();
- refreshOpener();
- window.close();
- return true;
-}
-
function openAddressbook(sender) {
var urlstr;
if (rows.length > 0) {
var url = (ApplicationBaseURL + currentMailbox + "/"
+ rows[0].substr(4) + "/viewsource");
- window.open(url);
+ window.open(url, "",
+ "width=680,height=520,resizable=1,scrollbars=1,toolbar=0,"
+ + "location=0,directories=0,status=0,menubar=0,copyhistory=0");
}
preventDefault(event);
if (!lasts)
lasts = 1;
- var eventDiv = newEventDIV(eventData[0], eventData[1], starts, lasts,
- null, null, title);
+ var eventDiv = newEventDIV(eventData[0], eventData[1], starts, lasts,
+ null, null, title);
siblings.push(eventDiv);
eventDiv.siblings = siblings;
var dayString = days[i].getDayString();
width: 38em;
padding-left: .5em; }
-div#compose_internetmarker {
- padding: 8px;
+div#compose_internetmarker
+{ padding: 8px;
text-align: center;
background-color: white;
border-color: red;
border-width: 2px;
- border-style: solid;
-}
+ border-style: solid; }
div#headerArea
{ border-top: 1px solid #fff;
padding-left: 5px;
border-left: 1px solid #888; }
+input.currentAttachment
+{ position: absolute;
+ top: 1em;
+ right: 1em; }
+
+input.attachment
+{ display: none; }
+
div#compose_attachments_list
-{
- width: 100%;
- height: 10em;
- background-color: #ffffff;
+{ background-color: #ffffff;
margin-left: 0px;
padding: 2px;
border-bottom: 1px solid #fff;
border-top: 2px solid #222;
border-left: 2px solid #222;
-moz-border-top-colors: #9c9a94 #000 transparent;
+ -moz-border-left-colors: #9c9a94 #000 transparent; }
+
+UL#attachments
+{ cursor: default;
+ margin: 0px;
+ padding: 0px;
+ width: 100%;
+ height: 10em;
+ border-bottom: 1px solid #fff;
+ border-right: 1px solid #fff;
+ border-top: 2px solid #222;
+ border-left: 2px solid #222;
+ background-color: #fff;
+ -moz-border-top-colors: #9c9a94 #000 transparent;
-moz-border-left-colors: #9c9a94 #000 transparent;
-}
+ list-style-type: none;
+ list-style-image: none;
+ overflow: auto;
+ overflow-x: hidden; }
+
+UL#attachments LI
+{ white-space: nowrap;
+ padding-bottom: 1px; }
+
+UL#attachments LI IMG
+{ vertical-align: bottom; }
DIV.pageContent TEXTAREA
{ position: absolute;
right: 0em;
bottom: 0em;
top: 17em; }
-
else
div.style.display = "";
}
+/* mail editor */
+
+function validateEditorInput(sender) {
+ var errortext = "";
+ var field;
+
+ field = document.pageform.subject;
+ if (field.value == "")
+ errortext = errortext + labels.error_missingsubject + "\n";
+
+ if (!UIxRecipientSelectorHasRecipients())
+ errortext = errortext + labels.error_missingrecipients + "\n";
+
+ if (errortext.length > 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);
+++ /dev/null
-/*
- Copyright (C) 2005 SKYRIX Software AG
-
- This file is part of OpenGroupware.org.
-
- OGo is free software; you can redistribute it and/or modify it under
- the terms of the GNU Lesser General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
-
- OGo is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
- License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with OGo; see the file COPYING. If not, write to the
- Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA.
-*/
-
-function updateAttachmentListInEditorWindow(sender) {
- var attachments;
-
- attachments = this.getAttachmentNames();
- window.opener.updateInlineAttachmentList(this, attachments);
-}
-
-function getAttachmentNames() {
- var e, s, names;
-
- e = document.getElementById('attachmentList');
- s = e.innerHTML;
- /* remove trailing delimiter */
- s = s.substr(0, s.length - 1);
- if (s == '') return null;
-
- /* probably no OS allows '/' in a file name */
- names = s.split('/');
- return names;
-}
newElement[i] = attributes[i];
if (htmlAttributes)
for (var i in htmlAttributes)
- newElement.setAttribute(i, attributes[i]);
+ newElement.setAttribute(i, htmlAttributes[i]);
if (parentNode)
parentNode.appendChild(newElement);