mirror of
https://github.com/moparisthebest/mod_xxxx
synced 2024-12-21 23:18:56 -05:00
215 lines
5.4 KiB
Lua
215 lines
5.4 KiB
Lua
local verse = require "verse";
|
|
local base64 = require "util.encodings".base64;
|
|
local uuid_generate = require "util.uuid".generate;
|
|
|
|
local xmlns_jingle_ibb = "urn:xmpp:jingle:transports:ibb:1";
|
|
local xmlns_ibb = "http://jabber.org/protocol/ibb";
|
|
assert(base64.encode("This is a test.") == "VGhpcyBpcyBhIHRlc3Qu", "Base64 encoding failed");
|
|
assert(base64.decode("VGhpcyBpcyBhIHRlc3Qu") == "This is a test.", "Base64 decoding failed");
|
|
local t_concat = table.concat
|
|
|
|
local ibb_conn = {};
|
|
local ibb_conn_mt = { __index = ibb_conn };
|
|
|
|
local function new_ibb(stream)
|
|
local conn = setmetatable({ stream = stream }, ibb_conn_mt)
|
|
conn = verse.eventable(conn);
|
|
return conn;
|
|
end
|
|
|
|
function ibb_conn:initiate(peer, sid, stanza)
|
|
self.block = 2048; -- ignored for now
|
|
self.stanza = stanza or 'iq';
|
|
self.peer = peer;
|
|
self.sid = sid or tostring(self):match("%x+$");
|
|
self.iseq = 0;
|
|
self.oseq = 0;
|
|
local feeder = function(stanza)
|
|
return self:feed(stanza)
|
|
end
|
|
self.feeder = feeder;
|
|
print("Hooking incomming IQs");
|
|
local stream = self.stream;
|
|
stream:hook("iq/".. xmlns_ibb, feeder)
|
|
if stanza == "message" then
|
|
stream:hook("message", feeder)
|
|
end
|
|
end
|
|
|
|
function ibb_conn:open(callback)
|
|
self.stream:send_iq(verse.iq{ to = self.peer, type = "set" }
|
|
:tag("open", {
|
|
xmlns = xmlns_ibb,
|
|
["block-size"] = self.block,
|
|
sid = self.sid,
|
|
stanza = self.stanza
|
|
})
|
|
, function(reply)
|
|
if callback then
|
|
if reply.attr.type ~= "error" then
|
|
callback(true)
|
|
else
|
|
callback(false, reply:get_error())
|
|
end
|
|
end
|
|
end);
|
|
end
|
|
|
|
function ibb_conn:send(data)
|
|
local stanza = self.stanza;
|
|
local st;
|
|
if stanza == "iq" then
|
|
st = verse.iq{ type = "set", to = self.peer }
|
|
elseif stanza == "message" then
|
|
st = verse.message{ to = self.peer }
|
|
end
|
|
|
|
local seq = self.oseq;
|
|
self.oseq = seq + 1;
|
|
|
|
st:tag("data", { xmlns = xmlns_ibb, sid = self.sid, seq = seq })
|
|
:text(base64.encode(data));
|
|
|
|
if stanza == "iq" then
|
|
self.stream:send_iq(st, function(reply)
|
|
self:event(reply.attr.type == "result" and "drained" or "error");
|
|
end)
|
|
else
|
|
stream:send(st)
|
|
self:event("drained");
|
|
end
|
|
end
|
|
|
|
function ibb_conn:feed(stanza)
|
|
if stanza.attr.from ~= self.peer then return end
|
|
local child = stanza[1];
|
|
if child.attr.sid ~= self.sid then return end
|
|
local ok;
|
|
if child.name == "open" then
|
|
self:event("connected");
|
|
self.stream:send(verse.reply(stanza))
|
|
return true
|
|
elseif child.name == "data" then
|
|
local bdata = stanza:get_child_text("data", xmlns_ibb);
|
|
local seq = tonumber(child.attr.seq);
|
|
local expected_seq = self.iseq;
|
|
if bdata and seq then
|
|
if seq ~= expected_seq then
|
|
self.stream:send(verse.error_reply(stanza, "cancel", "not-acceptable", "Wrong sequence. Packet lost?"))
|
|
self:close();
|
|
self:event("error");
|
|
return true;
|
|
end
|
|
self.iseq = seq + 1;
|
|
local data = base64.decode(bdata);
|
|
if self.stanza == "iq" then
|
|
self.stream:send(verse.reply(stanza))
|
|
end
|
|
self:event("incoming-raw", data);
|
|
return true;
|
|
end
|
|
elseif child.name == "close" then
|
|
self.stream:send(verse.reply(stanza))
|
|
self:close();
|
|
return true
|
|
end
|
|
end
|
|
|
|
--[[ FIXME some day
|
|
function ibb_conn:receive(patt)
|
|
-- is this even used?
|
|
print("ibb_conn:receive("..tostring(patt)..")");
|
|
assert(patt == "*a" or tonumber(patt));
|
|
local data = t_concat(self.ibuffer):sub(self.pos, tonumber(patt) or nil);
|
|
self.pos = self.pos + #data;
|
|
return data
|
|
end
|
|
|
|
function ibb_conn:dirty()
|
|
print("ibb_conn:dirty()");
|
|
return false -- ????
|
|
end
|
|
function ibb_conn:getfd()
|
|
return 0
|
|
end
|
|
function ibb_conn:settimeout(n)
|
|
-- ignore?
|
|
end
|
|
-]]
|
|
|
|
function ibb_conn:close()
|
|
self.stream:unhook("iq/".. xmlns_ibb, self.feeder)
|
|
self:event("disconnected");
|
|
end
|
|
|
|
function verse.plugins.jingle_ibb(stream)
|
|
stream:hook("ready", function ()
|
|
stream:add_disco_feature(xmlns_jingle_ibb);
|
|
end, 10);
|
|
|
|
local ibb = {};
|
|
|
|
function ibb:_setup()
|
|
local conn = new_ibb(self.stream);
|
|
conn.sid = self.sid or conn.sid;
|
|
conn.stanza = self.stanza or conn.stanza;
|
|
conn.block = self.block or conn.block;
|
|
conn:initiate(self.peer, self.sid, self.stanza);
|
|
self.conn = conn;
|
|
end
|
|
function ibb:generate_initiate()
|
|
print("ibb:generate_initiate() as ".. self.role);
|
|
local sid = uuid_generate();
|
|
self.sid = sid;
|
|
self.stanza = 'iq';
|
|
self.block = 2048;
|
|
local transport = verse.stanza("transport", { xmlns = xmlns_jingle_ibb,
|
|
sid = self.sid, stanza = self.stanza, ["block-size"] = self.block });
|
|
return transport;
|
|
end
|
|
function ibb:generate_accept(initiate_transport)
|
|
print("ibb:generate_accept() as ".. self.role);
|
|
local attr = initiate_transport.attr;
|
|
self.sid = attr.sid or self.sid;
|
|
self.stanza = attr.stanza or self.stanza;
|
|
self.block = attr["block-size"] or self.block;
|
|
self:_setup();
|
|
return initiate_transport;
|
|
end
|
|
function ibb:connect(callback)
|
|
if not self.conn then
|
|
self:_setup();
|
|
end
|
|
local conn = self.conn;
|
|
print("ibb:connect() as ".. self.role);
|
|
if self.role == "initiator" then
|
|
conn:open(function(ok, ...)
|
|
assert(ok, table.concat({...}, ", "));
|
|
callback(conn);
|
|
end);
|
|
else
|
|
callback(conn);
|
|
end
|
|
end
|
|
function ibb:info_received(jingle_tag)
|
|
print("ibb:info_received()");
|
|
-- TODO, what exactly?
|
|
end
|
|
function ibb:disconnect()
|
|
if self.conn then
|
|
self.conn:close()
|
|
end
|
|
end
|
|
function ibb:handle_accepted(jingle_tag) end
|
|
|
|
local ibb_mt = { __index = ibb };
|
|
stream:hook("jingle/transport/"..xmlns_jingle_ibb, function (jingle)
|
|
return setmetatable({
|
|
role = jingle.role,
|
|
peer = jingle.peer,
|
|
stream = jingle.stream,
|
|
jingle = jingle,
|
|
}, ibb_mt);
|
|
end);
|
|
end
|