Monotone-Parent: e8bfb90da0079ca2c3e5079818a7e7532b26ea31

Monotone-Revision: 7d281c6a5f9cd3517f1a818c99070b3bba45594c

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2007-07-27T20:03:05
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
Wolfgang Sourdeau 2007-07-27 20:03:05 +00:00
parent 55bd55f9ae
commit e47039bb31
6 changed files with 351 additions and 74 deletions

View file

@ -1,5 +1,9 @@
2007-07-27 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* 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

View file

@ -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"; },

View file

@ -25,14 +25,17 @@
#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>
@ -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]];

View file

@ -9,16 +9,27 @@
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"

View file

@ -43,14 +43,13 @@ DIV#subjectRow INPUT
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;
@ -66,11 +65,16 @@ div#attachmentsArea
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;
@ -78,8 +82,32 @@ div#compose_attachments_list
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;
@ -87,4 +115,3 @@ DIV.pageContent TEXTAREA
right: 0em;
bottom: 0em;
top: 17em; }

View file

@ -120,3 +120,150 @@ function updateInlineAttachmentList(sender, attachments) {
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);