2 local ipairs, pairs = ipairs, pairs;
3 local setmetatable = setmetatable;
4 local tostring = tostring;
6 local t_remove = table.remove;
7 local os_remove = os.remove;
8 local io_open = io.open;
10 local paths = require"util.paths";
11 local st = require "util.stanza";
12 local parse_xml_real = require "util.xml".parse;
14 local function getXml(user, host)
15 local jid = user.."@"..host;
16 local path = paths.join(prosody.paths.data, jid..".xml");
17 local f = io_open(path);
18 if not f then return; end
19 local s = f:read("*a");
21 return parse_xml_real(s);
23 local function setXml(user, host, xml)
24 local jid = user.."@"..host;
25 local path = paths.join(prosody.paths.data, jid..".xml");
26 local f, err = io_open(path, "w");
27 if not f then return f, err; end
29 local s = tostring(xml);
35 return os_remove(path);
38 local function getUserElement(xml)
39 if xml and xml.name == "server-data" then
40 local host = xml.tags[1];
41 if host and host.name == "host" then
42 local user = host.tags[1];
43 if user and user.name == "user" then
49 local function createOuterXml(user, host)
50 return st.stanza("server-data", {xmlns='urn:xmpp:pie:0'})
51 :tag("host", {jid=host})
52 :tag("user", {name = user});
54 local function removeFromArray(array, value)
55 for i,item in ipairs(array) do
62 local function removeStanzaChild(s, child)
63 removeFromArray(s.tags, child);
64 removeFromArray(s, child);
69 -- In order to support mod_auth_internal_hashed
70 local extended = "http://prosody.im/protocol/extended-xep0227\1";
73 get = function(self, user)
74 user = getUserElement(getXml(user, self.host));
75 if user and user.attr.password then
76 return { password = user.attr.password };
79 for k, v in pairs(user.attr) do
80 if k:sub(1, #extended) == extended then
81 data[k:sub(#extended+1)] = v;
87 set = function(self, user, data)
89 local xml = getXml(user, self.host);
90 if not xml then xml = createOuterXml(user, self.host); end
91 local usere = getUserElement(xml);
92 for k, v in pairs(data) do
93 if k == "password" then
94 usere.attr.password = v;
96 usere.attr[extended..k] = v;
99 return setXml(user, self.host, xml);
101 return setXml(user, self.host, nil);
106 get = function(self, user)
107 user = getUserElement(getXml(user, self.host));
109 local vcard = user:get_child("vCard", 'vcard-temp');
111 return st.preserialize(vcard);
115 set = function(self, user, data)
116 local xml = getXml(user, self.host);
117 local usere = xml and getUserElement(xml);
119 local vcard = usere:get_child("vCard", 'vcard-temp');
121 removeStanzaChild(usere, vcard);
126 vcard = st.deserialize(data);
127 usere:add_child(vcard);
129 return setXml(user, self.host, xml);
135 get = function(self, user)
136 user = getUserElement(getXml(user, self.host));
138 local private = user:get_child("query", "jabber:iq:private");
141 for _, tag in ipairs(private.tags) do
142 r[tag.name..":"..tag.attr.xmlns] = st.preserialize(tag);
148 set = function(self, user, data)
149 local xml = getXml(user, self.host);
150 local usere = xml and getUserElement(xml);
152 local private = usere:get_child("query", 'jabber:iq:private');
153 if private then removeStanzaChild(usere, private); end
154 if data and next(data) ~= nil then
155 private = st.stanza("query", {xmlns='jabber:iq:private'});
156 for _,tag in pairs(data) do
157 private:add_child(st.deserialize(tag));
159 usere:add_child(private);
161 return setXml(user, self.host, xml);
167 -----------------------------
170 function driver:open(datastore, typ)
171 local handler = handlers[datastore];
172 if not handler then return nil, "unsupported-datastore"; end
173 local instance = setmetatable({ host = module.host; datastore = datastore; }, { __index = handler });
174 if instance.init then instance:init(); end
178 module:provides("storage", driver);