(fix) proper handling of file attachments in S/MIME encrypted mails

pull/239/head
Ludovic Marcotte 2018-01-05 13:55:05 -05:00
parent 2f1c8cdbc8
commit c875302a86
4 changed files with 118 additions and 32 deletions

View File

@ -1,6 +1,6 @@
/* NSString+Mail.h - this file is part of SOGo
*
* Copyright (C) 2007-2014 Inverse inc.
* Copyright (C) 2007-2018 Inverse inc.
*
* 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
@ -34,6 +34,7 @@
- (int) indexOf: (unichar) _c;
- (NSString *) decodedHeader;
- (NSString *) asSafeFilename;
- (NSString *) asPreferredFilenameUsingPath: (NSString *) thePath;
@end

View File

@ -1,6 +1,6 @@
/* NSString+Mail.m - this file is part of SOGo
*
* Copyright (C) 2008-2014 Inverse inc.
* Copyright (C) 2008-2018 Inverse inc.
*
* 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
@ -732,4 +732,33 @@ convertChars (const char *oldString, unsigned int oldLength,
return safeName;
}
//
// We might end up here because of MUA that actually strips the
// Content-Disposition (and thus, the filename) when mails containing
// attachments have been forwarded. Thunderbird (2.x) does just that
// when forwarding mails with images attached to them (using cid:...).
//
- (NSString *) asPreferredFilenameUsingPath: (NSString *) thePath
{
NSString *filename;
filename = nil;
if (!thePath)
thePath = @"1";
if ([self hasPrefix: @"application/"] ||
[self hasPrefix: @"audio/"] ||
[self hasPrefix: @"image/"] ||
[self hasPrefix: @"video/"])
{
filename = [NSString stringWithFormat: @"unknown_%@", thePath];
}
else
{
if ([self isEqualToString: @"message/rfc822"])
filename = [NSString stringWithFormat: @"email_%@.eml", thePath];
}
return filename;
}
@end

View File

@ -779,9 +779,10 @@ static NSString *userAgent = nil;
//
- (void) _fetchAttachmentsFromMail: (SOGoMailObject *) sourceMail
{
unsigned int max, count;
NSArray *attachments;
NSDictionary *currentInfo;
NSArray *attachments;
unsigned int max, count;
attachments = [sourceMail fetchFileAttachments];
max = [attachments count];
@ -793,6 +794,70 @@ static NSString *userAgent = nil;
}
}
//
//
//
- (void) _fileAttachmentsFromPart: (id) thePart
{
if ([thePart isKindOfClass: [NGMimeBodyPart class]])
{
NSString *filename, *mimeType;
id body;
mimeType = [[thePart contentType] stringValue];
body = [thePart body];
filename = [(NGMimeContentDispositionHeaderField *)[thePart headerForKey: @"content-disposition"] filename];
if (!filename)
filename = [mimeType asPreferredFilenameUsingPath: nil];
if (filename)
{
NSDictionary *currentInfo;
currentInfo = [NSDictionary dictionaryWithObjectsAndKeys:
filename, @"filename",
mimeType, @"mimetype",
nil];
[self saveAttachment: body
withMetadata: currentInfo];
}
}
else if ([thePart isKindOfClass: [NGMimeMultipartBody class]])
{
NSArray *parts;
int i;
parts = [thePart parts];
for (i = 0; i < [parts count]; i++)
{
[self _fileAttachmentsFromPart: [parts objectAtIndex: i]];
}
}
}
//
//
//
- (void) _fetchAttachmentsFromEncryptedMail: (SOGoMailObject *) sourceMail
{
NSData *certificate;
certificate = [[self mailAccountFolder] certificate];
// If we got a user certificate, let's use it. Otherwise we fallback we
// don't try to get any attachments from the encrypted content
if (certificate)
{
NGMimeMessage *m;
m = [[sourceMail content] messageFromEncryptedDataAndCertificate: certificate];
[self _fileAttachmentsFromPart: [m body]];
}
}
//
//
//
@ -912,7 +977,10 @@ static NSString *userAgent = nil;
if ([[ud mailMessageForwarding] isEqualToString: @"inline"])
{
[self setText: [sourceMail contentForInlineForward]];
[self _fetchAttachmentsFromMail: sourceMail];
if ([sourceMail isEncrypted])
[self _fetchAttachmentsFromEncryptedMail: sourceMail];
else
[self _fetchAttachmentsFromMail: sourceMail];
}
else
{
@ -1009,21 +1077,24 @@ static NSString *userAgent = nil;
{
NSString *p, *pmime, *name, *mimeType;
if (![_attach isNotNull]) {
return [NSException exceptionWithHTTPStatus:400 /* Bad Request */
reason: @"Missing attachment content!"];
}
if (![_attach isNotNull])
{
return [NSException exceptionWithHTTPStatus: 400 /* Bad Request */
reason: @"Missing attachment content!"];
}
if (![self _ensureDraftFolderPath]) {
return [NSException exceptionWithHTTPStatus:500 /* Server Error */
reason: @"Could not create folder for draft!"];
}
if (![self _ensureDraftFolderPath])
{
return [NSException exceptionWithHTTPStatus: 500 /* Server Error */
reason: @"Could not create folder for draft!"];
}
name = [[metadata objectForKey: @"filename"] asSafeFilename];
p = [self pathToAttachmentWithName: name];
if (![_attach writeToFile: p atomically: YES])
{
return [NSException exceptionWithHTTPStatus:500 /* Server Error */
return [NSException exceptionWithHTTPStatus: 500 /* Server Error */
reason: @"Could not write attachment to draft!"];
}

View File

@ -786,8 +786,8 @@ static BOOL debugSoParts = NO;
if ([prefix hasSuffix: @"/"])
prefix = [prefix substringToIndex: [prefix length] - 1];
[self _feedFileAttachmentIds: attachmentIds
withInfos: [coreInfos objectForKey: @"bodystructure"]
andPrefix: prefix];
withInfos: [coreInfos objectForKey: @"bodystructure"]
andPrefix: prefix];
return attachmentIds;
}
@ -811,22 +811,7 @@ static BOOL debugSoParts = NO;
if (!filename)
{
// We might end up here because of MUA that actually strips the
// Content-Disposition (and thus, the filename) when mails containing
// attachments have been forwarded. Thunderbird (2.x) does just that
// when forwarding mails with images attached to them (using cid:...).
if ([mimeType hasPrefix: @"application/"] ||
[mimeType hasPrefix: @"audio/"] ||
[mimeType hasPrefix: @"image/"] ||
[mimeType hasPrefix: @"video/"])
{
filename = [NSString stringWithFormat: @"unknown_%@", path];
}
else
{
if ([mimeType isEqualToString: @"message/rfc822"])
filename = [NSString stringWithFormat: @"email_%@.eml", path];
}
filename = [mimeType asPreferredFilenameUsingPath: path];
}
if (filename)