From f8114fe1b0e239d418e2f1d05952c97170efc351 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 27 Nov 2010 19:49:29 +0000 Subject: Rename storage/mod_ejabberd to mod_storage_sql_ejabberd. Also rename configuration option. Untested. --- plugins/mod_storage_sql_ejabberd.lua | 232 +++++++++++++++++++++++++++++++++++ plugins/storage/mod_ejabberd.lua | 229 ---------------------------------- 2 files changed, 232 insertions(+), 229 deletions(-) create mode 100644 plugins/mod_storage_sql_ejabberd.lua delete mode 100644 plugins/storage/mod_ejabberd.lua (limited to 'plugins') diff --git a/plugins/mod_storage_sql_ejabberd.lua b/plugins/mod_storage_sql_ejabberd.lua new file mode 100644 index 00000000..74763c92 --- /dev/null +++ b/plugins/mod_storage_sql_ejabberd.lua @@ -0,0 +1,232 @@ + +local setmetatable = setmetatable; +local error = error; +local unpack = unpack; +local module = module; +local tostring = tostring; +local pairs, next = pairs, next; +local prosody = prosody; +local assert = assert; +local require = require; +local st = require "util.stanza"; +local DBI = require "DBI"; + +-- connect to db +local params = module:get_option("sql_ejabberd") or error("No sql_ejabberd config option"); +local database; +do + module:log("debug", "Opening database: %s", "dbi:"..params.driver..":"..params.database); + prosody.unlock_globals(); + local dbh, err = DBI.Connect( + params.driver, params.database, + params.username, params.password, + params.host, params.port + ); + prosody.lock_globals(); + assert(dbh, err); + dbh:autocommit(true); + database = dbh; +end + +-- initialize db +local ejabberd_init = module:require("ejabberd_init"); +ejabberd_init.init(database); + +local sqlcache = {}; +local function prepare(sql) + module:log("debug", "query: %s", sql); + local err; + local r = sqlcache[sql]; + if not r then + r, err = database:prepare(sql); + if not r then error("Unable to prepare SQL statement: "..err); end + sqlcache[sql] = r; + end + return r; +end + +local _parse_xml = module:require("xmlparse"); +local function parse_xml(str) + local s = _parse_xml(str); + if s and not s.gsub then + return st.preserialize(s); + end +end +local function unparse_xml(s) + return tostring(st.deserialize(s)); +end + + +local handlers = {}; + +handlers.accounts = { + get = function(self, user) + local select = self:query("select password from users where username=? and host=?", user, self.host); + 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=? and host=?", data.password, user, self.host) + or self:modify("insert into users (username, host, password) values (?, ?, ?)", user, self.host, data.password); + else + return self:modify("delete from users where username=? and host=?", user, self.host); + end + end; +}; +handlers.vcard = { + get = function(self, user) + local select = self:query("select vcard from vcard where username=? and host=?", user, self.host); + 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=? and host=?", data, user, self.host) + or self:modify("insert into vcard (username, host, vcard) values (?, ?, ?)", user, self.host, data); + else + return self:modify("delete from vcard where username=? and host=?", user, self.host); + end + end; +}; +handlers.private = { + get = function(self, user) + local select = self:query("select namespace,data from private_storage where username=? and host=?", user, self.host); + 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=? and host=?", user, self.host); + for namespace,text in pairs(data) do + self:modify("insert into private_storage (username, host, namespace, data) values (?, ?, ?, ?)", user, self.host, namespace, unparse_xml(text)); + end + return true; + else + return self:modify("delete from private_storage where username=? and host=?", user, self.host); + 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(row); + 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:query(sql, ...) + local stmt,err = prepare(sql); + if not stmt then + module:log("error", "Failed to prepare SQL [[%s]], error: %s", sql, err); + return nil, err; + end + local ok, err = stmt:execute(...); + if not ok then + module:log("error", "Failed to execute SQL [[%s]], error: %s", sql, err); + return nil, err; + end + return stmt; +end +function driver:modify(sql, ...) + local stmt, err = self:query(sql, ...); + if stmt and stmt:affected() > 0 then return stmt; end + return nil, err; +end + +function driver:open(datastore, typ) + local instance = setmetatable({ host = module.host, datastore = datastore }, self); + 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 + return instance; +end + +----------------------------- + +module:add_item("data-driver", driver); diff --git a/plugins/storage/mod_ejabberd.lua b/plugins/storage/mod_ejabberd.lua deleted file mode 100644 index 17528656..00000000 --- a/plugins/storage/mod_ejabberd.lua +++ /dev/null @@ -1,229 +0,0 @@ - -local setmetatable = setmetatable; -local error = error; -local unpack = unpack; -local module = module; -local tostring = tostring; -local pairs, next = pairs, next; -local prosody = prosody; -local assert = assert; -local require = require; -local st = require "util.stanza"; -local DBI = require "DBI"; - --- connect to db -local option_datastore_params = module:get_option("datastore_params") or error("Missing option: datastore_params"); -local database; -do - local driver, db = unpack(option_datastore_params); - module:log("debug", "Opening database: %s", "dbi:"..driver..":"..db); - prosody.unlock_globals(); - local dbh, err = DBI.Connect(unpack(option_datastore_params)); - prosody.lock_globals(); - assert(dbh, err); - dbh:autocommit(true) - database = dbh; -end - --- initialize db -local ejabberd_init = module:require("ejabberd_init"); -ejabberd_init.init(database); - -local sqlcache = {}; -local function prepare(sql) - module:log("debug", "query: %s", sql); - local err; - local r = sqlcache[sql]; - if not r then - r, err = database:prepare(sql); - if not r then error("Unable to prepare SQL statement: "..err); end - sqlcache[sql] = r; - end - return r; -end - -local _parse_xml = module:require("xmlparse"); -local function parse_xml(str) - local s = _parse_xml(str); - if s and not s.gsub then - return st.preserialize(s); - end -end -local function unparse_xml(s) - return tostring(st.deserialize(s)); -end - - -local handlers = {}; - -handlers.accounts = { - get = function(self, user) - local select = self:query("select password from users where username=? and host=?", user, self.host); - 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=? and host=?", data.password, user, self.host) - or self:modify("insert into users (username, host, password) values (?, ?, ?)", user, self.host, data.password); - else - return self:modify("delete from users where username=? and host=?", user, self.host); - end - end; -}; -handlers.vcard = { - get = function(self, user) - local select = self:query("select vcard from vcard where username=? and host=?", user, self.host); - 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=? and host=?", data, user, self.host) - or self:modify("insert into vcard (username, host, vcard) values (?, ?, ?)", user, self.host, data); - else - return self:modify("delete from vcard where username=? and host=?", user, self.host); - end - end; -}; -handlers.private = { - get = function(self, user) - local select = self:query("select namespace,data from private_storage where username=? and host=?", user, self.host); - 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=? and host=?", user, self.host); - for namespace,text in pairs(data) do - self:modify("insert into private_storage (username, host, namespace, data) values (?, ?, ?, ?)", user, self.host, namespace, unparse_xml(text)); - end - return true; - else - return self:modify("delete from private_storage where username=? and host=?", user, self.host); - 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(row); - 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:query(sql, ...) - local stmt,err = prepare(sql); - if not stmt then - module:log("error", "Failed to prepare SQL [[%s]], error: %s", sql, err); - return nil, err; - end - local ok, err = stmt:execute(...); - if not ok then - module:log("error", "Failed to execute SQL [[%s]], error: %s", sql, err); - return nil, err; - end - return stmt; -end -function driver:modify(sql, ...) - local stmt, err = self:query(sql, ...); - if stmt and stmt:affected() > 0 then return stmt; end - return nil, err; -end - -function driver:open(datastore, typ) - local instance = setmetatable({ host = module.host, datastore = datastore }, self); - 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 - return instance; -end - ------------------------------ - -module:add_item("data-driver", driver); -- cgit v1.2.3