diff --git a/.travis.yml b/.travis.yml index 7c414c5f..9bfec6ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ matrix: include: - node_js: 8 - node_js: 10 - - node_js: 6 - python: 2.7 language: python before_script: pip install flake8 diff --git a/function/random/README.md b/function/random/README.md index e27fdef7..95ed1b0e 100644 --- a/function/random/README.md +++ b/function/random/README.md @@ -9,15 +9,17 @@ Install Run the following command in your Node-RED user directory - typically `~/.node-red` npm install node-red-node-random - + Usage ----- A simple node to generate a random number when triggered. -If integer mode is selected (default) it will return an integer **between and including** the two values given - so selecting 1 to 6 will return values 1,2,3,4,5 or 6. +If you return an integer it can include both the low and high values. +`min <= n <= max` - so selecting 1 to 6 will return values 1,2,3,4,5 or 6. -If floating point mode is selected then it will return a number **between** the two values given - so selecting 1 to 6 will return values 1 < x < 6 . +If you return a floating point value it will be from the low value, up to, but +not including the high value. `min <= n < max` - so selecting 1 to 6 will return values 1 <= n < 6 . **Note:** This generates **numbers**. diff --git a/function/random/package.json b/function/random/package.json index 4898c021..c8395a23 100644 --- a/function/random/package.json +++ b/function/random/package.json @@ -1,6 +1,6 @@ { "name" : "node-red-node-random", - "version" : "0.1.0", + "version" : "0.1.2", "description" : "A Node-RED node that when triggered generates a random number between two values.", "dependencies" : { }, diff --git a/function/random/random.html b/function/random/random.html index 0f2c3824..3e103aef 100644 --- a/function/random/random.html +++ b/function/random/random.html @@ -28,8 +28,10 @@ 70% @@ -81,6 +86,7 @@ server: {value:"smtp.gmail.com",required:true}, port: {value:"465",required:true}, secure: {value: true}, + tls: {value: true}, name: {value:""}, dname: {value:""} }, diff --git a/social/email/61-email.js b/social/email/61-email.js index 92a7cdea..89dae648 100644 --- a/social/email/61-email.js +++ b/social/email/61-email.js @@ -14,9 +14,13 @@ module.exports = function(RED) { var nodemailer = require("nodemailer"); var Imap = require('imap'); var POP3Client = require("poplib"); - var MailParser = require("mailparser").MailParser; + var MailParser = require("mailparser-mit").MailParser; var util = require("util"); + if (parseInt(process.version.split("v")[1].split(".")[0]) < 8) { + throw "Error : Requires nodejs version >= 8."; + } + try { var globalkeys = RED.settings.email || require(process.env.NODE_RED_HOME+"/../emailkeys.js"); } @@ -30,6 +34,7 @@ module.exports = function(RED) { this.outserver = n.server; this.outport = n.port; this.secure = n.secure; + this.tls = true; var flag = false; if (this.credentials && this.credentials.hasOwnProperty("userid")) { this.userid = this.credentials.userid; @@ -50,12 +55,16 @@ module.exports = function(RED) { if (flag) { RED.nodes.addCredentials(n.id,{userid:this.userid, password:this.password, global:true}); } + if (n.tls === false){ + this.tls = false; + } var node = this; var smtpOptions = { host: node.outserver, port: node.outport, - secure: node.secure + secure: node.secure, + tls: {rejectUnauthorized: node.tls} } if (this.userid && this.password) { @@ -185,7 +194,7 @@ module.exports = function(RED) { // will be used to populate the email. // DCJ NOTE: - heirachical multipart mime parsers seem to not exist - this one is barely functional. function processNewMessage(msg, mailMessage) { - msg = JSON.parse(JSON.stringify(msg)); // Clone the message + msg = RED.util.cloneMessage(msg); // Clone the message // Populate the msg fields from the content of the email message // that we have just parsed. msg.payload = mailMessage.text; @@ -193,9 +202,9 @@ module.exports = function(RED) { msg.date = mailMessage.date; msg.header = mailMessage.headers; if (mailMessage.html) { msg.html = mailMessage.html; } - if (mailMessage.to && mailMessage.from.to > 0) { msg.to = mailMessage.to; } - if (mailMessage.cc && mailMessage.from.cc > 0) { msg.cc = mailMessage.cc; } - if (mailMessage.bcc && mailMessage.from.bcc > 0) { msg.bcc = mailMessage.bcc; } + if (mailMessage.to && mailMessage.to.length > 0) { msg.to = mailMessage.to; } + if (mailMessage.cc && mailMessage.cc.length > 0) { msg.cc = mailMessage.cc; } + if (mailMessage.bcc && mailMessage.bcc.length > 0) { msg.bcc = mailMessage.bcc; } if (mailMessage.from && mailMessage.from.length > 0) { msg.from = mailMessage.from[0].address; } if (mailMessage.attachments) { msg.attachments = mailMessage.attachments; } else { msg.attachments = []; } @@ -221,6 +230,7 @@ module.exports = function(RED) { function nextMessage() { if (currentMessage > maxMessage) { pop3Client.quit(); + setInputRepeatTimeout(); return; } pop3Client.retr(currentMessage); @@ -243,6 +253,7 @@ module.exports = function(RED) { }); pop3Client.on("error", function(err) { + setInputRepeatTimeout(); node.log("error: " + JSON.stringify(err)); }); @@ -258,6 +269,7 @@ module.exports = function(RED) { } else { node.log(util.format("login error: %s %j", status, rawData)); pop3Client.quit(); + setInputRepeatTimeout(); } }); @@ -279,6 +291,7 @@ module.exports = function(RED) { else { node.log(util.format("retr error: %s %j", status, rawData)); pop3Client.quit(); + setInputRepeatTimeout(); } }); @@ -318,6 +331,7 @@ module.exports = function(RED) { node.status({fill:"red", shape:"ring", text:"email.status.foldererror"}); node.error(RED._("email.errors.fetchfail", {folder:node.box}),err); imap.end(); + setInputRepeatTimeout(); return; } //console.log("> search - err=%j, results=%j", err, results); @@ -325,6 +339,7 @@ module.exports = function(RED) { //console.log(" [X] - Nothing to fetch"); node.status({}); imap.end(); + setInputRepeatTimeout(); return; } @@ -372,10 +387,12 @@ module.exports = function(RED) { } else { cleanup(); } + setInputRepeatTimeout(); }); fetch.once('error', function(err) { console.log('Fetch error: ' + err); + setInputRepeatTimeout(); }); }); // End of imap->search }); // End of imap->openInbox @@ -419,16 +436,19 @@ module.exports = function(RED) { this.on("close", function() { if (this.interval_id != null) { - clearInterval(this.interval_id); + clearTimeout(this.interval_id); } if (imap) { imap.destroy(); } }); - // Set the repetition timer as needed - if (!isNaN(this.repeat) && this.repeat > 0) { - this.interval_id = setInterval( function() { - node.emit("input",{}); - }, this.repeat ); + function setInputRepeatTimeout() + { + // Set the repetition timer as needed + if (!isNaN(node.repeat) && node.repeat > 0) { + node.interval_id = setTimeout( function() { + node.emit("input",{}); + }, node.repeat ); + } } node.emit("input",{}); diff --git a/social/email/README.md b/social/email/README.md index aaf84e6e..0cffc6e2 100644 --- a/social/email/README.md +++ b/social/email/README.md @@ -1,7 +1,7 @@ node-red-node-email =================== -Node-RED nodes to send and receive simple emails. +Node-RED nodes to send and receive simple emails. Pre-requisite @@ -9,7 +9,7 @@ Pre-requisite You will need valid email credentials for your email server. -**Note :** Version 1.x of this node requires Node.js v6 or newer. +**Note :** Version 1.x of this node requires **Node.js v8** or newer. Install @@ -18,10 +18,12 @@ Install Version 0.x of this node is usually installed by default by Node-RED. To install version 1.x you need to uninstall the existing version. - sudo npm uninstall -g node-red-node-email + cd /usr/lib/node_modules/node-red + sudo npm uninstall --unsafe-perm node-red-node-email Then run the following command in your Node-RED user directory - typically `~/.node-red` + cd ~/.node-red npm i node-red-node-email **Note :** this installs the new version locally rather than globally. This can then be managed by the palette manager. diff --git a/social/email/locales/en-US/61-email.json b/social/email/locales/en-US/61-email.json index fbe47766..d3f05375 100644 --- a/social/email/locales/en-US/61-email.json +++ b/social/email/locales/en-US/61-email.json @@ -13,6 +13,7 @@ "folder": "Folder", "protocol": "Protocol", "useSSL": "Use SSL?", + "useTLS": "Use TLS?", "disposition": "Disposition", "none": "None", "read": "Mark Read", diff --git a/social/email/package.json b/social/email/package.json index 985817e0..33476201 100644 --- a/social/email/package.json +++ b/social/email/package.json @@ -1,11 +1,11 @@ { "name": "node-red-node-email", - "version": "1.0.0", + "version": "1.0.4", "description": "Node-RED nodes to send and receive simple emails", "dependencies": { "imap": "^0.8.19", - "mailparser": "^0.6.2", - "nodemailer": "^4.6.4", + "mailparser-mit": "^0.6.2", + "nodemailer": "^4.6.8", "poplib": "^0.1.7" }, "repository": { @@ -30,6 +30,6 @@ "url": "http://nodered.org" }, "engines": { - "node": ">=6.0.0" + "node": ">=8.0.0" } } diff --git a/social/feedparser/32-feedparse.js b/social/feedparser/32-feedparse.js index 8d6a0001..6e8482ee 100644 --- a/social/feedparser/32-feedparse.js +++ b/social/feedparser/32-feedparse.js @@ -22,7 +22,7 @@ module.exports = function(RED) { var req = request(node.url, {timeout:10000, pool:false}); //req.setMaxListeners(50); req.setHeader('user-agent', 'Mozilla/5.0 (Node-RED)'); - req.setHeader('accept', 'text/html,application/xhtml+xml'); + req.setHeader('accept', 'application/rss+xml,text/html,application/xhtml+xml'); var feedparser = new FeedParser(); diff --git a/social/feedparser/package.json b/social/feedparser/package.json index 747710fb..26ee0a40 100644 --- a/social/feedparser/package.json +++ b/social/feedparser/package.json @@ -1,10 +1,10 @@ { "name": "node-red-node-feedparser", - "version": "0.1.13", + "version": "0.1.14", "description": "A Node-RED node to get RSS Atom feeds.", "dependencies": { "feedparser": "^2.2.9", - "request": "^2.83.0" + "request": "^2.88.0" }, "repository": { "type": "git", diff --git a/social/notify/57-notify.html b/social/notify/57-notify.html index d0fc85d4..fe3244a2 100644 --- a/social/notify/57-notify.html +++ b/social/notify/57-notify.html @@ -1,5 +1,5 @@ - - diff --git a/social/pushover/README.md b/social/pushover/README.md index 86c592f9..158ccae7 100644 --- a/social/pushover/README.md +++ b/social/pushover/README.md @@ -16,12 +16,14 @@ Usage Uses Pushover to push the `msg.payload` to a device that has the Pushover app installed. -Optionally uses `msg.topic` to set the title, `msg.device` to set the device -and `msg.priority` to set the priority, if not already set in the properties. -Optionally uses `msg.topic` to set the title, `msg.device` to set the device, -`msg.priority` to set the priority, `msg.url` to add a web address and `msg.url_title` -to add a url title - if not already set in the properties. +Optionally uses `msg.topic` to set the configuration, if not already set in the properties: + - `msg.device`: to set the device + - `msg.priority`: to set the priority + - `msg.topic`: to set the title + - `msg.url`: to add a web address + - `msg.url_title`: to add a url title + - `msg.sound`: to set the alert sound, see the [available options](https://pushover.net/api#sounds) The User-key and API-token are stored in a separate credentials file. diff --git a/social/pushover/package.json b/social/pushover/package.json index 2a52ec45..ccc56b22 100644 --- a/social/pushover/package.json +++ b/social/pushover/package.json @@ -1,6 +1,6 @@ { "name" : "node-red-node-pushover", - "version" : "0.0.12", + "version" : "0.0.13", "description" : "A Node-RED node to send alerts via Pushover", "dependencies" : { "pushover-notifications" : "~0.2.4" diff --git a/storage/sqlite/README.md b/storage/sqlite/README.md index 9d2b8d3c..ae94aee3 100644 --- a/storage/sqlite/README.md +++ b/storage/sqlite/README.md @@ -25,6 +25,8 @@ By it's very nature it is SQL injection... so *be careful* out there... Typically the returned payload will be an array of the result rows, (or an error). +You can load sqlite extensions by inputting a msg.extension property containing the full path and filename. + The reconnect timeout in milliseconds can be changed by adding a line to **settings.js** sqliteReconnectTime: 20000, diff --git a/storage/sqlite/ext/half.c b/storage/sqlite/ext/half.c new file mode 100644 index 00000000..5c746314 --- /dev/null +++ b/storage/sqlite/ext/half.c @@ -0,0 +1,30 @@ +/* Add your header comment here */ + +#include +SQLITE_EXTENSION_INIT1 + +/* +** The half() SQL function returns half of its input value. +*/ +static void halfFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + sqlite3_result_double(context, 0.5*sqlite3_value_double(argv[0])); +} + +/* SQLite invokes this routine once when it loads the extension. +** Create new functions, collating sequences, and virtual table +** modules here. This is usually the only exported symbol in +** the shared library. +*/ +int sqlite3_extension_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + SQLITE_EXTENSION_INIT2(pApi) + sqlite3_create_function(db, "half", 1, SQLITE_ANY, 0, halfFunc, 0, 0); + return 0; +} diff --git a/storage/sqlite/ext/half.dylib b/storage/sqlite/ext/half.dylib new file mode 100755 index 00000000..50bf666d Binary files /dev/null and b/storage/sqlite/ext/half.dylib differ diff --git a/storage/sqlite/package.json b/storage/sqlite/package.json index 7bf56945..9dd66ecb 100644 --- a/storage/sqlite/package.json +++ b/storage/sqlite/package.json @@ -1,6 +1,6 @@ { "name": "node-red-node-sqlite", - "version": "0.3.2", + "version": "0.3.5", "description": "A sqlite node for Node-RED", "dependencies": { "sqlite3": "^4.0.2" diff --git a/storage/sqlite/sqlite.html b/storage/sqlite/sqlite.html index 923f817c..28d5d966 100644 --- a/storage/sqlite/sqlite.html +++ b/storage/sqlite/sqlite.html @@ -77,6 +77,8 @@ be sure to include $ on the parameter object key.

Using any SQL Query, the result is returned in msg.payload

Typically the returned payload will be an array of the result rows, (or an error).

+

You can load sqlite extensions by inputting a msg.extension property containing the full + path and filename.

The reconnect timeout in milliseconds can be changed by adding a line to settings.js

sqliteReconnectTime: 20000,

diff --git a/storage/sqlite/sqlite.js b/storage/sqlite/sqlite.js index c5ec8e0b..27a92cad 100644 --- a/storage/sqlite/sqlite.js +++ b/storage/sqlite/sqlite.js @@ -43,89 +43,107 @@ module.exports = function(RED) { var node = this; node.status({}); - if (this.mydbConfig) { - this.mydbConfig.doConnect(); + if (node.mydbConfig) { + node.mydbConfig.doConnect(); node.status({fill:"green",shape:"dot",text:this.mydbConfig.mod}); var bind = []; - node.on("input", function(msg) { - if (this.sqlquery == "msg.topic"){ + + var doQuery = function(msg) { + if (node.sqlquery == "msg.topic"){ if (typeof msg.topic === 'string') { - bind = Array.isArray(msg.payload) ? msg.payload : []; - node.mydbConfig.db.all(msg.topic, bind, function(err, row) { - if (err) { node.error(err,msg); } - else { - msg.payload = row; - node.send(msg); - } - }); + if (msg.topic.length > 0) { + bind = Array.isArray(msg.payload) ? msg.payload : []; + node.mydbConfig.db.all(msg.topic, bind, function(err, row) { + if (err) { node.error(err,msg); } + else { + msg.payload = row; + node.send(msg); + } + }); + } } else { node.error("msg.topic : the query is not defined as a string",msg); node.status({fill:"red",shape:"dot",text:"msg.topic error"}); } } - if (this.sqlquery == "batch") { + if (node.sqlquery == "batch") { if (typeof msg.topic === 'string') { - node.mydbConfig.db.exec(msg.topic, function(err) { - if (err) { node.error(err,msg);} - else { - msg.payload = []; - node.send(msg); - } - }); + if (msg.topic.length > 0) { + node.mydbConfig.db.exec(msg.topic, function(err) { + if (err) { node.error(err,msg);} + else { + msg.payload = []; + node.send(msg); + } + }); + } } else { node.error("msg.topic : the query is not defined as string", msg); node.status({fill:"red", shape:"dot",text:"msg.topic error"}); } } - if (this.sqlquery == "fixed"){ - if (typeof this.sql === 'string'){ - bind = Array.isArray(msg.payload) ? msg.payload : []; - node.mydbConfig.db.all(this.sql, bind, function(err, row) { - if (err) { node.error(err,msg); } - else { - msg.payload = row; - node.send(msg); - } - }); + if (node.sqlquery == "fixed"){ + if (typeof node.sql === 'string') { + if (node.sql.length > 0) { + node.mydbConfig.db.all(node.sql, bind, function(err, row) { + if (err) { node.error(err,msg); } + else { + msg.payload = row; + node.send(msg); + } + }); + } } else{ - if (this.sql === null || this.sql == ""){ + if (node.sql === null || node.sql == "") { node.error("SQL statement config not set up",msg); node.status({fill:"red",shape:"dot",text:"SQL config not set up"}); } } } - if (this.sqlquery == "prepared"){ - if (typeof this.sql === 'string' && typeof msg.params !== "undefined" && typeof msg.params === "object"){ - node.mydbConfig.db.all(this.sql, msg.params, function(err, row) { - if (err) { node.error(err,msg); } - else { - msg.payload = row; - node.send(msg); - } - }); + if (node.sqlquery == "prepared"){ + if (typeof node.sql === 'string' && typeof msg.params !== "undefined" && typeof msg.params === "object") { + if (node.sql.length > 0) { + node.mydbConfig.db.all(node.sql, msg.params, function(err, row) { + if (err) { node.error(err,msg); } + else { + msg.payload = row; + node.send(msg); + } + }); + } } - else{ - if (this.sql === null || this.sql == ""){ + else { + if (node.sql === null || node.sql == "") { node.error("Prepared statement config not set up",msg); node.status({fill:"red",shape:"dot",text:"Prepared statement not set up"}); } - if (typeof msg.params == "undefined"){ + if (typeof msg.params == "undefined") { node.error("msg.params not passed"); node.status({fill:"red",shape:"dot",text:"msg.params not defined"}); } - else if (typeof msg.params != "object"){ + else if (typeof msg.params != "object") { node.error("msg.params not an object"); node.status({fill:"red",shape:"dot",text:"msg.params not an object"}); } } } + } + + node.on("input", function(msg) { + if (msg.hasOwnProperty("extension")) { + node.mydbConfig.db.loadExtension(msg.extension, function(err) { + if (err) { node.error(err,msg); } + else { doQuery(msg); } + }); + } + else { doQuery(msg); } }); } else { - this.error("Sqlite database not configured"); + node.error("Sqlite database not configured"); } } RED.nodes.registerType("sqlite",SqliteNodeIn); diff --git a/utility/daemon/daemon.html b/utility/daemon/daemon.html index 58bf99f6..bdd5f28d 100644 --- a/utility/daemon/daemon.html +++ b/utility/daemon/daemon.html @@ -11,12 +11,17 @@
- + + +
+
+ +
- +
@@ -62,6 +67,7 @@ name: {value:""}, command: {value:"",required:true}, args: {value:""}, + autorun: {value:true}, cr: {value:false}, redo: {value:true}, op: {value:"string"}, @@ -77,6 +83,9 @@ }, labelStyle: function() { return this.name?"node_label_italic":""; + }, + oneditprepare: function() { + if (this.autorun === undefined) { $("#node-input-autorun").prop('checked', true); } } }); diff --git a/utility/daemon/daemon.js b/utility/daemon/daemon.js index 07e49709..97568c7d 100644 --- a/utility/daemon/daemon.js +++ b/utility/daemon/daemon.js @@ -12,6 +12,8 @@ module.exports = function(RED) { this.redo = n.redo; this.running = false; this.closer = n.closer || "SIGKILL"; + this.autorun = true; + if (n.autorun === false) { this.autorun = false; } var node = this; function inputlistener(msg) { diff --git a/utility/daemon/package.json b/utility/daemon/package.json index faeb72bd..a45c56c0 100644 --- a/utility/daemon/package.json +++ b/utility/daemon/package.json @@ -1,6 +1,6 @@ { "name" : "node-red-node-daemon", - "version" : "0.0.21", + "version" : "0.0.22", "description" : "A Node-RED node that runs and monitors a long running system command.", "dependencies" : { },