Mercurial > psgxs
diff psgxs.js @ 23:5fc4ee90c1bc
A lot of refactorization. First attempt to modularize the server.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Sun, 31 Oct 2010 23:58:07 +0100 |
parents | 0f42c9c8085a |
children | c774f2ffb271 |
line wrap: on
line diff
--- a/psgxs.js +++ b/psgxs.js @@ -24,12 +24,18 @@ 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; @@ -51,9 +57,10 @@ process.addListener('uncaughtException', if (typeof xmpp.StanzaBuilder.cnode != 'function' || typeof xmpp.StanzaBuilder.prototype.cnode != 'function') { xmpp.StanzaBuilder.prototype.cnode = function (stanza) { - var parent = this; + 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; }; } @@ -70,898 +77,40 @@ function onIq(stanza) { else response = xmpp.iq({to: to, from: from, type: 'result'}); - if (type == 'get') { - - // XEP-0092: Software Version - if (stanza.getChild('query', 'jabber:iq:version')) { - var query = xmpp.stanza('query', {xmlns: 'jabber:iq:version'}) - .s('name').t('PSĜS') - .s('version').t(config.version) - .s('os').t(config.os); - response.cnode(query); - - // SECTION 5.1 - } else if (stanza.getChild('query', 'http://jabber.org/protocol/disco#info')) { - var query = stanza.getChild('query', 'http://jabber.org/protocol/disco#info'); - var nodeID = query.getAttribute('node'); - - // SECTION 5.3 - if (nodeID && nodeID != '') { - if (!storage.existsNode(nodeID)) - return makeError(response, errors.node_does_not_exist.n); + var sent = false; - var conf = storage.getConfiguration(nodeID); - if (typeof conf == 'number') - return makeError(response, conf); - - var type = 'leaf' - if (conf['pubsub#node_type']) - type = conf['pubsub#node_type']; - - var q = xmpp.stanza('query', {xmlns: 'http://jabber.org/protocol/disco#info', node: nodeID}) - q.s('identity', {category: 'pubsub', type: type}); - q.s('feature', {'var': 'http://jabber.org/protocol/pubsub'}); - - // SECTION 5.4 - if (config.enabled('meta-data')) { - var x = forms.build('result', 'node_metadata', storage.getMetadata(nodeID), true); - if (x) - q.cnode(x); - } - response.cnode(q); + for (var i in modules) { + var module = modules[i]; + if (module.type && (type != module.type)) + continue; - // SECTION 5.1 - } else { - var q = xmpp.stanza('query', {xmlns: 'http://jabber.org/protocol/disco#info'}) - .s('identity', {category: 'pubsub', type: 'service', name: 'PubSub JavaScript Server'}) - .s('feature', {'var': 'http://jabber.org/protocol/disco#info'}) - .s('feature', {'var': 'http://jabber.org/protocol/disco#items'}) - .s('feature', {'var': 'http://jabber.org/protocol/pubsub'}) - .s('feature', {'var': 'jabber:iq:version'}) - .s('feature', {'var': 'http://jabber.org/protocol/commands'}); + for (var j in stanza.tags) { + var child = stanza.tags[j]; + if (module.child && (child.name != module.child)) + continue; - for (var i in config.activated) - if (typeof i == 'string') - q.s('feature', {'var': 'http://jabber.org/protocol/pubsub#' + config.activated[i]}); - - response.cnode(q); - } + if (module.ns && (child.attr.xmlns != module.ns)) + continue; - // SECTION 5.2 - } else if (stanza.getChild('query', 'http://jabber.org/protocol/disco#items')) { - var query = stanza.getChild('query', 'http://jabber.org/protocol/disco#items'); - var q; - var children; - var nodeID = query.getAttribute('node'); - if (nodeID && nodeID != '') { - if (nodeID == 'http://jabber.org/protocol/commands') { - // XEP-0050: Ad-Hoc Commands - - q = xmpp.stanza('query', {xmlns: 'http://jabber.org/protocol/disco#items', node: nodeID}) - .s('item', {jid: componentJID, node: 'ping', name: 'Ping'}) - .s('item', {jid: componentJID, node: 'reload', name: 'Reload'}); + if (module.child == 'pubsub') { + var child2 = child.getChild(module.pschild, child.attr.xmlns); + if (child2) + child = child2; - response.cnode(q); - return conn.send(response); - } else { - if (!storage.existsNode(nodeID)) - return makeError(response, errors.node_does_not_exist.n); - - q = xmpp.stanza('query', {xmlns: 'http://jabber.org/protocol/disco#items', node: nodeID}); - - children = storage.getChildren(nodeID); - if (typeof children == 'number') - return makeError(response, children); - } - } else { - q = xmpp.stanza('query', {xmlns: 'http://jabber.org/protocol/disco#items'}); - - children = storage.getChildren(); - if (typeof children == 'number') - return makeError(response, children); + if (module.pschild && (!child || module.pschild != child2.name)) + continue; } - for (var i in children) { - var attr = {jid: componentJID}; - if (children[i] == 'node') { - if (config.enabled('meta-data')) { - var metadata = storage.getMetadata(i); - if (metadata['pubsub#title']) - attr.name = metadata['pubsub#title']; - } - attr.node = i; - - // SECTION 5.5 - } else - attr.name = i; - - q.s('item', attr); + var toSend = module.func(response, stanza, child, to); + if (toSend) { + conn.send(toSend); + sent = true; } - response.cnode(q); - } else if (stanza.getChild('pubsub', 'http://jabber.org/protocol/pubsub')) { - var pubsub = stanza.getChild('pubsub', 'http://jabber.org/protocol/pubsub'); - - // SECTION 5.6 - if (pubsub.getChild('subscriptions')) { - if (!config.enabled('retrieve-subscriptions')) - return makeError(response, errors.subscriptions_retrieval_not_supported.n); - - var subscriptions = pubsub.getChild('subscriptions'); - var subs; - - var nodeID = subscriptions.getAttribute('node'); - if (nodeID && nodeID != '') { - if (!storage.existsNode(nodeID)) - return makeError(response, errors.node_does_not_exist.n); - subs = storage.getSubscription(toBareJID(to), node); - } else - subs = storage.getSubscription(toBareJID(to)); - - var s = xmpp.stanza('subscriptions'); - for (i in subs) - s.s('subscription', {node: i, jid: to, subscription: subs[i].type, subid: subs[i].subid}); - - var p = xmpp.stanza('pubsub', {xmlns: 'http://jabber.org/protocol/pubsub'}); - p.cnode(s); - response.cnode(p); - - // SECTION 5.7 - } else if (pubsub.getChild('affiliations')) { - if (!config.enabled('retrieve-affiliations')) - return makeError(response, errors.affiliations_retrieval_not_supported.n); - - var affiliations = pubsub.getChild('affiliations'); - var nodeID = affiliations.getAttribute('node'); - var affils; - if (nodeID && nodeID != '') { - if (!storage.existsNode(nodeID)) - return makeError(response, errors.node_does_not_exist.n); - affils = {}; - affils[nodeID] = storage.getAffiliation(toBareJID(to), nodeID); - } else - affils = storage.getAffiliationsFromJID(toBareJID(to)); - - var s = xmpp.stanza('affiliations'); - for (i in affils) - s.s('affiliation', {node: i, affiliation: affils[i]}); - - var p = xmpp.stanza('pubsub', {xmlns: 'http://jabber.org/protocol/pubsub'}); - p.cnode(s); - response.cnode(p); - - // SECTION 6.3.2 - } else if (pubsub.getChild('options')) { - if (!config.enabled('subscription-options')) - return makeError(response, errors.sub.configure.subscription_options_not_supported.n); - - var options = pubsub.getChild('options'); - - var nodeID = options.getAttribute('node'); - if (!nodeID || nodeID == '') - return makeError(response, errors.nodeid_required.n); - if (!storage.existsNode(nodeID)) - return makeError(response, errors.node_does_not_exist.n); - - var jid = options.getAttribute('jid'); - if (!jid) - return makeError(response, errors.sub.configure.subscriber_jid_required.n); - if (toBareJID(jid) != toBareJID(to)) - return makeError(response, errors.sub.configure.insufficient_privileges.n); - - var subs = storage.getSubscription(jid, nodeID); - if (!subs.subid) // FIXME: better test for empty object. - return makeError(response, errors.sub.configure.no_such_subscriber.n); - - var s = xmpp.stanza('options', {node: nodeID, jid: jid}); - var p = xmpp.stanza('pubsub', {xmlns: 'http://jabber.org/protocol/pubsub'}); - var form = forms.build('form', 'subscribe_options', subs.options, true); - s.cnode(form); - p.cnode(s); - response.cnode(p); - - // SECTION 6.4 - } else if (pubsub.getChild('default')) { - if (!config.enabled('retrieve-default-sub')) - return makeError(response, errors.sub.default_options.default_subscription_configuration_retrieval_not_supported.n); - - var def = pubsub.getChild('default'); - - var nodeID = def.getAttribute('node'); - if (nodeID && !storage.existsNode(nodeID)) - return makeError(response, errors.node_does_not_exist.n); - - var p = xmpp.stanza('pubsub', {xmlns: 'http://jabber.org/protocol/pubsub'}); - var s; - if (nodeID) - s = xmpp.stanza('default', {node: nodeID}); - else - s = xmpp.stanza('default'); - - var form = forms.build('form', 'subscribe_options', 'default', false); - s.cnode(form); - p.cnode(s); - response.cnode(p); - - // SECTION 6.5 - } else if (pubsub.getChild('items')) { - if (!config.enabled('retrieve-items')) - return makeError(response, errors.sub.default_options.node_configuration_not_supported.n); - - var items = pubsub.getChild('items'); - - var nodeID = items.getAttribute('node'); - if (!nodeID || nodeID == '') - return makeError(response, errors.nodeid_required.n); - if (!storage.existsNode(nodeID)) - return makeError(response, errors.node_does_not_exist.n); - - var configuration = storage.getConfiguration(nodeID); - if (configuration['pubsub#access_model'] == 'whitelist') { - var affil = storage.getAffiliation(toBareJID(to), nodeID); - if (affil != 'super-owner' && affil != 'owner' && affil != 'publisher' && affil != 'member') - return makeError(response, errors.pub.publish.insufficient_privileges.n); - } - - var item = []; - for (var i=0; i<items.children.length; i++) { - var j = items.children[i]; - if (j.name == 'item' && j.attr['id'] && j.attr['id'] != '') - item.push(j.attr['id']); - } - - var max_items = items.getAttribute('max_items'); - if (max_items) - max_items = Number (max_items); - - if (item.length) { - var s = xmpp.stanza('items', {node: nodeID}); - - for (var i=0; i<item.length; i++) { - var j = storage.getItem(nodeID, item[i]); - if (typeof j == 'number') - return makeError(response, j); - if (j == errors.success) - continue; - - var k = xmpp.stanza('item', {id: item[i]}) - k.cnode(j); - s.cnode(k); - } - } else { - var s = xmpp.stanza('items', {node: nodeID}); - - var j; - if (max_items) - j = storage.getLastItem(nodeID, max_items); - else - j = storage.getItems(nodeID); - if (typeof j == 'number') - return makeError(response, j); - - var k = 0; - for (var i in j) { - var contentItem = xmpp.stanza('item', {id: i}).t(j[i].content); - s.cnode(contentItem); - } - } - var p = xmpp.stanza('pubsub', {xmlns: 'http://jabber.org/protocol/pubsub'}); - p.cnode(s); - response.cnode(p); - } else - return makeError(response, errors.feature_not_implemented.n); - } else if (stanza.getChild('pubsub', 'http://jabber.org/protocol/pubsub#owner')) { - var pubsub = stanza.getChild('pubsub', 'http://jabber.org/protocol/pubsub#owner'); - - // SECTION 8.2 - if (pubsub.getChild('configure')) { - if (!config.enabled('config-node')) - return makeError(response, errors.owner.configure.node_configuration_not_supported.n); - - var nodeID = pubsub.getChild('configure').getAttribute('node'); - if (!nodeID || nodeID == '') - return makeError(response, errors.nodeid_required.n); - if (!storage.existsNode(nodeID)) - return makeError(response, errors.node_does_not_exist.n); - - var affil = storage.getAffiliation(toBareJID(to), nodeID); - if (affil != 'super-owner' && affil != 'owner' && affil != 'publish-only') - return makeError(response, errors.pub.publish.insufficient_privileges.n); - - var p = xmpp.stanza('pubsub', {xmlns: 'http://jabber.org/protocol/pubsub#owner'}); - var s = xmpp.stanza('configure', {node: nodeID}); - var form = forms.build('form', 'node_config', 'default', true); - s.cnode(form); - p.cnode(s); - response.cnode(p); - - // SECTION 8.3 - } else if (pubsub.getChild('default')) { - if (!config.enabled('config-node')) - return makeError(response, errors.owner.default_options.node_configuration_not_supported.n); - - var p = xmpp.stanza('pubsub', {xmlns: 'http://jabber.org/protocol/pubsub#owner'}); - var s = xmpp.stanza('default'); - var form = forms.build('node_config', service_configuration.node_config, null, true); - s.cnode(form); - p.cnode(s); - response.cnode(p); - - // SECTION 8.8 - } else if (pubsub.getChild('subscriptions')) { - if (!config.enabled('manage-subscriptions')) - return makeError(response, errors.owner.manage_subscriptions.not_supported.n); - - var subscriptions = pubsub.getChild('subscriptions'); - - var nodeID = subscriptions.getAttribute('node'); - if (!nodeID || nodeID == '') - return makeError(response, errors.nodeid_required.n); - if (!storage.existsNode(nodeID)) - return makeError(response, errors.node_does_not_exist.n); - - var affil = storage.getAffiliation(toBareJID(to), nodeID); - if (affil != 'super-owner' && affil != 'owner') - return makeError(response, errors.forbidden.n); - - var p = xmpp.stanza('pubsub', {xmlns: 'http://jabber.org/protocol/pubsub#owner'}); - var s = xmpp.stanza('subscriptions', {node: nodeID}); - - var subs = storage.getSubscriptionsFromNodeID(nodeID) - for (var jid in subs) - s.s('subscription', {jid: jid, subscription: subs[jid].type, subid: subs[jid].subid}) - - p.cnode(s); - response.cnode(p); - - // SECTION 8.9 - } else if (pubsub.getChild('affiliations')) { - if (!config.enabled('modify-affiliations')) - return makeError(response, errors.owner.manage_affiliations.not_supported.n); - - var affiliations = pubsub.getChild('affiliations'); - - var nodeID = affiliations.getAttribute('node'); - if (!nodeID || nodeID == '') - return makeError(response, errors.nodeid_required.n); - if (!storage.existsNode(nodeID)) - return makeError(response, errors.node_does_not_exist.n); - - var affils = storage.getAffiliationsFromNodeID(nodeID); - var affil = affils[toBareJID(to)]; - if (affil != 'super-owner' && affil != 'owner') - return makeError(response, errors.owner.manage_affiliations.retrieve_list.entity_is_not_an_owner.n); - - var p = xmpp.stanza('pubsub', {xmlns: 'http://jabber.org/protocol/pubsub#owner'}); - var s = xmpp.stanza('affiliations', {node: nodeID}); - - for (var jid in affils) - s.s('affiliation', {jid: jid, affiliation: affils[jid]}) - - p.cnode(s); - response.cnode(p); - } else - return makeError(response, errors.feature_not_implemented.n); - } else - return makeError(response, errors.feature_not_implemented.n); - } else if (type == 'set') { - if (stanza.getChild('command', 'http://jabber.org/protocol/commands')) { - // XEP-0050: Ad-Hoc Commands - var command = stanza.getChild('command', 'http://jabber.org/protocol/commands'); - - var action = command.getAttribute('action'); - if (action != 'execute') - return makeError(response, errors.bad_request.n); - - var node = command.getAttribute('node'); - if (node == 'ping') { - var cmd = xmpp.stanza('command', {xmlns: 'http://jabber.org/protocol/commands', -// sessionid: 'list:20020923T213616Z-700', - node: node, - 'status': 'completed'}) - .c('note', {type: 'info'}).t('pong'); - response.cnode(cmd); - } else if (node == 'reload') { - storage.load(); - response.c('command', {xmlns: 'http://jabber.org/protocol/commands', - node: node, - 'status': 'completed'}) - .c('note', {type: 'info'}).t('The server has correctly reloaded.'); - } else - return makeError(response, errors.bad_request.n); - } else if (stanza.getChild('pubsub', 'http://jabber.org/protocol/pubsub')) { - var pubsub = stanza.getChild('pubsub', 'http://jabber.org/protocol/pubsub'); - - // SECTION 6.1 - if (pubsub.getChild('subscribe')) { - if (!config.enabled('subscribe')) - return makeError(response, errors.sub.subscribe.not_supported.n); - - var subscribe = pubsub.getChild('subscribe'); - - var nodeID = subscribe.getAttribute('node'); - if (!nodeID || nodeID == '') - return makeError(response, errors.nodeid_required.n); - if (!storage.existsNode(nodeID)) - return makeError(response, errors.node_does_not_exist.n); - - var configuration = storage.getConfiguration(nodeID); - if (!configuration['pubsub#subscribe']) - return makeError(response, errors.sub.subscribe.not_supported.n); - - var affil = storage.getAffiliation(toBareJID(to), nodeID); - if (affil == 'publish-only' || affil == 'outcast') - return makeError(response, errors.pub.publish.insufficient_privileges.n); - - var jid = subscribe.getAttribute('jid'); - if (!jid || toBareJID(jid) != toBareJID(to)) - return makeError(response, errors.sub.subscribe.jids_do_not_match.n); - - // SECTION 6.3.7 - var options = pubsub.getChild('options'); - if (options && config.enabled('subscription-options')) { - if (options.getAttribute('node') || options.getAttribute('jid')) - return makeError(response, errors.bad_request.n); - - var x = options.getChild('x', 'jabber:x:data'); - if (!x || x.getAttribute('type') != 'submit') - return makeError(response, errors.bad_request.n); - - var form = forms.parse(x, true); - if (typeof form == 'number') - return makeError(response, form); - - var conf = form; - } - - var subID; - if (configuration['pubsub#access_model'] == 'open') { - subID = storage.subscribe(nodeID, jid, 'subscribe', conf); - if (typeof subID == 'number') - return makeError(response, subID); - } else if (configuration['pubsub#access_model'] == 'authorize') { - subID = storage.subscribe(nodeID, jid, 'pending', conf); - if (typeof subID == 'number') - return makeError(response, subID); - - var affiliates = storage.getAffiliationsFromNodeID(nodeID); - var form = forms.build('form', 'subscribe_authorization', {allow: false, node: nodeID, subscriber_jid: jid}, true); //168 - - for (var i in affiliates) { - if (affiliates[i] == 'super-owner' || affiliates[i] == 'owner') { - var message = xmpp.message({to: i}).cnode(form); - conn.send(message); - } - } - } else if (configuration['pubsub#access_model'] == 'whitelist') { - var affil = storage.getAffiliation(jid, nodeID); - if (affil != 'super-owner' && affil != 'owner' && affil != 'publisher' && affil != 'member') - return makeError(response, errors.sub.subscribe.not_on_whitelist.n); - - subID = storage.subscribe(nodeID, jid, conf); - if (typeof subID == 'number') - return makeError(response, subID); - } - - response.c('pubsub', {xmlns: 'http://jabber.org/protocol/pubsub'}) - .c('subscription', {node: nodeID, jid: jid, subid: subID.subid, subscription: subID.type}); - - if (conf) - response.cnode(options); - - if (config.enabled('last-published')) { - var last = storage.getLastItem(nodeID); - if (typeof last != 'number') { - var item = storage.getItem(nodeID, last); - if (typeof item != 'number') { - var attr = {}; - attr[last] = {content: item}; - sendNotifs(jid, 'items', nodeID, attr); - } - } - } + } + } - // SECTION 6.2 - } else if (pubsub.getChild('unsubscribe')) { - if (!config.enabled('subscribe')) - return makeError(response, errors.sub.subscribe.not_supported.n); - - var unsubscribe = pubsub.getChild('unsubscribe'); - var nodeID = unsubscribe.getAttribute('node'); - if (!nodeID || nodeID == '') - return makeError(response, errors.nodeid_required.n); - if (!storage.existsNode(nodeID)) - return makeError(response, errors.node_does_not_exist.n); - - var jid = unsubscribe.getAttribute('jid'); - if (!jid || toBareJID(jid) != toBareJID(to)) - return makeError(response, errors.sub.unsubscribe.insufficient_privileges.n); - - var subID = storage.subscribe(nodeID, jid, 'none'); - if (typeof subID == 'number') - return makeError(response, subID); - - // SECTIONS 6.3.5 - } else if (pubsub.getChild('options')) { - if (!config.enabled('subscription-options')) - return makeError(response, errors.sub.subscribe.not_supported.n); - - var options = pubsub.getChild('options'); - - var nodeID = unsubscribe.getAttribute('node'); - if (!nodeID || nodeID == '') - return makeError(response, errors.nodeid_required.n); - if (!storage.existsNode(nodeID)) - return makeError(response, errors.node_does_not_exist.n); - - var jid = unsubscribe.getAttribute('jid'); - if (!jid || toBareJID(jid) != toBareJID(to)) - return makeError(response, errors.sub.unsubscribe.insufficient_privileges.n); - - var x = options.getChild('x', 'jabber:x:data'); - if (!x || x.getAttribute(type) != 'submit') - return makeError(response, errors.bad_request); - - var form = forms.parse(x, true); - if (typeof form == 'number') - return makeError(response, form); - - var set = storage.configureSubscription(nodeID, jid, form); - if (typeof form == 'number') - return makeError(response, form); - - // SECTION 7.1 - } else if (pubsub.getChild('publish')) { - if (!config.enabled('publish')) - return makeError(response, errors.pub.publish.item_publication_not_supported.n); - - var publish = pubsub.getChild('publish'); - var nodeID = publish.getAttribute('node'); - if (!nodeID || nodeID == '') - return makeError(response, errors.nodeid_required.n); - - var autocreate = false; - if (!storage.existsNode(nodeID)) { - if (config.enabled('auto-create')) - autocreate = true; - else - return makeError(response, errors.node_does_not_exist.n); - } - - var affil = storage.getAffiliation(toBareJID(to), nodeID); - if (typeof affil == 'number' && affil != errors.node_does_not_exist.n) - return makeError(response, affil); - if (!autocreate && affil != 'super-owner' && affil != 'owner' && affil != 'publisher' && affil != 'publish-only') - return makeError(response, errors.forbidden.n); - - var item = publish.getChild('item'); - var itemID = item.getAttribute('id'); - if (!config.enabled('item-ids') && itemID) - return makeError(response, errors.itemid_required.n); - itemID = itemID? itemID: utils.makeRandomId(); - - if (item.tags.length != 1) - return makeError(response, errors.pub.publish.bad_payload.n); - - var conf = storage.getConfiguration(nodeID); - var publishOptions = pubsub.getChild('publish-options'); - if (publishOptions && config.enabled('publish-options')) { - var x = publishOptions.getChild('x', 'jabber:x:data'); - if (!x || x.getAttribute('type') != 'submit') - return makeError(response, errors.bad_request.n); - - var form = forms.parse(x, true); - if (form.access_model != conf['pubsub#access_model'] && !autocreate) - return makeError(response, errors.pub.configuration.precondition.n); - } - - if (!config.enabled('persistent-items')) { - var notifs = storage.purgeNode(nodeID); - if (typeof notifs == 'number') - return makeError(response, r); - } - - if (autocreate) { - if (!form) - form = {}; - form['pubsub#creator'] = toBareJID(to); - - var r = storage.createNode(nodeID, form); - if (typeof r == 'number') - return makeError(response, r); - } - - var content = item.getChild(); - - subscribers = storage.setItem(nodeID, itemID, content); - if (typeof subscribers == 'number') - return makeError(response, subscribers); - - var attrs = {}; - if (content) - attrs[itemID] = {content: content}; - else - attrs[itemID] = {}; - sendNotifs(subscribers, 'items', nodeID, attrs); - - response.c('pubsub', {xmlns: 'http://jabber.org/protocol/pubsub'}) - .c('publish', {node: nodeID}) - .c('item', {id: itemID}); - - // SECTION 7.2 - } else if (pubsub.getChild('retract')) { - if (!config.enabled('retract-items')) - return makeError(response, errors.pub.retract.item_deletion_not_supported.n); - - var retract = pubsub.getChild('retract'); - - var nodeID = retract.getAttribute('node'); - if (!nodeID || nodeID == '') - return makeError(response, errors.nodeid_required.n); - if (!storage.existsNode(nodeID)) - return makeError(response, errors.node_does_not_exist.n); - - var item = retract.getChild('item'); - if (!item) - return makeError(response, errors.pub.retract.item_or_itemid_required.n); - - var itemID = item.getAttribute('id') - if (!itemID || itemID == '') - return makeError(response, errors.pub.retract.item_or_itemid_required.n); - - var affil = storage.getAffiliation(toBareJID(to), nodeID); - if (affil != 'super-owner' && affil != 'owner' && affil != 'publish-only') - return makeError(response, errors.forbidden.n); - - var subscribers = storage.deleteItem(nodeID, itemID); - if (typeof subscribers == 'number') - return makeError(response, subscribers); - - var attrs = {}; - attrs[itemID] = {}; - sendNotifs(subscribers, 'items', nodeID, attrs, 'retract') - - // SECTION 8.1 - } else if (pubsub.getChild('create')) { - if (!config.enabled('create-nodes')) - return makeError(response, errors.owner.create.node_creation_not_supported.n); - - var instant = false; - - var nodeID = pubsub.getChild('create').getAttribute('node'); - if (!nodeID || nodeID == '') { - if (!config.enabled('instant-nodes')) - return makeError(response, errors.owner.create.instant_nodes_not_supported.n); - nodeID = utils.makeRandomId(); - instant = true; - } - if (storage.existsNode(nodeID)) - return makeError(response, errors.owner.create.nodeid_already_exists.n); - - var bare = toBareJID(to); - var right = false; - - // Check for super-owner - for (var i in config.owner) - if (config.owner[i] == bare) - right = true; - - // Check for authorized user - for (var i in config.allowCreateNode) - if (config.allowCreateNode[i].exec(bare)) - right = true; - - if (!right) - return makeError(response, errors.forbidden.n); - - var configure = pubsub.getChild('configure'); - if (configure && config.enabled('create-and-configure')) { - if (!config.enabled('config-node')) - return makeError(response, errors.owner.configure.node_configuration_not_supported.n); - - if (configure.getAttribute('node')) - return makeError(response, errors.bad_request.n); - - var x = configure.getChild('x', 'jabber:x:data'); - if (!x || x.getAttribute('type') != 'submit') - return makeError(response, errors.bad_request.n); - - var form = forms.parse(x, true); - if (typeof form == 'number') - return makeError(response, form); - - var conf = form; - } - - if (!conf) - conf = {}; - conf['pubsub#creator'] = bare; - - var r = storage.createNode(nodeID, conf); - if (typeof r == 'number') - return makeError(response, r); - - if (instant) - response.c('pubsub', {xmlns: 'http://jabber.org/protocol/pubsub'}) - .c('create', {node: nodeID}); - } else - return makeError(response, errors.feature_not_implemented.n); - } else if (stanza.getChild('pubsub', 'http://jabber.org/protocol/pubsub#owner')) { - var pubsub = stanza.getChild('pubsub', 'http://jabber.org/protocol/pubsub#owner'); - - // SECTION 8.2.4 - if (pubsub.getChild('configure')) { - if (!config.enabled('config-node')) - return makeError(response, errors.owner.configure.node_configuration_not_supported.n); - - var configure = pubsub.getChild('configure'); - - var nodeID = configure.getAttribute('node'); - if (!nodeID) - return makeError(response, errors.nodeid_required.n); - if (!storage.existsNode(nodeID)) - return makeError(response, errors.node_does_not_exist.n); - - var affil = storage.getAffiliation(toBareJID(to), nodeID); - if (affil != 'super-owner' && affil != 'owner' && affil != 'publish-only') - return makeError(response, errors.forbidden.n); - - var x = configure.getChild('x', 'jabber:x:data'); - if (!x) - return makeError(response, errors.bad_request.n); - - var type = x.getAttribute('type'); - if (type == 'cancel') { - conn.send(response); - return; - } - if (type != 'submit') - return makeError(response, errors.bad_request.n); - - var form = forms.parse(x, true); - if (typeof form == 'number') - return makeError(response, form); - - var conf = form; - - var set = storage.configure(nodeID, conf); - if (typeof set == 'number') - return makeError(response, set); - - // SECTION 8.4 - } else if (pubsub.getChild('delete')) { - if (!config.enabled('delete-nodes')) - return makeError(response, errors.feature_not_implemented.n); //XXX - - var del = pubsub.getChild('delete'); - - var nodeID = del.getAttribute('node'); - if (!nodeID) - return makeError(response, errors.nodeid_required.n); - if (!storage.existsNode(nodeID)) - return makeError(response, errors.node_does_not_exist.n); - - var affil = storage.getAffiliation(toBareJID(to), nodeID); - if (affil != 'super-owner' && affil != 'owner') - return makeError(response, errors.forbidden.n); - - var notifs = storage.deleteNode(nodeID); - if (typeof notifs == 'number') - return makeError(response, r); - - sendNotifs(notifs, 'delete', nodeID); - - // SECTION 8.5 - } else if (pubsub.getChild('purge')) { - if (!config.enabled('purge-nodes')) - return makeError(response, errors.owner.purge.node_purging_not_supported.n); //XXX - - var purge = pubsub.getChild('purge'); - - var nodeID = purge.getAttribute('node'); - if (!nodeID) - return makeError(response, errors.nodeid_required.n); - if (!storage.existsNode(nodeID)) - return makeError(response, errors.node_does_not_exist.n); - - var affil = storage.getAffiliation(toBareJID(to), nodeID); - if (affil != 'super-owner' && affil != 'owner') - return makeError(response, errors.forbidden.n); - - if (!config.enabled('persistent-items')) //FIXME: autre condition, supporté par le node - return makeError(response, errors.owner.purge.node_does_not_persist_items.n); - - var notifs = storage.purgeNode(nodeID); - if (typeof notifs == 'number') - return makeError(response, r); - - sendNotifs(notifs, 'purge', nodeID); - - // SECTION 8.8.2 - } else if (pubsub.getChild('subscriptions')) { - if (!config.enabled('manage-subscriptions')) - return makeError(response, errors.owner.manage_subscriptions.not_supported.n); //XXX - - var subscriptions = pubsub.getChild('subscriptions'); - - var nodeID = subscriptions.getAttribute('node'); - if (!nodeID) - return makeError(response, errors.nodeid_required.n); - if (!storage.existsNode(nodeID)) - return makeError(response, errors.node_does_not_exist.n); - - var affil = storage.getAffiliation(toBareJID(to), nodeID); - if (affil != 'super-owner' && affil != 'owner') - return makeError(response, errors.forbidden.n); - - var e = false; - var tags2 = []; - for (i in subscriptions.tags) { - var tag = subscriptions.tags[i]; - var jid = tag.getAttribute('jid'); - var sub = tag.getAttribute('subscription'); - - if (sub == 'none' || sub == 'pending' || sub == 'subscribed' || sub == 'unconfigured') { - var set = storage.subscribe(nodeID, jid, sub); - - if (typeof set == 'number') { - e = true; - tags2.push(tag); - } else { - // SECTION 8.8.4 - sendNotifs(jid, 'subscription', nodeID, {jid: jid, subscription: sub}); - } - } else { - e = true; - tags2.push(tag); - } - } - - subscriptions.tags = tags2; - - if (e) - return makeError(response, errors.owner.manage_subscriptions.modify.multiple_simultaneous_modifications.n, pubsub); - - // SECTION 8.9.2 - } else if (pubsub.getChild('affiliations')) { - if (!config.enabled('modify-affiliations')) - return makeError(response, errors.owner.manage_affiliations.not_supported.n); //XXX - - var affiliations = pubsub.getChild('affiliations'); - - var nodeID = affiliations.getAttribute('node'); - if (!nodeID) - return makeError(response, errors.nodeid_required.n); - if (!storage.existsNode(nodeID)) - return makeError(response, errors.node_does_not_exist.n); - - var affil = storage.getAffiliation(toBareJID(to), nodeID); - if (affil != 'super-owner' && affil != 'owner') - return makeError(response, errors.forbidden.n); - - var e = false; - for (i in affiliations.children) { - var jid = affiliations.children[i].getAttribute('jid'); - var affiliation = affiliations.children[i].getAttribute('affiliation'); - - var set = storage.setAffiliation(nodeID, jid, affiliation); - if (typeof set == 'number') - e = true; - else { - // SECTION 8.9.4 - sendNotifs(jid, 'affiliations', nodeID, {jid: jid, affiliation: affiliation}); - affiliations.children.splice(i, 1); - } - } - - if (e) - return makeError(response, errors.owner.manage_affiliations.modify.multiple_simultaneous_modifications.n, pubsub); - } else - return makeError(response, errors.feature_not_implemented.n); - } else - return makeError(response, errors.feature_not_implemented.n); - } else - return makeError(response, errors.feature_not_implemented.n); - conn.send(response); + if (!sent) + conn.send(makeError(response, errors.feature_not_implemented.n)); } function onMessage(stanza) { @@ -991,7 +140,7 @@ function onMessage(stanza) { var type = allow? 'subscribed': 'none'; var set = storage.subscribe(nodeID, jid, type) //if (set.subid != subID) //TODO: support the multi-subscribe feature - sendNotifs(jid, 'subscription', nodeID, {jid: jid, subscription: type}); + notifs.send(jid, 'subscription', nodeID, {jid: jid, subscription: type}); } else return makeError(response, errors.feature_not_implemented.n); } else @@ -1013,177 +162,6 @@ function onPresence(stanza) { makeError(response, errors.feature_not_implemented.n); } -function makeError(response, errorNumber, payload) { - response.attr.type = 'error'; - if (payload) - response.cnode(payload); - - var e = errors.reverse[errorNumber]; - var error = xmpp.stanza('error', {type: e.type}); - - error.s(e.error, {xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'}) - - if (e.reason) { - if (e.feature) - error.s(e.reason, {xmlns: 'http://jabber.org/protocol/pubsub#errors', feature: e.feature}); - else - error.s(e.reason, {xmlns: 'http://jabber.org/protocol/pubsub#errors'}); - } - - response.cnode(error); - conn.send(response); -} - -function sendNotifs(notifs, type, nodeID, a1, a2) { - var ev = xmpp.stanza('event', {xmlns: 'http://jabber.org/protocol/pubsub#event'}); - - if (type == 'affiliations') { - ev.attr.xmlns = 'http://jabber.org/protocol/pubsub'; - - var args = {}; - for (i in a1) { - var attr = a1[i]; - if (i == 'affiliation') - args.affiliation = attr; - else if (i == 'jid') - args.jid = attr; - } - var affiliations = xmpp.stanza('affiliations', {node: nodeID}) - .c('affiliation', args); - ev.cnode(affiliations); - } else if (type == 'collection') { - var collection = xmpp.stanza('collection', {node: nodeID}); - if (a1 == 'associate') - collection.cnode('associate', {node: nodeID}); - else - collection.cnode('disassociate', {node: nodeID}); - ev.cnode(collection); - } else if (type == 'configuration') { - if (!config.enabled('config-node')) { - _('Error #4', 41) - return; - } - - var configuration = xmpp.stanza('configuration', {node: nodeID}); - if (a1) { - var x = forms.build('node_config', service_configuration.node_config, storage.getConfiguration(nodeID)); - if (x) - configuration.cnode(x); //TODO: voir exemple 150 - } - ev.cnode(configuration); - } else if (type == 'delete') { - var del = xmpp.stanza('delete', {node: nodeID}); - if (a1) - del.c('redirect', {uri: a1}); - ev.cnode(del); - } else if (type == 'items') { - var items = xmpp.stanza(type, {node: nodeID}); - if (a2 == 'retract') - for (var i in a1) - items.s('retract', {id: i}); - else { - for (var i in a1) { - var item = a1[i]; - var args = {}; - if (i != '') - args.id = i; - if (item.node) - args.node = item.node; - if (item.publisher) - args.publisher = item.publisher; - var it = xmpp.stanza('item', args); - if (item.content) - it.cnode(item.content); - items.cnode(it); - } - } - ev.cnode(items); - } else if (type == 'purge') { - ev.c('purge', {node: nodeID}); - } else if (type == 'subscription') { - if (!config.enabled('subscription-notifications')) - return; - - var args = {node: nodeID}; - for (i in a1) { - var attr = a1[i]; - if (i == 'subscription') { - if (attr == 'none' || attr == 'pending' || attr == 'subscribed' || attr == 'unconfigured') - args[i] = attr; - else { - _('Error #3', 41) - return; - } - } else if (i == 'jid' || i == 'subid') - args[i] = attr; - else if (i == 'expiry') - args[i] = attr.toString(); - } - if (!args.jid || args.jid == '') { - _('Error #2', 41) - return; - } - var sub = xmpp.stanza('subscription', args); - ev.cnode(sub); - } else { - _('Error #1', 41) - return; - } - - var subs; - if (typeof notifs == 'string') { - subs = {}; - subs[notifs] = storage.getSubscription(notifs, nodeID); - } else - subs = notifs; - - for (var i in subs) { - var sub = subs[i]; - - if (sub.options) { - if (typeof sub.options['pubsub#deliver'] != 'undefined' && !sub.options['pubsub#deliver']) - continue; - - if (typeof sub.options['pubsub#digest'] != 'undefined' && sub.options['pubsub#digest']) { - if (!sub.digest) - sub.digest = []; - sub.digest.push(ev) - - if (sub.digestTimeout) - continue; - - var freq; - if (typeof sub.options['pubsub#digest_frequency'] == 'undefined') - freq = 0; - else - freq = parseInt(sub.options['pubsub#digest_frequency']); - - if (freq == 0) - freq = 24*60*60*1000; - - setTimeout(sendDigest, freq, notifs[i], nodeID); - sub.digestTimeout = true; - continue; - } - } - - var message = xmpp.message({to: i, from: componentJID, id: conn.getUniqueId()}); - message.cnode(ev); - conn.send(message); - } -} - -function sendDigest(jid, nodeID) { - var sub = storage.getSubscription(jid, nodeID); - if (sub.digestTimeout) - sub.digestTimeout = false; - - var message = xmpp.message({to: jid, from: componentJID, id: conn.getUniqueId()}); - for (var i in sub.digest) - message.cnode(sub.digest[i]); - conn.send(message); -} - conn.connect(componentJID, componentPassword, function (status, condition) { if (status == xmpp.Status.CONNECTED) { conn.addHandler(onMessage, null, 'message', null, null, null);