-- Prosody IM
-- 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.
--
local setmetatable, type = setmetatable, type;
local pairs, ipairs = pairs, ipairs;
local char = string.char;
-local loadfile, setfenv, pcall = loadfile, setfenv, pcall;
+local pcall = pcall;
local log = require "util.logger".init("datamanager");
local io_open = io.open;
local os_remove = os.remove;
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 envloadfile = require"util.envload".envloadfile;
+local path_separator = assert ( package.config:match ( "^([^\n]+)" ) , "package.config not in standard form" ) -- Extract directory seperator from package.config (an undocumented string that comes with lua)
local lfs = require "lfs";
+local prosody = prosody;
local raw_mkdir;
if prosody.platform == "posix" then
return path;
end
-local data_path = "data";
+local data_path = (prosody and prosody.paths and prosody.paths.data) or ".";
local callbacks = {};
------- API -------------
username, host, datastore, data = f(username, host, datastore, data);
if username == false then break; end
end
-
+
return username, host, datastore, data;
end
function add_callback(func)
end
function load(username, host, datastore)
- local data, ret = loadfile(getpath(username, host, datastore));
+ local data, ret = envloadfile(getpath(username, host, datastore), {});
if not data then
local mode = lfs.attributes(getpath(username, host, datastore), "mode");
if not mode then
- log("debug", "Failed to load "..datastore.." storage ('"..ret.."') for user: "..(username or "nil").."@"..(host or "nil"));
+ log("debug", "Assuming empty %s storage ('%s') for user: %s@%s", datastore, ret, 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"));
+ log("error", "Failed to load %s storage ('%s') for user: %s@%s", datastore, ret, 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"));
+ log("error", "Unable to load %s storage ('%s') for user: %s@%s", datastore, ret, username or "nil", host or "nil");
return nil, "Error reading storage";
end
return ret;
-- save the datastore
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"));
+ log("error", "Unable to write to %s storage ('%s') for user: %s@%s", datastore, msg, username or "nil", host or "nil");
return nil, "Error saving to storage";
end
f:write("return ");
-- save the datastore
local f, msg = io_open(getpath(username, host, datastore, "list", true), "a+");
if not f then
- log("error", "Unable to write to "..datastore.." storage ('"..msg.."') for user: "..(username or "nil").."@"..(host or "nil"));
+ log("error", "Unable to write to %s storage ('%s') for user: %s@%s", datastore, msg, username or "nil", host or "nil");
return;
end
f:write("item(");
-- save the datastore
local f, msg = io_open(getpath(username, host, datastore, "list", true), "w+");
if not f then
- log("error", "Unable to write to "..datastore.." storage ('"..msg.."') for user: "..(username or "nil").."@"..(host or "nil"));
+ log("error", "Unable to write to %s storage ('%s') for user: %s@%s", datastore, msg, username or "nil", host or "nil");
return;
end
for _, d in ipairs(data) do
end
function list_load(username, host, datastore)
- local data, ret = loadfile(getpath(username, host, datastore, "list"));
+ local items = {};
+ local data, ret = envloadfile(getpath(username, host, datastore, "list"), {item = function(i) t_insert(items, i); end});
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 %s storage ('%s') for user: %s@%s", datastore, ret, 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 %s storage ('%s') for user: %s@%s", datastore, ret, 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;
+ log("error", "Unable to load %s storage ('%s') for user: %s@%s", datastore, ret, username or "nil", host or "nil");
+ return nil, "Error reading storage";
end
return items;
end
+function list_stores(username, host)
+ if not host then
+ return nil, "bad argument #2 to 'list_stores' (string expected, got nothing)";
+ end
+ local list = {};
+ local host_dir = format("%s/%s/", data_path, encode(host));
+ for node in lfs.dir(host_dir) do
+ if not node:match"^%." then -- dots should be encoded, this is probably . or ..
+ local store = decode(node);
+ local path = host_dir..node;
+ if username == true then
+ if lfs.attributes(path, "mode") == "directory" then
+ list[#list+1] = store;
+ end
+ elseif username then
+ if lfs.attributes(getpath(username, host, store), "mode")
+ or lfs.attributes(getpath(username, host, store, "list"), "mode") then
+ list[#list+1] = store;
+ end
+ elseif lfs.attributes(path, "mode") == "file" then
+ list[#list+1] = store:gsub("%.[dalist]+$","");
+ end
+ end
+ end
+ return list;
+end
+
return _M;