view psgxs.js @ 25:c774f2ffb271

Fix a typo.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Mon, 01 Nov 2010 00:24:50 +0100
parents 5fc4ee90c1bc
children b2faacfefb90
line wrap: on
line source

#!/usr/bin/env node

/*
 *  Copyright (C) 2010  Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
 *
 *  This file is part of PSĜS, a PubSub server written in JavaScript.
 *
 *  PSĜS is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License.
 *
 *  PSĜS is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with PSĜS.  If not, see <http://www.gnu.org/licenses/>.
 */

var xmpp = require('xmpp');
var sha1 = require('sha1');
require('./iso8601');
var storage = require('./storage');
var errors = require('./errors');
var makeError = errors.makeError;
var utils = require('./util');
var toBareJID = utils.toBareJID;
var config = require('./configuration');
var forms = require('./forms');
var conn = new xmpp.Connection();

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)
		console.log('\033['+c+';1m' + str + '\033[0m');
	else
		console.log(str);
};

process.addListener('uncaughtException', function (err) {
	console.log('\033[41;1mUncaught exception (' + err + '), this should never happen:\033[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');
	var to = stanza.getAttribute('from');
	var id = stanza.getAttribute('id');

	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'});

	var sent = false;

	for (var i in modules) {
		var module = modules[i];
		if (module.type && (type != module.type))
			continue;

		for (var j in stanza.tags) {
			var child = stanza.tags[j];
			if (module.child && (child.name != module.child))
				continue;

			if (module.ns && (child.attr.xmlns != module.ns))
				continue;

			if (module.child == 'pubsub') {
				var child2 = child.getChild(module.pschild, child.attr.xmlns);
				if (child2)
					child = child2;

				if (module.pschild && (!child || module.pschild != child.name))
					continue;
			}

			var toSend = module.func(response, stanza, child, to);
			if (toSend) {
				conn.send(toSend);
				sent = true;
			}
		}
	}

	if (!sent)
		conn.send(makeError(response, errors.feature_not_implemented.n));
}

function onMessage(stanza) {
	var from = stanza.getAttribute('to');
	var to = stanza.getAttribute('from');
	var id = stanza.getAttribute('id');

	var response;
	if (id)
		response = xmpp.message({to: to, from: from, id: id});
	else
		response = xmpp.message({to: to, from: from});

	var x = stanza.getChild('x', 'jabber:x:data');
	if (x) {
		var form = forms.parse(x);
		if (form.type == 'submit' && form.fields.FORM_TYPE.value == 'subscribe_authorization') {
			if (form.fields.subid && form.fields.subid.value)
				var subID = form.fields.subid.value;
			if (form.fields.node && form.fields.node.value)
				var nodeID = form.fields.node.value;
			if (form.fields.subscriber_jid && form.fields.subscriber_jid.value)
				var jid = form.fields.subscriber_jid.value;
			if (form.fields.allow && form.fields.allow.value)
				var allow = form.fields.allow.value;

			var type = allow? 'subscribed': 'none';
			var set = storage.subscribe(nodeID, jid, type)
			//if (set.subid != subID) //TODO: support the multi-subscribe feature
			notifs.send(jid, 'subscription', nodeID, {jid: jid, subscription: type});
		} else
			return makeError(response, errors.feature_not_implemented.n);
	} else
		return makeError(response, errors.feature_not_implemented.n);
	conn.send(response)
}

function onPresence(stanza) {
	var from = stanza.getAttribute('to');
	var to = stanza.getAttribute('from');
	var id = stanza.getAttribute('id');

	var response;
	if (id)
		response = xmpp.presence({to: to, from: from, id: id});
	else
		response = xmpp.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();

		var stdin = process.openStdin();
		stdin.setEncoding('utf8');
		stdin.addListener('data', storage.debug);
	} else
		conn.log(xmpp.LogLevel.DEBUG, 'New connection status: ' + status + (condition? (' ('+condition+')'): ''));
});