Fixed issue# 1790 - On reply of an email, the recipient will not be set if sender header contains invalid email addresses.

This commit is contained in:
Martin Edenhofer 2018-01-31 14:13:23 +01:00
parent 6f08071c3d
commit a0c04ed190
3 changed files with 419 additions and 169 deletions

View file

@ -890,6 +890,29 @@ class App.Utils
text = text.replace(/http(s|):\/\/[-A-Za-z0-9+&@#\/%?=~_\|!:,.;]+[-A-Za-z0-9+&@#\/%=~_|]/img, placeholder) text = text.replace(/http(s|):\/\/[-A-Za-z0-9+&@#\/%?=~_\|!:,.;]+[-A-Za-z0-9+&@#\/%=~_|]/img, placeholder)
text.length text.length
@parseAddressListLocal: (line) ->
recipients = emailAddresses.parseAddressList(line)
result = []
if !_.isEmpty(recipients)
for recipient in recipients
if recipient && recipient.address
result.push recipient.address
return result
# workaround for email-addresses.js issue with this kind of
# mail headers "From: invalid sender, realname <sender@example.com>"
# email-addresses.js is returning null because it can't parse the
# whole header
if _.isEmpty(recipients) && line.match('@')
recipients = line.split(',')
re = /(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/
for recipient in recipients
if recipient && recipient.match('@')
localResult = recipient.match(re)
if localResult && localResult[0]
result.push localResult[0]
result
@getRecipientArticle: (ticket, article, article_created_by, type, email_addresses = [], all) -> @getRecipientArticle: (ticket, article, article_created_by, type, email_addresses = [], all) ->
# empty form # empty form
@ -938,16 +961,18 @@ class App.Utils
# check if article sender is local # check if article sender is local
senderIsLocal = false senderIsLocal = false
if !_.isEmpty(article.from) if !_.isEmpty(article.from)
senders = emailAddresses.parseAddressList(article.from) senders = App.Utils.parseAddressListLocal(article.from)
if senders && senders[0] && senders[0].address if senders
senderIsLocal = isLocalAddress(senders[0].address) for sender in senders
if sender && sender.address && sender.address.match('@')
senderIsLocal = isLocalAddress(sender.address)
# check if article recipient is local # check if article recipient is local
recipientIsLocal = false recipientIsLocal = false
if !_.isEmpty(article.to) if !_.isEmpty(article.to)
recipients = emailAddresses.parseAddressList(article.to) recipients = App.Utils.parseAddressListLocal(article.to)
if recipients && recipients[0] && recipients[0].address if recipients && recipients[0]
recipientIsLocal = isLocalAddress(recipients[0].address) recipientIsLocal = isLocalAddress(recipients[0])
# sender is local # sender is local
if senderIsLocal if senderIsLocal
@ -971,14 +996,14 @@ class App.Utils
# filter for uniq recipients # filter for uniq recipients
recipientAddresses = {} recipientAddresses = {}
addAddresses = (addressLine, line) -> addAddresses = (addressLine, line) ->
lineNew = '' lineNew = ''
recipients = emailAddresses.parseAddressList(addressLine) recipients = App.Utils.parseAddressListLocal(addressLine)
if !_.isEmpty(recipients) if !_.isEmpty(recipients)
for recipient in recipients for recipient in recipients
if !_.isEmpty(recipient.address) if !_.isEmpty(recipient)
localRecipientAddress = recipient.address.toString().toLowerCase() localRecipientAddress = recipient.toString().toLowerCase()
# check if address is not local # check if address is not local
if !isLocalAddress(localRecipientAddress) if !isLocalAddress(localRecipientAddress)

View file

@ -1,6 +1,6 @@
// email-addresses.js - RFC 5322 email address parser // email-addresses.js - RFC 5322 email address parser
// v 2.0.1 // v 3.0.1
// //
// http://tools.ietf.org/html/rfc5322 // http://tools.ietf.org/html/rfc5322
// //
@ -186,27 +186,7 @@ function parse5322(opts) {
// "First Last" -> "First Last" // "First Last" -> "First Last"
// "First Last" -> "First Last" // "First Last" -> "First Last"
function collapseWhitespace(s) { function collapseWhitespace(s) {
function isWhitespace(c) { return s.replace(/([ \t]|\r\n)+/g, ' ').replace(/^\s*/, '').replace(/\s*$/, '');
return c === ' ' ||
c === '\t' ||
c === '\r' ||
c === '\n';
}
var i, str;
str = "";
for (i = 0; i < s.length; i += 1) {
if (!isWhitespace(s[i]) || !isWhitespace(s[i + 1])) {
str += s[i];
}
}
if (isWhitespace(str[0])) {
str = str.substring(1);
}
if (isWhitespace(str[str.length - 1])) {
str = str.substring(0, str.length - 1);
}
return str;
} }
// UTF-8 pseudo-production (RFC 6532) // UTF-8 pseudo-production (RFC 6532)
@ -597,10 +577,14 @@ function parse5322(opts) {
return wrap('domain', function domainCheckTLD() { return wrap('domain', function domainCheckTLD() {
var result = or(obsDomain, dotAtom, domainLiteral)(); var result = or(obsDomain, dotAtom, domainLiteral)();
if (opts.rejectTLD) { if (opts.rejectTLD) {
if (result.semantic.indexOf('.') < 0) { if (result && result.semantic && result.semantic.indexOf('.') < 0) {
return null; return null;
} }
} }
// strip all whitespace from domains
if (result) {
result.semantic = result.semantic.replace(/\s+/g, '');
}
return result; return result;
}()); }());
} }
@ -612,6 +596,36 @@ function parse5322(opts) {
)()); )());
} }
// 3.6.2 Originator Fields
// Below we only parse the field body, not the name of the field
// like "From:", "Sender:", or "Reply-To:". Other libraries that
// parse email headers can parse those and defer to these productions
// for the "RFC 5322" part.
// RFC 6854 2.1. Replacement of RFC 5322, Section 3.6.2. Originator Fields
// from = "From:" (mailbox-list / address-list) CRLF
function fromSpec() {
return wrap('from', or(
mailboxList,
addressList
)());
}
// RFC 6854 2.1. Replacement of RFC 5322, Section 3.6.2. Originator Fields
// sender = "Sender:" (mailbox / address) CRLF
function senderSpec() {
return wrap('sender', or(
mailbox,
address
)());
}
// RFC 6854 2.1. Replacement of RFC 5322, Section 3.6.2. Originator Fields
// reply-to = "Reply-To:" address-list CRLF
function replyToSpec() {
return wrap('reply-to', addressList());
}
// 4.1. Miscellaneous Obsolete Tokens // 4.1. Miscellaneous Obsolete Tokens
// obs-NO-WS-CTL = %d1-8 / ; US-ASCII control // obs-NO-WS-CTL = %d1-8 / ; US-ASCII control
@ -766,92 +780,186 @@ function parse5322(opts) {
// ast analysis // ast analysis
function findNode(name, root) { function findNode(name, root) {
var i, queue, node; var i, stack, node;
if (root === null || root === undefined) { return null; } if (root === null || root === undefined) { return null; }
queue = [root]; stack = [root];
while (queue.length > 0) { while (stack.length > 0) {
node = queue.shift(); node = stack.pop();
if (node.name === name) { if (node.name === name) {
return node; return node;
} }
for (i = 0; i < node.children.length; i += 1) { for (i = node.children.length - 1; i >= 0; i -= 1) {
queue.push(node.children[i]); stack.push(node.children[i]);
} }
} }
return null; return null;
} }
function findAllNodes(name, root) { function findAllNodes(name, root) {
var i, queue, node, result; var i, stack, node, result;
if (root === null || root === undefined) { return null; } if (root === null || root === undefined) { return null; }
queue = [root]; stack = [root];
result = []; result = [];
while (queue.length > 0) { while (stack.length > 0) {
node = queue.shift(); node = stack.pop();
if (node.name === name) { if (node.name === name) {
result.push(node); result.push(node);
} }
for (i = 0; i < node.children.length; i += 1) { for (i = node.children.length - 1; i >= 0; i -= 1) {
queue.push(node.children[i]); stack.push(node.children[i]);
}
}
return result;
}
function findAllNodesNoChildren(names, root) {
var i, stack, node, result, namesLookup;
if (root === null || root === undefined) { return null; }
stack = [root];
result = [];
namesLookup = {};
for (i = 0; i < names.length; i += 1) {
namesLookup[names[i]] = true;
}
while (stack.length > 0) {
node = stack.pop();
if (node.name in namesLookup) {
result.push(node);
// don't look at children (hence findAllNodesNoChildren)
} else {
for (i = node.children.length - 1; i >= 0; i -= 1) {
stack.push(node.children[i]);
}
} }
} }
return result; return result;
} }
function giveResult(ast) { function giveResult(ast) {
function grabSemantic(n) { var addresses, groupsAndMailboxes, i, groupOrMailbox, result;
return n !== null ? n.semantic : null;
}
var i, ret, addresses, addr, name, aspec, local, domain;
if (ast === null) { if (ast === null) {
return null; return null;
} }
ret = { ast: ast }; addresses = [];
addresses = findAllNodes('address', ast);
ret.addresses = [];
for (i = 0; i < addresses.length; i += 1) {
addr = addresses[i];
name = findNode('display-name', addr);
aspec = findNode('addr-spec', addr);
local = findNode('local-part', aspec);
domain = findNode('domain', aspec);
ret.addresses.push({
node: addr,
parts: {
name: name,
address: aspec,
local: local,
domain: domain
},
name: grabSemantic(name),
address: grabSemantic(aspec),
local: grabSemantic(local),
domain: grabSemantic(domain)
});
}
if (opts.simple) { // An address is a 'group' (i.e. a list of mailboxes) or a 'mailbox'.
ret = ret.addresses; groupsAndMailboxes = findAllNodesNoChildren(['group', 'mailbox'], ast);
for (i = 0; i < ret.length; i += 1) { for (i = 0; i < groupsAndMailboxes.length; i += 1) {
delete ret[i].node; groupOrMailbox = groupsAndMailboxes[i];
if (groupOrMailbox.name === 'group') {
addresses.push(giveResultGroup(groupOrMailbox));
} else if (groupOrMailbox.name === 'mailbox') {
addresses.push(giveResultMailbox(groupOrMailbox));
} }
} }
return ret;
result = {
ast: ast,
addresses: addresses,
};
if (opts.simple) {
result = simplifyResult(result);
}
if (opts.oneResult) {
return oneResult(result);
}
if (opts.simple) {
return result && result.addresses;
} else {
return result;
}
}
function giveResultGroup(group) {
var i;
var groupName = findNode('display-name', group);
var groupResultMailboxes = [];
var mailboxes = findAllNodesNoChildren(['mailbox'], group);
for (i = 0; i < mailboxes.length; i += 1) {
groupResultMailboxes.push(giveResultMailbox(mailboxes[i]));
}
return {
node: group,
parts: {
name: groupName,
},
type: group.name, // 'group'
name: grabSemantic(groupName),
addresses: groupResultMailboxes,
};
}
function giveResultMailbox(mailbox) {
var name = findNode('display-name', mailbox);
var aspec = findNode('addr-spec', mailbox);
var comments = findAllNodes('cfws', mailbox);
var local = findNode('local-part', aspec);
var domain = findNode('domain', aspec);
return {
node: mailbox,
parts: {
name: name,
address: aspec,
local: local,
domain: domain,
comments: comments
},
type: mailbox.name, // 'mailbox'
name: grabSemantic(name),
address: grabSemantic(aspec),
local: grabSemantic(local),
domain: grabSemantic(domain),
groupName: grabSemantic(mailbox.groupName),
};
}
function grabSemantic(n) {
return n !== null && n !== undefined ? n.semantic : null;
}
function simplifyResult(result) {
var i;
if (result && result.addresses) {
for (i = 0; i < result.addresses.length; i += 1) {
delete result.addresses[i].node;
}
}
return result;
}
function oneResult(result) {
if (!result) { return null; }
if (!opts.partial && result.addresses.length > 1) { return null; }
return result.addresses && result.addresses[0];
} }
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
var parseString, pos, len, parsed; var parseString, pos, len, parsed, startProduction;
opts = handleOpts(opts, {}); opts = handleOpts(opts, {});
if (opts === null) { return null; } if (opts === null) { return null; }
parseString = opts.input; parseString = opts.input;
startProduction = {
'address': address,
'address-list': addressList,
'angle-addr': angleAddr,
'from': fromSpec,
'group': group,
'mailbox': mailbox,
'mailbox-list': mailboxList,
'reply-to': replyToSpec,
'sender': senderSpec,
}[opts.startAt] || addressList;
if (!opts.strict) { if (!opts.strict) {
initialize(); initialize();
opts.strict = true; opts.strict = true;
parsed = addressList(parseString); parsed = startProduction(parseString);
if (opts.partial || !inStr()) { if (opts.partial || !inStr()) {
return giveResult(parsed); return giveResult(parsed);
} }
@ -859,46 +967,51 @@ function parse5322(opts) {
} }
initialize(); initialize();
parsed = addressList(parseString); parsed = startProduction(parseString);
if (!opts.partial && inStr()) { return null; } if (!opts.partial && inStr()) { return null; }
return giveResult(parsed); return giveResult(parsed);
} }
function parseOneAddressSimple(opts) { function parseOneAddressSimple(opts) {
var result; return parse5322(handleOpts(opts, {
oneResult: true,
opts = handleOpts(opts, {
rfc6532: true, rfc6532: true,
simple: true simple: true,
}); startAt: 'address-list',
if (opts === null) { return null; } }));
result = parse5322(opts);
if ((!result) ||
(!opts.partial &&
(opts.simple && result.length > 1) ||
(!opts.simple && result.addresses.length > 1))) {
return null;
}
return opts.simple ?
result && result[0] :
result && result.addresses && result.addresses[0];
} }
function parseAddressListSimple(opts) { function parseAddressListSimple(opts) {
var result; return parse5322(handleOpts(opts, {
opts = handleOpts(opts, {
rfc6532: true, rfc6532: true,
simple: true simple: true,
}); startAt: 'address-list',
if (opts === null) { return null; } }));
}
result = parse5322(opts); function parseFromSimple(opts) {
return parse5322(handleOpts(opts, {
rfc6532: true,
simple: true,
startAt: 'from',
}));
}
return opts.simple ? result : result.addresses; function parseSenderSimple(opts) {
return parse5322(handleOpts(opts, {
oneResult: true,
rfc6532: true,
simple: true,
startAt: 'sender',
}));
}
function parseReplyToSimple(opts) {
return parse5322(handleOpts(opts, {
rfc6532: true,
simple: true,
startAt: 'reply-to',
}));
} }
function handleOpts(opts, defs) { function handleOpts(opts, defs) {
@ -926,24 +1039,28 @@ function handleOpts(opts, defs) {
if (!defs) { return null; } if (!defs) { return null; }
defaults = { defaults = {
rfc6532: false, oneResult: false,
partial: false, partial: false,
rejectTLD: false,
rfc6532: false,
simple: false, simple: false,
startAt: 'address-list',
strict: false, strict: false,
rejectTLD: false
}; };
for (o in defaults) { for (o in defaults) {
if (isNullUndef(opts[o])) { if (isNullUndef(opts[o])) {
opts[o] = !isNullUndef(defs[o]) ? defs[o] : defaults[o]; opts[o] = !isNullUndef(defs[o]) ? defs[o] : defaults[o];
} }
opts[o] = !!opts[o];
} }
return opts; return opts;
} }
parse5322.parseOneAddress = parseOneAddressSimple; parse5322.parseOneAddress = parseOneAddressSimple;
parse5322.parseAddressList = parseAddressListSimple; parse5322.parseAddressList = parseAddressListSimple;
parse5322.parseFrom = parseFromSimple;
parse5322.parseSender = parseSenderSimple;
parse5322.parseReplyTo = parseReplyToSimple;
// in Zammad context, go back to non CommonJS // in Zammad context, go back to non CommonJS
// if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { // if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {

View file

@ -1982,34 +1982,106 @@ test('check getRecipientArticle format', function() {
lastname: 'lastname', lastname: 'lastname',
email: 'customer@example.com', email: 'customer@example.com',
} }
agent = {
login: 'login',
firstname: 'firstname',
lastname: 'lastname',
email: 'agent@example.com',
}
ticket = { ticket = {
customer: customer, customer: customer,
} }
article = { article = {
message_id: 'message_id7', message_id: 'message_id7',
created_by: agent,
type: { type: {
name: 'email', name: 'email',
}, },
sender: { sender: {
name: 'Agent', name: 'Customer',
}, },
from: 'customer2@example.com', from: 'some other invalid part, ' + customer.email,
to: 'customer@example.com', to: 'some group',
created_by: {
login: 'login',
firstname: 'firstname',
lastname: 'lastname',
email: 'article_created_by@example.com',
}
} }
result = { result = {
to: 'customer2@example.com', to: 'customer@example.com',
cc: '', cc: '',
body: '', body: '',
in_reply_to: 'message_id7', in_reply_to: 'message_id7',
} }
verify = App.Utils.getRecipientArticle(ticket, article, article.created_by, article.type) verify = App.Utils.getRecipientArticle(ticket, article, article.created_by, article.type)
console.log(verify)
deepEqual(verify, result)
customer = {
login: 'login',
firstname: 'firstname',
lastname: 'lastname',
email: 'customer@example.com',
}
ticket = {
customer: customer,
}
article = {
message_id: 'message_id7.1',
type: {
name: 'email',
},
sender: {
name: 'Customer',
},
from: 'some other invalid part, Some Realname ' + customer.email,
to: 'some group',
created_by: {
login: 'login',
firstname: 'firstname',
lastname: 'lastname',
email: 'article_created_by@example.com',
}
}
result = {
to: 'customer@example.com',
cc: '',
body: '',
in_reply_to: 'message_id7.1',
}
verify = App.Utils.getRecipientArticle(ticket, article, article.created_by, article.type)
console.log(verify)
deepEqual(verify, result)
customer = {
login: 'login',
firstname: 'firstname',
lastname: 'lastname',
email: 'customer@example.com',
}
ticket = {
customer: customer,
}
article = {
message_id: 'message_id7.2',
type: {
name: 'email',
},
sender: {
name: 'Customer',
},
from: 'some other invalid part, Some Realname ' + customer.email + ' , abc',
to: 'some group',
created_by: {
login: 'login',
firstname: 'firstname',
lastname: 'lastname',
email: 'article_created_by@example.com',
}
}
result = {
to: 'customer@example.com',
cc: '',
body: '',
in_reply_to: 'message_id7.2',
}
verify = App.Utils.getRecipientArticle(ticket, article, article.created_by, article.type)
console.log(verify)
deepEqual(verify, result) deepEqual(verify, result)
customer = { customer = {
@ -2036,11 +2108,11 @@ test('check getRecipientArticle format', function() {
sender: { sender: {
name: 'Agent', name: 'Agent',
}, },
from: 'agent@example.com', from: 'customer2@example.com',
to: 'customer@example.com', to: 'customer@example.com',
} }
result = { result = {
to: 'customer@example.com', to: 'customer2@example.com',
cc: '', cc: '',
body: '', body: '',
in_reply_to: 'message_id8', in_reply_to: 'message_id8',
@ -2072,9 +2144,8 @@ test('check getRecipientArticle format', function() {
sender: { sender: {
name: 'Agent', name: 'Agent',
}, },
from: 'Agent@Example.com', from: 'agent@example.com',
to: 'customer@example.com', to: 'customer@example.com',
cc: 'zammad@example.com',
} }
result = { result = {
to: 'customer@example.com', to: 'customer@example.com',
@ -2110,16 +2181,16 @@ test('check getRecipientArticle format', function() {
name: 'Agent', name: 'Agent',
}, },
from: 'Agent@Example.com', from: 'Agent@Example.com',
to: 'customer@example.com, agent@example.com', to: 'customer@example.com',
cc: 'zammad@example.com', cc: 'zammad@example.com',
} }
result = { result = {
to: 'customer@example.com, agent@example.com', to: 'customer@example.com',
cc: 'zammad@example.com', cc: '',
body: '', body: '',
in_reply_to: 'message_id10', in_reply_to: 'message_id10',
} }
verify = App.Utils.getRecipientArticle(ticket, article, article.created_by, article.type, [], true) verify = App.Utils.getRecipientArticle(ticket, article, article.created_by, article.type)
deepEqual(verify, result) deepEqual(verify, result)
customer = { customer = {
@ -2147,8 +2218,8 @@ test('check getRecipientArticle format', function() {
name: 'Agent', name: 'Agent',
}, },
from: 'Agent@Example.com', from: 'Agent@Example.com',
to: 'customeR@EXAMPLE.com, agent@example.com', to: 'customer@example.com, agent@example.com',
cc: 'zammad@example.com, customer@example.com', cc: 'zammad@example.com',
} }
result = { result = {
to: 'customer@example.com, agent@example.com', to: 'customer@example.com, agent@example.com',
@ -2156,7 +2227,7 @@ test('check getRecipientArticle format', function() {
body: '', body: '',
in_reply_to: 'message_id11', in_reply_to: 'message_id11',
} }
verify = App.Utils.getRecipientArticle(ticket, article, agent, article.type, [], true) verify = App.Utils.getRecipientArticle(ticket, article, article.created_by, article.type, [], true)
deepEqual(verify, result) deepEqual(verify, result)
customer = { customer = {
@ -2184,24 +2255,16 @@ test('check getRecipientArticle format', function() {
name: 'Agent', name: 'Agent',
}, },
from: 'Agent@Example.com', from: 'Agent@Example.com',
to: 'customeR@EXAMPLE.com, agent@example.com, zammad2@EXAMPLE.com', to: 'customeR@EXAMPLE.com, agent@example.com',
cc: 'zammad@example.com, customer2@example.com', cc: 'zammad@example.com, customer@example.com',
} }
result = { result = {
to: 'customer@example.com, agent@example.com', to: 'customer@example.com, agent@example.com',
cc: 'customer2@example.com', cc: 'zammad@example.com',
body: '', body: '',
in_reply_to: 'message_id12', in_reply_to: 'message_id12',
} }
email_addresses = [ verify = App.Utils.getRecipientArticle(ticket, article, agent, article.type, [], true)
{
email: 'zammad@example.com',
},
{
email: 'zammad2@example.com',
}
]
verify = App.Utils.getRecipientArticle(ticket, article, agent, article.type, email_addresses, true)
deepEqual(verify, result) deepEqual(verify, result)
customer = { customer = {
@ -2214,7 +2277,7 @@ test('check getRecipientArticle format', function() {
login: 'login', login: 'login',
firstname: 'firstname', firstname: 'firstname',
lastname: 'lastname', lastname: 'lastname',
email: 'AGENT@example.com', email: 'agent@example.com',
} }
ticket = { ticket = {
customer: customer, customer: customer,
@ -2253,21 +2316,27 @@ test('check getRecipientArticle format', function() {
login: 'login', login: 'login',
firstname: 'firstname', firstname: 'firstname',
lastname: 'lastname', lastname: 'lastname',
email: 'zammad@example.com', email: 'customer@example.com',
}
agent = {
login: 'login',
firstname: 'firstname',
lastname: 'lastname',
email: 'AGENT@example.com',
} }
ticket = { ticket = {
customer: customer, customer: customer,
} }
article = { article = {
message_id: 'message_id14', message_id: 'message_id14',
created_by: customer, created_by: agent,
type: { type: {
name: 'email', name: 'email',
}, },
sender: { sender: {
name: 'Agent', name: 'Agent',
}, },
from: 'zammad@EXAMPLE.com', from: 'Agent@Example.com',
to: 'customeR@EXAMPLE.com, agent@example.com, zammad2@EXAMPLE.com', to: 'customeR@EXAMPLE.com, agent@example.com, zammad2@EXAMPLE.com',
cc: 'zammad@example.com, customer2@example.com', cc: 'zammad@example.com, customer2@example.com',
} }
@ -2292,7 +2361,7 @@ test('check getRecipientArticle format', function() {
login: 'login', login: 'login',
firstname: 'firstname', firstname: 'firstname',
lastname: 'lastname', lastname: 'lastname',
email: 'customer@example.com', email: 'zammad@example.com',
} }
ticket = { ticket = {
customer: customer, customer: customer,
@ -2306,13 +2375,13 @@ test('check getRecipientArticle format', function() {
sender: { sender: {
name: 'Agent', name: 'Agent',
}, },
from: 'customer@example.com', from: 'zammad@EXAMPLE.com',
to: 'customer1@example.com, customer2@example.com, zammad@example.com', to: 'customeR@EXAMPLE.com, agent@example.com, zammad2@EXAMPLE.com',
cc: '', cc: 'zammad@example.com, customer2@example.com',
} }
result = { result = {
to: 'customer1@example.com, customer2@example.com, customer@example.com', to: 'customer@example.com, agent@example.com',
cc: '', cc: 'customer2@example.com',
body: '', body: '',
in_reply_to: 'message_id15', in_reply_to: 'message_id15',
} }
@ -2346,11 +2415,11 @@ test('check getRecipientArticle format', function() {
name: 'Agent', name: 'Agent',
}, },
from: 'customer@example.com', from: 'customer@example.com',
to: 'customer1@example.com, customer2@example.com, zammad@example.com, customer2+2@example.com', to: 'customer1@example.com, customer2@example.com, zammad@example.com',
cc: '', cc: '',
} }
result = { result = {
to: 'customer1@example.com, customer2@example.com, customer2+2@example.com, customer@example.com', to: 'customer1@example.com, customer2@example.com, customer@example.com',
cc: '', cc: '',
body: '', body: '',
in_reply_to: 'message_id16', in_reply_to: 'message_id16',
@ -2372,30 +2441,24 @@ test('check getRecipientArticle format', function() {
lastname: 'lastname', lastname: 'lastname',
email: 'customer@example.com', email: 'customer@example.com',
} }
agent = {
login: 'login',
firstname: 'firstname',
lastname: 'lastname',
email: 'zammad@example.com',
}
ticket = { ticket = {
customer: customer, customer: customer,
} }
article = { article = {
message_id: 'message_id17', message_id: 'message_id17',
created_by: agent, created_by: customer,
type: { type: {
name: 'email', name: 'email',
}, },
sender: { sender: {
name: 'Agent', name: 'Agent',
}, },
from: 'zammad@example.com', from: 'customer@example.com',
to: 'customer@example.com', to: 'customer1@example.com, customer2@example.com, zammad@example.com, customer2+2@example.com',
cc: '', cc: '',
} }
result = { result = {
to: 'customer@example.com', to: 'customer1@example.com, customer2@example.com, customer2+2@example.com, customer@example.com',
cc: '', cc: '',
body: '', body: '',
in_reply_to: 'message_id17', in_reply_to: 'message_id17',
@ -2435,6 +2498,51 @@ test('check getRecipientArticle format', function() {
sender: { sender: {
name: 'Agent', name: 'Agent',
}, },
from: 'zammad@example.com',
to: 'customer@example.com',
cc: '',
}
result = {
to: 'customer@example.com',
cc: '',
body: '',
in_reply_to: 'message_id18',
}
email_addresses = [
{
email: 'zammad@example.com',
},
{
email: 'zammad2@example.com',
}
]
verify = App.Utils.getRecipientArticle(ticket, article, agent, article.type, email_addresses, true)
deepEqual(verify, result)
customer = {
login: 'login',
firstname: 'firstname',
lastname: 'lastname',
email: 'customer@example.com',
}
agent = {
login: 'login',
firstname: 'firstname',
lastname: 'lastname',
email: 'zammad@example.com',
}
ticket = {
customer: customer,
}
article = {
message_id: 'message_id19',
created_by: agent,
type: {
name: 'email',
},
sender: {
name: 'Agent',
},
from: 'Sender <zammad@example.com>', from: 'Sender <zammad@example.com>',
to: 'Customer <customer@example.com>', to: 'Customer <customer@example.com>',
cc: '', cc: '',
@ -2443,7 +2551,7 @@ test('check getRecipientArticle format', function() {
to: 'customer@example.com', to: 'customer@example.com',
cc: '', cc: '',
body: '', body: '',
in_reply_to: 'message_id18', in_reply_to: 'message_id19',
} }
email_addresses = [ email_addresses = [
{ {
@ -2466,7 +2574,7 @@ test('check getRecipientArticle format', function() {
customer: agent, customer: agent,
} }
article = { article = {
message_id: 'message_id19', message_id: 'message_id20',
created_by: agent, created_by: agent,
type: { type: {
name: 'email', name: 'email',
@ -2482,7 +2590,7 @@ test('check getRecipientArticle format', function() {
to: 'agent@example.com', to: 'agent@example.com',
cc: '', cc: '',
body: '', body: '',
in_reply_to: 'message_id19', in_reply_to: 'message_id20',
} }
email_addresses = [ email_addresses = [
{ {