Mercurial > prosody-modules
diff mod_ircd/mod_ircd.in.lua @ 487:8bdab5489653
mod_ircd: code cleanup, added full logic for changing nicks (locally it works no traces), removed many comment lines (there was an over abundance of 'em they're in the .old_annotate file)
author | Marco Cirillo <maranda@lightwitch.org> |
---|---|
date | Fri, 02 Dec 2011 01:03:06 +0000 |
parents | f8cc2be7e16a |
children | 4885ca74515c |
line wrap: on
line diff
--- a/mod_ircd/mod_ircd.in.lua Mon Nov 28 18:14:22 2011 +0100 +++ b/mod_ircd/mod_ircd.in.lua Fri Dec 02 01:03:06 2011 +0000 @@ -4,10 +4,12 @@ -- -- IRC spec: -- http://tools.ietf.org/html/rfc2812 + local _module = module module = _G.module local module = _module --- +local client_xmlns = "jabber:client" + local component_jid, component_secret, muc_server, port_number = module.host, nil, module:get_option_string("conference_server"), module:get_option_number("listener_port", 7000); @@ -20,7 +22,7 @@ local verse = require "verse" require "verse.component" require "socket" -c = verse.new();--verse.logger()) +c = verse.new(); c:add_plugin("groupchat"); local function verse2prosody(e) @@ -33,29 +35,6 @@ c.type = "component"; c.send = core_post_stanza; --- This plugin is actually a verse based component, but that mode is currently commented out - --- Add some hooks for debugging ---c:hook("opened", function () print("Stream opened!") end); ---c:hook("closed", function () print("Stream closed!") end); ---c:hook("stanza", function (stanza) print("Stanza:", stanza) end); - --- This one prints all received data ---c:hook("incoming-raw", print, 1000); ---c:hook("stanza", print, 1000); ---c:hook("outgoing-raw", print, 1000); - --- Print a message after authentication ---c:hook("authentication-success", function () print("Logged in!"); end); ---c:hook("authentication-failure", function (err) print("Failed to log in! Error: "..tostring(err.condition)); end); - --- Print a message and exit when disconnected ---c:hook("disconnected", function () print("Disconnected!"); os.exit(); end); - --- Now, actually start the connection: ---c.connect_host = "127.0.0.1" ---c:connect_component(component_jid, component_secret); - local jid = require "util.jid"; local nodeprep = require "util.encodings".stringprep.nodeprep; @@ -128,7 +107,11 @@ local function irc2muc(channel, nick) local room = channel and nodeprep(channel:match("^#(%w+)")) or nil; - return jid.join(room, muc_server, nick) + if not nick then + return jid.join(room, muc_server); + else + return jid.join(room, muc_server, nick); + end end local function muc2irc(room) local channel, _, nick = jid.split(room); @@ -183,6 +166,7 @@ rooms = {}, roster = {} }; sessions[conn] = session; + function session.data(data) local parts = parse_line(data); module:log("debug", require"util.serialization".serialize(parts)); @@ -207,6 +191,7 @@ return module:log("debug", "Unknown command: %s", command); end end + function session.send(data) if type(data) == "string" then return conn:write(data.."\r\n"); @@ -217,6 +202,7 @@ end end end + if data then session.data(data); end @@ -224,6 +210,7 @@ function irc_listener.ondisconnect(conn, error) local session = sessions[conn]; + if session then for _, room in pairs(session.rooms) do room:leave("Disconnected"); @@ -238,21 +225,53 @@ sessions[conn] = nil; end +local function nick_inuse(nick) + if nicks[nick] then return true else return false end +end +local function change_nick_st(jid, room_jid, newnick) + return st.presence({ xmlns = xmlns_client, from = jid, to = room_jid, type = "unavailable" }):tag("status"):text("Changing nickname to "..newnick):up(); +end + function commands.NICK(session, args) - if session.nick then - session.send{from = muc_server, "484", "*", nick, "I'm afraid I can't let you do that"}; - --TODO Loop throug all rooms and change nick, with help from Verse. - return; - end local nick = args[1]; nick = nick:gsub("[^%w_]",""); - if nicks[nick] then - session.send{from=muc_server, "433", nick, "The nickname "..nick.." is already in use"}; + local full_jid = jid.join(nick, component_jid, "ircd"); + + if session.nick and not nick_inuse(nick) then -- changing nick + local oldnick = session.nick; + local old_full_jid = session.full_jid; + local old_ar_last = jids[old_full_jid]["ar_last"]; + local old_nicks_changing = jids[old_full_jid]["nicks_changing"]; + + -- update and replace session data + session.nick = nick; + session.full_jid = full_jid; + jids[old_full_jid] = nil; nicks[oldnick] = nil; + nicks[nick] = session; + jids[full_jid] = session; + jids[full_jid]["ar_last"] = old_ar_last; + jids[full_jid]["nicks_changing"] = old_nicks_changing; + + session.send{from=oldnick, "NICK", nick}; + + -- broadcast changes if required, todo: something better then forcing parting and rejoining + if session.rooms then + for id, room in pairs(session.rooms) do + session.nicks_changing[session.nick] = oldnick; + room:send(change_nick_st(old_full_jid, room.jid.."/"..oldnick, session.nick)); + commands.JOIN(session, { id }); + end + session.nicks_changing[session.nick] = nil; + end + return; + elseif nick_inuse(nick) then + session.send{from=muc_server, "433", nick, "The nickname "..nick.." is already in use"}; return; end - local full_jid = jid.join(nick, component_jid, "ircd"); + jids[full_jid] = session; jids[full_jid]["ar_last"] = {}; + jids[full_jid]["nicks_changing"] = {}; nicks[nick] = session; session.nick = nick; session.full_jid = full_jid; @@ -276,9 +295,7 @@ -- enforce by default on most servers (since the source host doesn't show it's sensible to have it "set") end -function commands.USER(session, params) - -- FIXME - -- Empty command for now +function commands.USER(session, params) -- To be done. end local function mode_map(am, rm, nicks) @@ -294,20 +311,25 @@ local channel = args[1]; if not channel then return end local room_jid = irc2muc(channel); - print(session.full_jid); + if not jids[session.full_jid].ar_last[room_jid] then jids[session.full_jid].ar_last[room_jid] = {}; end local room, err = c:join_room(room_jid, session.nick, { source = session.full_jid } ); if not room then return ":"..muc_server.." ERR :Could not join room: "..err end + session.rooms[channel] = room; - room.channel = channel; room.session = session; - session.send{from=session.nick, "JOIN", channel}; - if room.subject then - session.send{from=muc_server, 332, session.nick, channel ,room.subject}; + + if session.nicks_changing[session.nick] then -- my own nick is changing + commands.NAMES(session, channel); + else + session.send{from=session.nick, "JOIN", channel}; + if room.subject then + session.send{from=muc_server, 332, session.nick, channel, room.subject}; + end + commands.NAMES(session, channel); end - commands.NAMES(session, channel); room:hook("subject-changed", function(changed) session.send((":%s TOPIC %s :%s"):format(changed.by.nick, channel, changed.to or "")); @@ -332,7 +354,7 @@ if ar.nick and not jids[session.full_jid].ar_last[ar.room_jid][ar.nick] then jids[session.full_jid].ar_last[ar.room_jid][ar.nick] = {} end local x_ar = ar.stanza:get_child("x", "http://jabber.org/protocol/muc#user") if x_ar then - local xar_item = x_ar:get_child("item") + local xar_item = x_ar:get_child("item") if xar_item and xar_item.attr and ar.stanza.attr.type ~= "unavailable" then if xar_item.attr.affiliation and xar_item.attr.role then if not jids[session.full_jid].ar_last[ar.room_jid][ar.nick]["affiliation"] and @@ -358,23 +380,40 @@ c:hook("groupchat/joined", function(room) local session = room.session or jids[room.opts.source]; local channel = "#"..room.jid:match("^(.*)@"); - session.send{from=session.nick.."!"..session.nick, "JOIN", channel}; - if room.topic then - session.send{from=muc_server, 332, room.topic}; - end - commands.NAMES(session, channel) + room:hook("occupant-joined", function(nick) - session.send{from=nick.nick.."!"..nick.nick, "JOIN", channel}; + if session.nicks_changing[nick.nick] then + session.send{from=session.nicks_changing[nick.nick], "NICK", nick.nick}; + session.nicks_changing[nick.nick] = nil; + else + session.send{from=nick.nick, "JOIN", channel}; + end end); room:hook("occupant-left", function(nick) - jids[session.full_jid].ar_last[nick.jid:match("^(.*)/")][nick.nick] = nil; -- ugly - session.send{from=nick.nick.."!"..nick.nick, "PART", channel}; + if jids[session.full_jid] then jids[session.full_jid].ar_last[nick.jid:match("^(.*)/")][nick.nick] = nil; end + local status_code = + nick.presence:get_child("x","http://jabber.org/protocol/muc#user") and + nick.presence:get_child("x","http://jabber.org/protocol/muc#user"):get_child("status") and + nick.presence:get_child("x","http://jabber.org/protocol/muc#user"):get_child("status").attr.code; + + if status_code == "303" then + local newnick = + nick.presence:get_child("x","http://jabber.org/protocol/muc#user") and + nick.presence:get_child("x","http://jabber.org/protocol/muc#user"):get_child("status") and + nick.presence:get_child("x","http://jabber.org/protocol/muc#user"):get_child("status"):get_child("item") and + nick.presence:get_child("x","http://jabber.org/protocol/muc#user"):get_child("status"):get_child("item").attr.nick; + + session.nicks_changing[newnick] = nick.nick; return; + end + session.send{from=nick.nick, "PART", channel}; end); end); function commands.NAMES(session, channel) local nicks = { }; + if type(channel) == "table" then channel = channel[1] end local room = session.rooms[channel]; + local symbols_map = { owner = "~", administrator = "&", @@ -466,15 +505,13 @@ if session.rooms[channel] then local room = session.rooms[channel] for nick in pairs(room.occupants) do - --n=MattJ 91.85.191.50 irc.freenode.net MattJ H :0 Matthew Wild session.send{from=muc_server, 352, session.nick, channel, nick, nick, muc_server, nick, "H", "0 "..nick} end session.send{from=muc_server, 315, session.nick, channel, "End of /WHO list"}; end end -function commands.MODE(session, args) -- FIXME - -- emptied for the time being, until something sane which works is available. +function commands.MODE(session, args) -- Empty command end function commands.QUIT(session, args) @@ -488,21 +525,15 @@ session:close(); end -function commands.RAW(session, data) - --c:send(data) +function commands.RAW(session, data) -- Empty command end local function desetup() require "net.connlisteners".deregister("irc"); end ---c:hook("ready", function () - require "net.connlisteners".register("irc", irc_listener); - require "net.connlisteners".start("irc"); ---end); +require "net.connlisteners".register("irc", irc_listener); +require "net.connlisteners".start("irc"); module:hook("module-unloaded", desetup) - ---print("Starting loop...") ---verse.loop()