Last active
November 16, 2017 20:54
-
-
Save bseibold/5041603 to your computer and use it in GitHub Desktop.
Export Prosody data to XEP-0227 / XEP 227 / PIEFXIS format
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env lua | |
-- | |
-- (c) 2013 Bernhard Seibold | |
-- License: MIT/X11 | |
-- | |
-- Disclaimer: | |
-- =========== | |
-- | |
-- This is a quick and *DIRTY* hack to export Prosody data to XEP-0227 format. | |
-- Use at own risk. | |
-- | |
-- I'm not a Lua programmer, so please excuse the fugly code. | |
-- | |
-- Issues: | |
-- ======= | |
-- | |
-- * Only works with Lua 5.1 | |
-- * Exporting offline message is not supported yet | |
-- * There are probably lots of xml_escape calls missing and other encoding issues | |
-- * util.stanza failed when exporting private storage containing an empty table as xmlns. | |
-- The following patch was used, to be applied at around line 200 in function _dostring: | |
-- elseif not(k == "xmlns" and v == parentns) then | |
-- if type(v) == "table" and #v == 0 then | |
-- t_insert(buf, " "..k.."=''"); | |
-- else | |
-- t_insert(buf, " "..k.."='"..xml_escape(v).."'"); | |
-- end | |
-- end | |
-- | |
-- Usage: | |
-- ====== | |
-- | |
-- cd /var/lib/prosody | |
-- lua prosody_to_xep227 yourhost.com >yourhost_com.xml | |
-- | |
package.path = package.path..";/usr/lib/prosody/?.lua"; | |
package.cpath = package.cpath..";/usr/lib/prosody/?.so"; | |
prosody = { }; | |
prosody.platform = "unknown"; | |
if os.getenv("WINDIR") then | |
prosody.platform = "windows"; | |
elseif package.config:sub(1,1) == "/" then | |
prosody.platform = "posix"; | |
end | |
local lxp = require "lxp"; | |
local st = require "util.stanza"; | |
local xmppstream = require "util.xmppstream"; | |
local new_xmpp_handlers = xmppstream.new_sax_handlers; | |
local dm = require "util.datamanager" | |
dm.set_data_path("."); | |
local ns_separator = xmppstream.ns_separator; | |
local ns_pattern = xmppstream.ns_pattern; | |
local format = string.format; | |
local lfs = require "lfs"; | |
function xml_escape(str) | |
local escape_table = { ["'"] = "'", ["\""] = """, ["<"] = "<", [">"] = ">", ["&"] = "&" }; | |
return (string.gsub(str, "['&<>\"]", escape_table)); | |
end | |
function decode(str) | |
str = string.gsub (str, "+", " ") | |
str = string.gsub (str, "%%(%x%x)", function(h) return string.char(tonumber(h,16)) end) | |
str = string.gsub (str, "\r\n", "\n") | |
return str | |
end | |
function encode(s) | |
return s and (s:gsub("%W", function (c) return format("%%%02x", c:byte()); end)); | |
end | |
function print_offline(host, user) | |
local items = {}; | |
local file = format("%s/offline/%s.list", encode(host), user); | |
if err then return end | |
local item = function(i) t_insert(items, i); end; | |
local env = {item}; | |
if not lfs.attributes(file) then return end | |
x = loadfile(file, nil, {item = function(i) t_insert(items, i); end}); | |
local success, ret = pcall(x); | |
if not success then | |
print("ERR loading offline") | |
-- return | |
end | |
print("<offline-messages>"); | |
for _, stanza in ipairs(items) do | |
stanza = st.deserialize(stanza); | |
for k,v in pairs(stanza) do | |
print('K=',k,'V=',v); | |
end | |
end | |
print("</offline-messages>"); | |
end | |
function print_vcard(host, user) | |
local file = format("%s/vcard/%s.dat", encode(host), user); | |
local success, vcard = pcall(loadfile(file)); | |
if not success then | |
return | |
end | |
print(st.deserialize(vcard)); | |
end | |
function print_privacy(host, user) | |
local file = format("%s/privacy/%s.dat", encode(host), user); | |
local success, privacy = pcall(loadfile(file)); | |
if not success then | |
return | |
end | |
print("<query xmlns='jabber:iq:privacy'>"); | |
for k, v in pairs(privacy) do | |
if k == 'default' then | |
print(format("<default name='%s'/>", v)); | |
elseif k == 'lists' then | |
for _, data in pairs(v) do | |
print(format("<list name='%s'>", xml_escape(data['name']))); | |
for _,item in pairs(data['items']) do | |
print("<item"); | |
if item['type'] then print(format("type='%s'", item['type'])) end | |
if item['action'] then print(format("action='%s'", item['action'])) end | |
if item['value'] then print(format("value='%s'", item['value'])) end | |
if item['order'] then print(format("order='%d'", item['order'])) end | |
print(">"); | |
if item['message'] then print("<message/>") end | |
if item['presence-in'] then print("<presence-in/>") end | |
if item['presence-out'] then print("<presence-out/>") end | |
if item['iq'] then print("<iq/>") end | |
print("</item>"); | |
end | |
print("</list>"); | |
end | |
end | |
end | |
print("</query>"); | |
end | |
function print_private(host, user) | |
local file = format("%s/private/%s.dat", encode(host), user); | |
local success, private = pcall(loadfile(file)); | |
if not success then | |
return | |
end | |
print("<query xmlns='jabber:iq:private'>"); | |
for name, data in pairs(private) do | |
if type(data) == 'table' then | |
print(st.deserialize(data)); | |
end | |
end | |
print("</query>"); | |
end | |
function print_roster(host, user) | |
local file = format("%s/roster/%s.dat", encode(host), user); | |
local success, roster = pcall(loadfile(file)); | |
if not success then | |
return | |
end | |
print("<query xmlns='jabber:iq:roster'>"); | |
for jid, data in pairs(roster) do | |
if jid == false then | |
elseif jid == 'pending' then | |
else | |
print(format("<item jid='%s' name='%s' subscription='%s'>", jid, xml_escape(data['name'] or ''), data['subscription'])); | |
for group,ignore in pairs(data['groups']) do | |
print(format("<group>%s</group>", xml_escape(group))); | |
end | |
print("</item>"); | |
end | |
end | |
print("</query>"); | |
for jid, data in pairs(roster) do | |
if jid == 'pending' then | |
for k,v in pairs(data) do | |
print(format("<presence xmlns='jabber:client' type='subscribe' from='%s'/>", xml_escape(k))); | |
end | |
end | |
end | |
end | |
function print_host(host) | |
print("<?xml version='1.0' encoding='UTF-8'?>"); | |
print("<server-data xmlns='urn:xmpp:pie:0'>"); | |
print(format("<host jid='%s'>", host)); | |
ddir = format("%s/accounts/", encode(host)) | |
for file in lfs.dir(ddir) do | |
if lfs.attributes(ddir..file, "mode") == "file" then | |
local base, ext = file:match("^(.*)%.([dalist]+)$"); | |
if ext == 'dat' then | |
local data, ret = loadfile(ddir..file, {}); | |
local success, ret = pcall(data); | |
print(format("<user name='%s' password='%s'>", decode(base), ret['password'])); | |
print_roster(host, base); | |
print_private(host, base); | |
print_privacy(host, base); | |
--print_offline(host, base); | |
print_vcard(host, base); | |
print("</user>"); | |
end | |
end | |
end | |
print("</host>"); | |
print("</server-data>"); | |
end | |
print_host(arg[1]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment