1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
local lfs = require "lfs";
local st = require "util.stanza";
local parse_xml = require "util.xml".parse;
local os_getenv = os.getenv;
local io_open = io.open;
local assert = assert;
local ipairs = ipairs;
local coroutine = coroutine;
local print = print;
module "jabberd14"
local function is_dir(path) return lfs.attributes(path, "mode") == "directory"; end
local function is_file(path) return lfs.attributes(path, "mode") == "file"; end
local function clean_path(path)
return path:gsub("\\", "/"):gsub("//+", "/"):gsub("^~", os_getenv("HOME") or "~");
end
local function load_xml(path)
local f, err = io_open(path);
if not f then return f, err; end
local data = f:read("*a");
f:close();
if not data then return; end
return parse_xml(data);
end
local function load_spool_file(host, filename, path)
local xml = load_xml(path);
if not xml then return; end
local register_element = xml:get_child("query", "jabber:iq:register");
local username_element = register_element and register_element:get_child("username", "jabber:iq:register");
local password_element = register_element and register_element:get_child("password", "jabber:iq:auth");
local username = username_element and username_element:get_text();
local password = password_element and password_element:get_text();
if not username then
print("[warn] Missing /xdb/{jabber:iq:register}register/username> in file "..filename)
return;
elseif username..".xml" ~= filename then
print("[warn] Missing /xdb/{jabber:iq:register}register/username does not match filename "..filename);
return;
end
local userdata = {
user = username;
host = host;
stores = {};
};
local stores = userdata.stores;
stores.accounts = { password = password };
for i=1,#xml.tags do
local tag = xml.tags[i];
local xname = (tag.attr.xmlns or "")..":"..tag.name;
if tag.attr.j_private_flag == "1" and tag.attr.xmlns then
-- Private XML
stores.private = stores.private or {};
tag.attr.j_private_flag = nil;
stores.private[tag.attr.xmlns] = st.preserialize(tag);
elseif xname == "jabber:iq:auth:password" then
if stores.accounts.password ~= tag:get_text() then
if password then
print("[warn] conflicting passwords")
else
stores.accounts.password = tag:get_text();
end
end
elseif xname == "jabber:iq:register:query" then
-- already processed
elseif xname == "jabber:xdb:nslist:foo" then
-- ignore
elseif xname == "jabber:iq:auth:0k:zerok" then
-- ignore
elseif xname == "jabber:iq:roster:query" then
-- Roster
local roster = {};
local subscription_types = { from = true, to = true, both = true, none = true };
for _,item_element in ipairs(tag.tags) do
assert(item_element.name == "item");
assert(item_element.attr.jid);
assert(subscription_types[item_element.attr.subscription]);
assert((item_element.attr.ask or "subscribe") == "subscribe")
if item_element.name == "item" then
local groups = {};
for _,group_element in ipairs(item_element.tags) do
assert(group_element.name == "group");
groups[group_element:get_text()] = true;
end
local item = {
name = item_element.attr.name;
subscription = item_element.attr.subscription;
ask = item_element.attr.ask;
groups = groups;
};
roster[item_element.attr.jid] = item;
end
end
stores.roster = roster;
elseif xname == "jabber:iq:last:query" then
-- Last activity
elseif xname == "jabber:x:offline:foo" then
-- Offline messages
elseif xname == "vcard-temp:vCard" then
-- vCards
stores.vcard = st.preserialize(tag);
else
print("[warn] Unknown tag: "..xname);
end
end
return userdata;
end
local function loop_over_users(path, host, cb)
for file in lfs.dir(path) do
if file:match("%.xml$") then
local user = load_spool_file(host, file, path.."/"..file);
if user then cb(user); end
end
end
end
local function loop_over_hosts(path, cb)
for host in lfs.dir(path) do
if host ~= "." and host ~= ".." and is_dir(path.."/"..host) then
loop_over_users(path.."/"..host, host, cb);
end
end
end
function reader(input)
local path = clean_path(assert(input.path, "no input.path specified"));
assert(is_dir(path), "input.path is not a directory");
if input.host then
return coroutine.wrap(function() loop_over_users(input.path, input.host, coroutine.yield) end);
else
return coroutine.wrap(function() loop_over_hosts(input.path, coroutine.yield) end);
end
end
return _M;
|