# HG changeset patch # User Kim Alvefur # Date 1320167295 -3600 # Node ID 0fcd34ee73014de2e0fb4dfc6cbf919ef276d7fc # Parent 030404dd7609038a03b16a1072a4a38a3371f26d mod_ircd: Proper line parsing and generating. Fix PMs diff -r 030404dd7609 -r 0fcd34ee7301 mod_ircd/mod_ircd.in.lua --- a/mod_ircd/mod_ircd.in.lua Tue Nov 01 13:52:29 2011 +0100 +++ b/mod_ircd/mod_ircd.in.lua Tue Nov 01 18:08:15 2011 +0100 @@ -52,9 +52,33 @@ --c:connect_component(component_jid, component_secret); local jid = require "util.jid"; +local nodeprep = require "util.encodings".stringprep.nodeprep; + +local function parse_line(line) + local ret = {}; + if line:sub(1,1) == ":" then + ret.from, line = line:match("^:(%w+)%s+(.*)$"); + end + for part in line:gmatch("%S+") do + if part:sub(1,1) == ":" then + ret[#ret+1] = line:match(":(.*)$"); + break + end + ret[#ret+1]=part; + end + return ret; +end + +local function build_line(parts) + if #parts > 1 then + parts[#parts] = ":" .. parts[#parts]; + end + return (parts.from and ":"..parts.from.." " or "")..table.concat(parts, " "); +end local function irc2muc(channel, nick) - return jid.join(channel:gsub("^#", ""), muc_server, nick) + local room = channel and nodeprep(channel:match("^#(%w+)")) or nil; + return jid.join(room, muc_server, nick) end local function muc2irc(room) local channel, _, nick = jid.split(room); @@ -94,29 +118,37 @@ roster = {} }; sessions[conn] = session; function session.data(data) - local command, args = data:match("^%s*([^ ]+) *(.*)%s*$"); + local parts = parse_line(data); + module:log("debug", require"util.serialization".serialize(parts)); + local command = table.remove(parts, 1); if not command then return; end command = command:upper(); if not session.nick then if not (command == "USER" or command == "NICK") then - session.send(":" .. muc_server .. " 451 " .. command .. " :You have not registered") - return true; + module:log("debug", "Client tried to send command %s before registering", command); + return session.send{from=muc_server, 451, command, "You have not registered"} end end if commands[command] then - local ret = commands[command](session, args); + local ret = commands[command](session, parts); if ret then - session.send(ret.."\r\n"); + return session.send(ret); end else - session.send(":" .. muc_server .. " 421 " .. session.nick .. " " .. command .. " :Unknown command") - module:log("debug", "Unknown command: %s", command); + session.send{from=muc_server, 421, session.nick, command, "Unknown command"}; + return module:log("debug", "Unknown command: %s", command); end end function session.send(data) - return conn:write(data.."\r\n"); + if type(data) == "string" then + return conn:write(data.."\r\n"); + elseif type(data) == "table" then + local line = build_line(data); + module:log("debug", line); + conn:write(line.."\r\n"); + end end end if data then @@ -126,23 +158,30 @@ function irc_listener.ondisconnect(conn, error) local session = sessions[conn]; - for _, room in pairs(session.rooms) do - room:leave("Disconnected"); + if session then + for _, room in pairs(session.rooms) do + room:leave("Disconnected"); + end + if session.nick then + nicks[session.nick] = nil; + end + if session.full_jid then + jids[session.full_jid] = nil; + end end - jids[session.full_jid] = nil; - nicks[session.nick] = nil; sessions[conn] = nil; end -function commands.NICK(session, nick) +function commands.NICK(session, args) if session.nick then - session.send(":"..muc_server.." 484 * "..nick.." :I'm afraid I can't let you do that, "..nick); + session.send(":"..muc_server.." 484 * "..nick.." :I'm afraid I can't let you do that, "..session.nick); --TODO Loop throug all rooms and change nick, with help from Verse. return; end - nick = nick:match("^[%w_]+"); + local nick = args[1]; + nick = nick:gsub("[^%w_]",""); if nicks[nick] then - session.send(":"..session.host.." 433 * "..nick.." :The nickname "..nick.." is already in use"); + 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"); @@ -151,7 +190,8 @@ session.nick = nick; session.full_jid = full_jid; session.type = "c2s"; - session.send(":"..session.host.." 001 "..session.nick.." :Welcome to XMPP via the "..session.host.." gateway "..session.nick); + session.send{from = muc_server, 001, nick, "Welcome to XMPP via the "..session.host.." gateway "..session.nick}; + session.send{from=nick, "MODE", nick, "+i"}; -- why end function commands.USER(session, params) @@ -159,7 +199,8 @@ -- Empty command for now end -function commands.JOIN(session, channel) +function commands.JOIN(session, args) + local channel = args[1]; local room_jid = irc2muc(channel); print(session.full_jid); local room, err = c:join_room(room_jid, session.nick, { source = session.full_jid } ); @@ -169,8 +210,9 @@ session.rooms[channel] = room; room.channel = channel; room.session = session; - session.send(":"..session.nick.." JOIN :"..channel); - session.send(":"..session.host.." 332 "..session.nick.." "..channel.." :Connection in progress..."); + session.send{from=session.nick, "JOIN", channel}; + session.send{from=muc_server, 332, session.nick, channel ,"Connection in progress..."}; + room:hook("message", function(event) if not event.body then return end local nick, body = event.nick, event.body; @@ -178,7 +220,8 @@ if body:sub(1,4) == "/me " then body = "\1ACTION ".. body:sub(5) .. "\1" end - session.send(":"..nick.." PRIVMSG "..channel.." :"..body); + local type = event.stanza.attr.type; + session.send{from=nick, "PRIVMSG", type == "groupchat" and channel or nick, body}; --FIXME PM's probably won't work end end); @@ -187,21 +230,23 @@ c:hook("groupchat/joined", function(room) local session = room.session or jids[room.opts.source]; local channel = room.channel; + session.send{from=session.nick.."!"..session.nick, "JOIN", channel}; session.send((":%s!%s JOIN %s :"):format(session.nick, session.nick, channel)); if room.topic then - session.send((":%s 332 %s :%s"):format(session.host, channel, room.topic)); + session.send{from=muc_server, 332, room.topic}; end commands.NAMES(session, channel) - --FIXME Ones own mode get's lost - --session.send((":%s MODE %s +%s %s"):format(session.host, room.channel, modemap[nick.role], nick.nick)); + if session.nick.role then + session.send{from=muc_server, "MODE", channel, session.nick, modemap[session.nick.role], session.nick} + end room:hook("occupant-joined", function(nick) - session.send((":%s!%s JOIN :%s"):format(nick.nick, nick.nick, channel)); + session.send{from=nick.nick.."!"..nick.nick, "JOIN", channel}; if nick.role and modemap[nick.role] then - session.send((":%s MODE %s +%s %s"):format(session.host, room.channel, modemap[nick.role], nick.nick)); + session.send{from=nick.nick.."!"..nick.nick, "MODE", channel, modemap[nick.role], nick.nick}; end end); room:hook("occupant-left", function(nick) - session.send((":%s!%s PART %s :"):format(nick.nick, nick.nick, channel)); + session.send{from=nick.nick.."!"..nick.nick, "PART", room.channel}; end); end); @@ -217,53 +262,81 @@ table.insert(nicks, nick); end nicks = table.concat(nicks, " "); - --:molyb.irc.bnfh.org 353 derp = #grill-bit :derp hyamobi walt snuggles_ E-Rock kng grillbit gunnarbot Frink shedma zagabar zash Mrw00t Appiah J10 lectus peck EricJ soso mackt offer hyarion @pettter MMN-o session.send((":%s 353 %s = %s :%s"):format(session.host, session.nick, channel, nicks)); session.send((":%s 366 %s %s :End of /NAMES list."):format(session.host, session.nick, channel)); session.send(":"..session.host.." 353 "..session.nick.." = "..channel.." :"..nicks); end -function commands.PART(session, channel) - local channel, part_message = channel:match("^([^:]+):?(.*)$"); +function commands.PART(session, args) + local channel, part_message = unpack(args); channel = channel:match("^([%S]*)"); session.rooms[channel]:leave(part_message); session.send(":"..session.nick.." PART :"..channel); end -function commands.PRIVMSG(session, message) - local channel, message = message:match("^(%S+) :(.+)$"); - if message and #message > 0 and session.rooms[channel] then +function commands.PRIVMSG(session, args) + local channel, message = unpack(args); + if message and #message > 0 then if message:sub(1,8) == "\1ACTION " then message = "/me ".. message:sub(9,-2) end - module:log("debug", "%s sending PRIVMSG \"%s\" to %s", session.nick, message, channel); - session.rooms[channel]:send_message(message); + -- TODO clean out invalid chars + if channel:sub(1,1) == "#" then + if session.rooms[channel] then + module:log("debug", "%s sending PRIVMSG \"%s\" to %s", session.nick, message, channel); + session.rooms[channel]:send_message(message); + end + else -- private message + local nick = channel; + module:log("debug", "PM to %s", nick); + for channel, room in pairs(session.rooms) do + module:log("debug", "looking for %s in %s", nick, channel); + if room.occupants[nick] then + module:log("debug", "found %s in %s", nick, channel); + local who = room.occupants[nick]; + -- FIXME PMs in verse + --room:send_private_message(nick, message); + local pm = st.message({type="chat",to=who.jid}, message); + module:log("debug", "sending PM to %s: %s", nick, tostring(pm)); + room:send(pm) + break + end + end + end end end -function commands.PING(session, server) - session.send(":"..session.host..": PONG "..server); +function commands.PING(session, args) + session.send{from=muc_server, "PONG", args[1]}; end -function commands.WHO(session, channel) +function commands.WHO(session, args) + local channel = args[1]; 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(":"..session.host.." 352 "..session.nick.." "..channel.." "..nick.." "..nick.." "..session.host.." "..nick.." H :0 "..nick); + session.send{from=muc_server, 352, session.nick, channel, nick, nick, muc_server, nick, "H", "0 "..nick} end - session.send(":"..session.host.." 315 "..session.nick.." "..channel.. " :End of /WHO list"); + session.send{from=muc_server, 315, session.nick, channel, "End of /WHO list"}; end end -function commands.MODE(session, channel) - session.send(":"..session.host.." 324 "..session.nick.." "..channel.." +J"); +function commands._MODE(session, args) -- FIXME + local channel, target = unpack(args); + if target then + -- do stuff? + --room:set_affiliation(...) + else + -- What's 324? And +J ? + session.send{from=muc_server, 324, session.nick, channel, "+J"} + end end -function commands.QUIT(session, message) - session.send("ERROR :Closing Link: "..session.nick); +function commands.QUIT(session, args) + session.send{"ERROR", "Closing Link: "..session.nick}; for _, room in pairs(session.rooms) do - room:leave(message); + room:leave(args[1]); end jids[session.full_jid] = nil; nicks[session.nick] = nil;