wildduck/imap.js

264 lines
7.8 KiB
JavaScript
Raw Normal View History

2017-03-06 22:13:40 +08:00
'use strict';
const log = require('npmlog');
2017-07-16 19:37:33 +08:00
const config = require('wild-config');
2017-03-06 22:13:40 +08:00
const IMAPServerModule = require('./imap-core');
const IMAPServer = IMAPServerModule.IMAPServer;
const ImapNotifier = require('./lib/imap-notifier');
2017-03-06 22:13:40 +08:00
const Indexer = require('./imap-core/lib/indexer/indexer');
const MessageHandler = require('./lib/message-handler');
2017-04-21 01:10:03 +08:00
const UserHandler = require('./lib/user-handler');
2017-07-21 02:33:41 +08:00
const MailboxHandler = require('./lib/mailbox-handler');
const db = require('./lib/db');
const packageData = require('./package.json');
const certs = require('./lib/certs');
2018-10-18 15:37:32 +08:00
const Gelf = require('gelf');
const os = require('os');
2017-03-06 22:13:40 +08:00
const onFetch = require('./lib/handlers/on-fetch');
const onAuth = require('./lib/handlers/on-auth');
const onList = require('./lib/handlers/on-list');
const onLsub = require('./lib/handlers/on-lsub');
const onSubscribe = require('./lib/handlers/on-subscribe');
const onUnsubscribe = require('./lib/handlers/on-unsubscribe');
const onCreate = require('./lib/handlers/on-create');
const onRename = require('./lib/handlers/on-rename');
const onDelete = require('./lib/handlers/on-delete');
const onOpen = require('./lib/handlers/on-open');
const onStatus = require('./lib/handlers/on-status');
const onAppend = require('./lib/handlers/on-append');
const onStore = require('./lib/handlers/on-store');
const onExpunge = require('./lib/handlers/on-expunge');
const onCopy = require('./lib/handlers/on-copy');
const onMove = require('./lib/handlers/on-move');
const onSearch = require('./lib/handlers/on-search');
const onGetQuotaRoot = require('./lib/handlers/on-get-quota-root');
const onGetQuota = require('./lib/handlers/on-get-quota');
2017-11-07 00:00:09 +08:00
let logger = {
info(...args) {
args.shift();
log.info('IMAP', ...args);
},
2017-11-07 00:00:09 +08:00
debug(...args) {
args.shift();
log.silly('IMAP', ...args);
},
2017-11-07 00:00:09 +08:00
error(...args) {
args.shift();
log.error('IMAP', ...args);
}
};
2017-03-06 22:13:40 +08:00
2017-11-07 00:00:09 +08:00
let indexer;
let notifier;
let messageHandler;
let userHandler;
2017-07-21 02:33:41 +08:00
let mailboxHandler;
2018-10-18 15:37:32 +08:00
let loggelf;
2017-11-07 00:00:09 +08:00
let createInterface = (ifaceOptions, callback) => {
// Setup server
const serverOptions = {
secure: ifaceOptions.secure,
2017-12-01 16:02:40 +08:00
secured: ifaceOptions.secured,
2017-11-07 00:00:09 +08:00
disableSTARTTLS: ifaceOptions.disableSTARTTLS,
ignoreSTARTTLS: ifaceOptions.ignoreSTARTTLS,
useProxy: !!config.imap.useProxy,
ignoredHosts: config.imap.ignoredHosts,
id: {
2018-01-02 21:04:01 +08:00
name: config.imap.name || 'WildDuck IMAP Server',
2017-11-07 00:00:09 +08:00
version: config.imap.version || packageData.version,
vendor: config.imap.vendor || 'Kreata'
},
logger,
maxMessage: config.imap.maxMB * 1024 * 1024,
2018-11-16 16:01:18 +08:00
maxStorage: config.maxStorage * 1024 * 1024,
skipFetchLog: config.log.skipFetchLog
2017-11-07 00:00:09 +08:00
};
certs.loadTLSOptions(serverOptions, 'imap');
const server = new IMAPServer(serverOptions);
certs.registerReload(server, 'imap');
let started = false;
server.on('error', err => {
if (!started) {
started = true;
return callback(err);
}
logger.error(
{
err
},
'%s',
err.message
);
});
server.indexer = indexer;
server.notifier = notifier;
// setup command handlers for the server instance
2017-12-08 20:29:00 +08:00
server.onFetch = onFetch(server, messageHandler, userHandler.userCache);
server.onAuth = onAuth(server, userHandler, userHandler.userCache);
2017-11-07 00:00:09 +08:00
server.onList = onList(server);
server.onLsub = onLsub(server);
server.onSubscribe = onSubscribe(server);
server.onUnsubscribe = onUnsubscribe(server);
server.onCreate = onCreate(server, mailboxHandler);
server.onRename = onRename(server, mailboxHandler);
server.onDelete = onDelete(server, mailboxHandler);
server.onOpen = onOpen(server);
server.onStatus = onStatus(server);
2017-12-08 20:29:00 +08:00
server.onAppend = onAppend(server, messageHandler, userHandler.userCache);
2017-11-07 00:00:09 +08:00
server.onStore = onStore(server);
server.onExpunge = onExpunge(server, messageHandler);
server.onCopy = onCopy(server, messageHandler);
server.onMove = onMove(server, messageHandler);
server.onSearch = onSearch(server);
server.onGetQuotaRoot = onGetQuotaRoot(server);
server.onGetQuota = onGetQuota(server);
2018-10-31 16:04:32 +08:00
if (loggelf) {
server.loggelf = loggelf;
}
2017-11-07 00:00:09 +08:00
// start listening
server.listen(ifaceOptions.port, ifaceOptions.host, () => {
if (started) {
return server.close();
}
started = true;
callback(null, server);
});
};
module.exports = done => {
2017-04-13 16:35:39 +08:00
if (!config.imap.enabled) {
return setImmediate(() => done(null, false));
}
2018-10-18 15:37:32 +08:00
const component = config.log.gelf.component || 'wildduck';
const hostname = config.log.gelf.hostname || os.hostname();
const gelf =
config.log.gelf && config.log.gelf.enabled
? new Gelf(config.log.gelf.options)
: {
// placeholder
emit: () => false
};
loggelf = message => {
if (typeof message === 'string') {
message = {
short_message: message
};
}
2018-10-18 16:53:14 +08:00
2018-10-18 15:37:32 +08:00
message = message || {};
2018-10-18 16:53:14 +08:00
if (!message.short_message || message.short_message.indexOf(component.toUpperCase()) !== 0) {
message.short_message = component.toUpperCase() + ' ' + (message.short_message || '');
}
2018-10-18 15:37:32 +08:00
message.facility = component; // facility is deprecated but set by the driver if not provided
message.host = hostname;
message.timestamp = Date.now() / 1000;
message._component = component;
Object.keys(message).forEach(key => {
if (!message[key]) {
delete message[key];
}
});
2018-10-31 16:17:33 +08:00
try {
gelf.emit('gelf.log', message);
} catch (err) {
log.error('Gelf', err);
}
2018-10-18 15:37:32 +08:00
};
2018-10-10 21:19:20 +08:00
indexer = new Indexer({
database: db.database
2017-07-12 02:38:23 +08:00
});
2018-10-10 21:19:20 +08:00
// setup notification system for updates
notifier = new ImapNotifier({
database: db.database,
redis: db.redis
});
2017-07-21 02:33:41 +08:00
2018-10-10 21:19:20 +08:00
messageHandler = new MessageHandler({
database: db.database,
redis: db.redis,
gridfs: db.gridfs,
2018-10-18 15:37:32 +08:00
attachments: config.attachments,
loggelf: message => loggelf(message)
2018-10-10 21:19:20 +08:00
});
2017-11-07 00:00:09 +08:00
2018-10-10 21:19:20 +08:00
userHandler = new UserHandler({
database: db.database,
users: db.users,
redis: db.redis,
2018-10-18 15:37:32 +08:00
authlogExpireDays: config.log.authlogExpireDays,
loggelf: message => loggelf(message)
2018-10-10 21:19:20 +08:00
});
2018-10-10 21:19:20 +08:00
mailboxHandler = new MailboxHandler({
database: db.database,
users: db.users,
redis: db.redis,
2018-10-18 15:37:32 +08:00
notifier,
loggelf: message => loggelf(message)
2018-10-10 21:19:20 +08:00
});
2018-10-10 21:19:20 +08:00
let ifaceOptions = [
{
enabled: true,
secure: config.imap.secure,
disableSTARTTLS: config.imap.disableSTARTTLS,
ignoreSTARTTLS: config.imap.ignoreSTARTTLS,
host: config.imap.host,
port: config.imap.port
2017-09-26 14:58:37 +08:00
}
2018-10-10 21:19:20 +08:00
]
.concat(config.imap.interface || [])
.filter(iface => iface.enabled);
let iPos = 0;
let startInterfaces = () => {
if (iPos >= ifaceOptions.length) {
return done();
2017-07-12 02:38:23 +08:00
}
2018-10-10 21:19:20 +08:00
let opts = ifaceOptions[iPos++];
createInterface(opts, err => {
2017-07-12 02:38:23 +08:00
if (err) {
2017-11-07 00:00:09 +08:00
logger.error(
2017-07-12 02:38:23 +08:00
{
err,
2018-10-10 21:19:20 +08:00
tnx: 'bind'
2017-07-12 02:38:23 +08:00
},
2018-10-10 21:19:20 +08:00
'Failed starting %sIMAP interface %s:%s. %s',
opts.secure ? 'secure ' : '',
opts.host,
opts.port,
2017-07-12 02:38:23 +08:00
err.message
);
2018-10-10 21:19:20 +08:00
return done(err);
2017-07-12 02:38:23 +08:00
}
2018-10-10 21:19:20 +08:00
setImmediate(startInterfaces);
2017-07-12 02:38:23 +08:00
});
};
2018-10-10 21:19:20 +08:00
setImmediate(startInterfaces);
2017-03-06 22:13:40 +08:00
};