From 7af782ea9c6f1818e2e445b0695398ed7df42480 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Fri, 19 Feb 2010 22:32:28 +0500 Subject: mod_storage, plus a bit of SQL and XML. --- plugins/storage/ejabberdstore.lib.lua | 190 ++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 plugins/storage/ejabberdstore.lib.lua (limited to 'plugins/storage/ejabberdstore.lib.lua') diff --git a/plugins/storage/ejabberdstore.lib.lua b/plugins/storage/ejabberdstore.lib.lua new file mode 100644 index 00000000..7e8592a8 --- /dev/null +++ b/plugins/storage/ejabberdstore.lib.lua @@ -0,0 +1,190 @@ + +local handlers = {}; + +handlers.accounts = { + get = function(self, user) + local select = self:query("select password from users where username=?", user); + local row = select and select:fetch(); + if row then return { password = row[1] }; end + end; + set = function(self, user, data) + if data and data.password then + return self:modify("update users set password=? where username=?", data.password, user) + or self:modify("insert into users (username, password) values (?, ?)", user, data.password); + else + return self:modify("delete from users where username=?", user); + end + end; +}; +handlers.vcard = { + get = function(self, user) + local select = self:query("select vcard from vcard where username=?", user); + local row = select and select:fetch(); + if row then return parse_xml(row[1]); end + end; + set = function(self, user, data) + if data then + data = unparse_xml(data); + return self:modify("update vcard set vcard=? where username=?", data, user) + or self:modify("insert into vcard (username, vcard) values (?, ?)", user, data); + else + return self:modify("delete from vcard where username=?", user); + end + end; +}; +handlers.private = { + get = function(self, user) + local select = self:query("select namespace,data from private_storage where username=?", user); + if select then + local data = {}; + for row in select:rows() do + data[row[1]] = parse_xml(row[2]); + end + return data; + end + end; + set = function(self, user, data) + if data then + self:modify("delete from private_storage where username=?", user); + for namespace,text in pairs(data) do + self:modify("insert into private_storage (username, namespace, data) values (?, ?, ?)", user, namespace, unparse_xml(text)); + end + return true; + else + return self:modify("delete from private_storage where username=?", user); + end + end; + -- TODO map_set, map_get +}; +local subscription_map = { N = "none", B = "both", F = "from", T = "to" }; +local subscription_map_reverse = { none = "N", both = "B", from = "F", to = "T" }; +handlers.roster = { + get = function(self, user) + local select = self:query("select jid,nick,subscription,ask,server,subscribe,type from rosterusers where username=?", user); + if select then + local roster = { pending = {} }; + for row in select:rows() do + local jid,nick,subscription,ask,server,subscribe,typ = unpack(row); + local item = { groups = {} }; + if nick == "" then nick = nil; end + item.nick = nick; + item.subscription = subscription_map[subscription]; + if ask == "N" then ask = nil; + elseif ask == "O" then ask = "subscribe" + elseif ask == "I" then roster.pending[jid] = true; ask = nil; + elseif ask == "B" then roster.pending[jid] = true; ask = "subscribe"; + else module:log("debug", "bad roster_item.ask: %s", ask); ask = nil; end + item.ask = ask; + roster[jid] = item; + end + + select = self:query("select jid,grp from rostergroups where username=?", user); + if select then + for row in select:rows() do + local jid,grp = unpack(rows); + if roster[jid] then roster[jid].groups[grp] = true; end + end + end + select = self:query("select version from roster_version where username=?", user); + local row = select and select:fetch(); + if row then + roster[false] = { version = row[1]; }; + end + return roster; + end + end; + set = function(self, user, data) + if data and next(data) ~= nil then + self:modify("delete from rosterusers where username=?", user); + self:modify("delete from rostergroups where username=?", user); + self:modify("delete from roster_version where username=?", user); + local done = {}; + local pending = data.pending or {}; + for jid,item in pairs(data) do + if jid and jid ~= "pending" then + local subscription = subscription_map_reverse[item.subscription]; + local ask; + if pending[jid] then + if item.ask then ask = "B"; else ask = "I"; end + else + if item.ask then ask = "O"; else ask = "N"; end + end + local r = self:modify("insert into rosterusers (username,jid,nick,subscription,ask,askmessage,server,subscribe) values (?, ?, ?, ?, ?, '', '', '')", user, jid, item.nick or "", subscription, ask); + if not r then module:log("debug", "--- :( %s", tostring(r)); end + done[jid] = true; + for group in pairs(item.groups) do + self:modify("insert into rostergroups (username,jid,grp) values (?, ?, ?)", user, jid, group); + end + end + end + for jid in pairs(pending) do + if not done[jid] then + self:modify("insert into rosterusers (username,jid,nick,subscription,ask,askmessage,server,subscribe) values (?, ?, ?, ?, ?. ''. ''. '')", user, jid, "", "N", "I"); + end + end + local version = data[false] and data[false].version; + if version then + self:modify("insert into roster_version (username,version) values (?, ?)", user, version); + end + return true; + else + self:modify("delete from rosterusers where username=?", user); + self:modify("delete from rostergroups where username=?", user); + self:modify("delete from roster_version where username=?", user); + end + end; +}; + +----------------------------- +local driver = {}; +driver.__index = driver; + +function driver:prepare(sql) + module:log("debug", "query: %s", sql); + local err; + if not self.sqlcache then self.sqlcache = {}; end + local r = self.sqlcache[sql]; + if r then return r; end + r, err = self.database:prepare(sql); + if not r then error("Unable to prepare SQL statement: "..err); end + self.sqlcache[sql] = r; + return r; +end + +function driver:query(sql, ...) + local stmt = self:prepare(sql); + if stmt:execute(...) then return stmt; end +end +function driver:modify(sql, ...) + local stmt = self:query(sql, ...); + if stmt and stmt:affected() > 0 then return stmt; end +end + +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(dbtype, dbname, ...) + local instance = setmetatable({}, driver); + instance.__index = instance; + instance.database = get_database(dbtype, dbname, ...); + instance.ds_cache = {}; + return instance; +end + +return _M; -- cgit v1.2.3