mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-04-10 15:58:52 +00:00
Monotone-Parent: 3beea562a57fe58bc0ec7f6ec1ea8b43840f6655
Monotone-Revision: d5bcd77c68cb679b5a1b9a23a4cc86038b0e615e Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2008-08-22T18:43:08 Monotone-Branch: ca.inverse.sogo
This commit is contained in:
@@ -1,3 +1,12 @@
|
||||
2008-08-22 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* SoObjects/Mailer/SOGoHTMLMailBodyPart.[hm]: new class module
|
||||
implementing the HTML content body parts.
|
||||
|
||||
* UI/MailPartViewers/UIxMailPartHTMLViewer.m
|
||||
([UIxMailPartExternalHTMLViewer -init]): new class derived from
|
||||
UIxMailPartHTMLViewer but which as as a full page wrapper.
|
||||
|
||||
2008-08-22 Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
|
||||
* Modified SoObjects/Mailer/NSData+Mail.m
|
||||
|
||||
@@ -23,6 +23,7 @@ Mailer_OBJC_FILES += \
|
||||
SOGoTrashFolder.m \
|
||||
\
|
||||
SOGoMailBodyPart.m \
|
||||
SOGoHTMLMailBodyPart.m \
|
||||
SOGoImageMailBodyPart.m \
|
||||
SOGoMessageMailBodyPart.m \
|
||||
SOGoCalendarMailBodyPart.m \
|
||||
|
||||
62
SoObjects/Mailer/SOGoHTMLMailBodyPart.m
Normal file
62
SoObjects/Mailer/SOGoHTMLMailBodyPart.m
Normal file
@@ -0,0 +1,62 @@
|
||||
/* SOGoHTMLMailBodyPart.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2008 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 <NGObjWeb/SoClass.h>
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/WOResponse.h>
|
||||
#import <NGObjWeb/WORequest+So.h>
|
||||
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
|
||||
#import "SOGoMailBodyPart.h"
|
||||
|
||||
@interface SOGoHTMLMailBodyPart : SOGoMailBodyPart
|
||||
|
||||
@end
|
||||
|
||||
@implementation SOGoHTMLMailBodyPart
|
||||
|
||||
- (id) GETAction: (id) localContext
|
||||
{
|
||||
WORequest *request;
|
||||
NSString *uri;
|
||||
id response;
|
||||
|
||||
request = [localContext request];
|
||||
if ([request isSoWebDAVRequest])
|
||||
response = [super GETAction: localContext];
|
||||
else
|
||||
{
|
||||
response = [localContext response];
|
||||
uri = [[request uri] composeURLWithAction: @"view"
|
||||
parameters: [request formValues]
|
||||
andHash: NO];
|
||||
[response setStatus: 302 /* moved */];
|
||||
[response setHeader: uri forKey: @"location"];
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -353,57 +353,58 @@ static BOOL debugOn = NO;
|
||||
|
||||
/* actions */
|
||||
|
||||
- (id)GETAction:(id)_ctx {
|
||||
- (id) GETAction: (WOContext *) localContext
|
||||
{
|
||||
NSException *error;
|
||||
WOResponse *r;
|
||||
NSData *data;
|
||||
NSString *etag, *mimeType, *fileName;
|
||||
id response;
|
||||
|
||||
if ((error = [self matchesRequestConditionInContext:_ctx]) != nil) {
|
||||
// TODO: currently we fetch the body structure to get here - check this!
|
||||
/* check whether the mail still exists */
|
||||
if (![[self mailObject] doesMailExist]) {
|
||||
return [NSException exceptionWithHTTPStatus:404 /* Not Found */
|
||||
reason:@"mail was deleted"];
|
||||
error = [self matchesRequestConditionInContext: localContext];
|
||||
if (error)
|
||||
{
|
||||
response = error; /* return 304 or 416 */
|
||||
}
|
||||
return error; /* return 304 or 416 */
|
||||
}
|
||||
|
||||
[self debugWithFormat:@"should fetch body part: %@",
|
||||
[self bodyPartIdentifier]];
|
||||
|
||||
if ((data = [self fetchBLOB]) == nil) {
|
||||
return [NSException exceptionWithHTTPStatus:404 /* not found */
|
||||
reason:@"did not find body part"];
|
||||
}
|
||||
|
||||
[self debugWithFormat:@" fetched %d bytes: %@", [data length],
|
||||
[self partInfo]];
|
||||
else
|
||||
{
|
||||
// [self debugWithFormat: @"should fetch body part: %@",
|
||||
// [self bodyPartIdentifier]];
|
||||
data = [self fetchBLOB];
|
||||
if (data)
|
||||
{
|
||||
// [self debugWithFormat:@" fetched %d bytes: %@", [data length],
|
||||
// [self partInfo]];
|
||||
|
||||
// TODO: wrong, could be encoded
|
||||
r = [(WOContext *)_ctx response];
|
||||
mimeType = [self davContentType];
|
||||
if ([mimeType isEqualToString: @"application/x-xpinstall"])
|
||||
mimeType = @"application/octet-stream";
|
||||
|
||||
[r setHeader: mimeType forKey:@"content-type"];
|
||||
[r setHeader: [NSString stringWithFormat:@"%d", [data length]]
|
||||
forKey: @"content-length"];
|
||||
response = [localContext response];
|
||||
mimeType = [self davContentType];
|
||||
if ([mimeType isEqualToString: @"application/x-xpinstall"])
|
||||
mimeType = @"application/octet-stream";
|
||||
|
||||
[response setHeader: mimeType forKey: @"content-type"];
|
||||
[response setHeader: [NSString stringWithFormat:@"%d", [data length]]
|
||||
forKey: @"content-length"];
|
||||
|
||||
if (asAttachment)
|
||||
{
|
||||
fileName = [self filename];
|
||||
if ([fileName length])
|
||||
[r setHeader: [NSString stringWithFormat: @"attachment; filename=%@", fileName]
|
||||
forKey: @"content-disposition"];
|
||||
if (asAttachment)
|
||||
{
|
||||
fileName = [self filename];
|
||||
if ([fileName length])
|
||||
[response setHeader: [NSString stringWithFormat: @"attachment; filename=%@", fileName]
|
||||
forKey: @"content-disposition"];
|
||||
}
|
||||
|
||||
etag = [self davEntityTag];
|
||||
if (etag)
|
||||
[response setHeader: etag forKey: @"etag"];
|
||||
|
||||
[response setContent: data];
|
||||
}
|
||||
else
|
||||
response = [NSException exceptionWithHTTPStatus: 404 /* not found */
|
||||
reason: @"did not find body part"];
|
||||
}
|
||||
|
||||
if ((etag = [self davEntityTag]) != nil)
|
||||
[r setHeader:etag forKey:@"etag"];
|
||||
|
||||
[r setContent:data];
|
||||
|
||||
return r;
|
||||
return response;
|
||||
}
|
||||
|
||||
/* factory */
|
||||
@@ -454,6 +455,8 @@ static BOOL debugOn = NO;
|
||||
else if ([mimeType isEqualToString: @"text/calendar"]
|
||||
|| [mimeType isEqualToString: @"application/ics"])
|
||||
classString = @"SOGoCalendarMailBodyPart";
|
||||
else if ([mimeType isEqualToString: @"text/html"])
|
||||
classString = @"SOGoHTMLMailBodyPart";
|
||||
else if ([mimeType isEqualToString: @"text/x-vcard"])
|
||||
classString = @"SOGoVCardMailBodyPart";
|
||||
else if ([mimeType isEqualToString: @"message/rfc822"])
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
SOGoMailBodyPart = {
|
||||
superclass = "SOGoMailBaseObject";
|
||||
};
|
||||
SOGoHTMLMailBodyPart = {
|
||||
superclass = "SOGoMailBodyPart";
|
||||
};
|
||||
SOGoImageMailBodyPart = {
|
||||
superclass = "SOGoMailBodyPart";
|
||||
};
|
||||
|
||||
@@ -878,7 +878,7 @@ SEL SOGoSelectorForPropertySetter (NSString *property)
|
||||
NSException *error;
|
||||
id value;
|
||||
|
||||
request = [localContext request];
|
||||
request = [localContext request];
|
||||
if ([request isSoWebDAVRequest])
|
||||
{
|
||||
if ([self respondsToSelector: @selector (contentAsString)])
|
||||
|
||||
@@ -34,4 +34,13 @@
|
||||
|
||||
@end
|
||||
|
||||
@interface UIxMailPartExternalHTMLViewer : UIxMailPartViewer
|
||||
{
|
||||
id handler;
|
||||
}
|
||||
|
||||
- (NSString *) flatContentAsString;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* UIXMAILPARTHTMLVIEWER_H */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* UIxMailPartHTMLViewer.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007 Inverse groupe conseil
|
||||
* Copyright (C) 2007, 2008 Inverse groupe conseil
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
*
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <libxml/encoding.h>
|
||||
|
||||
#import <SoObjects/Mailer/SOGoMailObject.h>
|
||||
#import <SoObjects/Mailer/SOGoMailBodyPart.h>
|
||||
|
||||
#import "UIxMailPartHTMLViewer.h"
|
||||
|
||||
@@ -46,6 +47,52 @@
|
||||
#define showWhoWeAre()
|
||||
#endif
|
||||
|
||||
static xmlCharEncoding
|
||||
_xmlCharsetForCharset (NSString *charset)
|
||||
{
|
||||
struct { NSString *name; xmlCharEncoding encoding; } xmlEncodings[] = {
|
||||
{ @"us-ascii", XML_CHAR_ENCODING_ASCII},
|
||||
{ @"utf-8", XML_CHAR_ENCODING_UTF8},
|
||||
{ @"utf-16le", XML_CHAR_ENCODING_UTF16LE},
|
||||
{ @"utf-16be", XML_CHAR_ENCODING_UTF16BE},
|
||||
{ @"ucs-4le", XML_CHAR_ENCODING_UCS4LE},
|
||||
{ @"ucs-4be", XML_CHAR_ENCODING_UCS4BE},
|
||||
{ @"ebcdic", XML_CHAR_ENCODING_EBCDIC},
|
||||
// { @"iso-10646" , XML_CHAR_ENCODING_UCS4_2143},
|
||||
// { , XML_CHAR_ENCODING_UCS4_3412},
|
||||
// { @"ucs-2", XML_CHAR_ENCODING_UCS2},
|
||||
{ @"iso8859_1", XML_CHAR_ENCODING_8859_1},
|
||||
{ @"iso-8859-1", XML_CHAR_ENCODING_8859_1},
|
||||
{ @"iso-8859-2", XML_CHAR_ENCODING_8859_2},
|
||||
{ @"iso-8859-3", XML_CHAR_ENCODING_8859_3},
|
||||
{ @"iso-8859-4", XML_CHAR_ENCODING_8859_4},
|
||||
{ @"iso-8859-5", XML_CHAR_ENCODING_8859_5},
|
||||
{ @"iso-8859-6", XML_CHAR_ENCODING_8859_6},
|
||||
{ @"iso-8859-7", XML_CHAR_ENCODING_8859_7},
|
||||
{ @"iso-8859-8", XML_CHAR_ENCODING_8859_8},
|
||||
{ @"iso-8859-9", XML_CHAR_ENCODING_8859_9},
|
||||
{ @"iso-2022-jp", XML_CHAR_ENCODING_2022_JP},
|
||||
// { @"iso-2022-jp", XML_CHAR_ENCODING_SHIFT_JIS},
|
||||
{ @"euc-jp", XML_CHAR_ENCODING_EUC_JP}};
|
||||
unsigned count;
|
||||
xmlCharEncoding encoding;
|
||||
|
||||
encoding = XML_CHAR_ENCODING_NONE;
|
||||
count = 0;
|
||||
|
||||
while (encoding == XML_CHAR_ENCODING_NONE
|
||||
&& count < (sizeof (xmlEncodings) / sizeof (xmlEncodings[0])))
|
||||
if ([charset isEqualToString: xmlEncodings[count].name])
|
||||
encoding = xmlEncodings[count].encoding;
|
||||
else
|
||||
count++;
|
||||
|
||||
if (encoding == XML_CHAR_ENCODING_NONE)
|
||||
encoding = XML_CHAR_ENCODING_8859_1;
|
||||
|
||||
return encoding;
|
||||
}
|
||||
|
||||
@interface _UIxHTMLMailContentHandler : NSObject <SaxContentHandler, SaxLexicalHandler>
|
||||
{
|
||||
NSMutableString *result;
|
||||
@@ -227,7 +274,7 @@
|
||||
{
|
||||
resultPart = [NSMutableString new];
|
||||
[resultPart appendFormat: @"<%@", _rawName];
|
||||
|
||||
|
||||
max = [_attributes count];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
@@ -248,6 +295,14 @@
|
||||
else
|
||||
skipAttribute = YES;
|
||||
}
|
||||
else if ([name caseInsensitiveCompare: @"href"] == NSOrderedSame
|
||||
|| [name caseInsensitiveCompare: @"action"] == NSOrderedSame)
|
||||
{
|
||||
value = [_attributes valueAtIndex: count];
|
||||
skipAttribute = ([value rangeOfString: @"://"].location
|
||||
== NSNotFound
|
||||
&& ![value hasPrefix: @"#"]);
|
||||
}
|
||||
else
|
||||
value = [_attributes valueAtIndex: count];
|
||||
if (!skipAttribute)
|
||||
@@ -258,6 +313,7 @@
|
||||
|
||||
[resultPart appendString: @">"];
|
||||
[result appendString: resultPart];
|
||||
[resultPart release];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,62 +493,16 @@
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (xmlCharEncoding) _xmlCharsetForCharset: (NSString *) charset
|
||||
{
|
||||
struct { NSString *name; xmlCharEncoding encoding; } xmlEncodings[] = {
|
||||
{ @"us-ascii", XML_CHAR_ENCODING_ASCII},
|
||||
{ @"utf-8", XML_CHAR_ENCODING_UTF8},
|
||||
{ @"utf-16le", XML_CHAR_ENCODING_UTF16LE},
|
||||
{ @"utf-16be", XML_CHAR_ENCODING_UTF16BE},
|
||||
{ @"ucs-4le", XML_CHAR_ENCODING_UCS4LE},
|
||||
{ @"ucs-4be", XML_CHAR_ENCODING_UCS4BE},
|
||||
{ @"ebcdic", XML_CHAR_ENCODING_EBCDIC},
|
||||
// { @"iso-10646" , XML_CHAR_ENCODING_UCS4_2143},
|
||||
// { , XML_CHAR_ENCODING_UCS4_3412},
|
||||
// { @"ucs-2", XML_CHAR_ENCODING_UCS2},
|
||||
{ @"iso8859_1", XML_CHAR_ENCODING_8859_1},
|
||||
{ @"iso-8859-1", XML_CHAR_ENCODING_8859_1},
|
||||
{ @"iso-8859-2", XML_CHAR_ENCODING_8859_2},
|
||||
{ @"iso-8859-3", XML_CHAR_ENCODING_8859_3},
|
||||
{ @"iso-8859-4", XML_CHAR_ENCODING_8859_4},
|
||||
{ @"iso-8859-5", XML_CHAR_ENCODING_8859_5},
|
||||
{ @"iso-8859-6", XML_CHAR_ENCODING_8859_6},
|
||||
{ @"iso-8859-7", XML_CHAR_ENCODING_8859_7},
|
||||
{ @"iso-8859-8", XML_CHAR_ENCODING_8859_8},
|
||||
{ @"iso-8859-9", XML_CHAR_ENCODING_8859_9},
|
||||
{ @"iso-2022-jp", XML_CHAR_ENCODING_2022_JP},
|
||||
// { @"iso-2022-jp", XML_CHAR_ENCODING_SHIFT_JIS},
|
||||
{ @"euc-jp", XML_CHAR_ENCODING_EUC_JP}};
|
||||
unsigned count;
|
||||
xmlCharEncoding encoding;
|
||||
|
||||
encoding = XML_CHAR_ENCODING_NONE;
|
||||
count = 0;
|
||||
|
||||
while (encoding == XML_CHAR_ENCODING_NONE
|
||||
&& count < (sizeof (xmlEncodings) / sizeof (xmlEncodings[0])))
|
||||
if ([charset isEqualToString: xmlEncodings[count].name])
|
||||
encoding = xmlEncodings[count].encoding;
|
||||
else
|
||||
count++;
|
||||
|
||||
if (encoding == XML_CHAR_ENCODING_NONE)
|
||||
encoding = XML_CHAR_ENCODING_8859_1;
|
||||
|
||||
return encoding;
|
||||
}
|
||||
|
||||
- (xmlCharEncoding) _xmlCharEncoding
|
||||
{
|
||||
|
||||
NSString *charset;
|
||||
|
||||
charset = [[bodyInfo objectForKey:@"parameterList"]
|
||||
objectForKey: @"charset"];
|
||||
if (![charset length])
|
||||
charset = @"us-ascii";
|
||||
|
||||
return [self _xmlCharsetForCharset: [charset lowercaseString]];
|
||||
|
||||
return _xmlCharsetForCharset ([charset lowercaseString]);
|
||||
}
|
||||
|
||||
- (void) _parseContent
|
||||
@@ -541,3 +551,91 @@
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation UIxMailPartExternalHTMLViewer
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
handler = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[handler release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (xmlCharEncoding) _xmlCharEncoding
|
||||
{
|
||||
NSString *charset;
|
||||
|
||||
charset = [[bodyInfo objectForKey:@"parameterList"]
|
||||
objectForKey: @"charset"];
|
||||
if (![charset length])
|
||||
charset = @"us-ascii";
|
||||
|
||||
return _xmlCharsetForCharset ([charset lowercaseString]);
|
||||
}
|
||||
|
||||
- (void) _parseContent
|
||||
{
|
||||
NSObject <SaxXMLReader> *parser;
|
||||
NSData *preparsedContent;
|
||||
SOGoMailObject *mail;
|
||||
SOGoMailBodyPart *part;
|
||||
NSString *encoding;
|
||||
|
||||
part = [self clientObject];
|
||||
mail = [part mailObject];
|
||||
|
||||
preparsedContent = [part fetchBLOB];
|
||||
parser = [[SaxXMLReaderFactory standardXMLReaderFactory]
|
||||
createXMLReaderForMimeType: @"text/html"];
|
||||
encoding = [[part partInfo] valueForKey: @"encoding"];
|
||||
if (![encoding length])
|
||||
encoding = @"us-ascii";
|
||||
|
||||
handler = [_UIxHTMLMailContentHandler new];
|
||||
[handler setAttachmentIds: [mail fetchAttachmentIds]];
|
||||
[handler setContentEncoding: _xmlCharsetForCharset (encoding)];
|
||||
[parser setContentHandler: handler];
|
||||
[parser parseFromSource: preparsedContent];
|
||||
}
|
||||
|
||||
- (NSString *) filename
|
||||
{
|
||||
return [[self clientObject] filename];
|
||||
}
|
||||
|
||||
- (NSString *) cssContent
|
||||
{
|
||||
NSString *cssContent, *css;
|
||||
|
||||
if (!handler)
|
||||
[self _parseContent];
|
||||
|
||||
css = [handler css];
|
||||
if ([css length])
|
||||
cssContent
|
||||
= [NSString stringWithFormat: @"<style type=\"text/css\">%@</style>",
|
||||
[handler css]];
|
||||
else
|
||||
cssContent = @"";
|
||||
|
||||
return cssContent;
|
||||
}
|
||||
|
||||
- (NSString *) flatContentAsString
|
||||
{
|
||||
if (!handler)
|
||||
[self _parseContent];
|
||||
|
||||
return [handler result];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -8,6 +8,14 @@
|
||||
};
|
||||
|
||||
categories = {
|
||||
SOGoHTMLMailBodyPart = {
|
||||
methods = {
|
||||
view = {
|
||||
protectedBy = "View";
|
||||
pageName = "UIxMailPartExternalHTMLViewer";
|
||||
};
|
||||
};
|
||||
};
|
||||
SOGoCalendarMailBodyPart = {
|
||||
methods = {
|
||||
accept = {
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" standalone="yes"?>
|
||||
<!DOCTYPE var:component>
|
||||
<var:component 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"
|
||||
className="UIxPageFrame"
|
||||
const:popup="YES"
|
||||
const:toolbar="none"
|
||||
var:title="filename">
|
||||
<var:string value="cssContent" const:escapeHTML="NO" />
|
||||
<div class="SOGoHTMLMail-CSS-Delimiter mailer_htmlcontent"
|
||||
><var:string value="flatContentAsString" const:escapeHTML="NO" /></div>
|
||||
</var:component>
|
||||
4
UI/WebServerResources/UIxMailPartExternalHTMLViewer.css
Normal file
4
UI/WebServerResources/UIxMailPartExternalHTMLViewer.css
Normal file
@@ -0,0 +1,4 @@
|
||||
HTML, BODY
|
||||
{ background-color: #fff;
|
||||
font-size: normal;
|
||||
font-family: sans-serif; }
|
||||
Reference in New Issue
Block a user