merge of '0a3d8971fb4a3b2c5dfbe3f501204e4f46f3ce96'

and '411e18da9b8303cd9a4927e92d807baf5025523f'

Monotone-Parent: 0a3d8971fb4a3b2c5dfbe3f501204e4f46f3ce96
Monotone-Parent: 411e18da9b8303cd9a4927e92d807baf5025523f
Monotone-Revision: b8739c38c2f4892f1fb2d687073e8cd5538e75f8

Monotone-Author: flachapelle@inverse.ca
Monotone-Date: 2007-10-25T19:22:23
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
Francis Lachapelle
2007-10-25 19:22:23 +00:00
9 changed files with 250 additions and 92 deletions
+24
View File
@@ -1,3 +1,27 @@
2007-10-25 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* SoObjects/Mailer/NSData+Mail.m ([NSData
-bodyDataFromEncoding:encoding]): new utility method that decodes
the NSData instance properly depending on the encoding string
passed as parameter.
* SoObjects/Mailer/SOGoMailObject+Draft.m ([SOGoMailObject
-fetchFileAttachmentKeys]): fetch the attachment encoding as well.
* SoObjects/Mailer/SOGoMailObject.m ([SOGoMailObject
-stringForData:_datapartInfo:_info]): simplified by invoking
-bodyDataFromEncoding: from our new NSData category methods.
* SoObjects/Mailer/SOGoDraftObject.m ([SOGoDraftObject
-fetchMailForEditing:sourceMail]): work-around a bug in SOPE-mime
where only the body part of the first of the keys fetched was
returned. Also decodes the body parts properly following their
encoding.
* SoObjects/Mailer/NSData+Mail.[hm]: new extension module that
extends the NSData class with utility methods useful for handling
mail.
2007-10-23 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* SoObjects/SOGo/NSArray+Utilities.m
+3 -1
View File
@@ -30,7 +30,9 @@ Mailer_OBJC_FILES += \
SOGoDraftsFolder.m \
SOGoDraftObject.m \
\
SOGoMailForward.m
SOGoMailForward.m \
\
NSData+Mail.m
Mailer_RESOURCE_FILES += \
Version \
+36
View File
@@ -0,0 +1,36 @@
/* NSData+Mail.h - this file is part of SOGo
*
* Copyright (C) 2007 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef NSDATA_MAIL_H
#define NSDATA_MAIL_H
#import <Foundation/NSData.h>
@class NSString;
@interface NSData (SOGoMailUtilities)
- (NSData *) bodyDataFromEncoding: (NSString *) encoding;
@end
#endif /* NSDATA_MAIL_H */
+55
View File
@@ -0,0 +1,55 @@
/* NSData+Mail.m - this file is part of SOGo
*
* Copyright (C) 2007 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSString.h>
#import <NGExtensions/NGBase64Coding.h>
#import <NGExtensions/NGQuotedPrintableCoding.h>
#import "NSData+Mail.h"
@implementation NSData (SOGoMailUtilities)
- (NSData *) bodyDataFromEncoding: (NSString *) encoding
{
NSString *realEncoding;
NSData *decodedData;
realEncoding = [encoding lowercaseString];
if ([realEncoding isEqualToString: @"7bit"]
|| [realEncoding isEqualToString: @"8bit"])
decodedData = self;
else if ([realEncoding isEqualToString: @"base64"])
decodedData = [self dataByDecodingBase64];
else if ([realEncoding isEqualToString: @"quoted-printable"])
decodedData = [self dataByDecodingQuotedPrintable];
else
{
decodedData = nil;
NSLog (@"encoding '%@' unknown, returning nil data", realEncoding);
}
return decodedData;
}
@end
+36 -15
View File
@@ -56,6 +56,8 @@
#import <SoObjects/SOGo/NSString+Utilities.h>
#import <SoObjects/SOGo/SOGoMailer.h>
#import <SoObjects/SOGo/SOGoUser.h>
#import "NSData+Mail.h"
#import "SOGoMailAccount.h"
#import "SOGoMailFolder.h"
#import "SOGoMailObject.h"
@@ -411,30 +413,49 @@ static BOOL showTextAttachmentsInline = NO;
}
}
- (NSArray *) _attachmentBodiesFromPaths: (NSArray *) paths
fromResponseFetch: (NSDictionary *) fetch;
{
NSEnumerator *attachmentKeys;
NSMutableArray *bodies;
NSString *currentKey;
NSDictionary *body;
bodies = [NSMutableArray array];
attachmentKeys = [paths objectEnumerator];
while ((currentKey = [attachmentKeys nextObject]))
{
body = [fetch objectForKey: [currentKey lowercaseString]];
[bodies addObject: [body objectForKey: @"data"]];
}
return bodies;
}
- (void) _fetchAttachments: (NSArray *) parts
fromMail: (SOGoMailObject *) sourceMail
{
unsigned int count, max;
NSDictionary *currentPart, *attachment, *body;
NSArray *paths, *result;
NSArray *paths, *bodies;
NSData *body;
NSDictionary *currentInfo;
NGHashMap *response;
max = [parts count];
if (max > 0)
{
paths = [parts keysWithFormat: @"BODY[%{path}]"];
result = [[sourceMail fetchParts: paths] objectForKey: @"fetch"];
response = [[sourceMail fetchParts: paths] objectForKey: @"RawResponse"];
bodies = [self _attachmentBodiesFromPaths: paths
fromResponseFetch: [response objectForKey: @"fetch"]];
for (count = 0; count < max; count++)
{
currentPart = [parts objectAtIndex: count];
body = [[result objectAtIndex: count] objectForKey: @"body"];
attachment = [NSDictionary dictionaryWithObjectsAndKeys:
[currentPart objectForKey: @"filename"],
@"filename",
[currentPart objectForKey: @"mimetype"],
@"mime-type",
nil];
[self saveAttachment: [body objectForKey: @"data"]
withMetadata: attachment];
currentInfo = [parts objectAtIndex: count];
body = [[bodies objectAtIndex: count]
bodyDataFromEncoding: [currentInfo
objectForKey: @"encoding"]];
[self saveAttachment: body withMetadata: currentInfo];
}
}
}
@@ -529,7 +550,7 @@ static BOOL showTextAttachmentsInline = NO;
// error = [newDraft saveAttachment:content withName:@"forward.mail"];
attachment = [NSDictionary dictionaryWithObjectsAndKeys:
[sourceMail filenameForForward], @"filename",
@"message/rfc822", @"mime-type",
@"message/rfc822", @"mimetype",
nil];
[self saveAttachment: [sourceMail content]
withMetadata: attachment];
@@ -639,7 +660,7 @@ static BOOL showTextAttachmentsInline = NO;
reason: @"Could not write attachment to draft!"];
}
mimeType = [metadata objectForKey: @"mime-type"];
mimeType = [metadata objectForKey: @"mimetype"];
if ([mimeType length] > 0)
{
p = [self pathToAttachmentWithName:
+7 -5
View File
@@ -232,20 +232,22 @@
intoArray: (NSMutableArray *) keys
withPath: (NSString *) path
{
NSDictionary *parameters, *currentFile;
NSDictionary *disposition, *currentFile;
NSString *filename, *mimeType;
parameters = [[part objectForKey: @"disposition"]
objectForKey: @"parameterList"];
if (parameters)
disposition = [part objectForKey: @"disposition"];
filename = [[disposition objectForKey: @"parameterList"]
objectForKey: @"filename"];
if (filename)
{
filename = [parameters objectForKey: @"filename"];
mimeType = [NSString stringWithFormat: @"%@/%@",
[part objectForKey: @"type"],
[part objectForKey: @"subtype"]];
currentFile = [NSDictionary dictionaryWithObjectsAndKeys:
filename, @"filename",
[mimeType lowercaseString], @"mimetype",
[part
objectForKey: @"encoding"], @"encoding",
path, @"path", nil];
[keys addObject: currentFile];
}
+17 -25
View File
@@ -31,10 +31,8 @@
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WOResponse.h>
#import <NGObjWeb/NSException+HTTP.h>
#import <NGExtensions/NGBase64Coding.h>
#import <NGExtensions/NSNull+misc.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NGQuotedPrintableCoding.h>
#import <NGExtensions/NSString+Encoding.h>
#import <NGExtensions/NSString+misc.h>
#import <NGImap4/NGImap4Connection.h>
@@ -44,6 +42,8 @@
#import <SoObjects/SOGo/SOGoPermissions.h>
#import <SoObjects/SOGo/SOGoUser.h>
#import "NSData+Mail.h"
#import "SOGoMailFolder.h"
#import "SOGoMailAccount.h"
#import "SOGoMailManager.h"
@@ -619,37 +619,29 @@ static BOOL debugSoParts = NO;
}
/* convert parts to strings */
- (NSString *) stringForData: (NSData *) _data
partInfo: (NSDictionary *) _info
{
NSString *charset, *encoding, *s;
NSString *charset, *s;
NSData *mailData;
if (![_data isNotNull])
return nil;
s = nil;
encoding = [[_info objectForKey: @"encoding"] lowercaseString];
if ([encoding isEqualToString: @"7bit"]
|| [encoding isEqualToString: @"8bit"])
mailData = _data;
else if ([encoding isEqualToString: @"base64"])
mailData = [_data dataByDecodingBase64];
else if ([encoding isEqualToString: @"quoted-printable"])
mailData = [_data dataByDecodingQuotedPrintable];
charset = [[_info valueForKey: @"parameterList"] valueForKey: @"charset"];
if (![charset length])
if ([_data isNotNull])
{
s = [[NSString alloc] initWithData:mailData encoding:NSUTF8StringEncoding];
[s autorelease];
mailData
= [_data bodyDataFromEncoding: [_info objectForKey: @"encoding"]];
charset = [[_info valueForKey: @"parameterList"] valueForKey: @"charset"];
if (![charset length])
{
s = [[NSString alloc] initWithData: mailData encoding: NSUTF8StringEncoding];
[s autorelease];
}
else
s = [NSString stringWithData: mailData
usingEncodingNamed: charset];
}
else
s = [NSString stringWithData: mailData
usingEncodingNamed: charset];
s = nil;
return s;
}
+6 -5
View File
@@ -280,13 +280,14 @@ static NSArray *infoKeys = nil;
for (count = 0; count < max; count++)
{
part = [parts objectAtIndex: count];
header = (NGMimeContentDispositionHeaderField *) [part headerForKey: @"content-disposition"];
mimeType = [(NGMimeType *) [part headerForKey: @"content-type"] stringValue];
header = (NGMimeContentDispositionHeaderField *)
[part headerForKey: @"content-disposition"];
mimeType = [(NGMimeType *)
[part headerForKey: @"content-type"] stringValue];
attachment = [NSDictionary dictionaryWithObjectsAndKeys:
[header filename], @"filename",
mimeType, @"mime-type", nil];
[filenames setObject: attachment
forKey: [header name]];
mimeType, @"mimetype", nil];
[filenames setObject: attachment forKey: [header name]];
}
return filenames;
+66 -41
View File
@@ -16,7 +16,7 @@ function onContactAdd() {
w.focus();
return false;
}
}
function addContact(tag, fullContactName, contactId, contactName, contactEmail) {
if (!mailIsRecipient(contactEmail)) {
@@ -121,59 +121,76 @@ function updateInlineAttachmentList(sender, attachments) {
/* mail editor */
function validateEditorInput(sender) {
var errortext = "";
var field;
var errortext = "";
var field;
field = document.pageform.subject;
if (field.value == "")
errortext = errortext + labels["error_missingsubject"] + "\n";
field = document.pageform.subject;
if (field.value == "")
errortext = errortext + labels["error_missingsubject"] + "\n";
if (!UIxRecipientSelectorHasRecipients())
errortext = errortext + labels["error_missingrecipients"] + "\n";
if (!UIxRecipientSelectorHasRecipients())
errortext = errortext + labels["error_missingrecipients"] + "\n";
if (errortext.length > 0) {
alert(labels["error_validationfailed"] + ":\n" + errortext);
return false;
}
if (errortext.length > 0) {
alert(labels["error_validationfailed"] + ":\n" + errortext);
return false;
}
return true;
return true;
}
function clickedEditorSend(sender) {
if (!validateEditorInput(sender))
return false;
if (!validateEditorInput(sender))
return false;
window.shouldPreserve = true;
document.pageform.action = "send";
document.pageform.submit();
var input = currentAttachmentInput();
if (input)
input.parentNode.removeChild(input);
return false;
var toolbar = document.getElementById("toolbar");
if (!document.busyAnim)
document.busyAnim = startAnimation(toolbar);
window.shouldPreserve = true;
document.pageform.action = "send";
document.pageform.submit();
return false;
}
function currentAttachmentInput() {
var input = null;
var inputs = $("attachmentsArea").getElementsByTagName("input");
var i = 0;
while (!input && i < inputs.length)
if ($(inputs[i]).hasClassName("currentAttachment"))
input = inputs[i];
else
i++;
return input;
}
function clickedEditorAttach(sender) {
var area = $("attachmentsArea");
var input = currentAttachmentInput();
if (!input) {
var area = $("attachmentsArea");
if (!area.style.display) {
area.setStyle({ display: "block" });
onWindowResize(null);
}
var inputs = area.getElementsByTagName("input");
// Verify if there's already a visible file input field
for (var i = 0; i < inputs.length; i++)
if ($(inputs[i]).hasClassName("currentAttachment"))
return false;
// Add new file input field
var attachmentName = "attachment" + inputs.length;
var newAttachment = createElement("input", attachmentName,
"currentAttachment", null,
{ type: "file",
name: attachmentName },
area);
Event.observe(newAttachment, "change",
onAttachmentChange.bindAsEventListener(newAttachment));
if (!area.style.display) {
area.setStyle({ display: "block" });
onWindowResize(null);
}
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;
}
@@ -211,6 +228,14 @@ function createAttachment(node, list) {
}
function clickedEditorSave(sender) {
var input = currentAttachmentInput();
if (input)
input.parentNode.removeChild(input);
var toolbar = document.getElementById("toolbar");
if (!document.busyAnim)
document.busyAnim = startAnimation(toolbar);
window.shouldPreserve = true;
document.pageform.action = "save";
document.pageform.submit();