plugins/storage/mod_xep0227.lua

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