local socket = require'cqueues.socket' local class = require'r.class' local Channel = require'channel' local BasePylon = require 'pylon' local xml = require'xmpp.xml' local X,xmlify = xml.X, xml.xmlify local base64 = require'xmpp.base64' local sha1 = require'xmpp.sha1' local Xmpp = class.extend(BasePylon) function Xmpp.init(self) self:_check_fields"server component component_secret" self.nicks_inuse = {} end -- only use on local connections! function Xmpp._connect_component(self) local sock = assert(socket.connect(self.server, 5347)) self.sock = sock sock:setmode('bn','bn') -- yes, our component name goes in the 'to' field. don't ask me why local start = ([[]]):format(self.component) -- state of the art xml parser local function check_and_send(test, text) local x = sock:read('-2048') assert(x:find(test)) if text then sock:write(text) end end sock:write(start) local streamhead = sock:read('-2048') assert(streamhead:find'accept') local streamid = streamhead:match"id='(.-)'" sock:write(xmlify(X.handshake{sha1.sha1(streamid..self.component_secret)})) check_and_send('',nil) return sock end local THE_MUC = 'd@conference.ubq323.website' function Xmpp.recving(self) local function getmore() local function t(...) -- pprint(...) return ... end return t(self.sock:read'-2048') end for x in xml.stanzae(getmore) do -- pprint(x) -- print(xmlify(x)) local body = x'body' and x'body'[1] if x.label == 'message' then local fr = x.xarg.from local t = x.xarg.to local from_nick = fr:match("/(.*)") if not self.nicks_inuse[from_nick] and body and fr:match"/" and t == 'wilson@'..self.component then self.wilson:deliver(Channel(self, THE_MUC), { body = body, sender = '[x]'..from_nick }) end end end end function Xmpp.sending(self) local users_inuse = {} local function ensure_joined(muc,user,nick) if self.nicks_inuse[nick] then return end user = user:gsub("[^a-zA-Z0-9%.]","."):match("^%.*(.-)%.*$") while users_inuse[user] do user = user..'-' end local jid = user..'@'..self.component local mucjid = muc..'/'..nick self.nicks_inuse[nick] = true users_inuse[user] = true self.sock:write(xmlify( X.presence{from=jid, to=mucjid, X.x{xmlns='http://jabber.org/protocol/muc', X.history{maxstanzas='0'}}})) end ensure_joined(THE_MUC, 'wilson', 'wilson') for dest_channel, message in self.inbox:iter() do -- pprint(dest_channel, message) ensure_joined(THE_MUC, message.sender, message.sender) local user = message.sender:gsub("[^a-zA-Z0-9%.]","."):match("^%.*(.-)%.*$") local jid = user..'@'..self.component self.sock:write(xmlify( X.message{to=THE_MUC, type='groupchat', from=jid, X.body{message.body}})) end end return Xmpp