vpn.email
Version:
vpn.email client
220 lines (219 loc) • 8.37 kB
JavaScript
"use strict";
const Imap = require("imap");
const Async = require("async");
const mailcomposer = require("mailcomposer");
const mailparser = require("mailparser");
const idleInterval = 1000 * 60 * 60 * 24;
const openBox = (imap, mailBox, cb) => {
if (imap.imap.state !== 'authenticated') {
console.log(imap.imap.state);
return setTimeout(() => {
openBox(imap, mailBox, cb);
}, 1000);
}
imap.imap.openBox(mailBox, false, err => {
if (err) {
return imap.imap.addBox(mailBox, err1 => {
if (err1)
return cb(err);
openBox(imap, mailBox, cb);
});
}
return cb();
});
};
const getImapConnect = (nodeImap, debug, forever) => {
const keepalive = (/outlook.com$|/.test(nodeImap.imapServer));
const ret = {
user: nodeImap.imapUserName,
host: nodeImap.imapServer,
password: nodeImap.imapUserPassword,
port: parseInt(nodeImap.imapPortNumber),
tls: nodeImap.imapSsl,
debug: debug
? (err) => { console.log(new Date(), ' = ', err); }
: null,
keepalive: {
interval: 400,
idleInterval: idleInterval,
forceNoop: true
}
};
return ret;
};
class startImap {
constructor(imapAcc, listeningFolder, reConnect, delBox, newMailFunction, CallBack) {
this.imapAcc = imapAcc;
this.listeningFolder = listeningFolder;
this.reConnect = reConnect;
this.delBox = delBox;
this.newMailFunction = newMailFunction;
this.CallBack = CallBack;
this.lastNewMail = new Date();
this.checkBusy = null;
this.destroy = false;
this.reConnectCount = 0;
this.connected = false;
this.fetching = false;
this.fetchWait = false;
this.busy = false;
this.delayTime = null;
this.scanEmail = (imap) => {
this.fetching = true;
this.fetchWait = false;
return imap.search(['UNSEEN'], (err, results) => {
if (err) {
console.log('imap.search error ');
if (this.fetchWait)
return this.scanEmail(imap);
return this.fetching = false;
}
if (!results || !results.length) {
if (this.fetchWait)
return this.scanEmail(imap);
return this.fetching = false;
}
let fetch = imap.fetch(results, { markSeen: true, bodies: '' });
fetch.on('message', msg => {
let mp = new mailparser.MailParser();
mp.once('end', (msg) => {
if (msg.attachments && msg.attachments.length) {
return this.newMailFunction(msg.attachments[0].content);
}
/*
const interval = 100 + Math.random () * 200
this.imap._config.keepalive.interval = interval
console.log ( 'have not attachments' )
*/
});
msg.on('body', (data) => {
return data.pipe(mp);
});
msg.once('end', () => {
});
});
fetch.once('error', err => {
this.fetching = this.busy = false;
fetch.removeAllListeners();
fetch = null;
return console.log(this.imapAcc.imapUserName, ' fetch error ', err);
});
fetch.once('end', () => {
return Async.series([
next => imap.addFlags(results, ['\\Deleted'], next),
next => imap.expunge(results, next)
], err => {
fetch.removeAllListeners();
fetch = null;
//console.log ( 'fetch.once END!!' )
if (this.fetchWait)
return this.scanEmail(imap);
return this.busy = this.fetching = this.fetchWait = false;
/*
this.lastNewMail = new Date ()
const interval = 100 + Math.random () * 200
this.imap._config.keepalive.interval = interval
//console.log ( ' fetch end set new interval = ', interval )
*/
});
});
});
};
this.imap = null;
this.save = (enCtypeMessage, writeFolder, CallBack) => {
if (this.destroy)
return;
if (!this.connected) {
return setTimeout(() => {
this.save(enCtypeMessage, writeFolder, CallBack);
}, 1000);
}
this.busy = true;
const email = mailcomposer({
attachments: [{
filename: false,
content: enCtypeMessage
}]
});
return Async.waterfall([
next => email.build(next),
(data, next) => {
//console.log (`${ new Date().toISOString() }===========>[${jj.uuid}][${jj.serial}]->[${jj.command}][${jj.buffer.toString('hex',0,30)}]`)
this.imap.append(data, { mailbox: writeFolder }, next);
}
], err => {
this.busy = false;
if (err) {
console.log('imap save got error!', err.message);
return CallBack(err);
}
return CallBack();
});
};
const yyy = getImapConnect(imapAcc, false, true);
this.connectImap(yyy);
}
destroyImap() {
if (this.busy) {
console.log('this.busy destroy wait 5 seconds!', this.listeningFolder);
return setTimeout(() => {
this.destroyImap();
}, 5000);
}
this.destroy = true;
if (!this.delBox) {
return this.imap.end();
}
this.imap.delBox(this.listeningFolder, () => {
return this.imap.end();
});
}
connectImap(yyy) {
this.imap = new Imap(yyy);
this.imap.once('ready', err => {
return openBox(this, this.listeningFolder, err => {
if (err) {
this.destroyImap();
}
this.delayTime = new Date().getTime() - this.delayTime;
this.connected = true;
});
});
this.imap.on('mail', mail => {
this.busy = true;
if (this.fetching)
return this.fetchWait = true;
return this.scanEmail(this.imap);
});
this.imap.on('error', (err) => {
console.log('err!', err.message);
if (this.reConnect || /^Timed out while authenticating with server$|ECONNRESET/.test(err.message))
return setTimeout(() => {
if (this.imap && this.imap.connect) {
console.log('try re connect');
return this.imap.connect();
}
console.log('dont try again');
this.destroy = true;
return this.destroyImap();
}, 3000);
console.log('this.imap.on error, stop imap');
this.destroy = true;
this.imap.removeAllListeners();
this.imap.destroy();
return this.CallBack(err);
});
this.imap.once('end', () => {
if (this.reConnect && !this.destroy) {
return this.connectImap(yyy);
}
this.imap.removeAllListeners();
this.imap = null;
return this.CallBack(null, this.delayTime);
});
this.delayTime = new Date().getTime();
return this.imap.connect();
}
}
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = startImap;