view psgxs.js @ 56:99bd1d1ac071

Migration to node-xmpp, done!
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Wed, 10 Aug 2011 15:11:22 -0700
parents 0d3f18bb1d36
children addbf6bbfaa8
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/>.
 */

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

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 forms = require('./forms');

var notifs = require('./notifs');
notifs.setConnection(conn);

var modules = require('./modules');

function _(obj, color) {
	var str = require('sys').inspect(obj, false, null);
	if (color)
		console.log('\x1b['+c+';1m' + str + '\x1b[0m');
	else
		console.log(str);
};

process.addListener('uncaughtException', function (err) {
	console.log('\x1b[41;1mUncaught exception (' + err + '), this should never happen:\x1b[0m\n' + err.stack);
});

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 = new Element('iq', {to: to, from: from, type: 'result', id: id});
 	else
		response = new Element('iq', {to: to, from: from, type: 'result'});

	var send = {};

	if (stanza.children.length != 1)
		return makeError(response, errors.bad_request.n);

	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];

			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 != child.getNS()))
					continue;

				if (module.child2 && (module.child2 != child.name))
					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;
				}
			}
		}
	} 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));
}

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

	var response;
	if (id)
		response = new Element('message', {to: to, from: from, id: id});
	else
		response = new Element('message', {to: to, from: from});

	var send = false;

	for (var i in stanza.children) {
		var child = stanza.children[i];
		for (var k in modules) {
			var module = modules[k];

			if (module.stanza !== 'message')
				continue;

			if (module.type && (module.type != type))
				continue;

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

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

			if (module.number && (module.number != k))
				continue;

			send.response = module.func(response, stanza, child, 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));
	return;

	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 = new Element('presence', {to: to, from: from, id: id});
	else
		response = new Element('presence', {to: to, from: from});

	makeError(response, errors.feature_not_implemented.n);
}

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