plugins/storage/xep227store.lib.lua

1
local st = require "util.stanza";
2
 
3
local function getXml(user, host)
4
	local jid = user.."@"..host;
5
	local path = "data/"..jid..".xml";
6
	local f = io.open(path);
7
	if not f then return; end
8
	local s = f:read("*a");
9
	return parse_xml_real(s);
10
end
11
local function setXml(user, host, xml)
12
	local jid = user.."@"..host;
13
	local path = "data/"..jid..".xml";
14
	if xml then
15
		local f = io.open(path, "w");
16
		if not f then return; end
17
		local s = tostring(xml);
18
		f:write(s);
19
		f:close();
20
		return true;
21
	else
22
		return os.remove(path);
23
	end
24
end
25
local function getUserElement(xml)
26
	if xml and xml.name == "server-data" then
27
		local host = xml.tags[1];
28
		if host and host.name == "host" then
29
			local user = host.tags[1];
30
			if user and user.name == "user" then
31
				return user;
32
			end
33
		end
34
	end
35
end
36
local function createOuterXml(user, host)
37
	return st.stanza("server-data", {xmlns='http://www.xmpp.org/extensions/xep-0227.html#ns'})
38
		:tag("host", {jid=host})
39
			:tag("user", {name = user});
40
end
41
local function removeFromArray(array, value)
42
	for i,item in ipairs(array) do
43
		if item == value then
44
			table.remove(array, i);
45
			return;
46
		end
47
	end
48
end
49
local function removeStanzaChild(s, child)
50
	removeFromArray(s.tags, child);
51
	removeFromArray(s, child);
52
end
53
 
54
local handlers = {};
55
 
56
handlers.accounts = {
57
	get = function(self, user)
58
		local user = getUserElement(getXml(user, self.host));
59
		if user and user.attr.password then
60
			return { password = user.attr.password };
61
		end
62
	end;
63
	set = function(self, user, data)
64
		if data and data.password then
65
			local xml = getXml(user, self.host);
66
			if not xml then xml = createOuterXml(user, self.host); end
67
			local usere = getUserElement(xml);
68
			usere.attr.password = data.password;
69
			return setXml(user, self.host, xml);
70
		else
71
			return setXml(user, self.host, nil);
72
		end
73
	end;
74
};
75
handlers.vcard = {
76
	get = function(self, user)
77
		local user = getUserElement(getXml(user, self.host));
78
		if user then
79
			local vcard = user:get_child("vCard", 'vcard-temp');
80
			if vcard then
81
				return st.preserialize(vcard);
82
			end
83
		end
84
	end;
85
	set = function(self, user, data)
86
		local xml = getXml(user, self.host);
87
		local usere = xml and getUserElement(xml);
88
		if usere then
89
			local vcard = usere:get_child("vCard", 'vcard-temp');
90
			if vcard then
91
				removeStanzaChild(usere, vcard);
92
			elseif not data then
93
				return true;
94
			end
95
			if data then
96
				vcard = st.deserialize(data);
97
				usere:add_child(vcard);
98
			end
99
			return setXml(user, self.host, xml);
100
		end
101
		return true;
102
	end;
103
};
104
handlers.private = {
105
	get = function(self, user)
106
		local user = getUserElement(getXml(user, self.host));
107
		if user then
108
			local private = user:get_child("query", "jabber:iq:private");
109
			if private then
110
				local r = {};
111
				for _, tag in ipairs(private.tags) do
112
					r[tag.name..":"..tag.attr.xmlns] = st.preserialize(tag);
113
				end
114
				return r;
115
			end
116
		end
117
	end;
118
	set = function(self, user, data)
119
		local xml = getXml(user, self.host);
120
		local usere = xml and getUserElement(xml);
121
		if usere then
122
			local private = usere:get_child("query", 'jabber:iq:private');
123
			if private then removeStanzaChild(usere, private); end
124
			if data and next(data) ~= nil then
125
				private = st.stanza("query", {xmlns='jabber:iq:private'});
126
				for _,tag in pairs(data) do
127
					private:add_child(st.deserialize(tag));
128
				end
129
				usere:add_child(private);
130
			end
131
			return setXml(user, self.host, xml);
132
		end
133
		return true;
134
	end;
135
};
136
 
137
-----------------------------
138
local driver = {};
139
driver.__index = driver;
140
 
141
function driver:open(host, datastore, typ)
142
	local cache_key = host.." "..datastore;
143
	if self.ds_cache[cache_key] then return self.ds_cache[cache_key]; end
144
	local instance = setmetatable({}, self);
145
	instance.host = host;
146
	instance.datastore = datastore;
147
	local handler = handlers[datastore];
148
	if not handler then return nil; end
149
	for key,val in pairs(handler) do
150
		instance[key] = val;
151
	end
152
	if instance.init then instance:init(); end
153
	self.ds_cache[cache_key] = instance;
154
	return instance;
155
end
156
 
157
-----------------------------
158
local _M = {};
159
 
160
function _M.new()
161
	local instance = setmetatable({}, driver);
162
	instance.__index = instance;
163
	instance.ds_cache = {};
164
	return instance;
165
end
166
 
167
return _M;