plugins/storage/ejabberdstore.lib.lua

1
local handlers = {};
2
 
3
handlers.accounts = {
4
	get = function(self, user)
5
		local select = self:query("select password from users where username=?", user);
6
		local row = select and select:fetch();
7
		if row then return { password = row[1] }; end
8
	end;
9
	set = function(self, user, data)
10
		if data and data.password then
11
			return self:modify("update users set password=? where username=?", data.password, user)
12
				or self:modify("insert into users (username, password) values (?, ?)", user, data.password);
13
		else
14
			return self:modify("delete from users where username=?", user);
15
		end
16
	end;
17
};
18
handlers.vcard = {
19
	get = function(self, user)
20
		local select = self:query("select vcard from vcard where username=?", user);
21
		local row = select and select:fetch();
22
		if row then return parse_xml(row[1]); end
23
	end;
24
	set = function(self, user, data)
25
		if data then
26
			data = unparse_xml(data);
27
			return self:modify("update vcard set vcard=? where username=?", data, user)
28
				or self:modify("insert into vcard (username, vcard) values (?, ?)", user, data);
29
		else
30
			return self:modify("delete from vcard where username=?", user);
31
		end
32
	end;
33
};
34
handlers.private = {
35
	get = function(self, user)
36
		local select = self:query("select namespace,data from private_storage where username=?", user);
37
		if select then
38
			local data = {};
39
			for row in select:rows() do
40
				data[row[1]] = parse_xml(row[2]);
41
			end
42
			return data;
43
		end
44
	end;
45
	set = function(self, user, data)
46
		if data then
47
			self:modify("delete from private_storage where username=?", user);
48
			for namespace,text in pairs(data) do
49
				self:modify("insert into private_storage (username, namespace, data) values (?, ?, ?)", user, namespace, unparse_xml(text));
50
			end
51
			return true;
52
		else
53
			return self:modify("delete from private_storage where username=?", user);
54
		end
55
	end;
56
	-- TODO map_set, map_get
57
};
58
local subscription_map = { N = "none", B = "both", F = "from", T = "to" };
59
local subscription_map_reverse = { none = "N", both = "B", from = "F", to = "T" };
60
handlers.roster = {
61
	get = function(self, user)
62
		local select = self:query("select jid,nick,subscription,ask,server,subscribe,type from rosterusers where username=?", user);
63
		if select then
64
			local roster = { pending = {} };
65
			for row in select:rows() do
66
				local jid,nick,subscription,ask,server,subscribe,typ = unpack(row);
67
				local item = { groups = {} };
68
				if nick == "" then nick = nil; end
69
				item.nick = nick;
70
				item.subscription = subscription_map[subscription];
71
				if ask == "N" then ask = nil;
72
				elseif ask == "O" then ask = "subscribe"
73
				elseif ask == "I" then roster.pending[jid] = true; ask = nil;
74
				elseif ask == "B" then roster.pending[jid] = true; ask = "subscribe";
75
				else module:log("debug", "bad roster_item.ask: %s", ask); ask = nil; end
76
				item.ask = ask;
77
				roster[jid] = item;
78
			end
79
			
80
			select = self:query("select jid,grp from rostergroups where username=?", user);
81
			if select then
82
				for row in select:rows() do
83
					local jid,grp = unpack(rows);
84
					if roster[jid] then roster[jid].groups[grp] = true; end
85
				end
86
			end
87
			select = self:query("select version from roster_version where username=?", user);
88
			local row = select and select:fetch();
89
			if row then
90
				roster[false] = { version = row[1]; };
91
			end
92
			return roster;
93
		end
94
	end;
95
	set = function(self, user, data)
96
		if data and next(data) ~= nil then
97
			self:modify("delete from rosterusers where username=?", user);
98
			self:modify("delete from rostergroups where username=?", user);
99
			self:modify("delete from roster_version where username=?", user);
100
			local done = {};
101
			local pending = data.pending or {};
102
			for jid,item in pairs(data) do
103
				if jid and jid ~= "pending" then
104
					local subscription = subscription_map_reverse[item.subscription];
105
					local ask;
106
					if pending[jid] then
107
						if item.ask then ask = "B"; else ask = "I"; end
108
					else
109
						if item.ask then ask = "O"; else ask = "N"; end
110
					end
111
					local r = self:modify("insert into rosterusers (username,jid,nick,subscription,ask,askmessage,server,subscribe) values (?, ?, ?, ?, ?, '', '', '')", user, jid, item.nick or "", subscription, ask);
112
					if not r then module:log("debug", "--- :( %s", tostring(r)); end
113
					done[jid] = true;
114
					for group in pairs(item.groups) do
115
						self:modify("insert into rostergroups (username,jid,grp) values (?, ?, ?)", user, jid, group);
116
					end
117
				end
118
			end
119
			for jid in pairs(pending) do
120
				if not done[jid] then
121
					self:modify("insert into rosterusers (username,jid,nick,subscription,ask,askmessage,server,subscribe) values (?, ?, ?, ?, ?. ''. ''. '')", user, jid, "", "N", "I");
122
				end
123
			end
124
			local version = data[false] and data[false].version;
125
			if version then
126
				self:modify("insert into roster_version (username,version) values (?, ?)", user, version);
127
			end
128
			return true;
129
		else
130
			self:modify("delete from rosterusers where username=?", user);
131
			self:modify("delete from rostergroups where username=?", user);
132
			self:modify("delete from roster_version where username=?", user);
133
		end
134
	end;
135
};
136
 
137
-----------------------------
138
local driver = {};
139
driver.__index = driver;
140
 
141
function driver:prepare(sql)
142
	module:log("debug", "query: %s", sql);
143
	local err;
144
	if not self.sqlcache then self.sqlcache = {}; end
145
	local r = self.sqlcache[sql];
146
	if r then return r; end
147
	r, err = self.database:prepare(sql);
148
	if not r then error("Unable to prepare SQL statement: "..err); end
149
	self.sqlcache[sql] = r;
150
	return r;
151
end
152
 
153
function driver:query(sql, ...)
154
	local stmt = self:prepare(sql);
155
	if stmt:execute(...) then return stmt; end
156
end
157
function driver:modify(sql, ...)
158
	local stmt = self:query(sql, ...);
159
	if stmt and stmt:affected() > 0 then return stmt; end
160
end
161
 
162
function driver:open(host, datastore, typ)
163
	local cache_key = host.." "..datastore;
164
	if self.ds_cache[cache_key] then return self.ds_cache[cache_key]; end
165
	local instance = setmetatable({}, self);
166
	instance.host = host;
167
	instance.datastore = datastore;
168
	local handler = handlers[datastore];
169
	if not handler then return nil; end
170
	for key,val in pairs(handler) do
171
		instance[key] = val;
172
	end
173
	if instance.init then instance:init(); end
174
	self.ds_cache[cache_key] = instance;
175
	return instance;
176
end
177
 
178
-----------------------------
179
local _M = {};
180
 
181
function _M.new(dbtype, dbname, ...)
182
	local instance = setmetatable({}, driver);
183
	instance.__index = instance;
184
	instance.database = get_database(dbtype, dbname, ...);
185
	instance.ds_cache = {};
186
	return instance;
187
end
188
 
189
return _M;