Merge 0.10->trunk
[prosody.git] / tools / ejabberd2prosody.lua
index 0a6736d782b11e52389a25cc4fd26dea21ef3301..46a48f57fca2f8acf1d5556ee35ce76cf0c95240 100755 (executable)
@@ -30,7 +30,7 @@ dm.set_data_path("data");
 
 function build_stanza(tuple, stanza)
        assert(type(tuple) == "table", "XML node is of unexpected type: "..type(tuple));
-       if tuple[1] == "xmlelement" then
+       if tuple[1] == "xmlelement" or tuple[1] == "xmlel" then
                assert(type(tuple[2]) == "string", "element name has type: "..type(tuple[2]));
                assert(type(tuple[3]) == "table", "element attribute array has type: "..type(tuple[3]));
                assert(type(tuple[4]) == "table", "element children array has type: "..type(tuple[4]));
@@ -44,8 +44,10 @@ function build_stanza(tuple, stanza)
                for _, a in ipairs(tuple[4]) do build_stanza(a, stanza); end
                if up then stanza:up(); else return stanza end
        elseif tuple[1] == "xmlcdata" then
-               assert(type(tuple[2]) == "string", "XML CDATA has unexpected type: "..type(tuple[2]));
-               stanza:text(tuple[2]);
+               if type(tuple[2]) ~= "table" then
+                       assert(type(tuple[2]) == "string", "XML CDATA has unexpected type: "..type(tuple[2]));
+                       stanza:text(tuple[2]);
+               end -- else it's [], i.e., the null value, used for the empty string
        else
                error("unknown element type: "..serialize(tuple));
        end
@@ -54,13 +56,38 @@ function build_time(tuple)
        local Megaseconds,Seconds,Microseconds = unpack(tuple);
        return Megaseconds * 1000000 + Seconds;
 end
+function build_jid(tuple, full)
+       local node, jid, resource = tuple[1], tuple[2], tuple[3]
+       if type(node) == "string" and node ~= "" then
+               jid = tuple[1] .. "@" .. jid;
+       end
+       if full and type(resource) == "string" and resource ~= "" then
+               jid = jid .. "/" .. resource;
+       end
+       return jid;
+end
 
 function vcard(node, host, stanza)
        local ret, err = dm.store(node, host, "vcard", st.preserialize(stanza));
        print("["..(err or "success").."] vCard: "..node.."@"..host);
 end
 function password(node, host, password)
-       local ret, err = dm.store(node, host, "accounts", {password = password});
+       local data = {};
+       if type(password) == "string" then
+               data.password = password;
+       elseif type(password) == "table" and password[1] == "scram" then
+               local unb64 = require"mime".unb64;
+               local function hex(s)
+                       return s:gsub(".", function (c)
+                               return ("%02x"):format(c:byte());
+                       end);
+               end
+               data.stored_key = hex(unb64(password[2]));
+               data.server_key = hex(unb64(password[3]));
+               data.salt = unb64(password[4]);
+               data.iteration_count = password[5];
+       end
+       local ret, err = dm.store(node, host, "accounts", data);
        print("["..(err or "success").."] accounts: "..node.."@"..host);
 end
 function roster(node, host, jid, item)
@@ -103,10 +130,7 @@ function privacy(node, host, default, lists)
                                if _type == "jid" then
                                        if type(value) ~= "table" then print("[error] privacy: jid value is not valid: "..tostring(value)); break; end
                                        local _node, _host, _resource = value[1], value[2], value[3];
-                                       if (type(_node) == "table") then _node = nil; end
-                                       if (type(_host) == "table") then _host = nil; end
-                                       if (type(_resource) == "table") then _resource = nil; end
-                                       value = (_node and _node.."@".._host or _host)..(_resource and "/".._resource or "");
+                                       value = build_jid(value, true)
                                elseif _type == "none" then
                                        _type = nil;
                                        value = nil;
@@ -152,6 +176,40 @@ function privacy(node, host, default, lists)
        local ret, err = dm.store(node, host, "privacy", privacy);
        print("["..(err or "success").."] privacy: " ..node.."@"..host.." - "..count.." list(s)");
 end
+function muc_room(node, host, properties)
+       local store = { jid = node.."@"..host, _data = {}, _affiliations = {} };
+       for _,aff in ipairs(properties.affiliations) do
+               store._affiliations[build_jid(aff[1])] = aff[2][1] or aff[2];
+       end
+       store._data.subject = properties.subject;
+       if properties.subject_author then
+               store._data.subject_from = store.jid .. "/" .. properties.subject_author;
+       end
+       store._data.name = properties.title;
+       store._data.description = properties.description;
+       store._data.password = properties.password;
+       store._data.moderated = (properties.moderated == "true") or nil;
+       store._data.members_only = (properties.members_only == "true") or nil;
+       store._data.persistent = (properties.persistent == "true") or nil;
+       store._data.changesubject = (properties.allow_change_subj == "true") or nil;
+       store._data.whois = properties.anonymous == "true" and "moderators" or "anyone";
+       store._data.hidden = (properties.public_list == "false") or nil;
+
+       if not store._data.persistent then
+               return print("[error] muc_room: skipping non-persistent room: "..node.."@"..host);
+       end
+
+       local ret, err = dm.store(node, host, "config", store);
+       if ret then
+               ret, err = dm.load(nil, host, "persistent");
+               if ret or not err then
+                       ret = ret or {};
+                       ret[store.jid] = true;
+                       ret, err = dm.store(nil, host, "persistent", ret);
+               end
+       end
+       print("["..(err or "success").."] muc_room: " ..node.."@"..host);
+end
 
 
 local filters = {
@@ -163,7 +221,7 @@ local filters = {
        end;
        roster = function(tuple)
                local node = tuple[3][1]; local host = tuple[3][2];
-               local contact = (type(tuple[4][1]) == "table") and tuple[4][2] or tuple[4][1].."@"..tuple[4][2];
+               local contact = build_jid(tuple[4]);
                local name = tuple[5]; local subscription = tuple[6];
                local ask = tuple[7]; local groups = tuple[8];
                if type(name) ~= type("") then name = nil; end
@@ -196,7 +254,16 @@ local filters = {
        privacy = function(tuple)
                privacy(tuple[2][1], tuple[2][2], tuple[3], tuple[4]);
        end;
-       config = function(tuple)
+       muc_room = function(tuple)
+               local properties = {};
+               for _,pair in ipairs(tuple[3]) do
+                       if not(type(pair[2]) == "table" and #pair[2] == 0) then -- skip nil values
+                               properties[pair[1]] = pair[2];
+                       end
+               end
+               muc_room(tuple[2][1], tuple[2][2], properties);
+       end;
+       --[=[config = function(tuple)
                if tuple[2] == "hosts" then
                        local output = io.output(); io.output("prosody.cfg.lua");
                        io.write("-- Configuration imported from ejabberd --\n");
@@ -224,7 +291,7 @@ local filters = {
                        io.output(output);
                        print("prosody.cfg.lua created");
                end
-       end;
+       end;]=]
 };
 
 local arg = ...;