mod_storage_xep0227: Use configured storage path
[prosody.git] / plugins / mod_storage_xep0227.lua
1
2 local ipairs, pairs = ipairs, pairs;
3 local setmetatable = setmetatable;
4 local tostring = tostring;
5 local next = next;
6 local t_remove = table.remove;
7 local os_remove = os.remove;
8 local io_open = io.open;
9
10 local paths = require"util.paths";
11 local st = require "util.stanza";
12 local parse_xml_real = require "util.xml".parse;
13
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");
20         return parse_xml_real(s);
21 end
22 local function setXml(user, host, xml)
23         local jid = user.."@"..host;
24         local path = paths.join(prosody.paths.data, jid..".xml");
25         if xml then
26                 local f = io_open(path, "w");
27                 if not f then return; end
28                 local s = tostring(xml);
29                 f:write(s);
30                 f:close();
31                 return true;
32         else
33                 return os_remove(path);
34         end
35 end
36 local function getUserElement(xml)
37         if xml and xml.name == "server-data" then
38                 local host = xml.tags[1];
39                 if host and host.name == "host" then
40                         local user = host.tags[1];
41                         if user and user.name == "user" then
42                                 return user;
43                         end
44                 end
45         end
46 end
47 local function createOuterXml(user, host)
48         return st.stanza("server-data", {xmlns='http://www.xmpp.org/extensions/xep-0227.html#ns'})
49                 :tag("host", {jid=host})
50                         :tag("user", {name = user});
51 end
52 local function removeFromArray(array, value)
53         for i,item in ipairs(array) do
54                 if item == value then
55                         t_remove(array, i);
56                         return;
57                 end
58         end
59 end
60 local function removeStanzaChild(s, child)
61         removeFromArray(s.tags, child);
62         removeFromArray(s, child);
63 end
64
65 local handlers = {};
66
67 handlers.accounts = {
68         get = function(self, user)
69                 local user = getUserElement(getXml(user, self.host));
70                 if user and user.attr.password then
71                         return { password = user.attr.password };
72                 end
73         end;
74         set = function(self, user, data)
75                 if data and data.password then
76                         local xml = getXml(user, self.host);
77                         if not xml then xml = createOuterXml(user, self.host); end
78                         local usere = getUserElement(xml);
79                         usere.attr.password = data.password;
80                         return setXml(user, self.host, xml);
81                 else
82                         return setXml(user, self.host, nil);
83                 end
84         end;
85 };
86 handlers.vcard = {
87         get = function(self, user)
88                 local user = getUserElement(getXml(user, self.host));
89                 if user then
90                         local vcard = user:get_child("vCard", 'vcard-temp');
91                         if vcard then
92                                 return st.preserialize(vcard);
93                         end
94                 end
95         end;
96         set = function(self, user, data)
97                 local xml = getXml(user, self.host);
98                 local usere = xml and getUserElement(xml);
99                 if usere then
100                         local vcard = usere:get_child("vCard", 'vcard-temp');
101                         if vcard then
102                                 removeStanzaChild(usere, vcard);
103                         elseif not data then
104                                 return true;
105                         end
106                         if data then
107                                 vcard = st.deserialize(data);
108                                 usere:add_child(vcard);
109                         end
110                         return setXml(user, self.host, xml);
111                 end
112                 return true;
113         end;
114 };
115 handlers.private = {
116         get = function(self, user)
117                 local user = getUserElement(getXml(user, self.host));
118                 if user then
119                         local private = user:get_child("query", "jabber:iq:private");
120                         if private then
121                                 local r = {};
122                                 for _, tag in ipairs(private.tags) do
123                                         r[tag.name..":"..tag.attr.xmlns] = st.preserialize(tag);
124                                 end
125                                 return r;
126                         end
127                 end
128         end;
129         set = function(self, user, data)
130                 local xml = getXml(user, self.host);
131                 local usere = xml and getUserElement(xml);
132                 if usere then
133                         local private = usere:get_child("query", 'jabber:iq:private');
134                         if private then removeStanzaChild(usere, private); end
135                         if data and next(data) ~= nil then
136                                 private = st.stanza("query", {xmlns='jabber:iq:private'});
137                                 for _,tag in pairs(data) do
138                                         private:add_child(st.deserialize(tag));
139                                 end
140                                 usere:add_child(private);
141                         end
142                         return setXml(user, self.host, xml);
143                 end
144                 return true;
145         end;
146 };
147
148 -----------------------------
149 local driver = {};
150
151 function driver:open(host, datastore, typ)
152         local instance = setmetatable({}, self);
153         instance.host = host;
154         instance.datastore = datastore;
155         local handler = handlers[datastore];
156         if not handler then return nil; end
157         for key,val in pairs(handler) do
158                 instance[key] = val;
159         end
160         if instance.init then instance:init(); end
161         return instance;
162 end
163
164 module:provides("storage", driver);