fix(mail): pick proper "from" address when replying/forwarding

Fixes #5056
pull/283/head
Francis Lachapelle 2020-07-06 12:17:11 -04:00
parent 089935297c
commit c99170b9bc
7 changed files with 173 additions and 78 deletions

View File

@ -50,6 +50,7 @@
#import <SOGo/NSArray+Utilities.h> #import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSCalendarDate+SOGo.h> #import <SOGo/NSCalendarDate+SOGo.h>
#import <SOGo/NSDictionary+Utilities.h>
#import <SOGo/NSString+Utilities.h> #import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoBuild.h> #import <SOGo/SOGoBuild.h>
#import <SOGo/SOGoDomainDefaults.h> #import <SOGo/SOGoDomainDefaults.h>
@ -661,6 +662,53 @@ static NSString *userAgent = nil;
} }
} }
//
//
//
- (NSString *) _emailFromIdentity: (NSDictionary *) identity
{
NSString *fullName, *format;
fullName = [identity objectForKey: @"fullName"];
if ([fullName length])
format = @"%{fullName} <%{email}>";
else
format = @"%{email}";
return [identity keysWithFormat: format];
}
- (void) _fillInFromAddress: (NSMutableDictionary *) _info
fromSentMailbox: (BOOL) _fromSentMailbox
envelope: (NGImap4Envelope *) _envelope
{
NSDictionary *identity;
NSMutableArray *addrs;
NSString *email;
int i;
/* Pick the first email matching one of the account's identities */
addrs = [NSMutableArray array];
if (_fromSentMailbox)
[self _addRecipients: [_envelope from] toArray: addrs];
else
[self _addRecipients: [_envelope to] toArray: addrs];
if ([addrs count])
{
identity = nil;
for (i = 0; !identity && i < [addrs count]; i++)
{
email = [addrs objectAtIndex: i];
identity = [[[self container] mailAccountFolder] identityForEmail: email];
}
if (identity)
{
[_info setObject: [self _emailFromIdentity: identity] forKey: @"from"];
}
}
}
// //
// //
// //
@ -705,11 +753,9 @@ static NSString *userAgent = nil;
int i; int i;
identities = [[[self container] mailAccountFolder] identities]; identities = [[[self container] mailAccountFolder] identities];
for (i = 0; i < [identities count]; i++) for (i = 0; i < [identities count]; i++)
{ {
email = [[identities objectAtIndex: i] objectForKey: @"email"]; email = [[identities objectAtIndex: i] objectForKey: @"email"];
if (email) if (email)
[allRecipients addObject: email]; [allRecipients addObject: email];
} }
@ -726,7 +772,7 @@ static NSString *userAgent = nil;
else else
[addrs setArray: [_envelope from]]; [addrs setArray: [_envelope from]];
[self _purgeRecipients: allRecipients fromAddresses: addrs]; [self _purgeRecipients: allRecipients fromAddresses: addrs]; // addrs contain the recipient addresses without the any of the sender's addresses
[self _addEMailsOfAddresses: addrs toArray: to]; [self _addEMailsOfAddresses: addrs toArray: to];
[self _addRecipients: addrs toArray: allRecipients]; [self _addRecipients: addrs toArray: allRecipients];
[_info setObject: to forKey: @"to"]; [_info setObject: to forKey: @"to"];
@ -741,6 +787,11 @@ static NSString *userAgent = nil;
[self _addEMailsOfAddresses: [_envelope from] toArray: to]; [self _addEMailsOfAddresses: [_envelope from] toArray: to];
} }
/* Pick the first email matching one of the account's identities */
[self _fillInFromAddress: _info
fromSentMailbox: _fromSentMailbox
envelope: _envelope];
/* If we have no To but we have Cc recipients, let's move the Cc /* If we have no To but we have Cc recipients, let's move the Cc
to the To bucket... */ to the To bucket... */
if ([[_info objectForKey: @"to"] count] == 0 && [_info objectForKey: @"cc"]) if ([[_info objectForKey: @"to"] count] == 0 && [_info objectForKey: @"cc"])
@ -954,7 +1005,6 @@ static NSString *userAgent = nil;
{ {
BOOL fromSentMailbox; BOOL fromSentMailbox;
NSString *msgID; NSString *msgID;
NSMutableArray *addresses;
NSMutableDictionary *info; NSMutableDictionary *info;
NGImap4Envelope *sourceEnvelope; NGImap4Envelope *sourceEnvelope;
SOGoUserDefaults *ud; SOGoUserDefaults *ud;
@ -974,11 +1024,6 @@ static NSString *userAgent = nil;
if ([msgID length] > 0) if ([msgID length] > 0)
[self setInReplyTo: msgID]; [self setInReplyTo: msgID];
addresses = [NSMutableArray array];
[self _addEMailsOfAddresses: [sourceEnvelope to] toArray: addresses];
if ([addresses count])
[info setObject: [addresses objectAtIndex: 0] forKey: @"from"];
ud = [[context activeUser] userDefaults]; ud = [[context activeUser] userDefaults];
[self setText: [sourceMail contentForReply]]; [self setText: [sourceMail contentForReply]];
@ -994,19 +1039,28 @@ static NSString *userAgent = nil;
- (void) fetchMailForForwarding: (SOGoMailObject *) sourceMail - (void) fetchMailForForwarding: (SOGoMailObject *) sourceMail
{ {
NSDictionary *info, *attachment; BOOL fromSentMailbox;
NGImap4Envelope *sourceEnvelope;
NSDictionary *attachment;
NSMutableDictionary *info;
NSString *signature, *nl, *space; NSString *signature, *nl, *space;
SOGoUserDefaults *ud; SOGoUserDefaults *ud;
fromSentMailbox = [[sourceMail container] isKindOfClass: [SOGoSentFolder class]];
[sourceMail fetchCoreInfos]; [sourceMail fetchCoreInfos];
sourceEnvelope = [sourceMail envelope];
info = [NSMutableDictionary dictionaryWithCapacity: 2];
if ([sourceMail subjectForForward]) if ([sourceMail subjectForForward])
{ {
info = [NSDictionary dictionaryWithObject: [sourceMail subjectForForward] [info setObject: [sourceMail subjectForForward] forKey: @"subject"];
forKey: @"subject"];
[self setHeaders: info];
} }
[self _fillInFromAddress: info
fromSentMailbox: fromSentMailbox
envelope: sourceEnvelope];
[self setHeaders: info];
[self setSourceURL: [sourceMail imap4URLString]]; [self setSourceURL: [sourceMail imap4URLString]];
[self setSourceFlag: @"$Forwarded"]; [self setSourceFlag: @"$Forwarded"];
[self setSourceIMAP4ID: [[sourceMail nameInContainer] intValue]]; [self setSourceIMAP4ID: [[sourceMail nameInContainer] intValue]];

View File

@ -88,6 +88,7 @@ typedef enum {
- (NSArray *) identities; - (NSArray *) identities;
- (NSDictionary *) defaultIdentity; - (NSDictionary *) defaultIdentity;
- (NSDictionary *) identityForEmail: (NSString *) email;
- (NSString *) signature; - (NSString *) signature;
- (NSString *) encryption; - (NSString *) encryption;

View File

@ -694,6 +694,30 @@ static NSString *inboxFolderName = @"INBOX";
return defaultIdentity; // can be nil return defaultIdentity; // can be nil
} }
- (NSDictionary *) identityForEmail: (NSString *) email
{
NSDictionary *identity, *currentIdentity;
NSString *currentEmail;
unsigned int count, max;
identity = nil;
[self identities];
max = [identities count];
for (count = 0; count < max; count++)
{
currentIdentity = [identities objectAtIndex: count];
currentEmail = [currentIdentity objectForKey: @"email"];
if ([currentEmail caseInsensitiveCompare: email] == NSOrderedSame)
{
identity = currentIdentity;
break;
}
}
return identity; // can be nil
}
- (NSString *) signature - (NSString *) signature
{ {
NSDictionary *identity; NSDictionary *identity;

View File

@ -1,6 +1,6 @@
/* SOGoMailForward.m - this file is part of SOGo /* SOGoMailForward.m - this file is part of SOGo
* *
* Copyright (C) 2007-2017 Inverse inc. * Copyright (C) 2007-2020 Inverse inc.
* *
* This file is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -20,6 +20,7 @@
#import <Foundation/NSDictionary.h> #import <Foundation/NSDictionary.h>
#import <NGImap4/NGImap4EnvelopeAddress.h>
#import <NGObjWeb/WOContext+SoObjects.h> #import <NGObjWeb/WOContext+SoObjects.h>
#import <NGExtensions/NSString+misc.h> #import <NGExtensions/NSString+misc.h>
@ -30,6 +31,7 @@
#import "SOGoMailAccount.h" #import "SOGoMailAccount.h"
#import "SOGoMailObject+Draft.h" #import "SOGoMailObject+Draft.h"
#import "SOGoMailForward.h" #import "SOGoMailForward.h"
#import "SOGoSentFolder.h"
@implementation SOGoMailForward @implementation SOGoMailForward
@ -234,18 +236,43 @@
- (NSString *) signature - (NSString *) signature
{ {
NSString *signature, *mailSignature, *nl, *space; BOOL fromSentMailbox;
NGImap4EnvelopeAddress *address;
signature = [[sourceMail mailAccountFolder] signature]; NSArray *addresses;
NSDictionary *identity;
NSString *email, *signature, *mailSignature, *nl, *space;
int count, max;
if ([signature length]) fromSentMailbox = [[sourceMail container] isKindOfClass: [SOGoSentFolder class]];
{ if (fromSentMailbox)
nl = (htmlComposition ? @"<br />" : @"\n"); addresses = [sourceMail fromEnvelopeAddresses];
space = (htmlComposition ? @"&nbsp;" : @" ");
mailSignature = [NSString stringWithFormat: @"--%@%@%@", space, nl, signature];
}
else else
mailSignature = @""; addresses = [sourceMail toEnvelopeAddresses];
identity = nil;
mailSignature = @"";
max = [addresses count];
if (max)
{
// Pick the first email matching one of the account's identities
for (count = 0; !identity && count < max; count++)
{
address = [addresses objectAtIndex: count];
email = [address baseEMail];
identity = [[sourceMail mailAccountFolder] identityForEmail: email];
}
}
if (identity)
{
signature = [identity objectForKey: @"signature"];
if ([signature length])
{
nl = (htmlComposition ? @"<br />" : @"\n");
space = (htmlComposition ? @"&nbsp;" : @" ");
mailSignature = [NSString stringWithFormat: @"%@--%@%@%@", nl, space, nl, signature];
}
}
return mailSignature; return mailSignature;
} }

View File

@ -50,6 +50,7 @@
#import <Mailer/SOGoDraftObject.h> #import <Mailer/SOGoDraftObject.h>
#import <Mailer/SOGoDraftsFolder.h> #import <Mailer/SOGoDraftsFolder.h>
#import <SOGo/NSArray+Utilities.h> #import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSDictionary+Utilities.h>
#import <SOGo/NSObject+Utilities.h> #import <SOGo/NSObject+Utilities.h>
#import <SOGo/NSString+Utilities.h> #import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoDomainDefaults.h> #import <SOGo/SOGoDomainDefaults.h>
@ -98,19 +99,34 @@
/* compose */ /* compose */
- (NSString *) _emailFromIdentity: (NSDictionary *) identity
{
NSString *fullName, *format;
fullName = [identity objectForKey: @"fullName"];
if ([fullName length])
format = @"%{fullName} <%{email}>";
else
format = @"%{email}";
return [identity keysWithFormat: format];
}
- (WOResponse *) composeAction - (WOResponse *) composeAction
{ {
BOOL save, isHTML;
NSDictionary *data, *identity;
NSMutableDictionary *headers;
NSString *accountName, *mailboxName, *messageName;
NSString *value, *signature, *nl, *space; NSString *value, *signature, *nl, *space;
SOGoDraftObject *newDraftMessage; SOGoDraftObject *newDraftMessage;
NSMutableDictionary *headers;
NSDictionary *data;
NSString *accountName, *mailboxName, *messageName;
SOGoDraftsFolder *drafts; SOGoDraftsFolder *drafts;
SOGoMailAccount *co;
SOGoUserDefaults *ud; SOGoUserDefaults *ud;
id mailTo; id mailTo;
BOOL save, isHTML;
drafts = [[self clientObject] draftsFolderInContext: context]; co = [self clientObject];
drafts = [co draftsFolderInContext: context];
newDraftMessage = [drafts newDraft]; newDraftMessage = [drafts newDraft];
headers = [NSMutableDictionary dictionary]; headers = [NSMutableDictionary dictionary];
@ -134,25 +150,30 @@
save = YES; save = YES;
} }
if (save) identity = [co defaultIdentity];
[newDraftMessage setHeaders: headers]; if (identity)
signature = [[self clientObject] signature];
if ([signature length])
{ {
ud = [[context activeUser] userDefaults]; [headers setObject: [self _emailFromIdentity: identity] forKey: @"from"];
[newDraftMessage setIsHTML: [[ud mailComposeMessageType] isEqualToString: @"html"]]; signature = [identity objectForKey: @"signature"];
isHTML = [newDraftMessage isHTML]; if ([signature length])
nl = (isHTML? @"<br />" : @"\n"); {
space = (isHTML ? @"&nbsp;" : @" "); ud = [[context activeUser] userDefaults];
[newDraftMessage setIsHTML: [[ud mailComposeMessageType] isEqualToString: @"html"]];
[newDraftMessage setText: [NSString stringWithFormat: @"%@%@--%@%@%@", nl, nl, space, nl, signature]]; isHTML = [newDraftMessage isHTML];
nl = (isHTML? @"<br />" : @"\n");
space = (isHTML ? @"&nbsp;" : @" ");
[newDraftMessage setText: [NSString stringWithFormat: @"%@%@--%@%@%@", nl, nl, space, nl, signature]];
}
save = YES; save = YES;
} }
if (save)
[newDraftMessage storeInfo];
accountName = [[self clientObject] nameInContainer]; if (save)
{
[newDraftMessage setHeaders: headers];
[newDraftMessage storeInfo];
}
accountName = [co nameInContainer];
mailboxName = [drafts absoluteImap4Name]; // Ex: /INBOX/Drafts/ mailboxName = [drafts absoluteImap4Name]; // Ex: /INBOX/Drafts/
mailboxName = [mailboxName substringWithRange: NSMakeRange(1, [mailboxName length] -2)]; mailboxName = [mailboxName substringWithRange: NSMakeRange(1, [mailboxName length] -2)];
messageName = [newDraftMessage nameInContainer]; messageName = [newDraftMessage nameInContainer];

View File

@ -65,7 +65,6 @@
NSString *sourceUID; NSString *sourceUID;
NSString *sourceFolder; NSString *sourceFolder;
NSString *text; NSString *text;
NSMutableArray *fromEMails;
NSString *from; NSString *from;
SOGoMailFolder *sentFolder; SOGoMailFolder *sentFolder;
BOOL isHTML; BOOL isHTML;
@ -122,7 +121,6 @@ static NSArray *infoKeys = nil;
[priority release]; [priority release];
[receipt release]; [receipt release];
[sentFolder release]; [sentFolder release];
[fromEMails release];
[from release]; [from release];
[text release]; [text release];
[subject release]; [subject release];
@ -256,7 +254,7 @@ static NSArray *infoKeys = nil;
identities = [[[self clientObject] mailAccountFolder] identities]; identities = [[[self clientObject] mailAccountFolder] identities];
if ([identities count]) if ([identities count])
{ {
if (from) if ([from length])
{ {
allIdentities = [identities objectEnumerator]; allIdentities = [identities objectEnumerator];
valid = NO; valid = NO;
@ -278,11 +276,6 @@ static NSArray *infoKeys = nil;
from = nil; from = nil;
} }
} }
if (!from)
{
from = [self _emailFromIdentity: [[context activeUser] defaultIdentity]];
[from retain];
}
} }
return from; return from;
@ -413,31 +406,6 @@ static NSArray *infoKeys = nil;
return [UIxMailSizeFormatter sharedMailSizeFormatter]; return [UIxMailSizeFormatter sharedMailSizeFormatter];
} }
/* from addresses */
- (NSArray *) fromEMails
{
NSArray *identities;
int count, max;
NSString *email;
SOGoMailAccount *account;
if (!fromEMails)
{
account = [[self clientObject] mailAccountFolder];
identities = [account identities];
max = [identities count];
fromEMails = [[NSMutableArray alloc] initWithCapacity: max];
for (count = 0; count < max; count++)
{
email = [self _emailFromIdentity: [identities objectAtIndex: count]];
[fromEMails addObjectUniquely: email];
}
}
return fromEMails;
}
/* info loading */ /* info loading */
- (void) loadInfo: (NSDictionary *) _info - (void) loadInfo: (NSDictionary *) _info

View File

@ -443,7 +443,7 @@
return Message.$$resource.fetch(_this.$absolutePath({asDraft: true}), 'edit').then(function(data) { return Message.$$resource.fetch(_this.$absolutePath({asDraft: true}), 'edit').then(function(data) {
// Try to match a known account identity from the specified "from" address // Try to match a known account identity from the specified "from" address
var identity = _.find(_this.$mailbox.$account.identities, function(identity) { var identity = _.find(_this.$mailbox.$account.identities, function(identity) {
return data.from.toLowerCase().indexOf(identity.email) !== -1; return data.from && data.from.toLowerCase().indexOf(identity.email) !== -1;
}); });
if (identity) if (identity)
data.from = identity.full; data.from = identity.full;