Software / code / verse
Comparison
component.lua @ 84:d85d2443478e
verse.component: XEP-0114 support \o/
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Tue, 03 Aug 2010 09:17:23 +0100 |
| child | 150:728cc7f2f0c2 |
comparison
equal
deleted
inserted
replaced
| 83:8221f3c25fd4 | 84:d85d2443478e |
|---|---|
| 1 local verse = require "verse"; | |
| 2 local stream = verse.stream_mt; | |
| 3 | |
| 4 local jid_split = require "util.jid".split; | |
| 5 local lxp = require "lxp"; | |
| 6 local st = require "util.stanza"; | |
| 7 local sha1 = require "util.sha1".sha1; | |
| 8 | |
| 9 -- Shortcuts to save having to load util.stanza | |
| 10 verse.message, verse.presence, verse.iq, verse.stanza, verse.reply, verse.error_reply = | |
| 11 st.message, st.presence, st.iq, st.stanza, st.reply, st.error_reply; | |
| 12 | |
| 13 local init_xmlhandlers = require "core.xmlhandlers"; | |
| 14 | |
| 15 local xmlns_stream = "http://etherx.jabber.org/streams"; | |
| 16 local xmlns_component = "jabber:component:accept"; | |
| 17 | |
| 18 local stream_callbacks = { | |
| 19 stream_ns = xmlns_stream, | |
| 20 stream_tag = "stream", | |
| 21 default_ns = "jabber:client" }; | |
| 22 | |
| 23 function stream_callbacks.streamopened(stream, attr) | |
| 24 stream.stream_id = attr.id; | |
| 25 if not stream:event("opened", attr) then | |
| 26 stream.notopen = nil; | |
| 27 end | |
| 28 return true; | |
| 29 end | |
| 30 | |
| 31 function stream_callbacks.streamclosed(stream) | |
| 32 return stream:event("closed"); | |
| 33 end | |
| 34 | |
| 35 function stream_callbacks.handlestanza(stream, stanza) | |
| 36 if stanza.attr.xmlns == xmlns_stream then | |
| 37 return stream:event("stream-"..stanza.name, stanza); | |
| 38 elseif stanza.attr.xmlns then | |
| 39 return stream:event("stream/"..stanza.attr.xmlns, stanza); | |
| 40 end | |
| 41 | |
| 42 return stream:event("stanza", stanza); | |
| 43 end | |
| 44 | |
| 45 function stream:reset() | |
| 46 -- Reset stream | |
| 47 local parser = lxp.new(init_xmlhandlers(self, stream_callbacks), "\1"); | |
| 48 self.parser = parser; | |
| 49 | |
| 50 self.notopen = true; | |
| 51 | |
| 52 return true; | |
| 53 end | |
| 54 | |
| 55 function stream:connect_component(jid, pass) | |
| 56 self.jid, self.password = jid, pass; | |
| 57 self.username, self.host, self.resource = jid_split(jid); | |
| 58 | |
| 59 function self.data(conn, data) | |
| 60 local ok, err = self.parser:parse(data); | |
| 61 if ok then return; end | |
| 62 stream:debug("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " ")); | |
| 63 stream:close("xml-not-well-formed"); | |
| 64 end | |
| 65 | |
| 66 self:hook("incoming-raw", function (data) return self.data(self.conn, data); end); | |
| 67 | |
| 68 self.curr_id = 0; | |
| 69 | |
| 70 self.tracked_iqs = {}; | |
| 71 self:hook("stanza", function (stanza) | |
| 72 local id, type = stanza.attr.id, stanza.attr.type; | |
| 73 if id and stanza.name == "iq" and (type == "result" or type == "error") and self.tracked_iqs[id] then | |
| 74 self.tracked_iqs[id](stanza); | |
| 75 self.tracked_iqs[id] = nil; | |
| 76 return true; | |
| 77 end | |
| 78 end); | |
| 79 | |
| 80 self:hook("stanza", function (stanza) | |
| 81 if stanza.attr.xmlns == nil or stanza.attr.xmlns == "jabber:client" then | |
| 82 if stanza.name == "iq" and (stanza.attr.type == "get" or stanza.attr.type == "set") then | |
| 83 local xmlns = stanza.tags[1] and stanza.tags[1].attr.xmlns; | |
| 84 if xmlns then | |
| 85 ret = self:event("iq/"..xmlns, stanza); | |
| 86 if not ret then | |
| 87 ret = self:event("iq", stanza); | |
| 88 end | |
| 89 end | |
| 90 if ret == nil then | |
| 91 self:send(verse.error_reply(stanza, "cancel", "service-unavailable")); | |
| 92 return true; | |
| 93 end | |
| 94 else | |
| 95 ret = self:event(stanza.name, stanza); | |
| 96 end | |
| 97 end | |
| 98 return ret; | |
| 99 end, -1); | |
| 100 | |
| 101 self:hook("opened", function (attr) | |
| 102 print(self.jid, self.stream_id, attr.id); | |
| 103 local token = sha1(self.stream_id..pass, true); | |
| 104 | |
| 105 self:send(st.stanza("handshake", { xmlns = xmlns_component }):text(token)); | |
| 106 self:hook("stream/"..xmlns_component, function (stanza) | |
| 107 if stanza.name == "handshake" then | |
| 108 self:event("authentication-success"); | |
| 109 end | |
| 110 end); | |
| 111 end); | |
| 112 | |
| 113 local function stream_ready() | |
| 114 self:event("ready"); | |
| 115 end | |
| 116 self:hook("authentication-success", stream_ready, -1); | |
| 117 | |
| 118 -- Initialise connection | |
| 119 self:connect(self.connect_host or self.host, self.connect_port or 5347); | |
| 120 self:reopen(); | |
| 121 end | |
| 122 | |
| 123 function stream:reopen() | |
| 124 self:reset(); | |
| 125 self:send(st.stanza("stream:stream", { to = self.host, ["xmlns:stream"]='http://etherx.jabber.org/streams', | |
| 126 xmlns = xmlns_component, version = "1.0" }):top_tag()); | |
| 127 end | |
| 128 | |
| 129 function stream:close(reason) | |
| 130 if not self.notopen then | |
| 131 self:send("</stream:stream>"); | |
| 132 end | |
| 133 local on_disconnect = self.conn.disconnect(); | |
| 134 self.conn:close(); | |
| 135 on_disconnect(conn, reason); | |
| 136 end | |
| 137 | |
| 138 function stream:send_iq(iq, callback) | |
| 139 local id = self:new_id(); | |
| 140 self.tracked_iqs[id] = callback; | |
| 141 iq.attr.id = id; | |
| 142 self:send(iq); | |
| 143 end | |
| 144 | |
| 145 function stream:new_id() | |
| 146 self.curr_id = self.curr_id + 1; | |
| 147 return tostring(self.curr_id); | |
| 148 end |