mod_adhoc: Add support for commands only executable by global administrators
[prosody.git] / util / datamanager.lua
index 3982a710fecb448e776424086239398d8926c0f6..d5e9c88ca7ad0130b879060950d579420edb65d1 100644 (file)
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -21,12 +21,14 @@ local next = next;
 local t_insert = table.insert;
 local append = require "util.serialization".append;
 local path_separator = "/"; if os.getenv("WINDIR") then path_separator = "\\" end
+local lfs = require "lfs";
+local prosody = prosody;
 local raw_mkdir;
 
 if prosody.platform == "posix" then
        raw_mkdir = require "util.pposix".mkdir; -- Doesn't trample on umask
 else
-       raw_mkdir = require "lfs".mkdir;
+       raw_mkdir = lfs.mkdir;
 end
 
 module "datamanager"
@@ -55,14 +57,12 @@ local function mkdir(path)
        return path;
 end
 
-local data_path = "data";
+local data_path = (prosody and prosody.paths and prosody.paths.data) or ".";
 local callbacks = {};
 
 ------- API -------------
 
-local _set_data_path;
 function set_data_path(path)
-       if _set_data_path then return _set_data_path(path); end
        log("debug", "Setting data path to: %s", path);
        data_path = path;
 end
@@ -75,18 +75,14 @@ local function callback(username, host, datastore, data)
        
        return username, host, datastore, data;
 end
-local _add_callback;
 function add_callback(func)
-       if _add_callback then return _add_callback(func); end
        if not callbacks[func] then -- Would you really want to set the same callback more than once?
                callbacks[func] = true;
                callbacks[#callbacks+1] = func;
                return true;
        end
 end
-local _remove_callback;
 function remove_callback(func)
-       if _remove_callback then return _remove_callback(func); end
        if callbacks[func] then
                for i, f in ipairs(callbacks) do
                        if f == func then
@@ -98,9 +94,7 @@ function remove_callback(func)
        end
 end
 
-local _getpath;
 function getpath(username, host, datastore, ext, create)
-       if _getpath then return _getpath(username, host, datastore, ext, create); end
        ext = ext or "dat";
        host = (host and encode(host)) or "_global";
        username = username and encode(username);
@@ -116,26 +110,29 @@ function getpath(username, host, datastore, ext, create)
        end
 end
 
-local _load;
 function load(username, host, datastore)
-       if _load then return _load(username, host, datastore); end
        local data, ret = loadfile(getpath(username, host, datastore));
        if not data then
-               log("debug", "Failed to load "..datastore.." storage ('"..ret.."') for user: "..(username or "nil").."@"..(host or "nil"));
-               return nil;
+               local mode = lfs.attributes(getpath(username, host, datastore), "mode");
+               if not mode then
+                       log("debug", "Assuming empty "..datastore.." storage ('"..ret.."') for user: "..(username or "nil").."@"..(host or "nil"));
+                       return nil;
+               else -- file exists, but can't be read
+                       -- TODO more detailed error checking and logging?
+                       log("error", "Failed to load "..datastore.." storage ('"..ret.."') for user: "..(username or "nil").."@"..(host or "nil"));
+                       return nil, "Error reading storage";
+               end
        end
        setfenv(data, {});
        local success, ret = pcall(data);
        if not success then
                log("error", "Unable to load "..datastore.." storage ('"..ret.."') for user: "..(username or "nil").."@"..(host or "nil"));
-               return nil;
+               return nil, "Error reading storage";
        end
        return ret;
 end
 
-local _store;
 function store(username, host, datastore, data)
-       if _store then return _store(username, host, datastore, data); end
        if not data then
                data = {};
        end
@@ -149,7 +146,7 @@ function store(username, host, datastore, data)
        local f, msg = io_open(getpath(username, host, datastore, nil, true), "w+");
        if not f then
                log("error", "Unable to write to "..datastore.." storage ('"..msg.."') for user: "..(username or "nil").."@"..(host or "nil"));
-               return;
+               return nil, "Error saving to storage";
        end
        f:write("return ");
        append(f, data);
@@ -163,9 +160,7 @@ function store(username, host, datastore, data)
        return true;
 end
 
-local _list_append;
 function list_append(username, host, datastore, data)
-       if _list_append then return _list_append(username, host, datastore, data); end
        if not data then return; end
        if callback(username, host, datastore) == false then return true; end
        -- save the datastore
@@ -181,9 +176,7 @@ function list_append(username, host, datastore, data)
        return true;
 end
 
-local _list_store;
 function list_store(username, host, datastore, data)
-       if _list_store then return _list_store(username, host, datastore, data); end
        if not data then
                data = {};
        end
@@ -209,47 +202,27 @@ function list_store(username, host, datastore, data)
        return true;
 end
 
-local _list_load;
 function list_load(username, host, datastore)
-       if _list_load then return _list_load(username, host, datastore); end
        local data, ret = loadfile(getpath(username, host, datastore, "list"));
        if not data then
-               log("debug", "Failed to load "..datastore.." storage ('"..ret.."') for user: "..(username or "nil").."@"..(host or "nil"));
-               return nil;
+               local mode = lfs.attributes(getpath(username, host, datastore, "list"), "mode");
+               if not mode then
+                       log("debug", "Assuming empty "..datastore.." storage ('"..ret.."') for user: "..(username or "nil").."@"..(host or "nil"));
+                       return nil;
+               else -- file exists, but can't be read
+                       -- TODO more detailed error checking and logging?
+                       log("error", "Failed to load "..datastore.." storage ('"..ret.."') for user: "..(username or "nil").."@"..(host or "nil"));
+                       return nil, "Error reading storage";
+               end
        end
        local items = {};
        setfenv(data, {item = function(i) t_insert(items, i); end});
        local success, ret = pcall(data);
        if not success then
                log("error", "Unable to load "..datastore.." storage ('"..ret.."') for user: "..(username or "nil").."@"..(host or "nil"));
-               return nil;
+               return nil, "Error reading storage";
        end
        return items;
 end
 
-function set(t)
-       _set_data_path = t.set_data_path;
-       _add_callback = t.add_callback;
-       _remove_callback = t.remove_callback;
-       _getpath = t.getpath;
-       _load = t.load;
-       _store = t.store;
-       _list_append = t.list_append;
-       _list_store = t.list_store;
-       _list_load = t.list_load;
-end
-function get()
-       return {
-               set_data_path = _set_data_path;
-               add_callback = _add_callback;
-               remove_callback = _remove_callback;
-               getpath = _getpath;
-               load = _load;
-               store = _store;
-               list_append = _list_append;
-               list_store = _list_store;
-               list_load = _list_load;
-       };
-end
-
 return _M;