aboutsummaryrefslogtreecommitdiffstats
path: root/core/stanza_dispatch.lua
blob: e392b5ba9044688f8250022cdded9bd0f06d3dac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

require "util.stanza"

local st = stanza;

local t_concat = table.concat;
local format = string.format;

function init_stanza_dispatcher(session)
	local iq_handlers = {};

	local session_log = session.log;
	local log = function (type, msg) session_log(type, "stanza_dispatcher", msg); end
	local send = session.send;
	local send_to;
	do
		local _send_to = session.send_to;
		send_to = function (...) _send_to(session, ...); end
	end

	iq_handlers["jabber:iq:auth"] = 
		function (stanza)
			local username = stanza.tags[1]:child_with_name("username");
			local password = stanza.tags[1]:child_with_name("password");
			local resource = stanza.tags[1]:child_with_name("resource");
			if not (username and password and resource) then
				local reply = st.reply(stanza);
				send(reply:query("jabber:iq:auth")
					:tag("username"):up()
					:tag("password"):up()
					:tag("resource"):up());
				return true;			
			else
				username, password, resource = t_concat(username), t_concat(password), t_concat(resource);
				print(username, password, resource)
				local reply = st.reply(stanza);
				require "core.usermanager"
				if usermanager.validate_credentials(session.host, username, password) then
					-- Authentication successful!
					session.username = username;
					session.resource = resource;
					if not hosts[session.host].sessions[username] then
						hosts[session.host].sessions[username] = { sessions = {} };
					end
					hosts[session.host].sessions[username].sessions[resource] = session;
					send(st.reply(stanza));
					return true;
				else
					local reply = st.reply(stanza);
					reply.attr.type = "error";
					reply:tag("error", { code = "401", type = "auth" })
						:tag("not-authorized", { xmlns = "urn:ietf:params:xml:ns:xmpp-stanzas" });
					send(reply);
					return true;
				end
			end
			
		end
		
	iq_handlers["jabber:iq:roster"] =
		function (stanza)
			if stanza.attr.type == "get" then
				session.roster = session.roster or rostermanager.getroster(session.username, session.host);
				if session.roster == false then
					send(st.reply(stanza)
						:tag("error", { type = "wait" })
						:tag("internal-server-error", { xmlns = "urn:ietf:params:xml:ns:xmpp-stanzas"}));
					return true;
				else session.roster = session.roster or {};
				end
				local roster = st.reply(stanza)
							:query("jabber:iq:roster");
				for jid in pairs(session.roster) do
					roster:tag("item", { jid = jid, subscription = "none" }):up();
				end
				send(roster);
				return true;
			end
		end


	return	function (stanza)
			log("info", "--> "..tostring(stanza));
			if (not stanza.attr.to) or (hosts[stanza.attr.to] and hosts[stanza.attr.to].type == "local") then
				if stanza.name == "iq" then
					if not stanza.tags[1] then log("warn", "<iq> without child is invalid"); return; end
					if not stanza.attr.id then log("warn", "<iq> without id attribute is invalid"); end
					local xmlns = (stanza.tags[1].attr and stanza.tags[1].attr.xmlns) or nil;
					if not xmlns then log("warn", "Child of <iq> has no xmlns - invalid"); return; end
					if (((not stanza.attr.to) or stanza.attr.to == session.host or stanza.attr.to:match("@[^/]+$")) and (stanza.attr.type == "get" or stanza.attr.type == "set")) then -- Stanza sent to us
						if iq_handlers[xmlns] then
							if iq_handlers[xmlns](stanza) then return; end;
						end
						log("warn", "Unhandled namespace: "..xmlns);
						send(format("<iq type='error' id='%s'><error type='cancel'><service-unavailable/></error></iq>", stanza.attr.id));
						return;
					end
				elseif stanza.name == "presence" then
					if session.roster then
						-- Broadcast presence and probes
						local broadcast = st.presence({ from = session.username.."@"..session.host.."/"..session.resource });
						local probe = st.presence { from = broadcast.attr.from, type = "probe" };

						for child in stanza:children() do
							broadcast:tag(child.name, child.attr);
						end
						for contact in pairs(session.roster) do
							broadcast.attr.to = contact;
							send_to(contact, broadcast);
							--local host = jid.host(contact);
							--if hosts[host] and hosts[host].type == "local" then
								--local node, host = jid.split(contact);
								--if host[host].sessions[node]
								--local pres = st.presence { from = con
							--else
							--	probe.attr.to = contact;
							--	send_to(contact, probe);
							--end
						end
						
						-- Probe for our contacts' presence
					end
				end
			else
			--end				
			--if stanza.attr.to and ((not hosts[stanza.attr.to]) or hosts[stanza.attr.to].type ~= "local") then
				-- Need to route stanza
				stanza.attr.from = session.username.."@"..session.host;
				session:send_to(stanza.attr.to, stanza);
			end
		end

end