File

plugins/storage/xep227store.lib.lua @ 5877:615a0774e4cc

util.timer: Updated to use util.indexedbheap to provide a more complete API. Timers can now be stopped or rescheduled. Callbacks are now pcall'd. Adding/removing timers from within timer callbacks works better. Optional parameter can be passed when creating timer which gets passed to callback, eliminating the need for closures in various timer uses. Timers are now much more lightweight.
author Waqas Hussain <waqas20@gmail.com>
date Wed, 30 Oct 2013 17:44:42 -0400
parent 2678:c5882e2e12b5
line wrap: on
line source


local st = require "util.stanza";

local function getXml(user, host)
	local jid = user.."@"..host;
	local path = "data/"..jid..".xml";
	local f = io.open(path);
	if not f then return; end
	local s = f:read("*a");
	return parse_xml_real(s);
end
local function setXml(user, host, xml)
	local jid = user.."@"..host;
	local path = "data/"..jid..".xml";
	if xml then
		local f = io.open(path, "w");
		if not f then return; end
		local s = tostring(xml);
		f:write(s);
		f:close();
		return true;
	else
		return os.remove(path);
	end
end
local function getUserElement(xml)
	if xml and xml.name == "server-data" then
		local host = xml.tags[1];
		if host and host.name == "host" then
			local user = host.tags[1];
			if user and user.name == "user" then
				return user;
			end
		end
	end
end
local function createOuterXml(user, host)
	return st.stanza("server-data", {xmlns='http://www.xmpp.org/extensions/xep-0227.html#ns'})
		:tag("host", {jid=host})
			:tag("user", {name = user});
end
local function removeFromArray(array, value)
	for i,item in ipairs(array) do
		if item == value then
			table.remove(array, i);
			return;
		end
	end
end
local function removeStanzaChild(s, child)
	removeFromArray(s.tags, child);
	removeFromArray(s, child);
end

local handlers = {};

handlers.accounts = {
	get = function(self, user)
		local user = getUserElement(getXml(user, self.host));
		if user and user.attr.password then
			return { password = user.attr.password };
		end
	end;
	set = function(self, user, data)
		if data and data.password then
			local xml = getXml(user, self.host);
			if not xml then xml = createOuterXml(user, self.host); end
			local usere = getUserElement(xml);
			usere.attr.password = data.password;
			return setXml(user, self.host, xml);
		else
			return setXml(user, self.host, nil);
		end
	end;
};
handlers.vcard = {
	get = function(self, user)
		local user = getUserElement(getXml(user, self.host));
		if user then
			local vcard = user:get_child("vCard", 'vcard-temp');
			if vcard then
				return st.preserialize(vcard);
			end
		end
	end;
	set = function(self, user, data)
		local xml = getXml(user, self.host);
		local usere = xml and getUserElement(xml);
		if usere then
			local vcard = usere:get_child("vCard", 'vcard-temp');
			if vcard then
				removeStanzaChild(usere, vcard);
			elseif not data then
				return true;
			end
			if data then
				vcard = st.deserialize(data);
				usere:add_child(vcard);
			end
			return setXml(user, self.host, xml);
		end
		return true;
	end;
};
handlers.private = {
	get = function(self, user)
		local user = getUserElement(getXml(user, self.host));
		if user then
			local private = user:get_child("query", "jabber:iq:private");
			if private then
				local r = {};
				for _, tag in ipairs(private.tags) do
					r[tag.name..":"..tag.attr.xmlns] = st.preserialize(tag);
				end
				return r;
			end
		end
	end;
	set = function(self, user, data)
		local xml = getXml(user, self.host);
		local usere = xml and getUserElement(xml);
		if usere then
			local private = usere:get_child("query", 'jabber:iq:private');
			if private then removeStanzaChild(usere, private); end
			if data and next(data) ~= nil then
				private = st.stanza("query", {xmlns='jabber:iq:private'});
				for _,tag in pairs(data) do
					private:add_child(st.deserialize(tag));
				end
				usere:add_child(private);
			end
			return setXml(user, self.host, xml);
		end
		return true;
	end;
};

-----------------------------
local driver = {};
driver.__index = driver;

function driver:open(host, datastore, typ)
	local cache_key = host.." "..datastore;
	if self.ds_cache[cache_key] then return self.ds_cache[cache_key]; end
	local instance = setmetatable({}, self);
	instance.host = host;
	instance.datastore = datastore;
	local handler = handlers[datastore];
	if not handler then return nil; end
	for key,val in pairs(handler) do
		instance[key] = val;
	end
	if instance.init then instance:init(); end
	self.ds_cache[cache_key] = instance;
	return instance;
end

-----------------------------
local _M = {};

function _M.new()
	local instance = setmetatable({}, driver);
	instance.__index = instance;
	instance.ds_cache = {};
	return instance;
end

return _M;