Monotone-Parent: 2b043d9497bc939d7078d10d38953e92948da5aa
Monotone-Revision: ff9ea5325e680d04c8672e78e3bd74f60d7316c1 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-09-14T17:44:39 Monotone-Branch: ca.inverse.sogomaint-2.0.2
parent
dcf14c1b05
commit
6f9f415014
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
|||
2009-09-14 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* UI/MailPartViewers/UIxMailPartSignedViewer.[hm]: new module
|
||||
class that implements the viewer for multipart/signed messages.
|
||||
|
||||
* UI/WebServerResources/MailerUI.js (configureSignatureFlagImage):
|
||||
new method that check whether the message being displayed is
|
||||
signed and if so, displays the proper image depending on the
|
||||
validation status.
|
||||
|
||||
2009-09-14 Cyril Robert <crobert@inverse.ca>
|
||||
|
||||
* UI/Common/UIxPageFrame.m (commonLocalizableStrings): clabels are no longer
|
||||
|
|
1
NEWS
1
NEWS
|
@ -14,6 +14,7 @@
|
|||
- added support for remote ICS subscriptions
|
||||
- added support for ICS and vCard/LDIF import
|
||||
- added support for event delegation (resend an invitation to someone else)
|
||||
- added alpha support for checking and displaying signed messages
|
||||
|
||||
1.0-20090812 (1.0.4)
|
||||
--------------------
|
||||
|
|
|
@ -20,6 +20,7 @@ MailPartViewers_OBJC_FILES += \
|
|||
UIxMailPartImageViewer.m \
|
||||
UIxMailPartLinkViewer.m \
|
||||
UIxMailPartMixedViewer.m \
|
||||
UIxMailPartSignedViewer.m \
|
||||
UIxMailPartAlternativeViewer.m \
|
||||
UIxMailPartMessageViewer.m \
|
||||
UIxMailPartICalViewer.m \
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/* UIxMailPartSignedViewer.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2009 Inverse inc.
|
||||
*
|
||||
* 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 UIXMAILPARTSIGNEDVIEWER_H
|
||||
#define UIXMAILPARTSIGNEDVIEWER_H
|
||||
|
||||
#import "UIxMailPartViewer.h"
|
||||
|
||||
@class NSString;
|
||||
@class NGPart;
|
||||
|
||||
@interface UIxMailPartSignedViewer : UIxMailPartViewer
|
||||
{
|
||||
BOOL processed;
|
||||
NGPart *messagePart;
|
||||
|
||||
BOOL validSignature;
|
||||
NSString *validationError;
|
||||
}
|
||||
|
||||
- (NSString *) flatContentAsString;
|
||||
|
||||
- (BOOL) validSignature;
|
||||
- (NSString *) validationError;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* UIXMAILPARTSIGNEDVIEWER_H */
|
|
@ -0,0 +1,267 @@
|
|||
/* UIxMailPartSignedViewer.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2009 Inverse inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGMail/NGMimeMessage.h>
|
||||
#import <NGMail/NGMimeMessageParser.h>
|
||||
#import <NGMime/NGMimeBodyPart.h>
|
||||
#import <NGMime/NGMimeMultipartBody.h>
|
||||
#import <NGMime/NGMimeType.h>
|
||||
#import <NGMime/NGPart.h>
|
||||
|
||||
#import <Mailer/SOGoMailBodyPart.h>
|
||||
#import <Mailer/SOGoMailObject.h>
|
||||
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import <Mailer/NSString+Mail.h>
|
||||
|
||||
#import "UIxMailPartSignedViewer.h"
|
||||
|
||||
@interface NGMimeMessage (SOGoExtension)
|
||||
|
||||
- (id <NGMimePart>) mimePartFromPath: (NSArray *) path;
|
||||
|
||||
@end
|
||||
|
||||
@implementation NGMimeMessage (SOGoExtension)
|
||||
|
||||
- (id <NGMimePart>) mimePartFromPath: (NSArray *) path
|
||||
{
|
||||
int count, max, partNumber;
|
||||
BOOL overflow;
|
||||
id <NGMimePart> currentPart, foundPart;
|
||||
NSArray *parts;
|
||||
|
||||
foundPart = nil;
|
||||
overflow = NO;
|
||||
|
||||
currentPart = [self body];
|
||||
|
||||
max = [path count];
|
||||
for (count = 0; (!overflow && !foundPart) && count < max; count++)
|
||||
{
|
||||
partNumber = [[path objectAtIndex: count] intValue];
|
||||
if (partNumber == 0)
|
||||
foundPart = currentPart;
|
||||
else
|
||||
{
|
||||
if ([currentPart isKindOfClass: [NGMimeMultipartBody class]])
|
||||
{
|
||||
parts = [(NGMimeMultipartBody *) currentPart parts];
|
||||
if (partNumber <= [parts count])
|
||||
currentPart = [parts objectAtIndex: partNumber - 1];
|
||||
else
|
||||
overflow = YES;
|
||||
}
|
||||
else
|
||||
overflow = YES;
|
||||
}
|
||||
}
|
||||
if (!overflow)
|
||||
foundPart = currentPart;
|
||||
|
||||
return foundPart;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface NGMimeType (SOGoExtension)
|
||||
|
||||
- (BOOL) isEqualToString: (NSString *) otherType;
|
||||
|
||||
@end
|
||||
|
||||
@implementation NGMimeType (SOGoExtension)
|
||||
|
||||
- (BOOL) isEqualToString: (NSString *) otherType
|
||||
{
|
||||
NSString *thisString;
|
||||
|
||||
thisString = [NSString stringWithFormat: @"%@/%@",
|
||||
[self type], [self subType]];
|
||||
|
||||
return [thisString isEqualToString: otherType];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation UIxMailPartSignedViewer : UIxMailPartViewer
|
||||
|
||||
- (void) _setupParts
|
||||
{
|
||||
NSData *content;
|
||||
NGMimeMessageParser *parser;
|
||||
NGMimeMessage *message;
|
||||
NSArray *path;
|
||||
id co;
|
||||
NSArray *parts;
|
||||
|
||||
co = [self clientObject];
|
||||
|
||||
content = [co content];
|
||||
parser = [NGMimeMessageParser new];
|
||||
message = [parser parsePartFromData: content];
|
||||
if ([co respondsToSelector: @selector (bodyPartPath)])
|
||||
path = [(SOGoMailBodyPart *) co bodyPartPath];
|
||||
else
|
||||
path = [NSArray arrayWithObject: @"0"];
|
||||
parts = [(NGMimeMultipartBody *) [message mimePartFromPath: path] parts];
|
||||
if ([parts count] == 2)
|
||||
messagePart = [parts objectAtIndex: 0];
|
||||
|
||||
[parser release];
|
||||
}
|
||||
|
||||
- (NSString *) flatContentAsString
|
||||
{
|
||||
NSString *body, *content;
|
||||
NGMimeType *mimeType;
|
||||
|
||||
[self _setupParts];
|
||||
|
||||
mimeType = [messagePart contentType];
|
||||
if ([mimeType isEqualToString: @"text/plain"])
|
||||
{
|
||||
body = [[messagePart body] stringByEscapingHTMLString];
|
||||
content = [[body stringByDetectingURLs]
|
||||
stringByConvertingCRLNToHTML];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog (@"unhandled mime type in multipart/signed: '%@'", mimeType);
|
||||
content = nil;
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
- (X509_STORE *) _setupVerify
|
||||
{
|
||||
X509_STORE *store;
|
||||
X509_LOOKUP *lookup;
|
||||
BOOL success;
|
||||
|
||||
success = NO;
|
||||
|
||||
store = X509_STORE_new();
|
||||
|
||||
if (store)
|
||||
{
|
||||
lookup = X509_STORE_add_lookup(store,X509_LOOKUP_file());
|
||||
if (lookup)
|
||||
{
|
||||
X509_LOOKUP_load_file (lookup, NULL, X509_FILETYPE_DEFAULT);
|
||||
lookup = X509_STORE_add_lookup (store, X509_LOOKUP_hash_dir());
|
||||
if (lookup)
|
||||
{
|
||||
X509_LOOKUP_add_dir (lookup, NULL, X509_FILETYPE_DEFAULT);
|
||||
ERR_clear_error();
|
||||
success = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
if (store)
|
||||
{
|
||||
X509_STORE_free(store);
|
||||
store = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
- (void) _processMessage
|
||||
{
|
||||
BIO *msgBio, *inData;
|
||||
X509_STORE *x509Store;
|
||||
PKCS7 *p7;
|
||||
int err;
|
||||
NSData *signedData;
|
||||
char sslError[1024];
|
||||
|
||||
*sslError = 0;
|
||||
|
||||
ERR_clear_error();
|
||||
|
||||
signedData = [[self clientObject] content];
|
||||
msgBio = BIO_new_mem_buf ((void *) [signedData bytes], [signedData length]);
|
||||
|
||||
inData = NULL;
|
||||
p7 = SMIME_read_PKCS7 (msgBio, &inData);
|
||||
err = ERR_get_error();
|
||||
if (err)
|
||||
{
|
||||
ERR_error_string_n (err, sslError, 1023);
|
||||
validSignature = NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
x509Store = [self _setupVerify];
|
||||
validSignature = (PKCS7_verify(p7, NULL, x509Store, inData,
|
||||
NULL, PKCS7_DETACHED) == 1);
|
||||
|
||||
err = ERR_get_error();
|
||||
if (err)
|
||||
ERR_error_string_n (err, sslError, 1023);
|
||||
|
||||
if (x509Store)
|
||||
X509_STORE_free (x509Store);
|
||||
}
|
||||
|
||||
BIO_free (msgBio);
|
||||
if (inData)
|
||||
BIO_free (inData);
|
||||
|
||||
if (!validSignature)
|
||||
validationError = [NSString stringWithFormat: @"%s", sslError];
|
||||
|
||||
processed = YES;
|
||||
}
|
||||
|
||||
- (BOOL) validSignature
|
||||
{
|
||||
if (!processed)
|
||||
[self _processMessage];
|
||||
|
||||
return validSignature;
|
||||
}
|
||||
|
||||
- (NSString *) validationError
|
||||
{
|
||||
if (!processed)
|
||||
[self _processMessage];
|
||||
|
||||
return validationError;
|
||||
}
|
||||
|
||||
@end
|
|
@ -156,7 +156,7 @@
|
|||
|
||||
- (NSData *) content
|
||||
{
|
||||
return [[self clientPart] fetchBLOB];
|
||||
return [[self clientObject] fetchBLOB];
|
||||
}
|
||||
|
||||
- (NSString *) flatContentAsString
|
||||
|
|
|
@ -132,7 +132,7 @@ static BOOL showNamedTextAttachmentsInline = NO;
|
|||
/* Note: we cannot cache the multipart viewers, because it can be nested */
|
||||
// TODO: temporary workaround (treat it like a plain mixed part)
|
||||
|
||||
return [self mixedViewer];
|
||||
return [viewer pageWithName: @"UIxMailPartSignedViewer"];
|
||||
}
|
||||
|
||||
- (WOComponent *) alternativeViewer
|
||||
|
|
|
@ -331,6 +331,19 @@ INPUT#loadImagesButton
|
|||
right: 1em;
|
||||
}
|
||||
|
||||
#signedImage
|
||||
{
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
.popup #signedImage
|
||||
{
|
||||
top: 54px;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
TABLE.mailer_fieldtable
|
||||
{ top: 0px;
|
||||
left: 0px;
|
||||
|
|
|
@ -947,6 +947,7 @@ function loadMessage(idx) {
|
|||
}
|
||||
|
||||
configureLoadImagesButton();
|
||||
configureSignatureFlagImage();
|
||||
}
|
||||
|
||||
function configureLoadImagesButton() {
|
||||
|
@ -965,6 +966,30 @@ function configureLoadImagesButton() {
|
|||
}
|
||||
}
|
||||
|
||||
function configureSignatureFlagImage() {
|
||||
var signedPart = $("signedMessage");
|
||||
if (signedPart) {
|
||||
var loadImagesButton = $("loadImagesButton");
|
||||
var parentNode = loadImagesButton.parentNode;
|
||||
var valid = parseInt(signedPart.getAttribute("valid"));
|
||||
var flagImage;
|
||||
var error = null;
|
||||
if (valid) {
|
||||
flagImage = "signature-ok.png";
|
||||
} else {
|
||||
flagImage = "signature-not-ok.png";
|
||||
error = signedPart.getAttribute("error");
|
||||
}
|
||||
var attrs = { src: ResourcesURL + "/" + flagImage };
|
||||
if (error) {
|
||||
attrs["title"] = error;
|
||||
}
|
||||
var newImg = createElement("img", "signedImage", null,
|
||||
null, attrs);
|
||||
loadImagesButton.parentNode.insertBefore(newImg, loadImagesButton.nextSibling);
|
||||
}
|
||||
}
|
||||
|
||||
function configureLinksInMessage() {
|
||||
var messageDiv = $('messageContent');
|
||||
var mailContentDiv = document.getElementsByClassName('mailer_mailcontent',
|
||||
|
@ -1190,6 +1215,7 @@ function messageCallback(http) {
|
|||
configureLinksInMessage();
|
||||
resizeMailContent();
|
||||
configureLoadImagesButton();
|
||||
configureSignatureFlagImage();
|
||||
|
||||
if (http.callbackData) {
|
||||
var cachedMessage = new Array();
|
||||
|
|
|
@ -1,57 +1,58 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
|
||||
function onPrintCurrentMessage(event) {
|
||||
window.print();
|
||||
window.print();
|
||||
|
||||
preventDefault(event);
|
||||
preventDefault(event);
|
||||
}
|
||||
|
||||
function initPopupMailer(event) {
|
||||
configureLinksInMessage();
|
||||
resizeMailContent();
|
||||
configureLinksInMessage();
|
||||
resizeMailContent();
|
||||
|
||||
var loadImagesButton = $("loadImagesButton");
|
||||
if (loadImagesButton)
|
||||
loadImagesButton.observe("click",
|
||||
onMessageLoadImages.bindAsEventListener(loadImagesButton));
|
||||
var loadImagesButton = $("loadImagesButton");
|
||||
if (loadImagesButton)
|
||||
loadImagesButton.observe("click",
|
||||
onMessageLoadImages.bindAsEventListener(loadImagesButton));
|
||||
|
||||
configureLoadImagesButton();
|
||||
configureLoadImagesButton();
|
||||
configureSignatureFlagImage();
|
||||
}
|
||||
|
||||
function onMessageLoadImages(event) {
|
||||
var msguid = window.opener.Mailer.currentMessages[window.opener.Mailer.currentMailbox];
|
||||
var url = (window.opener.ApplicationBaseURL + window.opener.encodeURI(window.opener.Mailer.currentMailbox) + "/"
|
||||
+ msguid + "/view?noframe=1&unsafe=1");
|
||||
document.messageAjaxRequest
|
||||
= triggerAjaxRequest(url, messageCallback, msguid);
|
||||
var msguid = window.opener.Mailer.currentMessages[window.opener.Mailer.currentMailbox];
|
||||
var url = (window.opener.ApplicationBaseURL + window.opener.encodeURI(window.opener.Mailer.currentMailbox) + "/"
|
||||
+ msguid + "/view?noframe=1&unsafe=1");
|
||||
document.messageAjaxRequest
|
||||
= triggerAjaxRequest(url, messageCallback, msguid);
|
||||
}
|
||||
|
||||
function onICalendarButtonClick(event) {
|
||||
var link = $("iCalendarAttachment").value;
|
||||
if (link) {
|
||||
var urlstr = link + "/" + this.action;
|
||||
var currentMsg;
|
||||
if (window.opener && window.opener.open && !window.opener.closed && window.messageUID) {
|
||||
var c = window.opener;
|
||||
window.opener.triggerAjaxRequest(urlstr,
|
||||
window.opener.ICalendarButtonCallback,
|
||||
window.messageUID);
|
||||
var link = $("iCalendarAttachment").value;
|
||||
if (link) {
|
||||
var urlstr = link + "/" + this.action;
|
||||
var currentMsg;
|
||||
if (window.opener && window.opener.open && !window.opener.closed && window.messageUID) {
|
||||
var c = window.opener;
|
||||
window.opener.triggerAjaxRequest(urlstr,
|
||||
window.opener.ICalendarButtonCallback,
|
||||
window.messageUID);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
log("no link");
|
||||
else
|
||||
log("no link");
|
||||
}
|
||||
|
||||
function onMenuDeleteMessage(event) {
|
||||
if (window.opener && window.opener.open && !window.opener.closed) {
|
||||
var url = ApplicationBaseURL + encodeURI(mailboxName) + "/deleteMessages";
|
||||
var path = mailboxName + "/" + messageName;
|
||||
|
||||
window.opener.deleteMessageWithDelay(url, messageName, mailboxName, path);
|
||||
}
|
||||
if (window.opener && window.opener.open && !window.opener.closed) {
|
||||
var url = ApplicationBaseURL + encodeURI(mailboxName) + "/deleteMessages";
|
||||
var path = mailboxName + "/" + messageName;
|
||||
|
||||
window.opener.deleteMessageWithDelay(url, messageName, mailboxName, path);
|
||||
}
|
||||
|
||||
window.close();
|
||||
return false;
|
||||
window.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
document.observe("dom:loaded", initPopupMailer);
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
Loading…
Reference in New Issue