Merge 0.10->trunk
[prosody.git] / tools / openfire2prosody.lua
1 #!/usr/bin/env lua
2 -- Prosody IM
3 -- Copyright (C) 2008-2009 Waqas Hussain
4 --
5 -- This project is MIT/X11 licensed. Please see the
6 -- COPYING file in the source package for more information.
7 --
8
9 package.path = package.path..";../?.lua";
10 package.cpath = package.cpath..";../?.so"; -- needed for util.pposix used in datamanager
11
12 local my_name = arg[0];
13 if my_name:match("[/\\]") then
14         package.path = package.path..";"..my_name:gsub("[^/\\]+$", "../?.lua");
15         package.cpath = package.cpath..";"..my_name:gsub("[^/\\]+$", "../?.so");
16 end
17
18 -- ugly workaround for getting datamanager to work outside of prosody :(
19 prosody = { };
20 prosody.platform = "unknown";
21 if os.getenv("WINDIR") then
22         prosody.platform = "windows";
23 elseif package.config:sub(1,1) == "/" then
24         prosody.platform = "posix";
25 end
26
27 local parse_xml = require "util.xml".parse;
28
29 -----------------------------------------------------------------------
30
31 package.loaded["util.logger"] = {init = function() return function() end; end}
32 local dm = require "util.datamanager"
33 dm.set_data_path("data");
34
35 local arg = ...;
36 local help = "/? -? ? /h -h /help -help --help";
37 if not arg or help:find(arg, 1, true) then
38         print([[Openfire importer for Prosody
39
40   Usage: openfire2prosody.lua filename.xml hostname
41
42 ]]);
43         os.exit(1);
44 end
45
46 local host = select(2, ...) or "localhost";
47
48 local file = assert(io.open(arg));
49 local data = assert(file:read("*a"));
50 file:close();
51
52 local xml = assert(parse_xml(data));
53
54 assert(xml.name == "Openfire", "The input file is not an Openfire XML export");
55
56 local substatus_mapping = { ["0"] = "none", ["1"] = "to", ["2"] = "from", ["3"] = "both" };
57
58 for _,tag in ipairs(xml.tags) do
59         if tag.name == "User" then
60                 local username, password, roster;
61
62                 for _,tag in ipairs(tag.tags) do
63                         if tag.name == "Username" then
64                                 username = tag:get_text();
65                         elseif tag.name == "Password" then
66                                 password = tag:get_text();
67                         elseif tag.name == "Roster" then
68                                 roster = {};
69                                 local pending = {};
70                                 for _,tag in ipairs(tag.tags) do
71                                         if tag.name == "Item" then
72                                                 local jid = assert(tag.attr.jid, "Roster item has no JID");
73                                                 if tag.attr.substatus ~= "-1" then
74                                                         local item = {};
75                                                         item.name = tag.attr.name;
76                                                         item.subscription = assert(substatus_mapping[tag.attr.substatus], "invalid substatus");
77                                                         item.ask = tag.attr.askstatus == "0" and "subscribe" or nil;
78
79                                                         local groups = {};
80                                                         for _,tag in ipairs(tag) do
81                                                                 if tag.name == "Group" then
82                                                                         groups[tag:get_text()] = true;
83                                                                 end
84                                                         end
85                                                         item.groups = groups;
86                                                         roster[jid] = item;
87                                                 end
88                                                 if tag.attr.recvstatus == "1" then pending[jid] = true; end
89                                         end
90                                 end
91
92                                 if next(pending) then
93                                         roster[false] = { pending = pending };
94                                 end
95                         end
96                 end
97
98                 assert(username and password, "No username or password");
99
100                 local ret, err = dm.store(username, host, "accounts", {password = password});
101                 print("["..(err or "success").."] stored account: "..username.."@"..host.." = "..password);
102
103                 if roster then
104                         local ret, err = dm.store(username, host, "roster", roster);
105                         print("["..(err or "success").."] stored roster: "..username.."@"..host.." = "..password);
106                 end
107         end
108 end
109