UNPKG

vpn.email

Version:
276 lines (216 loc) 6.64 kB
import * as Imap from "imap"; import * as Async from "async"; import * as mailcomposer from "mailcomposer"; import * as mailparser from 'mailparser'; import * as shortID from 'shortid' import * as Net from 'net' import * as Stream from 'stream' const idleInterval = 1000 * 60 * 60 * 24 const openBox = ( imap: startImap, mailBox, cb: ( err?: Error ) => void ) => { 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: IinputData, debug: boolean, forever: boolean ) => { const keepalive = ( /outlook.com$|/.test (nodeImap.imapServer)) const ret : IMAP.Config = { 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; } export default class startImap { private lastNewMail = new Date() private checkBusy = null private destroy = false; private reConnectCount = 0 private connected = false private fetching = false private fetchWait = false private busy = false private delayTime = null private scanEmail = ( imap: IMAP.Connection ) => { 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: mailparser.ParsedMail ) => { 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: Stream.Readable ) => { 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 ) */ }) }) }) } public imap: IMAP.Connection = null; public save = ( enCtypeMessage: Buffer , writeFolder: string, CallBack: ICallBack ) => { 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: Buffer, 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 () }) } public 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 () }) } private connectImap ( yyy: IMAP.Config ) { 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: Error ) => { 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 (); } constructor ( private imapAcc: IinputData, private listeningFolder: string, private reConnect: boolean, private delBox: boolean, private newMailFunction: ( msg: Buffer ) => void, private CallBack: ICallBack ) { const yyy = getImapConnect ( imapAcc, false, true ); this.connectImap ( yyy ) } }