diff --git a/config/default.js b/config/default.js index 840d368d..7b431a25 100644 --- a/config/default.js +++ b/config/default.js @@ -151,7 +151,9 @@ module.exports = { password: 'socks pass' } */ - } + }, + + 'core/image-hashes': false // 'receiver' }, // You can define multiple listening SMTP interfaces, for example one for port 465, one for 587 etc diff --git a/lib/address-tools.js b/lib/address-tools.js index 1d78701f..bfcbd9d7 100644 --- a/lib/address-tools.js +++ b/lib/address-tools.js @@ -15,32 +15,29 @@ module.exports = { function validateAddress(headers, key) { let addressList = parseAddressList(headers, key, true); + addressList.forEach(address => { + try { + address.name = libmime.decodeWords(address.name || ''); + } catch (E) { + // most probably an unknown charset was used, so keep as is + } + }); return { - addresses: addressList.map(address => address.address), - set: address => { + addresses: addressList, + set() { + let address = [].concat([...arguments]); let values = []; parseAddressses([].concat(address || []), true).forEach(parsed => { if (!parsed || !parsed.address) { return; } - if (!parsed.name) { - let existing = addressList.find(entry => entry.address === parsed.address); - if (existing && existing.name) { - parsed.name = existing.name; - } - } - try { - parsed.name = libmime.decodeWords(parsed.name || ''); - if (!/^[\w ']*$/.test(parsed.name)) { // check if contains only letters and numbers and such - if (/^[\x20-\x7e]*$/.test(parsed.name)) { // check if only contains ascii characters - parsed.name = '"' + parsed.name.replace(/([\\"])/g, '\\$1') + '"'; - } else { // requires mime encoding - parsed.name = libmime.encodeWord(parsed.name, 'Q', 52); - } + if (!/^[\w ']*$/.test(parsed.name)) { // check if contains only letters and numbers and such + if (/^[\x20-\x7e]*$/.test(parsed.name)) { // check if only contains ascii characters + parsed.name = '"' + parsed.name.replace(/([\\"])/g, '\\$1') + '"'; + } else { // requires mime encoding + parsed.name = libmime.encodeWord(parsed.name, 'Q', 52); } - } catch (E) { - // most probably an unknown charset was used, keep as is } values.push(parsed.name ? parsed.name + ' <' + parsed.address + '>' : parsed.address); @@ -76,11 +73,21 @@ function parseAddressList(headers, key, withNames) { } function parseAddressses(headerList, withNames) { - let map = convertAddresses(headerList.map(addressparser), withNames); + let map = convertAddresses(headerList.map(address => { + if (typeof address === 'string') { + address = addressparser(address); + } + return address; + }), withNames); return Array.from(map).map(entry => entry[1]); } function normalizeAddress(address, withNames) { + if (typeof address === 'string') { + address = { + address + }; + } if (!address || !address.address) { return ''; } diff --git a/plugins/README.md b/plugins/README.md index 3a831658..be5fd87e 100644 --- a/plugins/README.md +++ b/plugins/README.md @@ -296,7 +296,7 @@ Where Return value is an object with the following properties: -- **addresses** an array of (plain) e-mail addresses found for that key +- **addresses** an array of e-mail addresses found for that key (structured values) - **set** _(addresses)_ a method that overrides original key with new addresses **Example** @@ -304,7 +304,12 @@ Return value is an object with the following properties: ```javascript // From: Sender Name let from = app.validateAddress(envelope.headers, 'from'); -from.addresses // ['sender@example.com'] -from.set('another@blurdybloop.com'); -// From: Sender Name +from.addresses // [{name:'Sender Name', address: 'sender@example.com'}] +from.set('My Name '); +// From: first@blurdybloop.com +from.set({ + name: 'My Name', + address: 'first@blurdybloop.com' +}); +// From: first@blurdybloop.com ``` diff --git a/plugins/core/image-hashes.js b/plugins/core/image-hashes.js new file mode 100644 index 00000000..fedf8b11 --- /dev/null +++ b/plugins/core/image-hashes.js @@ -0,0 +1,40 @@ +'use strict'; + + +const crypto = require('crypto'); + +// Set module title +module.exports.title = 'Image Hashes'; + +// Initialize the module +module.exports.init = (app, done) => { + // This example calculates MD5 hash for every image in the message + app.addStreamHook((envelope, node) => /^(image|application)\//i.test(node.contentType), (envelope, node, source, done) => { + let hash = crypto.createHash('md5'); + let filename = node.filename; + let contentType = node.contentType; + let bytes = 0; + + source.on('data', chunk => { + bytes += chunk.length; + hash.update(chunk); + }); + + source.on('end', () => { + if (!envelope.attachments) { + envelope.attachments = []; + } + hash = hash.digest('hex'); + envelope.attachments.push({ + name: filename, + type: contentType, + hash + }); + app.logger.info('ImageHash', '%s ATTACHMENT name="%s" type="%s" size=%s md5=%s', envelope.id, filename || '', contentType, bytes, hash); + done(); + }); + }); + + // all set up regarding this plugin + done(); +}; diff --git a/test/address-tools-test.js b/test/address-tools-test.js index d8e67fdb..96243cf5 100644 --- a/test/address-tools-test.js +++ b/test/address-tools-test.js @@ -70,7 +70,16 @@ module.exports['#validateAddress'] = test => { let parsed = addressTools.validateAddress(headers, 'from'); - test.deepEqual(parsed.addresses, ['andris1@kreata.ee', 'andris2@kreata.ee', 'andris3@kreata.ee']); + test.deepEqual(parsed.addresses, [{ + name: '', + address: 'andris1@kreata.ee' + }, { + name: 'Andris4', + address: 'andris2@kreata.ee' + }, { + name: 'Andris3', + address: 'andris3@kreata.ee' + }]); parsed.set('Juhan Liiv '); @@ -113,16 +122,28 @@ module.exports['#validateAddress, multiple'] = test => { let parsed = addressTools.validateAddress(headers, 'to'); - test.deepEqual(parsed.addresses, ['andris1@kreata.ee', 'andris2@kreata.ee', 'andris3@kreata.ee']); + test.deepEqual(parsed.addresses, [{ + name: '', + address: 'andris1@kreata.ee' + }, { + name: 'Andris4', + address: 'andris2@kreata.ee' + }, { + name: 'Andris3', + address: 'andris3@kreata.ee' + }]); - parsed.set('Juhan Liiv , Jõgeva , andris3@kreata.ee'); + parsed.set('Juhan Liiv , Jõgeva , andris3@kreata.ee', { + name: 'Andris3', + address: 'andris4@kreata.ee' + }); test.deepEqual(headers.getList(), [{ key: 'x-prev', line: 'X-Prev: previous line' }, { key: 'to', - line: 'to: Juhan Liiv , =?UTF-8?Q?J=C3=B5geva?=\r\n , Andris3 ' + line: 'to: Juhan Liiv , =?UTF-8?Q?J=C3=B5geva?=\r\n , andris3@kreata.ee, Andris3 ' }, { key: 'x-mid', line: 'X-Mid: middle line'