Merge 0.9->trunk
authorMatthew Wild <mwild1@gmail.com>
Tue, 14 May 2013 08:39:32 +0000 (09:39 +0100)
committerMatthew Wild <mwild1@gmail.com>
Tue, 14 May 2013 08:39:32 +0000 (09:39 +0100)
plugins/muc/mod_muc.lua
plugins/muc/muc.lib.lua
plugins/storage/ejabberdstore.lib.lua [new file with mode: 0644]
plugins/storage/mod_storage.lua [new file with mode: 0644]
util-src/hashes.c

index 7861092c40598dfa7aabbbb2780d5c580732db08..0f1beb0e5f1f6801ce8de79299c2903764ac4009 100644 (file)
@@ -83,6 +83,7 @@ function create_room(jid)
        room.route_stanza = room_route_stanza;
        room.save = room_save;
        rooms[jid] = room;
+       module:fire_event("muc-room-created", { room = room });
        return room;
 end
 
index a5aba3c8d31986854e946282b5d940c3fe0292ac..1ea231f3de198543d3ce02ff77a75e54cdf098a9 100644 (file)
@@ -767,6 +767,7 @@ function room_mt:destroy(newjid, reason, password)
                self._occupants[nick] = nil;
        end
        self:set_persistent(false);
+       module:fire_event("muc-room-destroyed", { room = self });
 end
 
 function room_mt:handle_to_room(origin, stanza) -- presence changes and groupchat messages, along with disco/etc
diff --git a/plugins/storage/ejabberdstore.lib.lua b/plugins/storage/ejabberdstore.lib.lua
new file mode 100644 (file)
index 0000000..7e8592a
--- /dev/null
@@ -0,0 +1,190 @@
+\r
+local handlers = {};\r
+\r
+handlers.accounts = {\r
+       get = function(self, user)\r
+               local select = self:query("select password from users where username=?", user);\r
+               local row = select and select:fetch();\r
+               if row then return { password = row[1] }; end\r
+       end;\r
+       set = function(self, user, data)\r
+               if data and data.password then\r
+                       return self:modify("update users set password=? where username=?", data.password, user)\r
+                               or self:modify("insert into users (username, password) values (?, ?)", user, data.password);\r
+               else\r
+                       return self:modify("delete from users where username=?", user);\r
+               end\r
+       end;\r
+};\r
+handlers.vcard = {\r
+       get = function(self, user)\r
+               local select = self:query("select vcard from vcard where username=?", user);\r
+               local row = select and select:fetch();\r
+               if row then return parse_xml(row[1]); end\r
+       end;\r
+       set = function(self, user, data)\r
+               if data then\r
+                       data = unparse_xml(data);\r
+                       return self:modify("update vcard set vcard=? where username=?", data, user)\r
+                               or self:modify("insert into vcard (username, vcard) values (?, ?)", user, data);\r
+               else\r
+                       return self:modify("delete from vcard where username=?", user);\r
+               end\r
+       end;\r
+};\r
+handlers.private = {\r
+       get = function(self, user)\r
+               local select = self:query("select namespace,data from private_storage where username=?", user);\r
+               if select then\r
+                       local data = {};\r
+                       for row in select:rows() do\r
+                               data[row[1]] = parse_xml(row[2]);\r
+                       end\r
+                       return data;\r
+               end\r
+       end;\r
+       set = function(self, user, data)\r
+               if data then\r
+                       self:modify("delete from private_storage where username=?", user);\r
+                       for namespace,text in pairs(data) do\r
+                               self:modify("insert into private_storage (username, namespace, data) values (?, ?, ?)", user, namespace, unparse_xml(text));\r
+                       end\r
+                       return true;\r
+               else\r
+                       return self:modify("delete from private_storage where username=?", user);\r
+               end\r
+       end;\r
+       -- TODO map_set, map_get\r
+};\r
+local subscription_map = { N = "none", B = "both", F = "from", T = "to" };\r
+local subscription_map_reverse = { none = "N", both = "B", from = "F", to = "T" };\r
+handlers.roster = {\r
+       get = function(self, user)\r
+               local select = self:query("select jid,nick,subscription,ask,server,subscribe,type from rosterusers where username=?", user);\r
+               if select then\r
+                       local roster = { pending = {} };\r
+                       for row in select:rows() do\r
+                               local jid,nick,subscription,ask,server,subscribe,typ = unpack(row);\r
+                               local item = { groups = {} };\r
+                               if nick == "" then nick = nil; end\r
+                               item.nick = nick;\r
+                               item.subscription = subscription_map[subscription];\r
+                               if ask == "N" then ask = nil;\r
+                               elseif ask == "O" then ask = "subscribe"\r
+                               elseif ask == "I" then roster.pending[jid] = true; ask = nil;\r
+                               elseif ask == "B" then roster.pending[jid] = true; ask = "subscribe";\r
+                               else module:log("debug", "bad roster_item.ask: %s", ask); ask = nil; end\r
+                               item.ask = ask;\r
+                               roster[jid] = item;\r
+                       end\r
+                       \r
+                       select = self:query("select jid,grp from rostergroups where username=?", user);\r
+                       if select then\r
+                               for row in select:rows() do\r
+                                       local jid,grp = unpack(rows);\r
+                                       if roster[jid] then roster[jid].groups[grp] = true; end\r
+                               end\r
+                       end\r
+                       select = self:query("select version from roster_version where username=?", user);\r
+                       local row = select and select:fetch();\r
+                       if row then\r
+                               roster[false] = { version = row[1]; };\r
+                       end\r
+                       return roster;\r
+               end\r
+       end;\r
+       set = function(self, user, data)\r
+               if data and next(data) ~= nil then\r
+                       self:modify("delete from rosterusers where username=?", user);\r
+                       self:modify("delete from rostergroups where username=?", user);\r
+                       self:modify("delete from roster_version where username=?", user);\r
+                       local done = {};\r
+                       local pending = data.pending or {};\r
+                       for jid,item in pairs(data) do\r
+                               if jid and jid ~= "pending" then\r
+                                       local subscription = subscription_map_reverse[item.subscription];\r
+                                       local ask;\r
+                                       if pending[jid] then\r
+                                               if item.ask then ask = "B"; else ask = "I"; end\r
+                                       else\r
+                                               if item.ask then ask = "O"; else ask = "N"; end\r
+                                       end\r
+                                       local r = self:modify("insert into rosterusers (username,jid,nick,subscription,ask,askmessage,server,subscribe) values (?, ?, ?, ?, ?, '', '', '')", user, jid, item.nick or "", subscription, ask);\r
+                                       if not r then module:log("debug", "--- :( %s", tostring(r)); end\r
+                                       done[jid] = true;\r
+                                       for group in pairs(item.groups) do\r
+                                               self:modify("insert into rostergroups (username,jid,grp) values (?, ?, ?)", user, jid, group);\r
+                                       end\r
+                               end\r
+                       end\r
+                       for jid in pairs(pending) do\r
+                               if not done[jid] then\r
+                                       self:modify("insert into rosterusers (username,jid,nick,subscription,ask,askmessage,server,subscribe) values (?, ?, ?, ?, ?. ''. ''. '')", user, jid, "", "N", "I");\r
+                               end\r
+                       end\r
+                       local version = data[false] and data[false].version;\r
+                       if version then\r
+                               self:modify("insert into roster_version (username,version) values (?, ?)", user, version);\r
+                       end\r
+                       return true;\r
+               else\r
+                       self:modify("delete from rosterusers where username=?", user);\r
+                       self:modify("delete from rostergroups where username=?", user);\r
+                       self:modify("delete from roster_version where username=?", user);\r
+               end\r
+       end;\r
+};\r
+\r
+-----------------------------\r
+local driver = {};\r
+driver.__index = driver;\r
+\r
+function driver:prepare(sql)\r
+       module:log("debug", "query: %s", sql);\r
+       local err;\r
+       if not self.sqlcache then self.sqlcache = {}; end\r
+       local r = self.sqlcache[sql];\r
+       if r then return r; end\r
+       r, err = self.database:prepare(sql);\r
+       if not r then error("Unable to prepare SQL statement: "..err); end\r
+       self.sqlcache[sql] = r;\r
+       return r;\r
+end\r
+\r
+function driver:query(sql, ...)\r
+       local stmt = self:prepare(sql);\r
+       if stmt:execute(...) then return stmt; end\r
+end\r
+function driver:modify(sql, ...)\r
+       local stmt = self:query(sql, ...);\r
+       if stmt and stmt:affected() > 0 then return stmt; end\r
+end\r
+\r
+function driver:open(host, datastore, typ)\r
+       local cache_key = host.." "..datastore;\r
+       if self.ds_cache[cache_key] then return self.ds_cache[cache_key]; end\r
+       local instance = setmetatable({}, self);\r
+       instance.host = host;\r
+       instance.datastore = datastore;\r
+       local handler = handlers[datastore];\r
+       if not handler then return nil; end\r
+       for key,val in pairs(handler) do\r
+               instance[key] = val;\r
+       end\r
+       if instance.init then instance:init(); end\r
+       self.ds_cache[cache_key] = instance;\r
+       return instance;\r
+end\r
+\r
+-----------------------------\r
+local _M = {};\r
+\r
+function _M.new(dbtype, dbname, ...)\r
+       local instance = setmetatable({}, driver);\r
+       instance.__index = instance;\r
+       instance.database = get_database(dbtype, dbname, ...);\r
+       instance.ds_cache = {};\r
+       return instance;\r
+end\r
+\r
+return _M;\r
diff --git a/plugins/storage/mod_storage.lua b/plugins/storage/mod_storage.lua
new file mode 100644 (file)
index 0000000..e22de82
--- /dev/null
@@ -0,0 +1,83 @@
+
+module:set_global();
+
+local cache = { data = {} };
+function cache:get(key) return self.data[key]; end
+function cache:set(key, val) self.data[key] = val; return val; end
+
+local DBI = require "DBI";
+function get_database(driver, db, ...)
+       local uri = "dbi:"..driver..":"..db;
+       return cache:get(uri) or cache:set(uri, (function(...)
+               module:log("debug", "Opening database: %s", uri);
+               prosody.unlock_globals();
+               local dbh = assert(DBI.Connect(...));
+               prosody.lock_globals();
+               dbh:autocommit(true)
+               return dbh;
+       end)(driver, db, ...));
+end
+
+local st = require "util.stanza";
+local _parse_xml = module:require("xmlparse");
+parse_xml_real = _parse_xml;
+function parse_xml(str)
+       local s = _parse_xml(str);
+       if s and not s.gsub then
+               return st.preserialize(s);
+       end
+end
+function unparse_xml(s)
+       return tostring(st.deserialize(s));
+end
+
+local drivers = {};
+
+--local driver = module:require("sqlbasic").new("SQLite3", "hello.sqlite");
+local option_datastore = module:get_option("datastore");
+local option_datastore_params = module:get_option("datastore_params") or {};
+if option_datastore then
+       local driver = module:require(option_datastore).new(unpack(option_datastore_params));
+       table.insert(drivers, driver);
+end
+
+local datamanager = require "util.datamanager";
+local olddm = {};
+local dm = {};
+for key,val in pairs(datamanager) do olddm[key] = val; end
+
+do -- driver based on old datamanager
+       local dmd = {};
+       dmd.__index = dmd;
+       function dmd:open(host, datastore)
+               return setmetatable({ host = host, datastore = datastore }, dmd);
+       end
+       function dmd:get(user) return olddm.load(user, self.host, self.datastore); end
+       function dmd:set(user, data) return olddm.store(user, self.host, self.datastore, data); end
+       table.insert(drivers, dmd);
+end
+
+local function open(...)
+       for _,driver in pairs(drivers) do
+               local ds = driver:open(...);
+               if ds then return ds; end
+       end
+end
+
+local _data_path;
+--function dm.set_data_path(path) _data_path = path; end
+--function dm.add_callback(...) end
+--function dm.remove_callback(...) end
+--function dm.getpath(...) end
+function dm.load(username, host, datastore)
+       local x = open(host, datastore);
+       return x:get(username);
+end
+function dm.store(username, host, datastore, data)
+       return open(host, datastore):set(username, data);
+end
+--function dm.list_append(...) return driver:list_append(...); end
+--function dm.list_store(...) return driver:list_store(...); end
+--function dm.list_load(...) return driver:list_load(...); end
+
+for key,val in pairs(dm) do datamanager[key] = val; end
index 8f7d7140836f1ca030d08f33e728fefdc47bdb35..39737ae097bd505896063e115a59c4479f3d1578 100644 (file)
 
 #include <string.h>
 #include <stdlib.h>
+
+#ifdef _MSC_VER
+typedef unsigned __int32 uint32_t;
+#else
 #include <inttypes.h>
+#endif
 
 #include "lua.h"
 #include "lauxlib.h"