Diff

mod_vjud/mod_vjud.lua @ 715:b1268d3aa6ce

mod_vjud: Add. Thanks waqas for the base code.
author Kim Alvefur <zash@zash.se>
date Wed, 20 Jun 2012 15:14:34 +0200
child 730:274bb1a96122
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_vjud/mod_vjud.lua	Wed Jun 20 15:14:34 2012 +0200
@@ -0,0 +1,149 @@
+local dm_load = require "util.datamanager".load;
+local dm_store = require "util.datamanager".store;
+
+local usermanager = require "core.usermanager";
+local dataforms_new = require "util.dataforms".new;
+local jid_split = require "util.jid".prepped_split;
+local vcard = module:require "vcard";
+
+local st = require "util.stanza";
+local template = require "util.template";
+
+local get_reply = template[[
+<query xmlns="jabber:iq:search">
+  <instructions>Fill in one or more fields to search for any matching Jabber users.</instructions>
+  <first/>
+  <last/>
+  <nick/>
+  <email/>
+</query>
+]].apply({});
+local item_template = template[[
+<item xmlns="jabber:iq:search" jid="{jid}">
+  <first>{first}</first>
+  <last>{last}</last>
+  <nick>{nick}</nick>
+  <email>{email}</email>
+</item>
+]];
+
+module:add_feature("jabber:iq:search");
+
+local opted_in;
+function module.load()
+	opted_in = dm_load(nil, module.host, "user_index") or {};
+end
+function module.unload()
+	dm_store(nil, module.host, "user_index", opted_in);
+end
+
+local opt_in_layout = dataforms_new{
+	title = "Search settings";
+	instructions = "Do you want to appear in search results?";
+	{
+		name = "searchable",
+		label = "Appear in search results?",
+		type = "boolean",
+	},
+};
+local vCard_mt = {
+	__index = function(t, k)
+		for i=1,#t do
+			if t[i].name == k then
+				t[k] = t[i];
+				return t[i]
+			end
+		end
+	end
+};
+
+local function get_user_vcard(user)
+	local vCard = dm_load(user, module.host, "vcard");
+	if vCard then
+		vCard = st.deserialize(vCard);
+		vCard = vcard.xep54_to_lua(vCard);
+		return setmetatable(vCard, vCard_mt);
+	end
+end
+
+local at_host = "@"..module.host;
+
+module:hook("iq/host/jabber:iq:search:query", function(event)
+	local origin, stanza = event.origin, event.stanza;
+
+	if stanza.attr.type == "get" then
+		origin.send(st.reply(stanza):add_child(get_reply));
+	else -- type == "set"
+		local query = stanza.tags[1];
+		local reply = st.reply(stanza):query("jabber:iq:search");
+		local first, last, nick, email =
+			query:get_child_text"first",
+			query:get_child_text"last",
+			query:get_child_text"nick",
+			query:get_child_text"email";
+		first = first and #first and first;
+		last = last and #last and last;
+		nick = nick and #nick and nick;
+		email = email and #email and email;
+		local username, hostname = jid_split(email);
+		if hostname == module.host and username and usermanager.user_exists(username, hostname) then
+			local vCard = get_user_vcard(username);
+			if vCard then
+				reply:add_child(item_template.apply{
+					jid = username..at_host;
+					first = vCard.N and vCard.N[1] or nil;
+					last = vCard.N and vCard.N[2] or nil;
+					nick = vCard.NICKNAME and vCard.NICKNAME[1] or username;
+					email = vCard.EMAIL and vCard.EMAIL[1] or nil;
+				});
+			end
+		else
+			for username in pairs(opted_in) do
+				local vCard = get_user_vcard(username);
+				if vCard and (
+				(not first or (vCard.N and vCard.N[2] == first)) or
+				(not last or (vCard.N and vCard.N[1] == last)) or
+				(not nick or (vCard.NICKNAME and vCard.NICKNAME[1] == nick)) or
+				(not email or (vCard.EMAIL and vCard.EMAIL[1] == email))) then
+					reply:add_child(item_template.apply{
+						jid = username..at_host;
+						first = vCard.N and vCard.N[1] or nil;
+						last = vCard.N and vCard.N[2] or nil;
+						nick = vCard.NICKNAME and vCard.NICKNAME[1] or username;
+						email = vCard.EMAIL and vCard.EMAIL[1] or nil;
+					});
+				end
+			end
+		end
+		origin.send(reply);
+	end
+	return true;
+end);
+
+local function opt_in_handler(self, data, state)
+	local username, hostname = jid_split(data.from);
+	if state then -- the second return value
+		if data.action == "cancel" then
+			return { status = "canceled" };
+		end
+
+		if not username or not hostname or hostname ~= module.host then
+			return { status = "error", error = { type = "cancel",
+				condition = "forbidden", message = "Invalid user or hostname." } };
+		end
+
+		local fields = opt_in_layout:data(data.form);
+		opted_in[username] = fields.searchable or nil
+
+		return { status = "completed" }
+	else -- No state, send the form.
+		return { status = "executing", actions  = { "complete" },
+			form = { layout = opt_in_layout, data = { searchable = opted_in[username] } } }, true;
+	end
+end
+
+local adhoc_new = module:require "adhoc".new;
+local adhoc_vjudsetup = adhoc_new("Search settings", "vjudsetup", opt_in_handler);--, "self");-- and nil);
+module:depends"adhoc";
+module:provides("adhoc", adhoc_vjudsetup);
+