Merge branch 'master' of github.com:node-red/node-red-nodes

This commit is contained in:
Andreas Martens 2020-10-21 14:20:50 +01:00
commit d289272afe
38 changed files with 543 additions and 118 deletions

View File

@ -11,5 +11,5 @@
"shadow": true,
"sub": true,
"proto": true,
"esversion": 6
"esversion": 8
}

View File

@ -8,10 +8,10 @@ matrix:
- node_js: 12
- node_js: 10
- node_js: 8
- python: 2.7
language: python
before_script: pip install flake8
script: flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
# - python: 2.7
# language: python
# before_script: pip install flake8
# script: flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
- python: 3.7
language: python
dist: xenial # required for Python 3.7 (travis-ci/travis-ci#9069)
@ -23,7 +23,10 @@ before_install:
before_script:
# Remove the './node_modules/.bin:' entry, see https://github.com/travis-ci/travis-ci/issues/8813
- export PATH=`echo ${PATH} | sed -re 's,(^|:)(./)?node_modules/.bin($|:),\1,'`
- npm install -g istanbul grunt-cli coveralls
- npm install -g nyc grunt-cli coveralls
- npm install node-red
script:
- istanbul cover grunt --report lcovonly && istanbul report text && ( cat coverage/lcov.info | $(npm get prefix)/bin/coveralls || true ) && rm -rf coverage
# - istanbul cover grunt --report lcovonly && istanbul report text && ( cat coverage/lcov.info | $(npm get prefix)/bin/coveralls || true ) && rm -rf coverage
# - nyc --check-coverage --reporter=text --reporter=lcovonly --reporter=html grunt
# - nyc grunt && rm -rf coverage .nyc_output
- nyc grunt && nyc report --reporter=text-lcov | coveralls

View File

@ -1,3 +1,3 @@
# check coverage of tests... and browse report
istanbul cover ./node_modules/.bin/grunt --report lcovonly && istanbul report html
nyc --check-coverage --reporter=html grunt
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome coverage/index.html

View File

@ -70,8 +70,7 @@
<script type="text/html" data-template-name="rpi-gpio in">
<div class="form-row" style="min-width: 540px">
<label><i class="fa fa-circle"></i> <span data-i18n="rpi-gpio.pinname"></span></label>
<input type="text" id="node-input-pin" style="display:none;">
<label><i class="fa fa-circle"></i> <span data-i18n="rpi-gpio.pinname"></span></label>
<div class="rpi-gpio-pinTable">
<div class="pinTableBody" id="pinform">
<div class="pinTableRow">
@ -157,6 +156,10 @@
</div>
</div>
</div>
<div class="form-row">
<label>&nbsp;&nbsp;&nbsp;&nbsp;</label>
<input type="text" id="node-input-pin" style="width: 352px">
</div>
<div class="form-row">
<label for="node-input-intype"><i class="fa fa-level-up"></i> <span data-i18n="rpi-gpio.label.resistor"></span></label>
<select type="text" id="node-input-intype" style="width:100px;">
@ -187,12 +190,29 @@
"5":"29", "6":"31", "12":"32", "13":"33", "19":"35", "16":"36", "26":"37", "20":"38", "21":"40"
};
var pinsInUse = {};
var validPinValues = Object.values(bcm2pin);
var isEnvVar = function (value) {
var re = /^\${([0-9a-zA-Z_]+)}$/;
var match = value.match(re);
return Boolean(match);
};
var isInt = function (value) {
return parseInt(value).toString() === value.trim();
};
var uncheckAll = function() {
for (var i=0; i< validPinValues.length; i++) {
$("#pinform input[value="+validPinValues[i]+"]").prop('checked', false);
}
}
var validatePin = function (value) {
return isEnvVar(value) || (isInt(value) && validPinValues.includes(value));
};
RED.nodes.registerType('rpi-gpio in',{
category: 'Raspberry Pi',
color:"#c6dbef",
defaults: {
name: { value:"" },
pin: { value:"tri",required:true,validate:RED.validators.number() },
pin: { value:"tri",required:true,validate:validatePin },
intype: { value:"tri" },
debounce: { value:"25" },
read: { value:false }
@ -227,11 +247,20 @@
pinsInUse = data || {};
$('#pin-tip').html(pintip + Object.keys(data));
});
for (var i=0; i< validPinValues.length; i++) {
$("#pinform input[value="+validPinValues[i]+"]").on("change", function (evt) {
$("#node-input-pin").val(evt.currentTarget.value);
$("#node-input-pin").removeClass("input-error");
});
}
$("#node-input-pin").on("change", function() {
if ($("#node-input-pin").val()) {
$("#pinform input[value="+$("#node-input-pin").val()+"]").prop('checked', true);
}
var pinnew = $("#node-input-pin").val();
if (pinnew && isInt(pinnew) && validPinValues.includes(pinnew)) {
$("#pinform input[value="+pinnew+"]").prop('checked', true);
} else {
uncheckAll();
}
if ((pinnew) && (pinnew !== pinnow)) {
if (pinsInUse.hasOwnProperty(pinnew)) {
RED.notify(pinname+" "+pinnew+" "+alreadyuse,"warn");
@ -256,7 +285,6 @@
<script type="text/html" data-template-name="rpi-gpio out">
<div class="form-row" style="min-width: 540px">
<label><i class="fa fa-circle"></i> <span data-i18n="rpi-gpio.pinname"></span></label>
<input type="text" id="node-input-pin" style="display:none;">
<div class="rpi-gpio-pinTable">
<div class="pinTableBody" id="pinform">
<div class="pinTableRow">
@ -342,6 +370,10 @@
</div>
</div>
</div>
<div class="form-row">
<label>&nbsp;&nbsp;&nbsp;&nbsp;</label>
<input type="text" id="node-input-pin" style="width: 352px">
</div>
<div class="form-row" id="node-set-pwm">
<label>&nbsp;&nbsp;&nbsp;&nbsp;<span data-i18n="rpi-gpio.label.type"></span></label>
<select id="node-input-out" style="width: 250px;">
@ -381,12 +413,29 @@
"5":"29", "6":"31", "12":"32", "13":"33", "19":"35", "16":"36", "26":"37", "20":"38", "21":"40"
};
var pinsInUse = {};
var validPinValues = Object.values(bcm2pin);
var isEnvVar = function (value) {
var re = /^\${([0-9a-zA-Z_]+)}$/;
var match = value.match(re);
return Boolean(match);
};
var isInt = function (value) {
return parseInt(value).toString() === value.trim();
};
var uncheckAll = function() {
for (var i=0; i< validPinValues.length; i++) {
$("#pinform input[value="+validPinValues[i]+"]").prop('checked', false);
}
}
var validatePin = function (value) {
return isEnvVar(value) || (isInt(value) && validPinValues.includes(value));
};
RED.nodes.registerType('rpi-gpio out',{
category: 'Raspberry Pi',
color:"#c6dbef",
defaults: {
name: { value:"" },
pin: { value:"",required:true,validate:RED.validators.number() },
pin: { value:"",required:true,validate:validatePin },
set: { value:"" },
level: { value:"0" },
freq: {value:""},
@ -428,11 +477,19 @@
$('#pin-tip').html(pintip + Object.keys(data));
});
for (var i=0; i< validPinValues.length; i++) {
$("#pinform input[value="+validPinValues[i]+"]").on("change", function (evt) {
$("#node-input-pin").val(evt.currentTarget.value);
$("#node-input-pin").removeClass("input-error");
});
}
$("#node-input-pin").on("change", function() {
if ($("#node-input-pin").val()) {
$("#pinform input[value="+$("#node-input-pin").val()+"]").prop('checked', true);
}
var pinnew = $("#node-input-pin").val();
if (pinnew && isInt(pinnew) && validPinValues.includes(pinnew)) {
$("#pinform input[value="+pinnew+"]").prop('checked', true);
} else {
uncheckAll();
}
if ((pinnew) && (pinnew !== pinnow)) {
if (pinsInUse.hasOwnProperty(pinnew)) {
RED.notify(pinname+" "+pinnew+" "+alreadyuse,"warn");

View File

@ -1,6 +1,6 @@
{
"name": "node-red-node-pi-gpio",
"version": "1.1.1",
"version": "1.2.0",
"description": "The basic Node-RED node for Pi GPIO",
"dependencies" : {
},

View File

@ -1,6 +1,6 @@
{
"name": "node-red-node-pi-gpiod",
"version": "0.0.13",
"version": "0.1.0",
"description": "A node-red node for PiGPIOd",
"dependencies" : {
"js-pigpio": "*"

View File

@ -46,13 +46,13 @@ module.exports = function(RED) {
PiGPIO.set_glitch_filter(node.pin,node.debounce);
node.status({fill:"green",shape:"dot",text:"node-red:common.status.ok"});
node.cb = PiGPIO.callback(node.pin, PiGPIO.EITHER_EDGE, function(gpio, level, tick) {
node.send({ topic:"pi/"+node.pio, payload:Number(level) });
node.send({ topic:"pi/"+node.pio, payload:Number(level), host:node.host });
node.status({fill:"green",shape:"dot",text:level});
});
if (node.read) {
setTimeout(function() {
PiGPIO.read(node.pin, function(err, level) {
node.send({ topic:"pi/"+node.pio, payload:Number(level) });
node.send({ topic:"pi/"+node.pio, payload:Number(level), host:node.host });
node.status({fill:"green",shape:"dot",text:level});
});
}, 20);

View File

@ -336,10 +336,12 @@ WeMoNG.prototype.getSocketStatus = function getSocketStatus(socket) {
res.on('end', function(){
xml2js.parseString(data, function(err, result){
if (!err) {
if (!err && result["s:Envelope"]) {
var status = result["s:Envelope"]["s:Body"][0]["u:GetBinaryStateResponse"][0]["BinaryState"][0];
status = parseInt(status);
def.resolve(status);
} else {
def.reject();
}
});
});
@ -401,12 +403,14 @@ WeMoNG.prototype.getLightStatus = function getLightStatus(light) {
};
def.resolve(obj);
} else {
def.reject();
console.log("err");
}
});
}
} else {
console.log("err");
def.reject();
}
});
});
@ -489,6 +493,8 @@ WeMoNG.prototype.parseEvent = function parseEvent(evt) {
msg.capabilityName = capabilityMap[msg.capability];
msg.value = res['StateEvent']['Value'][0];
def.resolve(msg);
} else {
def.reject();
}
});
} else if (prop.hasOwnProperty('BinaryState')) {

View File

@ -1,6 +1,6 @@
{
"name": "node-red-node-wemo",
"version": "0.1.17",
"version": "0.1.18",
"description": "Input and Output nodes for Belkin WeMo devices",
"repository": "https://github.com/node-red/node-red-nodes/tree/master/hardware",
"main": "WeMoNG.js",

View File

@ -57,6 +57,7 @@
<script type="text/html" data-help-name="serial out">
<p>Provides a connection to an outbound serial port.</p>
<p>Only the <code>msg.payload</code> is sent.</p>
<p>Optionally the baudrate can be changed using <code>msg.baudrate</code></p>
<p>Optionally the new line character used to split the input can be appended to every message sent out to the serial port.</p>
<p>Binary payloads can be sent by using a Buffer object.</p>
</script>
@ -111,6 +112,7 @@
</li>
<li><code>msg.count</code> if set this will override the configured number of characters as long as it is less than the number configured.</li>
<li><code>msg.waitfor</code> single character, escape code, or hex code. If set, the node will wait until it matches that character in the stream and then start the output.</li>
<li>Optionally the baudrate can be changed using <code>msg.baudrate</code></li>
</ul>
<h3>Outputs</h3>
<ul>

View File

@ -41,6 +41,19 @@ module.exports = function(RED) {
node.port = serialPool.get(this.serialConfig);
node.on("input",function(msg) {
if (msg.hasOwnProperty("baudrate")) {
var baud = parseInt(msg.baudrate);
if (isNaN(baud)) {
node.error(RED._("serial.errors.badbaudrate"),msg);
} else {
node.port.update({baudRate: baud},function(err,res) {
if (err) {
var errmsg = err.toString().replace("Serialport","Serialport "+node.port.serial.path);
node.error(errmsg,msg);
}
});
}
}
if (!msg.hasOwnProperty("payload")) { return; } // do nothing unless we have a payload
var payload = node.port.encodePayload(msg.payload);
node.port.write(payload,function(err,res) {
@ -121,6 +134,19 @@ module.exports = function(RED) {
node.port = serialPool.get(this.serialConfig);
// Serial Out
node.on("input",function(msg) {
if (msg.hasOwnProperty("baudrate")) {
var baud = parseInt(msg.baudrate);
if (isNaN(baud)) {
node.error(RED._("serial.errors.badbaudrate"),msg);
} else {
node.port.update({baudRate: baud},function(err,res) {
if (err) {
var errmsg = err.toString().replace("Serialport","Serialport "+node.port.serial.path);
node.error(errmsg,msg);
}
});
}
}
if (!msg.hasOwnProperty("payload")) { return; } // do nothing unless we have a payload
if (msg.hasOwnProperty("count") && (typeof msg.count === "number") && (node.serialConfig.out === "count")) {
node.serialConfig.newline = msg.count;
@ -249,6 +275,7 @@ module.exports = function(RED) {
return payload;
},
write: function(m,cb) { this.serial.write(m,cb); },
update: function(m,cb) { this.serial.update(m,cb); },
enqueue: function(msg,sender,cb) {
var payload = this.encodePayload(msg.payload);
var qobj = {

View File

@ -66,7 +66,8 @@
"unexpected-close": "serial port __port__ closed unexpectedly",
"disconnected": "serial port __port__ disconnected",
"closed": "serial port __port__ closed",
"list": "Failed to list ports. Please enter manually."
"list": "Failed to list ports. Please enter manually.",
"badbaudrate": "Baudrate is invalid"
}
}
}

View File

@ -51,7 +51,8 @@
"unexpected-close": "serial port __port__ closed unexpectedly",
"disconnected": "serial port __port__ disconnected",
"closed": "serial port __port__ closed",
"list": "ポートのリスト化に失敗しました。手動で入力してください。"
"list": "ポートのリスト化に失敗しました。手動で入力してください。",
"badbaudrate": "ボーレートが不正です"
}
}
}

View File

@ -1,9 +1,9 @@
{
"name" : "node-red-node-serialport",
"version" : "0.10.3",
"version" : "0.11.0",
"description" : "Node-RED nodes to talk to serial ports",
"dependencies" : {
"serialport" : "^8.0.8"
"serialport" : "^9.0.1"
},
"repository" : {
"type":"git",

View File

@ -107,7 +107,7 @@ Values depends on the oids being requested.
### snmp-subtree
Simple SNMP oid subtree fetcher. Triggered by any input.
Simple SNMP oid subtree fetcher. Triggered by any input. Reads from OID specified and any below it.
`msg.host` may contain the host.
@ -127,7 +127,7 @@ Values depends on the oids being requested.
### snmp-walker
Simple SNMP oid walker fetcher. Triggered by any input.
Simple SNMP oid walker fetcher. Triggered by any input. Reads from OID specified to the end of the table.
`msg.host` may contain the host.

View File

@ -1,6 +1,6 @@
{
"name" : "node-red-node-snmp",
"version" : "0.0.24",
"version" : "0.0.25",
"description" : "A Node-RED node that looks for SNMP oids.",
"dependencies" : {
"net-snmp" : "1.2.4"

View File

@ -224,7 +224,7 @@
</script>
<script type="text/html" data-help-name="snmp subtree">
<p>Simple SNMP oid subtree fetcher. Triggered by any input.</p>
<p>Simple SNMP oid subtree fetcher. Triggered by any input. Reads all OIDS at and below the current base OID.</p>
<p><code>msg.host</code> may contain the host.</p>
<p><code>msg.community</code> may contain the community.</p>
<p><code>msg.oid</code> may contain the oid of a table to request.</p>
@ -287,12 +287,15 @@
</script>
<script type="text/html" data-help-name="snmp walker">
<p>Simple SNMP oid walker fetcher. Triggered by any input.</p>
<p>Simple SNMP oid walker fetcher. Triggered by any input.
Fetches all nodes from this OID to the end of the table.</p>
<p><code>msg.host</code> may contain the host.</p>
<p><code>msg.community</code> may contain the community.</p>
<p><code>msg.oid</code> may contain the oid of a table to request.</p>
<p>OID must be numeric. iso. is the same a 1. </p>
<p>The node will output <code>msg.payload</code> and <code>msg.oid</code>.</p>
<p><b>Note</b>: This node does indeed "walk" down the tree. This is different behaviour to
the typical snmpwalk command line app.</p>
</script>
<script type="text/javascript">

View File

@ -33,32 +33,33 @@
"devDependencies": {
"exif": "^0.6.0",
"feedparser": "^2.2.10",
"grunt": "^1.1.0",
"grunt": "^1.3.0",
"grunt-cli": "^1.3.2",
"grunt-contrib-jshint": "^2.1.0",
"grunt-jscs": "^3.0.1",
"grunt-lint-inline": "^1.0.0",
"grunt-simple-mocha": "^0.4.1",
"imap": "^0.8.19",
"mailparser": "^2.7.7",
"markdown-it": "^10.0.0",
"mailparser": "^3.0.0",
"markdown-it": "^11.0.0",
"mocha": "~6.2.3",
"msgpack-lite": "^0.1.26",
"multilang-sentiment": "^1.2.0",
"ngeohash": "^0.6.3",
"node-red": "^1.0.6",
"node-red": "^1.1.3",
"node-red-node-test-helper": "~0.2.5",
"nodemailer": "^6.4.6",
"nodemailer": "^6.4.10",
"poplib": "^0.1.7",
"proxyquire": "^2.1.3",
"pushbullet": "^2.4.0",
"sentiment": "^2.1.0",
"should": "^13.2.3",
"sinon": "~7.5.0",
"smtp-server": "^3.7.0",
"supertest": "^4.0.2",
"when": "^3.7.8"
},
"engines": {
"node": ">=8.6.0"
"node": ">=8.17.0"
}
}

View File

@ -1,9 +1,9 @@
{
"name": "node-red-node-markdown",
"version": "0.1.4",
"version": "0.2.0",
"description": "A Node-RED node to convert a markdown string to html.",
"dependencies": {
"markdown-it": "^10.0.0"
"markdown-it": "^11.0.0"
},
"repository": {
"type": "git",

View File

@ -86,7 +86,7 @@
return this._("email.email");
},
label: function() {
return this.dname||this.name||"email";
return this.dname||this.name||this._("email.email");
},
labelStyle: function() {
return (this.dname)?"node_label_italic":"";
@ -280,3 +280,37 @@
});
})();
</script>
<script type="text/html" data-template-name="e-mail mta">
<div class="form-row">
<label for="node-input-port"><i class="fa fa-random"></i> <span data-i18n="email.label.port"></span></label>
<input type="text" id="node-input-port" style="width:70%;"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div>
<div class="form-tips" id="node-tip"><span data-i18n="[html]email.tip.mta"></span></div>
</script>
<script type="text/javascript">
RED.nodes.registerType('e-mail mta',{
category: 'social',
color:"#c7e9c0",
defaults: {
name: {value:""},
port: {value:"1025",required:true},
},
inputs:0,
outputs:1,
icon: "envelope.png",
paletteLabel: function() { return this._("email.email") + " MTA" },
label: function() {
return this.name||this._("email.email") + " MTA";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
}
});
</script>

View File

@ -1,3 +1,4 @@
/* eslint-disable indent */
/**
* POP3 protocol - RFC1939 - https://www.ietf.org/rfc/rfc1939.txt
@ -11,11 +12,13 @@
module.exports = function(RED) {
"use strict";
var nodemailer = require("nodemailer");
var util = require("util");
var Imap = require('imap');
var POP3Client = require("poplib");
var SimpleParser = require("mailparser").simpleParser;
var util = require("util");
var nodemailer = require("nodemailer");
var simpleParser = require("mailparser").simpleParser;
var SMTPServer = require("smtp-server").SMTPServer;
//var microMTA = require("micromta").microMTA;
if (parseInt(process.version.split("v")[1].split(".")[0]) < 8) {
throw "Error : Requires nodejs version >= 8.";
@ -291,8 +294,8 @@ module.exports = function(RED) {
// 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));
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);
@ -341,17 +344,29 @@ module.exports = function(RED) {
ss = true;
node.status({fill:"blue", shape:"dot", text:"email.status.fetching"});
//console.log("> ready");
// Open the inbox folder
// Open the folder
imap.openBox(node.box, // Mailbox name
false, // Open readonly?
function(err, box) {
//console.log("> Inbox err : %j", err);
//console.log("> Inbox open: %j", box);
if (err) {
s = false;
var boxs = [];
imap.getBoxes(function(err,boxes) {
if (err) { return; }
for (var prop in boxes) {
if (boxes.hasOwnProperty(prop)) {
if (boxes[prop].children) {
boxs.push(prop+"/{"+Object.keys(boxes[prop].children)+'}');
}
else { boxs.push(prop); }
}
}
node.error(RED._("email.errors.fetchfail", {folder:node.box+". Folders - "+boxs.join(', ')}),err);
});
node.status({fill:"red", shape:"ring", text:"email.status.foldererror"});
node.error(RED._("email.errors.fetchfail", {folder:node.box}),err);
imap.end();
s = false;
setInputRepeatTimeout();
return;
}
@ -394,7 +409,7 @@ module.exports = function(RED) {
//console.log("> Fetch message - msg=%j, seqno=%d", imapMessage, seqno);
imapMessage.on('body', function(stream, info) {
//console.log("> message - body - stream=?, info=%j", info);
SimpleParser(stream, {}, function(err, parsed) {
simpleParser(stream, {}, function(err, parsed) {
if (err) {
node.status({fill:"red", shape:"ring", text:"email.status.parseerror"});
node.error(RED._("email.errors.parsefail", {folder:node.box}),err);
@ -412,19 +427,21 @@ module.exports = function(RED) {
var cleanup = function() {
imap.end();
s = false;
setInputRepeatTimeout();
};
if (this.disposition === "Delete") {
if (node.disposition === "Delete") {
imap.addFlags(results, "\Deleted", cleanup);
} else if (this.disposition === "Read") {
} else if (node.disposition === "Read") {
imap.addFlags(results, "\Seen", cleanup);
} else {
cleanup();
}
setInputRepeatTimeout();
});
fetch.once('error', function(err) {
console.log('Fetch error: ' + err);
imap.end();
s = false;
setInputRepeatTimeout();
});
}
@ -442,7 +459,7 @@ module.exports = function(RED) {
if (node.protocol === "POP3") {
checkPOP3(msg);
} else if (node.protocol === "IMAP") {
if (s === false) { checkIMAP(msg); }
if (s === false && ss == false) { checkIMAP(msg); }
}
} // End of checkEmail
@ -499,4 +516,61 @@ module.exports = function(RED) {
global: { type:"boolean" }
}
});
function EmailMtaNode(n) {
RED.nodes.createNode(this,n);
this.port = n.port;
var node = this;
node.mta = new SMTPServer({
secure: false,
logger: false,
disabledCommands: ['AUTH', 'STARTTLS'],
onData: function (stream, session, callback) {
simpleParser(stream, { skipTextToHtml:true, skipTextLinks:true }, (err, parsed) => {
if (err) { node.error(RED._("email.errors.parsefail"),err); }
else {
node.status({fill:"green", shape:"dot", text:""});
var msg = {}
msg.payload = parsed.text;
msg.topic = parsed.subject;
msg.date = parsed.date;
msg.header = {};
parsed.headers.forEach((v, k) => {msg.header[k] = v;});
if (parsed.html) { msg.html = parsed.html; }
if (parsed.to) {
if (typeof(parsed.to) === "string" && parsed.to.length > 0) { msg.to = parsed.to; }
else if (parsed.to.hasOwnProperty("text") && parsed.to.text.length > 0) { msg.to = parsed.to.text; }
}
if (parsed.cc) {
if (typeof(parsed.cc) === "string" && parsed.cc.length > 0) { msg.cc = parsed.cc; }
else if (parsed.cc.hasOwnProperty("text") && parsed.cc.text.length > 0) { msg.cc = parsed.cc.text; }
}
if (parsed.cc && parsed.cc.length > 0) { msg.cc = parsed.cc; }
if (parsed.bcc && parsed.bcc.length > 0) { msg.bcc = parsed.bcc; }
if (parsed.from && parsed.from.value && parsed.from.value.length > 0) { msg.from = parsed.from.value[0].address; }
if (parsed.attachments) { msg.attachments = parsed.attachments; }
else { msg.attachments = []; }
node.send(msg); // Propagate the message down the flow
setTimeout(function() { node.status({})}, 500);
}
callback();
});
}
});
node.mta.listen(node.port);
node.mta.on("error", err => {
node.error("Error: " + err.message, err);
});
node.on("close", function() {
node.mta.close();
});
}
RED.nodes.registerType("e-mail mta",EmailMtaNode);
};

View File

@ -26,7 +26,7 @@
<p>Additionally <code>msg.header</code> contains the complete header object including
<i>to</i>, <i>cc</i> and other potentially useful properties.</p>
<p>It can optionally mark the message as Read (default), Delete it, or leave unmarked (None).</p>
<p>Uses the <a href="https://github.com/mscdex/node-imap/blob/master/README.md" target="_new">node-imap module</a> - see that page for
<p>Uses the <a href="https://github.com/mscdex/node-imap/blob/master/README.md" target="_new">node-imap module</a> - see that page for
information on the <code>msg.criteria</code> format if needed.</p>
<p><b>Note</b>: uses IMAP with SSL to port 993.</p>
<p>Any attachments supplied in the incoming email can be found in the <code>msg.attachments</code> property. This will be an array of objects where
@ -51,3 +51,13 @@
</script>
<script type="text/html" data-help-name="e-mail mta">
<p>Mail Transfer Agent - listens on a port for incoming SMTP mail.</p>
<p><b>Note</b>: "NOT for production use" as there is no security built in.
This is primarily for local testing of outbound mail sending, but could be used
as a mail forwarder to a real email service if required.</p>
<p>To use ports below 1024, for example 25 or 465, you may need to get privileged access.
On linux systems this can be done by running
<pre>sudo setcap 'cap_net_bind_service=+eip' $(which node)</pre>
and restarting Node-RED. Be aware - this gives all node applications access to all ports.</p>
</script>

View File

@ -34,7 +34,8 @@
"default-message": "__description__\n\nFile from Node-RED is attached: __filename__",
"tip": {
"cred": "<b>Note:</b> Copied credentials from global emailkeys.js file.",
"recent": "Tip: Only retrieves the single most recent email."
"recent": "Tip: Only retrieves the single most recent email.",
"mta": "<b>Note:</b> To use ports below 1024 you may need elevated (root) privileges. See help sidebar."
},
"status": {
"messagesent": "Message sent: __response__",
@ -47,6 +48,7 @@
"inboxzero": "you have achieved Inbox Zero",
"sending": "sending",
"sendfail": "send failed",
"parseerror": "Failed to parse message",
"connecterror": "connect error"
},
"errors": {
@ -56,6 +58,7 @@
"nosmtptransport": "No SMTP transport. See info panel.",
"nopayload": "No payload to send",
"fetchfail": "Failed to fetch folder: __folder__",
"parsefail": "Failed to parse message",
"messageerror": "Fetch message error: __error__",
"refreshtoolarge": "Refresh interval too large. Limiting to 2147483 seconds"
}

View File

@ -38,3 +38,13 @@
<p>POP3プロトコルでのデフォルトポート番号は、素のTCPでは110番、SSLでは995番です。IMAPプロトコルでは、素のTCPでは143番、SSLでは993番です。</p>
</script>
<script type="text/html" data-help-name="e-mail mta">
<p>メール転送エージェント - 入ってくるSMTPメールのため、ポートでリッスンします。</p>
<p><b>注釈</b>: セキュリティが組み込まれていないため、"プロダクション向けではありません"。
これは主に、外部へのメール送信のローカルテスト向けですが、必要に応じて実際のメールサービスへのメール転送としても使用できます。</p>
<p>1024未満のポート(例えば25や465など)を使用するには、特権的アクセスを得る必要がある場合があります。
Linuxシステムでは以下のコマンドを実行し、Node-REDを再起動することで達成できます。
<pre>sudo setcap cap_net_bind_service=+eip $(which node)</pre>
これによって、全てのnodeアプリケーションが全ポートにアクセスできる様になることに注意してください.</p>
</script>

View File

@ -21,7 +21,8 @@
"default-message": "__description__\n\nNode-REDからファイルが添付されました: __filename__",
"tip": {
"cred": "<b>注釈:</b> emailkeys.jsファイルから認証情報をコピーしました。",
"recent": "注釈: 最新のメールを1件のみ取得します。"
"recent": "注釈: 最新のメールを1件のみ取得します。",
"mta": "<b>注釈:</b> 1024未満のポートを使用するには、昇格された(root)特権が必要です。ヘルプサイドバーを参照してください。"
},
"status": {
"messagesent": "メッセージを送信しました: __response__",
@ -34,6 +35,7 @@
"inboxzero": "受信トレイにメールがありません",
"sending": "送信中",
"sendfail": "送信が失敗しました",
"parseerror": "メッセージのパースに失敗",
"connecterror": "接続エラー"
},
"errors": {
@ -43,6 +45,7 @@
"nosmtptransport": "SMTP転送が設定されていません。「情報」タブを参照してください",
"nopayload": "送信するペイロードがありません",
"fetchfail": "フォルダの受信に失敗しました: __folder__",
"parsefail": "メッセージのパースに失敗",
"messageerror": "メッセージ受信エラー: __error__"
}
}

View File

@ -1,12 +1,13 @@
{
"name": "node-red-node-email",
"version": "1.7.8",
"description": "Node-RED nodes to send and receive simple emails",
"version": "1.8.1",
"description": "Node-RED nodes to send and receive simple emails.",
"dependencies": {
"imap": "^0.8.19",
"mailparser": "^2.7.7",
"nodemailer": "^6.4.6",
"poplib": "^0.1.7"
"poplib": "^0.1.7",
"mailparser": "^3.0.0",
"nodemailer": "~6.4.10",
"smtp-server": "^3.7.0"
},
"repository": {
"type": "git",
@ -18,7 +19,8 @@
"email",
"gmail",
"imap",
"pop"
"pop",
"mta"
],
"node-red": {
"nodes": {

View File

@ -3,9 +3,7 @@ module.exports = function(RED) {
"use strict";
var PushBullet = require('pushbullet');
var fs = require('fs');
var util = require('util');
var when = require('when');
var nodefn = require('when/node');
var EventEmitter = require('events').EventEmitter;
function onError(err, node) {
@ -127,17 +125,19 @@ module.exports = function(RED) {
stream.on('close', function() {
self.emitter.emit('stream_disconnected');
if (!closing) {
if (tout) { clearTimeout(tout); }
tout = setTimeout(function() {
stream.connect();
},15000);
}, 15000);
}
});
stream.on('error', function(err) {
self.emitter.emit('stream_error', err);
if (!closing) {
if (tout) { clearTimeout(tout); }
tout = setTimeout(function() {
stream.connect();
},15000);
}, 15000);
}
});
stream.connect();
@ -229,10 +229,14 @@ module.exports = function(RED) {
msg.payload = incoming.body;
}
else if (incoming.type === 'dismissal') {
msg.topic = "dismissal";
msg.topic = "Push dismissed";
msg.payload = incoming.iden;
}
else if (incoming.type === 'sms_changed') {
msg.topic = "SMS: "+ incoming.notifications[0].title;
msg.payload = incoming.notifications[0].body;
msg.message = incoming;
}
else {
this.error("unknown push type: " + incoming.type + " content: " + JSON.stringify(incoming));
return;
@ -257,8 +261,7 @@ module.exports = function(RED) {
try {
pushkeys = RED.settings.pushbullet || require(process.env.NODE_RED_HOME+"/../pushkey.js");
}
catch(err) {
}
catch(err) { }
var cred = RED.nodes.getCredentials(n.id);
// get old apikey
@ -327,7 +330,7 @@ module.exports = function(RED) {
try {
this.deviceid = this.credentials.deviceid;
}
catch(err) {}
catch(err) { }
}
if (configNode) {

View File

@ -1,6 +1,6 @@
{
"name" : "node-red-node-pushbullet",
"version" : "0.0.14",
"version" : "0.0.17",
"description" : "A Node-RED node to send alerts via Pushbullet",
"dependencies" : {
"pushbullet": "^2.4.0",

View File

@ -103,8 +103,8 @@ module.exports = function(RED) {
if (err) { node.error(err,msg); }
else {
try {
response = JSON.parse(response);
if (response.status !== 1) { node.error("[57-pushover.js] Error: "+response); }
var responseObject = JSON.parse(response);
if (responseObject.status !== 1) { node.error("[57-pushover.js] Error: "+response); }
}
catch(e) {
node.error("[57-pushover.js] Error: "+response);

View File

@ -155,7 +155,7 @@ module.exports = function(RED) {
}
}
else if(stanza.attrs.type === 'result'){
// AM To-Do check for 'bind' result with our current jid
// To-Do check for 'bind' result with our current jid
var query = stanza.getChild('query');
if (RED.settings.verbose || LOGITALL) {that.log("result!");}
if (RED.settings.verbose || LOGITALL) {that.log(query);}
@ -164,7 +164,6 @@ module.exports = function(RED) {
}
});
// We shouldn't have any errors here that the input/output nodes can't handle
// if you need to see everything though; uncomment this block
// this.client.on('error', err => {
@ -497,6 +496,10 @@ module.exports = function(RED) {
node.error("Server doesn't exist "+xmpp.options.service,err);
node.status({fill:"red",shape:"ring",text:"bad address"});
}
if (err.errno === "ENOTFOUND") {
node.error("Server doesn't exist "+xmpp.options.service,err);
node.status({fill:"red",shape:"ring",text:"bad address"});
}
else if (err === "XMPP authentication failure") {
node.error(err,err);
node.status({fill:"red",shape:"ring",text:"XMPP authentication failure"});

View File

@ -1,6 +1,6 @@
{
"name": "node-red-node-xmpp",
"version": "0.2.4",
"version": "0.3.0",
"description": "A Node-RED node to talk to an XMPP server",
"dependencies": {
"@xmpp/client": "^0.11.1"

View File

@ -1,11 +1,29 @@
<script type="text/x-red" data-template-name="mongodb">
<script type="text/html" data-template-name="mongodb">
<div class="form-row">
<label for="node-config-input-hostname"><i class="fa fa-bookmark"></i> <span data-i18n="mongodb.label.host"></span></label>
<input class="input-append-left" type="text" id="node-config-input-hostname" placeholder="localhost" style="width: 40%;" >
<label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> <span data-i18n="mongodb.label.port"></span></label>
<input type="text" id="node-config-input-port" style="width:45px">
<label for="node-config-input-hostname"><i class="fa fa-bookmark"></i><span data-i18n="mongodb.label.host"></span></label>
<input class="input-append-left" type="text" id="node-config-input-hostname" placeholder="localhost">
</div>
<div class="form-row node-config-input-topology">
<label for="node-config-input-topology"><span data-i18n="mongodb.label.topology"></span></label>
<select id="node-config-input-topology">
<option type="button" class="red-ui-button toggle topology-group" selected value="direct">Direct (mongodb://)</button>
<option type="button" class="red-ui-button toggle topology-group" value="replicaset">RelicaSet/Cluster (mongodb://)</button>
<option type="button" class="red-ui-button toggle topology-group" value="dnscluster">DNS Cluster (mongodb+srv://)</button>
</select>
</div>
<div class="form-row node-config-connectOptions">
<label for="node-config-input-connectOptions"><i class="fa fa-wrench"></i><span data-i18n="mongodb.label.connectOptions"></span></label>
<input type="text" id="node-config-input-connectOptions">
</div>
<div class="form-row node-config-input-port">
<label for="node-config-input-port"><i class="fa fa-plug"></i><span data-i18n="mongodb.label.port"></span></label>
<input type="text" id="node-config-input-port" style="width:55px;">
</div>
<div class="form-row">
<label for="node-config-input-db"><i class="fa fa-database"></i> <span data-i18n="mongodb.label.database"></span></label>
<input type="text" id="node-config-input-db">
@ -30,6 +48,8 @@
color: "rgb(218, 196, 180)",
defaults: {
hostname: {value: "127.0.0.1", required: true},
topology: {value: "direct", required: true},
connectOptions: {value: "", required: false},
port: {value: 27017, required: true},
db: {value: "", required: true},
name: {value: ""}
@ -39,13 +59,60 @@
password: {type: "password"}
},
label: function() {
return this.name || this.hostname + ":" + this.port + "/" + this.db;
}
return this.name || this.db + "@" + this.hostname;
},
oneditprepare: function() {
$("#node-config-input-topology").on("change", function() {
var topology = $("#node-config-input-topology option:selected").val();
if (topology === "direct") {
$(".node-config-input-port").show();
} else {
$(".node-config-input-port").hide();
}
});
},
});
</script>
<script type="text/html" data-help-name="mongodb">
<p>Define a connection method to your MongoDB server instance.</p>
<p>There are 3 supported options:
<details><summary>Standard/direct</summary>
For databases that request connections in the form
<code>
mongodb://[username]:[password]@[hostname]:[port]/[dbname]
</code>
Most often used for local MongoDB instances (localhost:27017), and other stand-alone instances.
</details>
<details><summary>Standard/replicaset</summary>
For databases that request connections in the form
<code>
mongodb://[username]:[password]@[hostnameA]:[port],[hostnameB]:[port]/[dbname]?replicaSet=[replsetname]
</code>
Often used with <q>database as a service</q> offerings,
or on-premises instances that have been configured for availability and resilience
</details>
<details><summary>Clustered by DNS seedlist</summary>
For databases that request connections in the form
<code>
mongodb+srv://[username]:[password]@[clustername]/[dbname]?retryWrites=true&w=majority
</code>
A configuration of MongoDB instances that provide availability and performance
through replication and sharding, accessed through a cluster alias name, rather than
by specific host:port connections. This is the default for MongoDB instances in the
<a href="https://www.mongodb.com/cloud/atlas" target="_blank">Atlas cloud service</a>.
</details>
<p><strong>Connect options</strong> is where you add the optional parameters required by your MongoDB instance.
This might include:
<ul><li>w=majority</li><li>replicaSet=replset</li><li>authSource=admin</li></ul> and any other options appropriate -
full set available at <a href="https://docs.mongodb.com/manual/reference/connection-string/" target="_blank">
Connection String URI Format — MongoDB Manual</a>.
<p>If you are connecting to <a href="https://cloud.ibm.com/catalog/services/databases-for-mongodb-group" target="_blank">
IBM Databases for MongoDB</a>, as a replica-set, be sure to append <code>ssl=true&tlsAllowInvalidCertificates=true </code>
to the <strong>Connect options</strong>.
</script>
<script type="text/x-red" data-template-name="mongodb out">
<script type="text/html" data-template-name="mongodb out">
<div class="form-row">
<label for="node-input-mongodb"><i class="fa fa-bookmark"></i> <span data-i18n="mongodb.label.server"></span></label>
<input type="text" id="node-input-mongodb">
@ -85,29 +152,28 @@
<div class="form-tips" id="node-warning" style="display: none"><span data-i18n="[html]mongodb.tip"></span></div>
</script>
<script type="text/x-red" data-help-name="mongodb out">
<script type="text/html" data-help-name="mongodb out">
<p>A simple MongoDB output node. Can save, insert, update and remove objects from a chosen collection.</p>
<p>Save will update an existing object or insert a new object if one does not already exist.</p>
<p>Insert will insert a new object.</p>
<p>Save and insert either store <code>msg</code> or <code>msg.payload</code>.</p>
<p>Update will modify an existing object or objects. The query to select objects to update uses <code>msg.query</code>,
<p>Update will modify an existing object or objects. The query to select objects to update uses <code>msg.query</code>
and the update to the element uses <code>msg.payload</code>. If <code>msg.query._id</code> is
a valid mongo ObjectId string it will be converted to an ObjectId type.</p>
<p>Update can add an object if it does not exist or update multiple objects.</p>
<p>Update can add a object if it does not exist or update multiple objects.</p>
<p>Remove will remove objects that match the query passed in on <code>msg.payload</code>. A blank query will delete
<i>all of the objects</i> in the collection.</p>
<p>You can either set the collection method in the node config or on <code>msg.collection</code>. Setting it in the
node will override <code>msg.collection</code>.</p>
<p>By default, MongoDB creates an <i>_id</i> property as the primary key, so repeated injections of the
<p>By default MongoDB creates an <i>_id</i> property as the primary key - so repeated injections of the
same <code>msg</code> will result in many database entries.</p>
<p>If this is NOT the desired behaviour, i.e., you want repeated entries to overwrite, then you must set
<p>If this is NOT the desired behaviour - ie. you want repeated entries to overwrite, then you must set
the <code>msg._id</code> property to be a constant by the use of a previous function node.</p>
<p>This could be a unique constant or you could create one based on some other msg property.</p>
<p>Currently we do not limit or cap the collection size, however this may well change.</p>
<p>Currently we do not limit or cap the collection size at all... this may well change.</p>
</script>
<script type="text/javascript">
function oneditprepare() {
$("#node-input-operation").change(function () {
var id = $("#node-input-operation option:selected").val();
@ -150,7 +216,7 @@
align: "right",
label: function() {
var mongoNode = RED.nodes.node(this.mongodb);
return this.name || (mongoNode ? mongoNode.label() + " " + this.collection: "mongodb");
return this.name || (mongoNode ? mongoNode.label() + " " + this.collection : "mongodb");
},
labelStyle: function() {
return this.name ? "node_label_italic" : "";
@ -160,7 +226,7 @@
</script>
<script type="text/x-red" data-template-name="mongodb in">
<script type="text/html" data-template-name="mongodb in">
<div class="form-row">
<label for="node-input-mongodb"><i class="fa fa-bookmark"></i> <span data-i18n="mongodb.label.server"></span></label>
<input type="text" id="node-input-mongodb">
@ -184,12 +250,12 @@
<div class="form-tips" id="node-warning" style="display: none"><span data-i18n="[html]mongodb.tip"></span></div>
</script>
<script type="text/x-red" data-help-name="mongodb in">
<script type="text/html" data-help-name="mongodb in">
<p>Calls a MongoDB collection method based on the selected operator.</p>
<p>Find queries a collection using the <code>msg.payload</code> as the query statement as per the .find() function.
Optionally, you may also set a <code>msg.projection</code> object (via a function) to constrain the returned
fields. You can also set a <code>msg.sort</code> object, a <code>msg.limit</code> number and a <code>msg.skip</code> number.</p>
<p>Count returns a count of the number of documents in a collection, or matches a query using the
Optionally, you may also (via a function) set a <code>msg.projection</code> object to constrain the returned
fields, a <code>msg.sort</code> object, a <code>msg.limit</code> number and a <code>msg.skip</code> number.</p>
<p>Count returns a count of the number of documents in a collection or matching a query using the
<code>msg.payload</code> as the query statement.</p>
<p>Aggregate provides access to the aggregation pipeline using the <code>msg.payload</code> as the pipeline array.</p>
<p>You can either set the collection method in the node config or on <code>msg.collection</code>. Setting it in
@ -200,7 +266,6 @@
</script>
<script type="text/javascript">
RED.nodes.registerType('mongodb in', {
category: 'storage-input',
color: "rgb(218, 196, 180)",
@ -215,7 +280,7 @@
icon: "mongodb.png",
label: function() {
var mongoNode = RED.nodes.node(this.mongodb);
return this.name || (mongoNode ? mongoNode.label() + " " + this.collection: "mongodb");
return this.name || (mongoNode ? mongoNode.label() + " " + this.collection : "mongodb");
},
labelStyle: function() {
return this.name ? "node_label_italic" : "";

View File

@ -1,4 +1,5 @@
module.exports = function(RED) {
"use strict";
var mongo = require('mongodb');
@ -11,13 +12,37 @@ module.exports = function(RED) {
this.port = n.port;
this.db = n.db;
this.name = n.name;
this.connectOptions= n.connectOptions;
this.topology = n.topology;
//console.log(this);
var clustered = (this.topology !== "direct") || false;
var url = "mongodb://";
if (this.credentials && this.credentials.user && this.credentials.password) {
url += this.credentials.user+":"+this.credentials.password+"@";
if (this.topology === "dnscluster") {
url = "mongodb+srv://";
}
if (this.credentials && this.credentials.user && this.credentials.password) {
this.user = this.credentials.user;
this.password = this.credentials.password;
} else {
this.user = n.user;
this.password = n.password;
}
if (this.user) {
url += this.user+":"+this.password+"@";
}
if (clustered) {
url += this.hostname + "/" + this.db
} else {
url += this.hostname + ":" + this.port + "/" + this.db;
}
if (this.connectOptions){
url += "?" + this.connectOptions;
}
url += this.hostname+":"+this.port+"/"+this.db;
console.log("MongoDB URL: " + url);
this.url = url;
}
@ -49,7 +74,7 @@ module.exports = function(RED) {
var noerror = true;
var connectToDB = function() {
MongoClient.connect(node.mongoConfig.url, function(err, db) {
MongoClient.connect(node.mongoConfig.url, function(err, client) {
if (err) {
node.status({fill:"red",shape:"ring",text:RED._("mongodb.status.error")});
if (noerror) { node.error(err); }
@ -58,9 +83,12 @@ module.exports = function(RED) {
}
else {
node.status({fill:"green",shape:"dot",text:RED._("mongodb.status.connected")});
node.clientDb = db;
node.clientDb = client.db();
var db = client.db();
//console.log( db);
noerror = true;
var coll;
if (node.collection) {
coll = db.collection(node.collection);
}
@ -174,7 +202,8 @@ module.exports = function(RED) {
var noerror = true;
var connectToDB = function() {
MongoClient.connect(node.mongoConfig.url, function(err,db) {
console.log("connecting: " + node.mongoConfig.url);
MongoClient.connect(node.mongoConfig.url, function(err,client) {
if (err) {
node.status({fill:"red",shape:"ring",text:RED._("mongodb.status.error")});
if (noerror) { node.error(err); }
@ -183,7 +212,8 @@ module.exports = function(RED) {
}
else {
node.status({fill:"green",shape:"dot",text:RED._("mongodb.status.connected")});
node.clientDb = db;
node.clientDb = client.db();
var db = client.db();
noerror = true;
var coll;
node.on("input", function(msg) {
@ -216,7 +246,7 @@ module.exports = function(RED) {
skip = 0;
}
coll.find(selector,msg.projection).sort(msg.sort).limit(limit).skip(skip).toArray(function(err, items) {
coll.find(selector).project(msg.projection).sort(msg.sort).limit(limit).skip(skip).toArray(function(err, items) {
if (err) {
node.error(err);
}
@ -249,8 +279,16 @@ module.exports = function(RED) {
node.error(err);
}
else {
msg.payload = result;
node.send(msg);
cursor.toArray(function(cursorError, cursorDocs) {
console.log(cursorDocs);
if (cursorError) {
node.error(cursorError);
}
else {
msg.payload = cursorDocs;
node.send(msg);
}
});
}
});
}

View File

@ -16,13 +16,23 @@ Install
-------
Run the following command in your Node-RED user directory - typically `~/.node-red`
```
npm install node-red-node-mongodb
```
Note that this package requires a MongoDB client package at least version 3.6.1 - if you have an older (version 2) client,
you may need to remove that before installing this
```
npm remove mongodb
npm install node-red-node-mongodb
```
Usage
-----
Nodes to save and retrieve data in a local MongoDB instance.
Nodes to save and retrieve data in a MongoDB instance - the database server can be local (mongodb//:localhost:27017), remote (mongodb://hostname.network:27017),
replica-set or cluster (mongodb://hostnameA.network:27017,hostnameB.network:27017), and DNS seedlist cluster (mongodb+srv://clustername.network).
Reference [MongoDB docs](https://docs.mongodb.com/manual/reference/connection-string/) to see which connection method (host or clustered) to use for your MongoDB instance.
### Input

View File

@ -2,6 +2,8 @@
"mongodb": {
"label": {
"host": "Host",
"topology":"Connection topology",
"connectOptions":"Connect options",
"port": "Port",
"database": "Database",
"username": "Username",

View File

@ -1,9 +1,9 @@
{
"name" : "node-red-node-mongodb",
"version" : "0.0.14",
"version" : "0.2.2",
"description" : "Node-RED nodes to talk to an Mongo database",
"dependencies" : {
"mongodb" : "^2.2.34"
"mongodb" : "^3.6.2"
},
"repository" : {
"type":"git",
@ -20,5 +20,11 @@
"name": "Dave Conway-Jones",
"email": "ceejay@vnet.ibm.com",
"url": "http://nodered.org"
},
"contributors": [
{
"name": "Ross Cruickshank",
"email": "ross@vnet.ibm.com"
}
]
}

View File

@ -1,9 +1,9 @@
{
"name": "node-red-node-sqlite",
"version": "0.4.3",
"version": "0.4.4",
"description": "A sqlite node for Node-RED",
"dependencies": {
"sqlite3": "~4.1.1"
"sqlite3": "~4.2.0"
},
"repository": {
"type": "git",

View File

@ -43,6 +43,7 @@ describe('email Node', function () {
id: "n1",
type: "e-mail",
name: "emailout",
port: 1025,
wires: [
[]
]
@ -188,4 +189,64 @@ describe('email Node', function () {
})
});
describe('email mta', function () {
it('should catch an email send to localhost 1025', function (done) {
var flow = [{
id: "n1",
type: "e-mail mta",
name: "emailmta",
port: 1025,
wires: [
["n2"]
]
},
{
id:"n2",
type:"helper"
},
{
id: "n3",
type: "e-mail",
dname: "testout",
server: "localhost",
secure: false,
port: 1025,
wires: [
[]
]
}];
helper.load(emailNode, flow, function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var n3 = helper.getNode("n3");
n1.should.have.property('port', 1025);
n2.on("input", function(msg) {
//console.log("GOT",msg);
try {
msg.should.have.a.property("payload",'Hello World\n');
msg.should.have.a.property("topic","Test");
msg.should.have.a.property("from",'foo@example.com');
msg.should.have.a.property("to",'bar@example.com');
msg.should.have.a.property("attachments");
msg.should.have.a.property("header");
done();
}
catch(e) {
done(e)
}
});
n3.emit("input", {
payload: "Hello World",
topic: "Test",
from: "foo@example.com",
to: "bar@example.com"
});
//done();
});
});
});
});