mirror of
https://github.com/node-red/node-red-nodes.git
synced 2025-03-01 10:37:43 +00:00
Update POP3 dependency
Removed dependency to poplib.js, moved to node-pop3. Re-wrote checkPOP3 function asynchronously using the new library. Added some node.status changes to mimic IMAP behaviour.
This commit is contained in:
parent
4d5eb1c811
commit
7964a1e7e3
@ -49,7 +49,7 @@
|
||||
"node-red": "^2.1.4",
|
||||
"node-red-node-test-helper": "^0.2.7",
|
||||
"nodemailer": "^6.7.2",
|
||||
"poplib": "^0.1.7",
|
||||
"node-pop3": "^0.8.0",
|
||||
"proxyquire": "^2.1.3",
|
||||
"pushbullet": "^2.4.0",
|
||||
"sentiment": "^2.1.0",
|
||||
|
@ -6,7 +6,7 @@ const { domainToUnicode } = require("url");
|
||||
* POP3 protocol - RFC1939 - https://www.ietf.org/rfc/rfc1939.txt
|
||||
*
|
||||
* Dependencies:
|
||||
* * poplib - https://www.npmjs.com/package/poplib
|
||||
* * node-pop3 - https://www.npmjs.com/package/node-pop3
|
||||
* * nodemailer - https://www.npmjs.com/package/nodemailer
|
||||
* * imap - https://www.npmjs.com/package/imap
|
||||
* * mailparser - https://www.npmjs.com/package/mailparser
|
||||
@ -16,7 +16,7 @@ module.exports = function(RED) {
|
||||
"use strict";
|
||||
var util = require("util");
|
||||
var Imap = require('imap');
|
||||
var POP3Client = require("./poplib.js");
|
||||
var Pop3Command = require("node-pop3");
|
||||
var nodemailer = require("nodemailer");
|
||||
var simpleParser = require("mailparser").simpleParser;
|
||||
var SMTPServer = require("smtp-server").SMTPServer;
|
||||
@ -178,6 +178,7 @@ module.exports = function(RED) {
|
||||
// Setup the EmailInNode
|
||||
function EmailInNode(n) {
|
||||
var imap;
|
||||
var pop3;
|
||||
|
||||
RED.nodes.createNode(this,n);
|
||||
this.name = n.name;
|
||||
@ -272,106 +273,75 @@ module.exports = function(RED) {
|
||||
// Check the POP3 email mailbox for any new messages. For any that are found,
|
||||
// retrieve each message, call processNewMessage to process it and then delete
|
||||
// the messages from the server.
|
||||
function checkPOP3(msg,send,done) {
|
||||
var currentMessage;
|
||||
var maxMessage;
|
||||
//node.log("Checking POP3 for new messages");
|
||||
|
||||
// Form a new connection to our email server using POP3.
|
||||
var pop3Client = new POP3Client(
|
||||
node.inport, node.inserver,
|
||||
{enabletls: node.useSSL} // Should we use SSL to connect to our email server?
|
||||
);
|
||||
|
||||
// If we have a next message to retrieve, ask to retrieve it otherwise issue a
|
||||
// quit request.
|
||||
function nextMessage() {
|
||||
if (currentMessage > maxMessage) {
|
||||
pop3Client.quit();
|
||||
setInputRepeatTimeout();
|
||||
done();
|
||||
return;
|
||||
}
|
||||
pop3Client.retr(currentMessage);
|
||||
currentMessage++;
|
||||
} // End of nextMessage
|
||||
|
||||
pop3Client.on("stat", function(status, data) {
|
||||
// Data contains:
|
||||
// {
|
||||
// count: <Number of messages to be read>
|
||||
// octect: <size of messages to be read>
|
||||
// }
|
||||
if (status) {
|
||||
currentMessage = 1;
|
||||
maxMessage = data.count;
|
||||
nextMessage();
|
||||
} else {
|
||||
node.log(util.format("stat error: %s %j", status, data));
|
||||
}
|
||||
async function checkPOP3(msg,send,done) {
|
||||
var tout = (node.repeat > 0) ? node.repeat - 500 : 15000;
|
||||
var currentMessage = 1;
|
||||
var maxMessage = 0;
|
||||
var nextMessage;
|
||||
|
||||
pop3 = new Pop3Command({
|
||||
"host": node.inserver,
|
||||
"tls": node.useSSL,
|
||||
"timeout": tout,
|
||||
"port": node.inport
|
||||
});
|
||||
try {
|
||||
node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connecting"});
|
||||
await pop3.connect();
|
||||
|
||||
pop3Client.on("error", function(err) {
|
||||
await pop3.command('USER', node.userid);
|
||||
await pop3.command('PASS', node.password);
|
||||
} catch(err) {
|
||||
node.error(err.message,err);
|
||||
node.status({fill:"red",shape:"ring",text:"email.status.connecterror"});
|
||||
setInputRepeatTimeout();
|
||||
node.log("error: " + JSON.stringify(err));
|
||||
done();
|
||||
});
|
||||
|
||||
pop3Client.on("connect", function() {
|
||||
//node.log("We are now connected");
|
||||
pop3Client.login(node.userid, node.password);
|
||||
});
|
||||
|
||||
pop3Client.on("login", function(status, rawData) {
|
||||
//node.log("login: " + status + ", " + rawData);
|
||||
if (status) {
|
||||
pop3Client.stat();
|
||||
} else {
|
||||
node.log(util.format("login error: %s %j", status, rawData));
|
||||
pop3Client.quit();
|
||||
setInputRepeatTimeout();
|
||||
done();
|
||||
return;
|
||||
}
|
||||
maxMessage = (await pop3.STAT()).split(" ")[0];
|
||||
if(maxMessage>0) {
|
||||
node.status({fill:"blue", shape:"dot", text:"email.status.fetching"});
|
||||
while(currentMessage<=maxMessage) {
|
||||
try {
|
||||
nextMessage = await pop3.RETR(currentMessage);
|
||||
} catch(err) {
|
||||
node.error(RED._("email.errors.fetchfail", err.message),err);
|
||||
node.status({fill:"red",shape:"ring",text:"email.status.fetcherror"});
|
||||
setInputRepeatTimeout();
|
||||
done();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// We have now received a new email message. Create an instance of a mail parser
|
||||
// and pass in the email message. The parser will signal when it has parsed the message.
|
||||
simpleParser(nextMessage, {}, function(err, parsed) {
|
||||
//node.log(util.format("simpleParser: on(end): %j", mailObject));
|
||||
if (err) {
|
||||
node.status({fill:"red", shape:"ring", text:"email.status.parseerror"});
|
||||
node.error(RED._("email.errors.parsefail", {folder:node.box}), err);
|
||||
}
|
||||
else {
|
||||
processNewMessage(msg, parsed);
|
||||
}
|
||||
});
|
||||
//processNewMessage(msg, nextMessage);
|
||||
} catch(err) {
|
||||
node.error(RED._("email.errors.parsefail", {folder:node.box}), err);
|
||||
node.status({fill:"red",shape:"ring",text:"email.status.parseerror"});
|
||||
setInputRepeatTimeout();
|
||||
done();
|
||||
return;
|
||||
}
|
||||
await pop3.DELE(currentMessage);
|
||||
currentMessage++;
|
||||
}
|
||||
});
|
||||
await pop3.QUIT();
|
||||
node.status({fill:"green",shape:"dot",text:"finished"});
|
||||
setTimeout(status_clear, 5000);
|
||||
setInputRepeatTimeout();
|
||||
done();
|
||||
}
|
||||
|
||||
pop3Client.on("retr", function(status, msgNumber, data, rawData) {
|
||||
// node.log(util.format("retr: status=%s, msgNumber=%d, data=%j", status, msgNumber, data));
|
||||
if (status) {
|
||||
// We have now received a new email message. Create an instance of a mail parser
|
||||
// and pass in the email message. The parser will signal when it has parsed the message.
|
||||
simpleParser(data, {}, function(err, parsed) {
|
||||
//node.log(util.format("simpleParser: on(end): %j", mailObject));
|
||||
if (err) {
|
||||
node.status({fill:"red", shape:"ring", text:"email.status.parseerror"});
|
||||
node.error(RED._("email.errors.parsefail", {folder:node.box}), err);
|
||||
}
|
||||
else {
|
||||
processNewMessage(msg, parsed);
|
||||
}
|
||||
});
|
||||
pop3Client.dele(msgNumber);
|
||||
}
|
||||
else {
|
||||
node.log(util.format("retr error: %s %j", status, rawData));
|
||||
pop3Client.quit();
|
||||
setInputRepeatTimeout();
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
pop3Client.on("invalid-state", function(cmd) {
|
||||
node.log("Invalid state: " + cmd);
|
||||
});
|
||||
|
||||
pop3Client.on("locked", function(cmd) {
|
||||
node.log("We were locked: " + cmd);
|
||||
});
|
||||
|
||||
// When we have deleted the last processed message, we can move on to
|
||||
// processing the next message.
|
||||
pop3Client.on("dele", function(status, msgNumber) {
|
||||
nextMessage();
|
||||
});
|
||||
} // End of checkPOP3
|
||||
|
||||
|
||||
@ -595,6 +565,10 @@ module.exports = function(RED) {
|
||||
}
|
||||
});
|
||||
|
||||
function status_clear() {
|
||||
node.status({});
|
||||
}
|
||||
|
||||
function setInputRepeatTimeout() {
|
||||
// Set the repetition timer as needed
|
||||
if (!isNaN(node.repeat) && node.repeat > 0) {
|
||||
|
@ -4,12 +4,14 @@
|
||||
"description": "Node-RED nodes to send and receive simple emails.",
|
||||
"dependencies": {
|
||||
"imap": "^0.8.19",
|
||||
"node-pop3": "^0.8.0",
|
||||
"mailparser": "~3.5.0",
|
||||
"nodemailer": "^6.8.0",
|
||||
"smtp-server": "^3.11.0"
|
||||
},
|
||||
"bundledDependencies": [
|
||||
"imap",
|
||||
"node-pop3",
|
||||
"mailparser",
|
||||
"nodemailer",
|
||||
"smtp-server"
|
||||
|
@ -1,859 +0,0 @@
|
||||
/*
|
||||
|
||||
Node.js POP3 client library
|
||||
|
||||
Copyright (C) 2011-2013 by Ditesh Shashikant Gathani <ditesh@gathani.org>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
var net = require("net"),
|
||||
tls = require("tls"),
|
||||
util = require("util"),
|
||||
crypto = require("crypto"),
|
||||
events = require("events");
|
||||
|
||||
// Constructor
|
||||
function POP3Client(port, host, options) {
|
||||
|
||||
if (options === undefined) { options = {}; }
|
||||
|
||||
// Optional constructor arguments
|
||||
var enabletls = options.enabletls !== undefined ? options.enabletls: false;
|
||||
var ignoretlserrs = options.ignoretlserrs !== undefined ? options.ignoretlserrs: false;
|
||||
var debug = options.debug || false;
|
||||
|
||||
var tlsDirectOpts = options.tlsopts !== undefined ? options.tlsopts: {};
|
||||
|
||||
// Private variables follow
|
||||
var self = this;
|
||||
var response = null;
|
||||
var checkResp = true;
|
||||
var bufferedData = "";
|
||||
var state = 0;
|
||||
var locked = false;
|
||||
var multiline = false;
|
||||
var socket = null;
|
||||
var tlssock = null;
|
||||
var callback = function(resp, data) {
|
||||
|
||||
if (resp === false) {
|
||||
|
||||
locked = false;
|
||||
callback = function() {};
|
||||
self.emit("connect", false, data);
|
||||
|
||||
} else {
|
||||
|
||||
// Checking for APOP support
|
||||
var banner = data.trim();
|
||||
var bannerComponents = banner.split(" ");
|
||||
|
||||
for(var i=0; i < bannerComponents.length; i++) {
|
||||
|
||||
if (bannerComponents[i].indexOf("@") > 0) {
|
||||
|
||||
self.data["apop"] = true;
|
||||
self.data["apop-timestamp"] = bannerComponents[i];
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
state = 1;
|
||||
self.data["banner"] = banner;
|
||||
self.emit("connect", true, data);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// Public variables follow
|
||||
this.data = {
|
||||
|
||||
host: host,
|
||||
port: port,
|
||||
banner: "",
|
||||
stls: false,
|
||||
apop: false,
|
||||
username: "",
|
||||
tls: enabletls,
|
||||
ignoretlserrs: ignoretlserrs
|
||||
|
||||
};
|
||||
|
||||
// Privileged methods follow
|
||||
this.setCallback = function(cb) { callback = cb; };
|
||||
this.getCallback = function() { return callback };
|
||||
this.setState = function(val) { state = val; };
|
||||
this.getState = function() { return state; };
|
||||
this.setLocked = function(val) { locked = val; };
|
||||
this.getLocked = function() { return locked; };
|
||||
this.setMultiline = function(val) { multiline = val; };
|
||||
this.getMultiline = function() { return multiline; };
|
||||
|
||||
// Writes to remote server socket
|
||||
this.write = function(command, argument) {
|
||||
|
||||
var text = command;
|
||||
|
||||
if (argument !== undefined) { text = text + " " + argument + "\r\n"; }
|
||||
else { text = text + "\r\n"; }
|
||||
|
||||
if (debug) { console.log("Client: " + util.inspect(text)); }
|
||||
|
||||
socket.write(text);
|
||||
|
||||
};
|
||||
|
||||
// Kills the socket connection
|
||||
this.end = function() {
|
||||
socket.end();
|
||||
};
|
||||
|
||||
// Upgrades a standard unencrypted TCP connection to use TLS
|
||||
// Liberally copied and modified from https://gist.github.com/848444
|
||||
// starttls() should be a private function, but I can't figure out
|
||||
// how to get a public prototypal method (stls) to talk to private method (starttls)
|
||||
// which references private variables without going through a privileged method
|
||||
this.starttls = function(options) {
|
||||
|
||||
var s = socket;
|
||||
s.removeAllListeners("end");
|
||||
s.removeAllListeners("data");
|
||||
s.removeAllListeners("error");
|
||||
socket=null;
|
||||
|
||||
var sslcontext = require('crypto').createCredentials(options);
|
||||
var pair = tls.createSecurePair(sslcontext, false);
|
||||
var cleartext = pipe(pair);
|
||||
|
||||
pair.on('secure', function() {
|
||||
|
||||
var verifyError = pair.ssl.verifyError();
|
||||
cleartext.authorized = true;
|
||||
|
||||
if (verifyError) {
|
||||
|
||||
cleartext.authorized = false;
|
||||
cleartext.authorizationError = verifyError;
|
||||
|
||||
}
|
||||
|
||||
cleartext.on("data", onData);
|
||||
cleartext.on("error", onError);
|
||||
cleartext.on("end", onEnd);
|
||||
socket=cleartext;
|
||||
(self.getCallback())(cleartext.authorized, cleartext.authorizationError);
|
||||
|
||||
});
|
||||
|
||||
cleartext._controlReleased = true;
|
||||
|
||||
function pipe(pair) {
|
||||
|
||||
pair.encrypted.pipe(s);
|
||||
s.pipe(pair.encrypted);
|
||||
|
||||
pair.fd = s.fd;
|
||||
var cleartext = pair.cleartext;
|
||||
cleartext.socket = s;
|
||||
cleartext.encrypted = pair.encrypted;
|
||||
cleartext.authorized = false;
|
||||
|
||||
function onerror(e) {
|
||||
if (cleartext._controlReleased) { cleartext.emit('error', e); }
|
||||
}
|
||||
|
||||
function onclose() {
|
||||
s.removeListener('error', onerror);
|
||||
s.removeListener('close', onclose);
|
||||
}
|
||||
|
||||
s.on('error', onerror);
|
||||
s.on('close', onclose);
|
||||
return cleartext;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// Private methods follow
|
||||
// Event handlers follow
|
||||
function onData(data) {
|
||||
|
||||
data = data.toString("ascii");
|
||||
bufferedData += data;
|
||||
|
||||
if (debug) { console.log("Server: " + util.inspect(data)); }
|
||||
|
||||
if (checkResp === true) {
|
||||
|
||||
if (bufferedData.substr(0, 3) === "+OK") {
|
||||
|
||||
checkResp = false;
|
||||
response = true;
|
||||
|
||||
} else if (bufferedData.substr(0, 4) === "-ERR") {
|
||||
|
||||
checkResp = false;
|
||||
response = false;
|
||||
|
||||
// The following is only used for SASL
|
||||
} else if (multiline === false) {
|
||||
|
||||
checkResp = false;
|
||||
response = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (checkResp === false) {
|
||||
|
||||
if (multiline === true && (response === false || bufferedData.substr(bufferedData.length-5) === "\r\n.\r\n")) {
|
||||
|
||||
// Make a copy to avoid race conditions
|
||||
var responseCopy = response;
|
||||
var bufferedDataCopy = bufferedData;
|
||||
|
||||
response = null;
|
||||
checkResp = true;
|
||||
multiline = false;
|
||||
bufferedData = "";
|
||||
|
||||
callback(responseCopy, bufferedDataCopy);
|
||||
|
||||
} else if (multiline === false) {
|
||||
|
||||
// Make a copy to avoid race conditions
|
||||
var responseCopy = response;
|
||||
var bufferedDataCopy = bufferedData;
|
||||
|
||||
response = null;
|
||||
checkResp = true;
|
||||
multiline = false;
|
||||
bufferedData = "";
|
||||
|
||||
callback(responseCopy, bufferedDataCopy);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onError(err) {
|
||||
if (err.errno === 111) { self.emit("connect", false, err); }
|
||||
else { self.emit("error", err); }
|
||||
}
|
||||
|
||||
function onEnd(data) {
|
||||
self.setState(0);
|
||||
socket = null;
|
||||
}
|
||||
|
||||
function onClose() {
|
||||
self.emit("close");
|
||||
}
|
||||
|
||||
// Constructor code follows
|
||||
// Set up EventEmitter constructor function
|
||||
events.EventEmitter.call(this);
|
||||
|
||||
// Remote end socket
|
||||
if (enabletls === true) {
|
||||
|
||||
tlssock = tls.connect({
|
||||
host: host,
|
||||
port: port,
|
||||
rejectUnauthorized: !self.data.ignoretlserrs
|
||||
}, function() {
|
||||
|
||||
if (tlssock.authorized === false && self.data["ignoretlserrs"] === false) {
|
||||
self.emit("tls-error", tlssock.authorizationError);
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
socket = tlssock;
|
||||
|
||||
} else { socket = new net.createConnection(port, host); }
|
||||
|
||||
// Set up event handlers
|
||||
socket.on("data", onData);
|
||||
socket.on("error", onError);
|
||||
socket.on("end", onEnd);
|
||||
socket.on("close", onClose);
|
||||
|
||||
}
|
||||
|
||||
util.inherits(POP3Client, events.EventEmitter);
|
||||
|
||||
POP3Client.prototype.login = function (username, password) {
|
||||
|
||||
var self = this;
|
||||
|
||||
if (self.getState() !== 1) { self.emit("invalid-state", "login"); }
|
||||
else if (self.getLocked() === true) { self.emit("locked", "login"); }
|
||||
else {
|
||||
|
||||
self.setLocked(true);
|
||||
self.setCallback(function(resp, data) {
|
||||
|
||||
if (resp === false) {
|
||||
|
||||
self.setLocked(false);
|
||||
self.setCallback(function() {});
|
||||
self.emit("login", false, data);
|
||||
|
||||
} else {
|
||||
|
||||
self.setCallback(function(resp, data) {
|
||||
|
||||
self.setLocked(false);
|
||||
self.setCallback(function() {});
|
||||
|
||||
if (resp !== false) { self.setState(2); }
|
||||
self.emit("login", resp, data);
|
||||
|
||||
});
|
||||
|
||||
self.setMultiline(false);
|
||||
self.write("PASS", password);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
self.setMultiline(false);
|
||||
self.write("USER", username);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// SASL AUTH implementation
|
||||
// Currently supports SASL PLAIN and CRAM-MD5
|
||||
POP3Client.prototype.auth = function (type, username, password) {
|
||||
|
||||
type = type.toUpperCase();
|
||||
var self = this;
|
||||
var types = {"PLAIN": 1, "CRAM-MD5": 1};
|
||||
var initialresp = "";
|
||||
|
||||
if (self.getState() !== 1) { self.emit("invalid-state", "auth"); }
|
||||
else if (self.getLocked() === true) { self.emit("locked", "auth"); }
|
||||
|
||||
if ((type in types) === false) {
|
||||
|
||||
self.emit("auth", false, "Invalid auth type", null);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
function tlsok() {
|
||||
|
||||
if (type === "PLAIN") {
|
||||
|
||||
initialresp = " " + new Buffer(username + "\u0000" + username + "\u0000" + password).toString("base64") + "=";
|
||||
self.setCallback(function(resp, data) {
|
||||
|
||||
if (resp !== false) { self.setState(2); }
|
||||
self.emit("auth", resp, data, data);
|
||||
|
||||
});
|
||||
|
||||
} else if (type === "CRAM-MD5") {
|
||||
|
||||
self.setCallback(function(resp, data) {
|
||||
|
||||
if (resp === false) { self.emit("auth", resp, "Server responded -ERR to AUTH CRAM-MD5", data); }
|
||||
else {
|
||||
|
||||
var challenge = new Buffer(data.trim().substr(2), "base64").toString();
|
||||
var hmac = crypto.createHmac("md5", password);
|
||||
var response = new Buffer(username + " " + hmac.update(challenge).digest("hex")).toString("base64");
|
||||
|
||||
self.setCallback(function(resp, data) {
|
||||
|
||||
var errmsg = null;
|
||||
|
||||
if (resp !== false) { self.setState(2); }
|
||||
else {errmsg = "Server responded -ERR to response"; }
|
||||
|
||||
self.emit("auth", resp, null, data);
|
||||
|
||||
});
|
||||
|
||||
self.write(response);
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
self.write("AUTH " + type + initialresp);
|
||||
|
||||
}
|
||||
|
||||
if (self.data["tls"] === false && self.data["stls"] === false) {
|
||||
|
||||
// Remove all existing STLS listeners
|
||||
self.removeAllListeners("stls");
|
||||
|
||||
self.on("stls", function(resp, rawdata) {
|
||||
|
||||
if (resp === false) {
|
||||
|
||||
// We (optionally) ignore self signed cert errors,
|
||||
// in blatant violation of RFC 2595, Section 2.4
|
||||
if (self.data["ignoretlserrs"] === true && rawdata === "DEPTH_ZERO_SELF_SIGNED_CERT"){ tlsok(); }
|
||||
else { self.emit("auth", false, "Unable to upgrade connection to STLS", rawdata); }
|
||||
|
||||
} else { tlsok(); }
|
||||
|
||||
});
|
||||
|
||||
self.stls();
|
||||
|
||||
} else { tlsok(); }
|
||||
};
|
||||
|
||||
POP3Client.prototype.apop = function (username, password) {
|
||||
|
||||
var self = this;
|
||||
|
||||
if (self.getState() !== 1) { self.emit("invalid-state", "apop"); }
|
||||
else if (self.getLocked() === true) { self.emit("locked", "apop"); }
|
||||
else if (self.data["apop"] === false) { self.emit("apop", false, "APOP support not detected on remote server"); }
|
||||
else {
|
||||
|
||||
self.setLocked(true);
|
||||
self.setCallback(function(resp, data) {
|
||||
|
||||
self.setLocked(false);
|
||||
self.setCallback(function() {});
|
||||
|
||||
if (resp === true) { self.setState(2); }
|
||||
self.emit("apop", resp, data);
|
||||
|
||||
});
|
||||
|
||||
self.setMultiline(false);
|
||||
self.write("APOP", username + " " + crypto.createHash("md5").update(self.data["apop-timestamp"] + password).digest("hex"));
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
POP3Client.prototype.stls = function() {
|
||||
|
||||
var self = this;
|
||||
|
||||
if (self.getState() !== 1) { self.emit("invalid-state", "stls"); }
|
||||
else if (self.getLocked() === true) { self.emit("locked", "stls"); }
|
||||
else if (self.data["tls"] === true) { self.emit("stls", false, "Unable to execute STLS as TLS connection already established"); }
|
||||
else {
|
||||
|
||||
self.setLocked(true);
|
||||
self.setCallback(function(resp, data) {
|
||||
|
||||
self.setLocked(false);
|
||||
self.setCallback(function() {});
|
||||
|
||||
if (resp === true) {
|
||||
|
||||
self.setCallback(function(resp, data) {
|
||||
|
||||
if (resp === false && self.data["ignoretlserrs"] === true && data === "DEPTH_ZERO_SELF_SIGNED_CERT") {resp = true; }
|
||||
self.data["stls"] = true;
|
||||
self.emit("stls", resp, data);
|
||||
|
||||
});
|
||||
|
||||
self.starttls();
|
||||
|
||||
} else { self.emit("stls", false, data); }
|
||||
});
|
||||
|
||||
self.setMultiline(false);
|
||||
self.write("STLS");
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
POP3Client.prototype.top = function(msgnumber, lines) {
|
||||
|
||||
var self = this;
|
||||
|
||||
if (self.getState() !== 2) { self.emit("invalid-state", "top"); }
|
||||
else if (self.getLocked() === true) { self.emit("locked", "top"); }
|
||||
else {
|
||||
|
||||
self.setCallback(function(resp, data) {
|
||||
|
||||
var returnValue = null;
|
||||
self.setLocked(false);
|
||||
self.setCallback(function() {});
|
||||
|
||||
if (resp !== false) {
|
||||
|
||||
returnValue = "";
|
||||
var startOffset = data.indexOf("\r\n", 0) + 2;
|
||||
var endOffset = data.indexOf("\r\n.\r\n", 0) + 2;
|
||||
|
||||
if (endOffset > startOffset) {returnValue = data.substr(startOffset, endOffset-startOffset); }
|
||||
|
||||
}
|
||||
|
||||
self.emit("top", resp, msgnumber, returnValue, data);
|
||||
|
||||
});
|
||||
|
||||
self.setMultiline(true);
|
||||
self.write("TOP", msgnumber + " " + lines);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
POP3Client.prototype.list = function(msgnumber) {
|
||||
|
||||
var self = this;
|
||||
|
||||
if (self.getState() !== 2) { self.emit("invalid-state", "list"); }
|
||||
else if (self.getLocked() === true) { self.emit("locked", "list"); }
|
||||
else {
|
||||
|
||||
self.setLocked(true);
|
||||
self.setCallback(function(resp, data) {
|
||||
|
||||
var returnValue = null;
|
||||
var msgcount = 0;
|
||||
self.setLocked(false);
|
||||
self.setCallback(function() {});
|
||||
|
||||
if (resp !== false) {
|
||||
|
||||
returnValue = [];
|
||||
var listitem = "";
|
||||
if (msgnumber !== undefined) {
|
||||
|
||||
msgcount = 1
|
||||
listitem = data.split(" ");
|
||||
returnValue[listitem[1]] = listitem[2];
|
||||
|
||||
} else {
|
||||
|
||||
var offset = 0;
|
||||
var newoffset = 0;
|
||||
var returnValue = [];
|
||||
var startOffset = data.indexOf("\r\n", 0) + 2;
|
||||
var endOffset = data.indexOf("\r\n.\r\n", 0) + 2;
|
||||
|
||||
if (endOffset > startOffset) {
|
||||
|
||||
data = data.substr(startOffset, endOffset-startOffset);
|
||||
|
||||
while(true) {
|
||||
|
||||
if (offset > endOffset) { break; }
|
||||
|
||||
newoffset = data.indexOf("\r\n", offset);
|
||||
|
||||
if (newoffset < 0) { break; }
|
||||
|
||||
msgcount++;
|
||||
listitem = data.substr(offset, newoffset-offset);
|
||||
listitem = listitem.split(" ");
|
||||
returnValue[listitem[0]] = listitem[1];
|
||||
offset = newoffset + 2;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.emit("list", resp, msgcount, msgnumber, returnValue, data);
|
||||
|
||||
});
|
||||
|
||||
if (msgnumber !== undefined) { self.setMultiline(false); }
|
||||
else { self.setMultiline(true); }
|
||||
|
||||
self.write("LIST", msgnumber);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
POP3Client.prototype.stat = function() {
|
||||
|
||||
var self = this;
|
||||
|
||||
if (self.getState() !== 2) { self.emit("invalid-state", "stat"); }
|
||||
else if (self.getLocked() === true) { self.emit("locked", "stat"); }
|
||||
else {
|
||||
|
||||
self.setLocked(true);
|
||||
self.setCallback(function(resp, data) {
|
||||
|
||||
var returnValue = null;
|
||||
self.setLocked(false);
|
||||
self.setCallback(function() {});
|
||||
|
||||
if (resp !== false) {
|
||||
|
||||
var listitem = data.split(" ");
|
||||
returnValue = {
|
||||
|
||||
"count": listitem[1].trim(),
|
||||
"octets": listitem[2].trim(),
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
self.emit("stat", resp, returnValue, data);
|
||||
|
||||
});
|
||||
|
||||
self.setMultiline(false);
|
||||
self.write("STAT", undefined);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
POP3Client.prototype.uidl = function(msgnumber) {
|
||||
|
||||
var self = this;
|
||||
|
||||
if (self.getState() !== 2) { self.emit("invalid-state", "uidl"); }
|
||||
else if (self.getLocked() === true) { self.emit("locked", "uidl"); }
|
||||
else {
|
||||
|
||||
self.setLocked(true);
|
||||
self.setCallback(function(resp, data) {
|
||||
|
||||
var returnValue = null;
|
||||
self.setLocked(false);
|
||||
self.setCallback(function() {});
|
||||
|
||||
if (resp !== false) {
|
||||
|
||||
returnValue = [];
|
||||
var listitem = "";
|
||||
if (msgnumber !== undefined) {
|
||||
|
||||
listitem = data.split(" ");
|
||||
returnValue[listitem[1]] = listitem[2].trim();
|
||||
|
||||
} else {
|
||||
|
||||
var offset = 0;
|
||||
|
||||
var newoffset = 0;
|
||||
var returnValue = [];
|
||||
var startOffset = data.indexOf("\r\n", 0) + 2;
|
||||
var endOffset = data.indexOf("\r\n.\r\n", 0) + 2;
|
||||
|
||||
if (endOffset > startOffset) {
|
||||
|
||||
data = data.substr(startOffset, endOffset-startOffset);
|
||||
endOffset -= startOffset;
|
||||
|
||||
while (offset < endOffset) {
|
||||
|
||||
newoffset = data.indexOf("\r\n", offset);
|
||||
listitem = data.substr(offset, newoffset-offset);
|
||||
listitem = listitem.split(" ");
|
||||
returnValue[listitem[0]] = listitem[1];
|
||||
offset = newoffset + 2;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.emit("uidl", resp, msgnumber, returnValue, data);
|
||||
|
||||
});
|
||||
|
||||
if (msgnumber !== undefined) { self.setMultiline(false); }
|
||||
else { self.setMultiline(true); }
|
||||
|
||||
self.write("UIDL", msgnumber);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
POP3Client.prototype.retr = function(msgnumber) {
|
||||
|
||||
var self = this;
|
||||
|
||||
if (self.getState() !== 2) { self.emit("invalid-state", "retr"); }
|
||||
else if (self.getLocked() === true) { self.emit("locked", "retr"); }
|
||||
else {
|
||||
|
||||
self.setLocked(true);
|
||||
self.setCallback(function(resp, data) {
|
||||
|
||||
var returnValue = null;
|
||||
self.setLocked(false);
|
||||
self.setCallback(function() {});
|
||||
|
||||
if (resp !== false) {
|
||||
|
||||
var startOffset = data.indexOf("\r\n", 0) + 2;
|
||||
var endOffset = data.indexOf("\r\n.\r\n", 0);
|
||||
returnValue = data.substr(startOffset, endOffset-startOffset);
|
||||
|
||||
}
|
||||
|
||||
self.emit("retr", resp, msgnumber, returnValue, data);
|
||||
|
||||
});
|
||||
|
||||
self.setMultiline(true);
|
||||
self.write("RETR", msgnumber);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
POP3Client.prototype.dele = function(msgnumber) {
|
||||
|
||||
var self = this;
|
||||
|
||||
if (self.getState() !== 2) { self.emit("invalid-state", "dele"); }
|
||||
else if (self.getLocked() === true) { self.emit("locked", "dele"); }
|
||||
else {
|
||||
|
||||
self.setLocked(true);
|
||||
self.setCallback(function(resp, data) {
|
||||
|
||||
self.setLocked(false);
|
||||
self.setCallback(function() {});
|
||||
self.emit("dele", resp, msgnumber, data);
|
||||
|
||||
});
|
||||
|
||||
self.setMultiline(false);
|
||||
self.write("DELE", msgnumber);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
POP3Client.prototype.noop = function() {
|
||||
|
||||
var self = this;
|
||||
|
||||
if (self.getState() !== 2) { self.emit("invalid-state", "noop"); }
|
||||
else if (self.getLocked() === true) { self.emit("locked", "noop"); }
|
||||
else {
|
||||
|
||||
self.setLocked(true);
|
||||
self.setCallback(function(resp, data) {
|
||||
|
||||
self.setLocked(false);
|
||||
self.setCallback(function() {});
|
||||
self.emit("noop", resp, data);
|
||||
|
||||
});
|
||||
|
||||
self.setMultiline(false);
|
||||
self.write("NOOP", undefined);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
POP3Client.prototype.rset = function() {
|
||||
|
||||
var self = this;
|
||||
|
||||
if (self.getState() !== 2) { self.emit("invalid-state", "rset"); }
|
||||
else if (self.getLocked() === true) { self.emit("locked", "rset"); }
|
||||
else {
|
||||
|
||||
self.setLocked(true);
|
||||
self.setCallback(function(resp, data) {
|
||||
|
||||
self.setLocked(false);
|
||||
self.setCallback(function() {});
|
||||
self.emit("rset", resp, data);
|
||||
|
||||
});
|
||||
|
||||
self.setMultiline(false);
|
||||
self.write("RSET", undefined);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
POP3Client.prototype.capa = function() {
|
||||
|
||||
var self = this;
|
||||
|
||||
if (self.getState() === 0) { self.emit("invalid-state", "quit"); }
|
||||
else if (self.getLocked() === true) { self.emit("locked", "capa"); }
|
||||
else {
|
||||
|
||||
self.setLocked(true);
|
||||
self.setCallback(function(resp, data) {
|
||||
|
||||
var returnValue = null;
|
||||
self.setLocked(false);
|
||||
self.setCallback(function() {});
|
||||
|
||||
if (resp === true) {
|
||||
|
||||
var startOffset = data.indexOf("\r\n", 0) + 2;
|
||||
var endOffset = data.indexOf("\r\n.\r\n", 0);
|
||||
returnValue = data.substr(startOffset, endOffset-startOffset);
|
||||
returnValue = returnValue.split("\r\n");
|
||||
|
||||
}
|
||||
|
||||
self.emit("capa", resp, returnValue, data);
|
||||
|
||||
});
|
||||
|
||||
self.setMultiline(true);
|
||||
self.write("CAPA", undefined);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
POP3Client.prototype.quit = function() {
|
||||
|
||||
var self = this;
|
||||
|
||||
if (self.getState() === 0) { self.emit("invalid-state", "quit"); }
|
||||
else if (self.getLocked() === true) { self.emit("locked", "quit"); }
|
||||
else {
|
||||
|
||||
self.setLocked(true);
|
||||
self.setCallback(function(resp, data) {
|
||||
|
||||
self.setLocked(false);
|
||||
self.setCallback(function() {});
|
||||
|
||||
self.end();
|
||||
self.emit("quit", resp, data);
|
||||
|
||||
});
|
||||
|
||||
self.setMultiline(false);
|
||||
self.write("QUIT", undefined);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = POP3Client;
|
Loading…
x
Reference in New Issue
Block a user