vpn.email
Version:
vpn.email client
291 lines (194 loc) • 7.97 kB
text/typescript
import * as IMAP from 'imap';
import * as event from 'events';
import * as mailparser from 'mailparser';
import * as async from 'async';
import * as smtpClass from './smtpClass';
interface nodeImap {
imap_account: string;
imap_password: string;
}
const Mailparser = mailparser.MailParser;
/**
* @param imap {IMAP.Connection} imap Connection.
* @param mailBox {string} mail box name that want open
* @cb {function} call back function
*/
const openInbox = ( imap, mailBox: string, cb: ( err?: Error, box? ) => void ) => {
imap.openBox ( mailBox, false, err => {
if ( err ) {
imap.addBox ( mailBox, err1 => {
if ( err1 )
return cb ( err1 );
return openInbox ( imap, mailBox, cb );
})
}
cb ();
})
}
/**
* @param imap {IMAP.Connection}
* @param clearBox {boolean}
* @param events {event.EventEmitter}
* Decryption (msg.attachments[0].content.toString('utf8') , key.password, key.private, service.public_key, ( err, data ) => {
* data.signatures[0].valid
*/
const scanEmail = ( imap, clearBox = false, events: event.EventEmitter, CallBack: ICallBack = null ) => {
async.waterfall ([ next => {
imap.search ( [ 'UNSEEN' ], next );
}, ( results, next ) => {
if ( !results || !results.length )
return next ();
const fetch = imap.fetch ( results, { markSeen : true, bodies: [ '' ]});
let ret = [];
fetch.on ( 'message', msg => {
let mp = new Mailparser ();
let buffer = '';
mp.once ( 'end', msg => {
events.emit ( 'email', msg );
})
msg.on ( 'body', data => {
data.on ('data', ( chunk ) => {
buffer += chunk.toString ()
})
})
msg.once ( 'end', () => {
mp.write ( buffer );
mp.end ()
})
})
fetch.once ( 'error', err => {
next ( err )
})
fetch.once ( 'end', () => {
if ( clearBox )
return imap.addFlags ( results, [ '\\Deleted' ], next );
next ( null );
})
}], err => {
if ( err ) return events.emit ( 'error', err );
if ( CallBack && typeof CallBack === 'function' )
CallBack ()
})
}
/***
* @param user {string} imap user name.
* @param password {string} imap user password
* @param mailBoxName {string} open mail box name
* @param forever {boolean} if forever true
*
* event emit ***
* @param error {Error} when err
* @param email {mailparser.ParsedMail []} new email data
*
* event listen ***
* @param save
*/
export default class imapConnect {
private _imapConnects: IMAP.Connection;
static type = 'class imapConnect ';
public _events = new event.EventEmitter ();
private imapEnd = false;
private haveError = false;
public openFolder = false;
private CallBack = null;
constructor ( private user: string, private password: string, private host: string, private port: number,
private tls: boolean, private newMailCheck: boolean, private mailBoxName,
private clearBox:boolean, private forever: boolean, private isTest: boolean, private debug: boolean) {
const ImapConnectConfig = {
user: user,
host: host,
password: password,
port: port,
tls: tls,
debug: debug
? ( err ) => { console.log ( new Date(), ' = ', err )}
: null,
keepalive: true
}
this.imapEnd = !forever
this._imapConnects = new IMAP ( ImapConnectConfig )
if ( ! isTest )
this.connect ()
}
public connect ( CallBack : ICallBack = null ) {
this.CallBack = CallBack;
this._imapConnects.once ( 'ready', () => {
if ( this.mailBoxName ) {
const loop = () => {
if ( this._imapConnects.state !== 'authenticated' ) {
return setTimeout (() => {
loop ()
}, 1000 );
}
openInbox ( this._imapConnects, this.mailBoxName, ( err, box ) => {
if ( err ) {
console.log ( err.message );
}
console.log ( 'watch mail box ready:', this.mailBoxName )
this.openFolder = true;
this._events.emit ( 'imapReady' )
if ( this.imapEnd ) {
this._imapConnects.destroy ();
}
if ( CallBack && typeof CallBack === 'function' ) {
CallBack ( null, this )
}
})
}
loop();
}
})
this._imapConnects.on ( 'mail', () => {
if ( this.newMailCheck ) {
scanEmail ( this._imapConnects, this.clearBox, this._events );
}
})
this._events.once ( 'end', () => {
//console.log ('this._imapConnects.once end')
this._imapConnects.destroy ();
this._events.emit ( 'end' );
})
this._imapConnects.once ( 'error', ( err ) => {
console.log ('this._imapConnects.once error')
if ( this.forever ) {
this._imapConnects.connect ();
}
this._events.emit ( 'error', err );
})
this._imapConnects.connect ();
}
public save ( boxName:string, email: mailcomposer, CallBack: ICallBack ) {
if ( this._imapConnects.state !== 'authenticated' ) {
return setTimeout (() => {
this.save ( boxName, email, CallBack )
}, 2000 );
}
console.log ( 'save message to folder', boxName )
async.waterfall ([
next => {
email.build ( next );
}, ( data, next ) => {
this._imapConnects.append ( data, { mailbox: boxName }, next );
}
], ( err, data ) => {
if ( err ) {
return this._imapConnects.addBox ( boxName, err => {
if ( err ) {
return CallBack ( err );
}
this.save ( boxName, email, CallBack );
})
}
if ( !this.forever ) {
this._imapConnects.end ();
}
CallBack ()
})
}
public distroy () {
this._imapConnects.removeAllListeners()
this._imapConnects.delBox ( this.mailBoxName, () => {
this._imapConnects.destroy ()
})
}
}