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