changeset 56:99bd1d1ac071

Migration to node-xmpp, done!
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Wed, 10 Aug 2011 15:11:22 -0700
parents fd69d35cf2e6
children addbf6bbfaa8
files backends/directory.js backends/file.js configuration.js errors.js fdsq.js forms.js modules.js modules/mod_disco.js modules/mod_http.js modules/mod_owner.js modules/mod_publish.js modules/mod_publish_message.js nodes.js notifs.js psgxs.js storage.js
diffstat 16 files changed, 161 insertions(+), 186 deletions(-) [+]
line wrap: on
line diff
--- a/backends/directory.js
+++ b/backends/directory.js
@@ -74,6 +74,7 @@ backend.save = function(dir) {
 }
 
 backend.load = function(dir) {
+	var parse = require('ltx').parse;
 	if (!dir)
 		dir = 'data';
 
@@ -86,23 +87,11 @@ backend.load = function(dir) {
 		}
 
 		fs.readdir(dir, function(err, files) {
-			var xmpp = require('xmpp');
-			function parseStanza(path, content) {
-				var stanza = null;
-				var stream = new xmpp.Stream({
-					stanza: function (stanza) {
-						path[content] = stanza;
-					}
-				});
-				stream.opened = true;
-				stream.data(path[content]);
-			}
-
 			function endParsing(o) {
 				var regexp = /\d{4}-\d\d-\d\dT\d\d:\d\d:\d\dZ/;
 				for (var i in o) {
 					if (typeof o[i] == 'string' && i == 'content')
-						parseStanza(o, i);
+						o[i] = parse(o[i]);
 					else if (typeof o[i] == 'string' && regexp(o[i])) {
 						var today = new Date();
 						today.setFromISO8601(o[i]);
@@ -120,6 +109,9 @@ backend.load = function(dir) {
 				if (/^\./.test(file))
 					continue;
 
+				if (!/\.json$/.test(file))
+					continue;
+
 				var nodeID = decodeURI(file.replace(/\.json$/, '').replace('%2f', '/'));
 
 				var data = fs.readFileSync(dir+'/'+file).toString();
--- a/backends/file.js
+++ b/backends/file.js
@@ -50,23 +50,12 @@ backend.save = function(file) {
 }
 
 backend.load = function(file) {
-	var xmpp = require('xmpp');
-	function parseStanza(path, content) {
-		var stanza = null;
-		var stream = new xmpp.Stream({
-			stanza: function (stanza) {
-				path[content] = stanza;
-			}
-		});
-		stream.opened = true;
-		stream.data(path[content]);
-	}
-
+	var parse = require('ltx').parse;
 	function endParsing(o) {
 		var regexp = /\d{4}-\d\d-\d\dT\d\d:\d\d:\d\dZ/;
 		for (var i in o) {
 			if (typeof o[i] == 'string' && i == 'content')
-				parseStanza(o, i);
+				o[i] = parse(o[i]);
 			else if (typeof o[i] == 'string' && regexp(o[i])) {
 				var today = new Date();
 				today.setFromISO8601(o[i]);
--- a/configuration.js
+++ b/configuration.js
@@ -21,18 +21,17 @@
 
 var config = exports;
 
-config.jid = 'pubsub.example.org';
+config.jid = 'pubsub.ubuntu';
 config.password = 'hellohello';
-config.host = 'localhost';
-config.port = 5347;
-config.superOwner = ['you@example.com'];
+config.superOwner = ['you@ubuntu'];
 config.version = '0.1';
 config.os = 'GNU/Linux';
-config.allowCreateNode = [/@example\.com$/]; // value is an array of RegExp JIDs. If only super-owner should be able to create nodes, use [].
+config.allowCreateNode = [/@ubuntu$/]; // value is an array of RegExp JIDs. If only super-owner should be able to create nodes, use [].
 config.backend = 'directory'; // Put backends in “backends” directory.
 config.access = 'open'; // values include open, whitelist (by members) and authorize (owners of the node receive notification). presence and roster aren’t implemented yet.
 config.pluginsDir = 'modules';
 config.hideNonAccessibleNodes = true;
+config.debug = true;
 
 config.activated = [
 	'auto-create',
--- a/errors.js
+++ b/errors.js
@@ -197,20 +197,22 @@ var reverse = {};
 })(errors);
 
 exports.makeError = function(response, errorNumber, payload) {
-	response.attr.type = 'error';
+	response.attrs.type = 'error';
 	if (payload)
 		response.cnode(payload);
 
 	var e = reverse[errorNumber];
-	response.c('error', {type: e.type});
 
-	response.c(e.error, {xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'}).up();
+	var Element = require('ltx').Element;
+	var error = new Element('error', {type: e.type});
+	error.c(e.error, {xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'}).up();
+	response.cnode(error);
 
 	if (e.reason) {
 		if (e.feature)
-			response.c(e.reason, {xmlns: 'http://jabber.org/protocol/pubsub#errors', feature: e.feature});
+			error.c(e.reason, {xmlns: 'http://jabber.org/protocol/pubsub#errors', feature: e.feature}).up();
 		else
-			response.c(e.reason, {xmlns: 'http://jabber.org/protocol/pubsub#errors'});
+			error.c(e.reason, {xmlns: 'http://jabber.org/protocol/pubsub#errors'}).up();
 	}
 
 	return response;
--- a/fdsq.js
+++ b/fdsq.js
@@ -19,41 +19,14 @@
 
 'use strict';
 
-var sha1hex = require('sha1').hex;
+var JID = require('node-xmpp').JID;
 
 var fdsq = exports;
-fdsq.makeRandomId = function() {
-	return sha1hex(Date()+Math.random());
-};
-
-var JID = function(jid) {
-	this.full = jid;
-
-	var s = jid.indexOf('/');
-	if (s == -1)
-		this.resource = '';
-	else {
-		this.resource = jid.substring(s+1);
-		jid = jid.substr(0, s);
-	}
-
-	var a = jid.indexOf('@');
-	if (a == -1) {
-		this.user = '';
-		this.server = jid;
-	} else {
-		this.user = jid.substr(0, a);
-		this.server = jid.substr(a+1);
-	}
-	this.bare = jid;
-};
 
 fdsq.toBare = function(jid) {
-	var j = new JID(jid);
-	return j.bare;
+	return new JID(jid).bare().toString();
 };
 
 fdsq.toResource = function(jid) {
-	var j = new JID(jid);
-	return j.resource;
+	return new JID(jid).resource;
 };
--- a/forms.js
+++ b/forms.js
@@ -19,7 +19,7 @@
 
 'use strict';
 
-var xmpp = require('xmpp')
+var Element = require('ltx').Element;
 var service_configuration = require('./configuration').service_configuration;
 
 var parseBoolean = function(b) {
@@ -29,7 +29,7 @@ var parseBoolean = function(b) {
 }
 
 exports.build = function(type, desc, content, labels, title, instructions) {
-	var x = xmpp.stanza('x', {xmlns: 'jabber:x:data', type: type});
+	var x = new Element('x', {xmlns: 'jabber:x:data', type: type});
 
 	if (typeof desc == 'string')
 		desc = service_configuration[desc];
--- a/modules.js
+++ b/modules.js
@@ -31,7 +31,8 @@ var fdsq = require('./fdsq');
 var sandbox = {
 	process: process,
 	config: require('./configuration'),
-	xmpp: require('xmpp'),
+	Element: require('ltx').Element,
+	uuid: require('uuid'),
 	errors: require('./errors'),
 	forms: require('./forms'),
 	makeError: require('./errors').makeError,
@@ -39,7 +40,6 @@ var sandbox = {
 	NS: require('./namespaces'),
 	require: require,
 	storage: require('./storage'),
-	makeRandomId: fdsq.makeRandomId,
 	JID: {
 		toBare: fdsq.toBare,
 		toResource: fdsq.toResource
@@ -54,11 +54,11 @@ for (var i in files) {
 
 	fs.readFile(dir + '/' + file, function(err, data) {
 		if (err) {
-			console.log('ERROR: loading module “'+file+'”.'); // FIXME: file is always the last file of the list…
+			console.log('Erreur de chargement de module.');
 			return;
 		}
 
-		Script.runInNewContext(data, sandbox, dir + '/' + file); // FIXME: the same.
+		Script.runInNewContext(data, sandbox, dir + '/' + file);
 		var module = sandbox.exports;
 		sandbox.exports = {};
 
@@ -67,6 +67,7 @@ for (var i in files) {
 				console.log('WARNING: module '+j+' already loaded.');
 
 			modules[j] = module[j];
+			console.log('Module '+j+' loaded!');
 		}
 	});
 }
--- a/modules/mod_disco.js
+++ b/modules/mod_disco.js
@@ -53,7 +53,7 @@ exports.disco_info = {
 
 		// SECTION 5.1: Discover Features
 		} else {
-			response.c('query', {xmlns: NS.DISCO_INFO})
+			var query = new Element('query', {xmlns: NS.DISCO_INFO})
 				.c('identity', {category: 'pubsub', type: 'service', name: 'PubSub JavaScript Server'}).up()
 				.c('feature', {'var': NS.DISCO_INFO}).up()
 				.c('feature', {'var': NS.DISCO_ITEMS}).up()
@@ -61,9 +61,11 @@ exports.disco_info = {
 				.c('feature', {'var': 'jabber:iq:version'}).up()
 				.c('feature', {'var': NS.COMMANDS}).up();
 
+			response.cnode(query);
+
 			for (var i in config.activated)
 				if (typeof i == 'string')
-					response.c('feature', {'var': 'http://jabber.org/protocol/pubsub#' + config.activated[i]}).up();
+					query.c('feature', {'var': 'http://jabber.org/protocol/pubsub#' + config.activated[i]}).up();
 		}
 
 		return response;
--- a/modules/mod_http.js
+++ b/modules/mod_http.js
@@ -31,7 +31,6 @@ var regex = /^mod_.*\.js/;
 var Script = process.binding('evals').Script;
 var sandbox = {
 	config: require('./configuration'),
-	xmpp: require('xmpp'),
 	errors: require('./errors'),
 	forms: require('./forms'),
 	makeError: require('./errors').makeError,
--- a/modules/mod_owner.js
+++ b/modules/mod_owner.js
@@ -35,7 +35,7 @@ exports.create = {
 		if (!nodeID || nodeID == '') {
 			if (!config.enabled('instant-nodes'))
 				return makeError(response, errors.owner.create.instant_nodes_not_supported.n);
-			nodeID = makeRandomId();
+			nodeID = uuid();
 			instant = true;
 		}
 		if (storage.existsNode(nodeID))
--- a/modules/mod_publish.js
+++ b/modules/mod_publish.js
@@ -51,7 +51,7 @@ exports.publish = {
 		var itemID = item.getAttribute('id');
 		if (!config.enabled('item-ids') && itemID)
 			return makeError(response, errors.itemid_required.n);
-		itemID = itemID? itemID: makeRandomId();
+		itemID = itemID? itemID: uuid();
 
 		if (item.tags.length != 1)
 			return makeError(response, errors.pub.publish.bad_payload.n);
--- a/modules/mod_publish_message.js
+++ b/modules/mod_publish_message.js
@@ -46,7 +46,7 @@ exports.publishMessage = {
 
 		if (!config.enabled('item-ids'))
 			return makeError(response, errors.itemid_required.n);
-		var itemID = makeRandomId();
+		var itemID = uuid();
 
 		var now = new Date();
 
--- a/nodes.js
+++ b/nodes.js
@@ -24,7 +24,7 @@ var errors = require('./errors');
 var config = require('./configuration');
 var service_configuration = config.service_configuration;
 var Configuration = config.Configuration;
-var makeRandomId = require('./fdsq').makeRandomId;
+var uuid = require('uuid');
 
 exports.Item = function() {
 	this.content = null;
@@ -94,7 +94,7 @@ exports.Node.prototype = {
 			if (this.subscribers[jid])
 				subid = this.subscribers[jid].subid;
 			else
-				subid = makeRandomId();
+				subid = uuid();
 		}
 
 		this.subscribers[jid] = {
--- a/notifs.js
+++ b/notifs.js
@@ -1,6 +1,6 @@
 'use strict';
 
-var xmpp = require('xmpp');
+var Element = require('ltx').Element;
 var storage = require('./storage');
 var config = require('./configuration');
 var conn;
@@ -14,24 +14,24 @@ function _(obj, color) {
 };
 
 exports.send = function(notifs, type, nodeID, a1, a2) {
-	var ev = xmpp.stanza('event', {xmlns: 'http://jabber.org/protocol/pubsub#event'});
+	var ev = new Element('event', {xmlns: 'http://jabber.org/protocol/pubsub#event'});
 
 	if (type == 'affiliations') {
-		ev.attr.xmlns = 'http://jabber.org/protocol/pubsub';
+		ev.attrs.xmlns = 'http://jabber.org/protocol/pubsub';
 
 		var args = {};
 		for (i in a1) {
-			var attr = a1[i];
+			var attrs = a1[i];
 			if (i == 'affiliation')
-				args.affiliation = attr;
+				args.affiliation = attrs;
 			else if (i == 'jid')
-				args.jid = attr;
+				args.jid = attrs;
 		}
-		var affiliations = xmpp.stanza('affiliations', {node: nodeID})
+		var affiliations = new Element('affiliations', {node: nodeID})
 			.c('affiliation', args);
 		ev.cnode(affiliations);
 	} else if (type == 'collection') {
-		var collection = xmpp.stanza('collection', {node: nodeID});
+		var collection = new Element('collection', {node: nodeID});
 		if (a1 == 'associate')
 			collection.cnode('associate', {node: nodeID});
 		else
@@ -43,7 +43,7 @@ exports.send = function(notifs, type, no
 			return;
 		}
 
-		var configuration = xmpp.stanza('configuration', {node: nodeID});
+		var configuration = new Element('configuration', {node: nodeID});
 		if (a1) {
 			var x = forms.build('node_config', config.service_configuration.node_config, storage.getConfiguration(nodeID));
 			if (x)
@@ -51,12 +51,12 @@ exports.send = function(notifs, type, no
 		}
 		ev.cnode(configuration);
 	} else if (type == 'delete') {
-		var del = xmpp.stanza('delete', {node: nodeID});
+		var del = new Element('delete', {node: nodeID});
 		if (a1)
 			del.c('redirect', {uri: a1});
 		ev.cnode(del);
 	} else if (type == 'items') {
-		var items = xmpp.stanza(type, {node: nodeID});
+		var items = new Element(type, {node: nodeID});
 		if (a2 == 'retract')
 			for (var i in a1)
 				items.s('retract', {id: i});
@@ -70,7 +70,7 @@ exports.send = function(notifs, type, no
 					args.node = item.node;
 				if (item.publisher)
 					args.publisher = item.publisher;
-				var it = xmpp.stanza('item', args);
+				var it = new Element('item', args);
 				if (item.content)
 					it.cnode(item.content);
 				items.cnode(it);
@@ -85,24 +85,24 @@ exports.send = function(notifs, type, no
 
 		var args = {node: nodeID};
 		for (i in a1) {
-			var attr = a1[i];
+			var attrs = a1[i];
 			if (i == 'subscription') {
-				if (attr == 'none' || attr == 'pending' || attr == 'subscribed' || attr == 'unconfigured')
-					args[i] = attr;
+				if (attrs == 'none' || attrs == 'pending' || attrs == 'subscribed' || attrs == 'unconfigured')
+					args[i] = attrs;
 				else {
 					_('Error #3', 41)
 					return;
 				}
 			} else if (i == 'jid' || i == 'subid')
-				args[i] = attr;
+				args[i] = attrs;
 			else if (i == 'expiry')
-				args[i] = attr.toString();
+				args[i] = attrs.toString();
 		}
 		if (!args.jid || args.jid == '') {
 			_('Error #2', 41)
 			return;
 		}
-		var sub = xmpp.stanza('subscription', args);
+		var sub = new Element('subscription', args);
 		ev.cnode(sub);
 	} else {
 		_('Error #1', 41)
@@ -151,7 +151,7 @@ exports.send = function(notifs, type, no
 			}
 		}
 
-		var message = xmpp.message({to: i, from: config.jid, id: conn.getUniqueId(), type: 'headline'});
+		var message = new Element('message', {to: i, from: config.jid, id: conn.getUniqueId(), type: 'headline'});
 		message.cnode(ev);
 		conn.send(message);
 	}
@@ -162,7 +162,7 @@ exports.sendDigest = function(jid, nodeI
 	if (sub.digestTimeout)
 		sub.digestTimeout = false;
 
-	var message = xmpp.message({to: jid, from: config.jid, id: conn.getUniqueId(), type: 'headline'});
+	var message = new Element('message', {to: jid, from: config.jid, id: conn.getUniqueId(), type: 'headline'});
 	for (var i in sub.digest)
 		message.cnode(sub.digest[i]);
 	conn.send(message);
--- a/psgxs.js
+++ b/psgxs.js
@@ -19,31 +19,61 @@
  *  along with PSĜS.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-'use strict';
+//'use strict';
+
+var config = require('./configuration');
+
+var xmpp = require('node-xmpp');
+var conn = new xmpp.Component({
+	jid: config.jid,
+	password: config.password,
+	host: 'localhost',
+	port: 5347
+});
+
+if (config.debug)
+	(function() {
+		var send = conn.send;
+		conn.send = function(s) {
+			console.log('Sent: ' + s + '');
+			send.call(conn, s);
+		};
+	})();
 
-var xmpp = require('xmpp');
-var sha1 = require('sha1');
+conn.on('stanza', function (stanza) {
+	if (config.debug)
+		console.log('Recv: ' + stanza + '');
+
+	if (stanza.is('iq'))
+		onIq(stanza);
+	else if (stanza.is('message'))
+		onMessage(stanza);
+	else if (stanza.is('presence'))
+		onPresence(stanza);
+});
+
+conn._uniqueId = 42;
+conn.getUniqueId = function(suffix) {
+	return ++this._uniqueId + (suffix?(":"+suffix):"");
+};
+
+var Element = xmpp.Element;
+Element.prototype.getAttribute = function(name) {
+	return this.attrs[name];
+};
+
+
 require('./iso8601');
 var storage = require('./storage');
 var errors = require('./errors');
 var makeError = errors.makeError;
-var fdsq = require('./fdsq');
-var toBare = fdsq.toBare;
-var config = require('./configuration');
 var forms = require('./forms');
-var conn = new xmpp.Connection(config.host, config.port);
 
 var notifs = require('./notifs');
 notifs.setConnection(conn);
 
 var modules = require('./modules');
 
-var service_configuration = config.service_configuration;
-var componentJID = config.jid;
-var componentPassword = config.password;
-
-conn.log = function (_, m) { console.log(m); };
-
 function _(obj, color) {
 	var str = require('sys').inspect(obj, false, null);
 	if (color)
@@ -56,17 +86,6 @@ process.addListener('uncaughtException',
 	console.log('\x1b[41;1mUncaught exception (' + err + '), this should never happen:\x1b[0m\n' + err.stack);
 });
 
-if (typeof xmpp.StanzaBuilder.cnode != 'function' || typeof xmpp.StanzaBuilder.prototype.cnode != 'function') {
-	xmpp.StanzaBuilder.prototype.cnode = function (stanza)
-	{
-		var parent = this.last_node[this.last_node.length-1];
-		parent.tags.push(stanza);
-		parent.children.push(stanza);
-		this.last_node.push(stanza);
-		return this;
-	};
-}
-
 function onIq(stanza) {
 	var type = stanza.getAttribute('type');
 	var from = stanza.getAttribute('to');
@@ -75,45 +94,24 @@ function onIq(stanza) {
 
 	var response;
 	if (id)
-		response = xmpp.iq({to: to, from: from, type: 'result', id: id});
-	else
-		response = xmpp.iq({to: to, from: from, type: 'result'});
+		response = new Element('iq', {to: to, from: from, type: 'result', id: id});
+ 	else
+		response = new Element('iq', {to: to, from: from, type: 'result'});
 
 	var send = {};
 
-	for (var i in stanza.tags) {
-		var child1 = stanza.tags[i];
-		if (child1.name == 'pubsub') {
-			for (var j in child1.tags) {
-				var child2 = child1.tags[j];
-
-				for (var k in modules) {
-					var module = modules[k];
-
-					if (module.stanza && (module.stanza != 'iq'))
-						continue;
-
-					if (module.type && (module.type != type))
-						continue;
+	if (stanza.children.length != 1)
+		return makeError(response, errors.bad_request.n);
 
-					if (module.child2 && (module.child2 != child2.name))
-						continue;
-
-					if (module.ns && (module.ns != child2.attr.xmlns))
-						continue;
-
-					if (module.number && (module.number != j))
-						continue;
+	var payload = stanza.children[0];
+	var tag = payload.name;
+	var ns = payload.attrs.xmlns;
+	var contents = payload.children;
+ 
+	if (tag == 'pubsub') {
+		for (var j in contents) {
+			var child = contents[j];
 
-					send.response = module.func(response, stanza, child2, to, from);
-					if (send.response) {
-						response = send.response;
-						send.good = true;
-						delete send.response;
-					}
-				}
-			}
-		} else {
 			for (var k in modules) {
 				var module = modules[k];
 
@@ -123,16 +121,19 @@ function onIq(stanza) {
 				if (module.type && (module.type != type))
 					continue;
 
-				if (module.child && (module.child != child1.name))
+				if (module.child && (module.child != tag))
 					continue;
 
-				if (module.ns && (module.ns != child1.attr.xmlns))
+				if (module.ns && (module.ns != child.getNS()))
+					continue;
+
+				if (module.child2 && (module.child2 != child.name))
 					continue;
 
 				if (module.number && (module.number != k))
 					continue;
 
-				send.response = module.func(response, stanza, child1, to, from);
+				send.response = module.func(response, stanza, payload, to, from);
 				if (send.response) {
 					response = send.response;
 					send.good = true;
@@ -140,6 +141,32 @@ function onIq(stanza) {
 				}
 			}
 		}
+	} else {
+		for (var k in modules) {
+			var module = modules[k];
+
+			if (module.stanza && (module.stanza != 'iq'))
+				continue;
+
+			if (module.type && (module.type != type))
+				continue;
+
+			if (module.child && (module.child != tag))
+				continue;
+
+			if (module.ns && (module.ns != ns))
+				continue;
+
+			if (module.number && (module.number != k))
+				continue;
+
+			send.response = module.func(response, stanza, payload, to, from);
+			if (send.response) {
+				response = send.response;
+				send.good = true;
+				delete send.response;
+			}
+		}
 	}
 
 	conn.send(send.good? response: makeError(response, errors.feature_not_implemented.n));
@@ -152,14 +179,14 @@ function onMessage(stanza) {
 
 	var response;
 	if (id)
-		response = xmpp.message({to: to, from: from, id: id});
+		response = new Element('message', {to: to, from: from, id: id});
 	else
-		response = xmpp.message({to: to, from: from});
+		response = new Element('message', {to: to, from: from});
 
 	var send = false;
 
-	for (var i in stanza.tags) {
-		var child = stanza.tags[i];
+	for (var i in stanza.children) {
+		var child = stanza.children[i];
 		for (var k in modules) {
 			var module = modules[k];
 
@@ -172,7 +199,7 @@ function onMessage(stanza) {
 			if (module.child && (module.child != child.name))
 				continue;
 
-			if (module.ns && (module.ns != child.attr.xmlns))
+			if (module.ns && (module.ns != child.attrs.xmlns))
 				continue;
 
 			if (module.number && (module.number != k))
@@ -221,27 +248,18 @@ function onPresence(stanza) {
 
 	var response;
 	if (id)
-		response = xmpp.presence({to: to, from: from, id: id});
+		response = new Element('presence', {to: to, from: from, id: id});
 	else
-		response = xmpp.presence({to: to, from: from});
+		response = new Element('presence', {to: to, from: from});
 
 	makeError(response, errors.feature_not_implemented.n);
 }
 
-conn.connect(componentJID, componentPassword, function (status, condition) {
-	if (status == xmpp.Status.CONNECTED) {
-		conn.addHandler(onMessage, null, 'message', null, null,  null);
-		conn.addHandler(onIq, null, 'iq', null, null,  null);
-		conn.addHandler(onPresence, null, 'presence', null, null,  null);
+if (process.argv.length >= 3)
+	storage.load(process.argv[2]);
+else
+	storage.load();
 
-		if (process.argv.length >= 3)
-			storage.load(process.argv[2]);
-		else
-			storage.load();
-
-		var stdin = process.openStdin();
-		stdin.setEncoding('utf8');
-		stdin.addListener('data', storage.debug);
-	} else
-		conn.log(xmpp.LogLevel.DEBUG, 'New connection status: ' + status + (condition? (' ('+condition+')'): ''));
-});
+var stdin = process.openStdin();
+stdin.setEncoding('utf8');
+stdin.addListener('data', storage.debug);
--- a/storage.js
+++ b/storage.js
@@ -20,7 +20,6 @@
 'use strict';
 
 var fs = require('fs');
-var sha1hex = require('sha1').hex;
 require('./iso8601');
 var errors = require('./errors');
 var config = require('./configuration');
@@ -28,6 +27,7 @@ var service_configuration = config.servi
 var Configuration = config.Configuration;
 var fdsq = require('./fdsq');
 var toBare = fdsq.toBare;
+var uuid = require('uuid');
 
 var nodes = require('./nodes');
 var Node = nodes.Node;
@@ -208,7 +208,7 @@ storage.setItem = function(nodeID, itemI
 		return node;
 
 	if (typeof itemID != 'string')
-		itemID = fdsq.makeRandomId();
+		itemID = uuid();
 
 	var i = node.setItem(itemID, content);
 	if (content)