Skip to content

Commit

Permalink
fix(mail): Fix images not displayed when forward / reply to a mail. F…
Browse files Browse the repository at this point in the history
…ixes #3981
  • Loading branch information
WoodySlum committed Mar 7, 2023
1 parent 0d2f6d8 commit 4dc8ef9
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 17 deletions.
92 changes: 78 additions & 14 deletions SoObjects/Mailer/SOGoDraftObject.m
Original file line number Diff line number Diff line change
Expand Up @@ -859,7 +859,7 @@ - (void) _fillInReplyAddresses: (NSMutableDictionary *) _info
//
//
//
- (void) _fetchAttachmentsFromMail: (SOGoMailObject *) sourceMail
- (void) _fetchAttachmentsFromMail: (SOGoMailObject *) sourceMail onlyImages: (BOOL) onlyImages
{
NSMutableDictionary *currentInfo;
NSArray *attachments;
Expand All @@ -871,15 +871,19 @@ - (void) _fetchAttachmentsFromMail: (SOGoMailObject *) sourceMail
for (count = 0; count < max; count++)
{
currentInfo = [attachments objectAtIndex: count];
[self saveAttachment: [currentInfo objectForKey: @"body"]
if (!onlyImages
|| (onlyImages && [[NGMimeBodyPart imageMimeTypes] containsObject: [currentInfo objectForKey: @"mimetype"]])) {
[self saveAttachment: [currentInfo objectForKey: @"body"]
withMetadata: currentInfo];
}

}
}

//
//
//
- (void) _fileAttachmentsFromPart: (id) thePart
- (void) _fileAttachmentsFromPart: (id) thePart onlyImages: (BOOL) onlyImages
{
// Small hack to avoid SOPE's stupid behavior to wrap a multipart
// object in a NGMimeBodyPart.
Expand All @@ -889,10 +893,15 @@ - (void) _fileAttachmentsFromPart: (id) thePart

if ([thePart isKindOfClass: [NGMimeBodyPart class]])
{
NSString *filename, *mimeType;
NSString *filename, *mimeType, *bodyId;
id body;

if (onlyImages && ![thePart isImage]) {
return;
}

mimeType = [[thePart contentType] stringValue];
bodyId = [[thePart contentId] stringValue];
body = [thePart body];
filename = [(NGMimeContentDispositionHeaderField *)[thePart headerForKey: @"content-disposition"] filename];

Expand All @@ -906,6 +915,7 @@ - (void) _fileAttachmentsFromPart: (id) thePart
currentInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
filename, @"filename",
mimeType, @"mimetype",
bodyId, @"bodyid",
nil];
[self saveAttachment: body
withMetadata: currentInfo];
Expand All @@ -919,7 +929,7 @@ - (void) _fileAttachmentsFromPart: (id) thePart
parts = [thePart parts];
for (i = 0; i < [parts count]; i++)
{
[self _fileAttachmentsFromPart: [parts objectAtIndex: i]];
[self _fileAttachmentsFromPart: [parts objectAtIndex: i] onlyImages: onlyImages];
}
}
}
Expand All @@ -928,7 +938,7 @@ - (void) _fileAttachmentsFromPart: (id) thePart
//
//
//
- (void) _fetchAttachmentsFromEncryptedMail: (SOGoMailObject *) sourceMail
- (void) _fetchAttachmentsFromEncryptedMail: (SOGoMailObject *) sourceMail onlyImages: (BOOL) onlyImages
{
NSData *certificate;

Expand All @@ -941,20 +951,20 @@ - (void) _fetchAttachmentsFromEncryptedMail: (SOGoMailObject *) sourceMail
NGMimeMessage *m;

m = [[sourceMail content] messageFromEncryptedDataAndCertificate: certificate];
[self _fileAttachmentsFromPart: [m body]];
[self _fileAttachmentsFromPart: [m body] onlyImages: onlyImages];
}
}


//
//
//
- (void) _fetchAttachmentsFromOpaqueSignedMail: (SOGoMailObject *) sourceMail
- (void) _fetchAttachmentsFromOpaqueSignedMail: (SOGoMailObject *) sourceMail onlyImages: (BOOL) onlyImages
{
NGMimeMessage *m;

m = [[sourceMail content] messageFromOpaqueSignedData];
[self _fileAttachmentsFromPart: [m body]];
[self _fileAttachmentsFromPart: [m body] onlyImages: onlyImages];
}


Expand All @@ -973,7 +983,7 @@ - (void) fetchMailForEditing: (SOGoMailObject *) sourceMail

[sourceMail fetchCoreInfos];

[self _fetchAttachmentsFromMail: sourceMail];
[self _fetchAttachmentsFromMail: sourceMail onlyImages: NO];
info = [NSMutableDictionary dictionaryWithCapacity: 16];
subject = [sourceMail subject];
if ([subject length] > 0)
Expand Down Expand Up @@ -1057,6 +1067,22 @@ - (void) fetchMailForReplying: (SOGoMailObject *) sourceMail
[self setSourceIMAP4ID: [[sourceMail nameInContainer] intValue]];
[self setSourceFolderWithMailObject: sourceMail];


ud = [[context activeUser] userDefaults];
// TODO: Change mailMessageForwarding for reply
if ([[ud mailMessageForwarding] isEqualToString: @"inline"])
{
[self setText: [sourceMail contentForInlineForward]];
if ([sourceMail isEncrypted])
[self _fetchAttachmentsFromEncryptedMail: sourceMail onlyImages: YES];
else if ([sourceMail isOpaqueSigned])
[self _fetchAttachmentsFromOpaqueSignedMail: sourceMail onlyImages: YES];
else
[self _fetchAttachmentsFromMail: sourceMail onlyImages: YES];
}

[self save];

[self storeInfo];
}

Expand Down Expand Up @@ -1090,15 +1116,16 @@ - (void) fetchMailForForwarding: (SOGoMailObject *) sourceMail

/* attach message */
ud = [[context activeUser] userDefaults];

if ([[ud mailMessageForwarding] isEqualToString: @"inline"])
{
[self setText: [sourceMail contentForInlineForward]];
if ([sourceMail isEncrypted])
[self _fetchAttachmentsFromEncryptedMail: sourceMail];
[self _fetchAttachmentsFromEncryptedMail: sourceMail onlyImages: NO];
else if ([sourceMail isOpaqueSigned])
[self _fetchAttachmentsFromOpaqueSignedMail: sourceMail];
[self _fetchAttachmentsFromOpaqueSignedMail: sourceMail onlyImages: NO];
else
[self _fetchAttachmentsFromMail: sourceMail];
[self _fetchAttachmentsFromMail: sourceMail onlyImages: NO];
}
else
{
Expand Down Expand Up @@ -1195,7 +1222,7 @@ - (NSException *) saveAttachment: (NSData *) _attach
withMetadata: (NSMutableDictionary *) metadata
{
NSFileManager *fm;
NSString *p, *pmime, *name, *baseName, *extension, *mimeType;
NSString *p, *pmime, *pbodyId, *name, *baseName, *extension, *mimeType, *bodyId;
int i;

if (![_attach isNotNull])
Expand All @@ -1216,6 +1243,7 @@ - (NSException *) saveAttachment: (NSData *) _attach
fm = [NSFileManager defaultManager];
p = [self pathToAttachmentWithName: name];
i = 1;
bodyId = nil;

while ([fm isReadableFileAtPath: p])
{
Expand Down Expand Up @@ -1244,6 +1272,18 @@ - (NSException *) saveAttachment: (NSData *) _attach
reason: @"Could not write attachment to draft!"];
}
}

bodyId = [metadata objectForKey: @"bodyId"];
if ([bodyId length] > 0)
{
pbodyId = [self pathToAttachmentWithName: [NSString stringWithFormat: @".%@.bodyid", name]];
if (![[bodyId dataUsingEncoding: NSUTF8StringEncoding] writeToFile: pbodyId atomically: YES])
{
[[NSFileManager defaultManager] removeFileAtPath: p handler: nil];
return [NSException exceptionWithHTTPStatus: 500 /* Server Error */
reason: @"Could not write body idattachment to draft!"];
}
}

return nil; /* everything OK */
}
Expand Down Expand Up @@ -1381,6 +1421,27 @@ - (NSString *) contentTypeForAttachmentWithName: (NSString *) _name
return s;
}

- (NSString *) bodyIdForAttachmentWithName: (NSString *) _name
{
NSString *s, *p;
NSData *bodyIdData;

p = [self pathToAttachmentWithName: [NSString stringWithFormat: @".%@.bodyid", _name]];
bodyIdData = [NSData dataWithContentsOfFile: p];
if (bodyIdData)
{
s = [[NSString alloc] initWithData: bodyIdData
encoding: NSUTF8StringEncoding];
[s autorelease];
}
else
{
s = nil;
}

return s;
}

- (NSString *) contentDispositionForAttachmentWithName: (NSString *) _name
andContentType: (NSString *) _type
{
Expand Down Expand Up @@ -1441,6 +1502,9 @@ - (NGMimeBodyPart *) bodyPartForAttachmentWithName: (NSString *) _name
else if ([s hasPrefix: @"message/rfc822"])
attachAsRFC822 = YES;
}
if ((s = [self bodyIdForAttachmentWithName:_name]) != nil) {
[map setObject: s forKey: @"content-id"];
}
if ((s = [self contentDispositionForAttachmentWithName: _name andContentType: s]))
{
NGMimeContentDispositionHeaderField *o;
Expand Down
8 changes: 6 additions & 2 deletions SoObjects/SOGo/GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ SOGo_HEADER_FILES = \
SOGoTextTemplateFile.h \
SOGoZipArchiver.h \
\
JWT.h
JWT.h \
\
NGMimeBodyPart+SOGo.h

all::
@touch SOGoBuild.m
Expand Down Expand Up @@ -176,7 +178,9 @@ SOGo_OBJC_FILES = \
SOGoTextTemplateFile.m \
SOGoZipArchiver.m \
\
JWT.m
JWT.m \
\
NGMimeBodyPart+SOGo.m

SOGo_C_FILES += lmhash.c aes.c crypt_blowfish.c pkcs5_pbkdf2.c

Expand Down
35 changes: 35 additions & 0 deletions SoObjects/SOGo/NGMimeBodyPart+SOGo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* NGMimeBodyPart+SOGo.h - this file is part of SOGo
*
* Copyright (C) 2023 Alinto
*
* Author: Sébastien Mizrahi <smizrahi@alinto.eu>
*
* 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 NGMIMEBODYPART_SOGO_H
#define NGMIMEBODYPART_SOGO_H

#import <NGMime/NGMimeBodyPart.h>

@interface NGMimeBodyPart (SOGoExtensions)

+ (NSArray *) imageMimeTypes;
- (BOOL) isImage;

@end

#endif /* NGMIMEBODYPART_SOGO_H */
41 changes: 41 additions & 0 deletions SoObjects/SOGo/NGMimeBodyPart+SOGo.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/* NGMimeBodyPart+SOGo.m - this file is part of SOGo
*
* Copyright (C) 2023 Alinto
*
* Author: Sébastien Mizrahi <smizrahi@alinto.eu>
*
* 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 "NGMimeBodyPart+SOGo.h"

#import <Foundation/NSString.h>
#import <Foundation/NSArray.h>

@implementation NGMimeBodyPart (SOGoExtensions)

+ (NSArray *) imageMimeTypes
{
return [NSArray arrayWithObjects: @"image/png", @"image/gif", @"image/tiff"
, @"image/jpeg", @"image/bmp", @"image/svg+xml", @"image/webp", nil];
}

- (BOOL) isImage
{
return [[NGMimeBodyPart imageMimeTypes] containsObject: [[self contentType] stringValue]];
}

@end
34 changes: 33 additions & 1 deletion UI/MailerUI/UIxMailEditor.m
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#import <SOGo/NSDictionary+Utilities.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/WOResourceManager+SOGo.h>
#import <SOGo/NGMimeBodyPart+SOGo.h>
#import <SOGoUI/UIxComponent.h>
#import <Mailer/SOGoDraftObject.h>
#import <Mailer/SOGoMailObject+Draft.h>
Expand Down Expand Up @@ -702,6 +703,34 @@ - (BOOL) hasAttachments
return [[self attachmentAttrs] count] > 0 ? YES : NO;
}

/*
* This method replace cid images in body with base64 inline image data
*/
- (void) setBase64ImagesInText:(SOGoDraftObject *) draft
{
NSString *contentId, *lText;
NGMimeBodyPart *mime;

if ([self isHTML] && [[draft fetchAttachmentAttrs] count] > 0) {
for (NSDictionary *draftFileAttachement in [draft fetchAttachmentAttrs]) {
mime = [draftFileAttachement objectForKey: @"part"];
if ([mime isImage]) {
contentId = [mime contentId];
contentId = [contentId stringByReplacingOccurrencesOfString: @"<" withString: @"cid:"];
contentId = [contentId stringByReplacingOccurrencesOfString: @">" withString: @""];

if ([[mime encoding] isEqualToString: @"base64"]) {
lText = [text stringByReplacingOccurrencesOfString: contentId
withString: [NSString stringWithFormat: @"data:%@;base64,%@",
[[mime contentType] stringValue],
[NSString stringWithUTF8String: [[mime body] bytes]]]];
[self setText: lText];
}
}
}
}
}

- (id <WOActionResults>) editAction
{
id <WOActionResults> response;
Expand All @@ -720,7 +749,6 @@ - (BOOL) hasAttachments
data = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[self localeCode], @"locale",
[NSNumber numberWithBool: [self isHTML]], @"isHTML",
text, @"text",
nil];
if ((value = [self from]))
[data setObject: value forKey: @"from"];
Expand All @@ -737,6 +765,10 @@ - (BOOL) hasAttachments
if ((value = [self attachmentAttrs]))
[data setObject: value forKey: @"attachmentAttrs"];

[self setBase64ImagesInText: co];
[data setObject: text forKey: @"text"];


response = [self responseWithStatus: 200
andString: [data jsonRepresentation]];

Expand Down

0 comments on commit 4dc8ef9

Please sign in to comment.