Merge 0.7->trunk
[prosody.git] / plugins / mod_disco.lua
1 -- Prosody IM
2 -- Copyright (C) 2008-2010 Matthew Wild
3 -- Copyright (C) 2008-2010 Waqas Hussain
4 -- 
5 -- This project is MIT/X11 licensed. Please see the
6 -- COPYING file in the source package for more information.
7 --
8
9 local componentmanager_get_children = require "core.componentmanager".get_children;
10 local is_contact_subscribed = require "core.rostermanager".is_contact_subscribed;
11 local jid_split = require "util.jid".split;
12 local jid_bare = require "util.jid".bare;
13 local st = require "util.stanza"
14
15 local disco_items = module:get_option("disco_items") or {};
16 do -- validate disco_items
17         for _, item in ipairs(disco_items) do
18                 local err;
19                 if type(item) ~= "table" then
20                         err = "item is not a table";
21                 elseif type(item[1]) ~= "string" then
22                         err = "item jid is not a string";
23                 elseif item[2] and type(item[2]) ~= "string" then
24                         err = "item name is not a string";
25                 end
26                 if err then
27                         module:log("error", "option disco_items is malformed: %s", err);
28                         disco_items = {}; -- TODO clean up data instead of removing it?
29                         break;
30                 end
31         end
32 end
33
34 module:add_identity("server", "im", "Prosody"); -- FIXME should be in the non-existing mod_router
35 module:add_feature("http://jabber.org/protocol/disco#info");
36 module:add_feature("http://jabber.org/protocol/disco#items");
37
38 module:hook("iq/host/http://jabber.org/protocol/disco#info:query", function(event)
39         local origin, stanza = event.origin, event.stanza;
40         if stanza.attr.type ~= "get" then return; end
41         local node = stanza.tags[1].attr.node;
42         if node and node ~= "" then return; end -- TODO fire event?
43
44         local reply = st.reply(stanza):query("http://jabber.org/protocol/disco#info");
45         local done = {};
46         for _,identity in ipairs(module:get_host_items("identity")) do
47                 local identity_s = identity.category.."\0"..identity.type;
48                 if not done[identity_s] then
49                         reply:tag("identity", identity):up();
50                         done[identity_s] = true;
51                 end
52         end
53         for _,feature in ipairs(module:get_host_items("feature")) do
54                 if not done[feature] then
55                         reply:tag("feature", {var=feature}):up();
56                         done[feature] = true;
57                 end
58         end
59         origin.send(reply);
60         return true;
61 end);
62 module:hook("iq/host/http://jabber.org/protocol/disco#items:query", function(event)
63         local origin, stanza = event.origin, event.stanza;
64         if stanza.attr.type ~= "get" then return; end
65         local node = stanza.tags[1].attr.node;
66         if node and node ~= "" then return; end -- TODO fire event?
67
68         local reply = st.reply(stanza):query("http://jabber.org/protocol/disco#items");
69         for jid in pairs(componentmanager_get_children(module.host)) do
70                 reply:tag("item", {jid = jid}):up();
71         end
72         for _, item in ipairs(disco_items) do
73                 reply:tag("item", {jid=item[1], name=item[2]}):up();
74         end
75         origin.send(reply);
76         return true;
77 end);
78 module:hook("iq/bare/http://jabber.org/protocol/disco#info:query", function(event)
79         local origin, stanza = event.origin, event.stanza;
80         if stanza.attr.type ~= "get" then return; end
81         local node = stanza.tags[1].attr.node;
82         if node and node ~= "" then return; end -- TODO fire event?
83         local username = jid_split(stanza.attr.to) or origin.username;
84         if not stanza.attr.to or is_contact_subscribed(username, module.host, jid_bare(stanza.attr.from)) then
85                 local reply = st.reply(stanza):tag('query', {xmlns='http://jabber.org/protocol/disco#info'});
86                 if not reply.attr.from then reply.attr.from = origin.username.."@"..origin.host; end -- COMPAT To satisfy Psi when querying own account
87                 module:fire_event("account-disco-info", { session = origin, stanza = reply });
88                 origin.send(reply);
89                 return true;
90         end
91 end);
92 module:hook("iq/bare/http://jabber.org/protocol/disco#items:query", function(event)
93         local origin, stanza = event.origin, event.stanza;
94         if stanza.attr.type ~= "get" then return; end
95         local node = stanza.tags[1].attr.node;
96         if node and node ~= "" then return; end -- TODO fire event?
97         local username = jid_split(stanza.attr.to) or origin.username;
98         if not stanza.attr.to or is_contact_subscribed(username, module.host, jid_bare(stanza.attr.from)) then
99                 local reply = st.reply(stanza):tag('query', {xmlns='http://jabber.org/protocol/disco#items'});
100                 if not reply.attr.from then reply.attr.from = origin.username.."@"..origin.host; end -- COMPAT To satisfy Psi when querying own account
101                 module:fire_event("account-disco-items", { session = origin, stanza = reply });
102                 origin.send(reply);
103                 return true;
104         end
105 end);