changeset 470:4f9224369e69

mod_ircd: merged in various changes including -- code to propagate aff/role changes as modes, topic hooks/command, scarecrow motd banner, default port.
author Marco Cirillo <maranda@lightwitch.org>
date Tue, 01 Nov 2011 23:41:02 +0000
parents ff03a325aa41
children fffac0eef024
files mod_ircd/mod_ircd.in.lua
diffstat 1 files changed, 130 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/mod_ircd/mod_ircd.in.lua	Tue Nov 01 19:46:07 2011 +0100
+++ b/mod_ircd/mod_ircd.in.lua	Tue Nov 01 23:41:02 2011 +0000
@@ -129,16 +129,32 @@
 	local channel, _, nick = jid.split(room);
 	return "#"..channel, nick;
 end
-local rolemap = {
-	moderator = "@",
-	participant = "+",
+local role_map = {
+        moderator = "@",
+        participant = "",
+        visitor = "",
+        none = ""
+}
+local aff_map = {
+	owner = "~",
+	administrator = "&",
+	member = "+",
+	none = ""
 }
-local modemap = {
-	moderator = "o",
-	participant = "v",
+local role_modemap = {
+        moderator = "o",
+        participant = "",
+        visitor = "",
+        none = ""
+}
+local aff_modemap = {
+	owner = "q",
+	administrator = "a",
+	member = "v",
+	none = ""
 }
 
-local irc_listener = { default_port = 6667, default_mode = "*l" };
+local irc_listener = { default_port = 7000, default_mode = "*l" };
 
 local sessions = {};
 local jids = {};
@@ -231,15 +247,28 @@
 	end
 	local full_jid = jid.join(nick, component_jid, "ircd");
 	jids[full_jid] = session;
+	jids[full_jid]["ar_last"] = {};
 	nicks[nick] = session;
 	session.nick = nick;
 	session.full_jid = full_jid;
 	session.type = "c2s";
-	session.send{from = muc_server, "001", nick, "Welcome to IRC gateway to XMPP!"};
-	session.send{from = muc_server, "002", nick, module.host.." running Prosody "..prosody.version};
+	
+	session.send{from = muc_server, "001", nick, "Welcome in the IRC to MUC XMPP Gateway, "..nick};
+	session.send{from = muc_server, "002", nick, "Your host is "..muc_server.." running Prosody "..prosody.version};
 	session.send{from = muc_server, "003", nick, os.date(nil, prosody.start_time)}
-	session.send{from = muc_server, "004", table.concat({muc_server, "alpha", "i", "ov"}, " ")};
-	session.send{from = nick, "MODE", nick, "+i"}; -- why
+	session.send{from = muc_server, "004", table.concat({muc_server, "alpha", "i", "aoqv"}, " ")};
+	session.send{from = muc_server, "375", nick, "- "..muc_server.." Message of the day -"};
+	session.send{from = muc_server, "372", nick, "-"};
+	session.send{from = muc_server, "372", nick, "- Please be warned that this is only a partial irc implementation,"};
+	session.send{from = muc_server, "372", nick, "- it's made to facilitate users transiting away from irc to XMPP."};
+	session.send{from = muc_server, "372", nick, "-"};
+	session.send{from = muc_server, "372", nick, "- Prosody is _NOT_ an IRC Server and it never will."};
+	session.send{from = muc_server, "372", nick, "- We also would like to remind you that this plugin is provided as is,"};
+	session.send{from = muc_server, "372", nick, "- it's still an Alpha and it's still a work in progress, use it at your sole"};
+	session.send{from = muc_server, "372", nick, "- risk as there's a not so little chance something will break."};
+	
+	session.send{from = nick, "MODE", nick, "+i"}; -- why -> Invisible mode setting, 
+						       --        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)
@@ -247,21 +276,38 @@
 	-- Empty command for now
 end
 
+local function mode_map(am, rm, nicks)
+	local rnick;
+	local c_modes;
+	c_modes = aff_modemap[am]..role_modemap[rm]
+	rnick = string.rep(nicks.." ", c_modes:len())
+	if c_modes == "" then return nil, nil end
+	return c_modes, rnick
+end
+
 function commands.JOIN(session, args)
 	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 ":"..session.host.." ERR :Could not join room: "..err
+		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};
-	session.send{from=muc_server, 332, session.nick, channel ,"Connection in progress..."};
-
+	if room.subject then
+	       	session.send{from=muc_server, 332, session.nick, channel ,room.subject};
+        end
+	commands.NAMES(session, channel);
+	
+	room:hook("subject-changed", function(changed) 
+	       	session.send((":%s TOPIC %s :%s"):format(changed.by, channel, changed.to or ""));
+	end);
+	
 	room:hook("message", function(event)
 		if not event.body then return end
 		local nick, body = event.nick, event.body;
@@ -274,52 +320,92 @@
 			--FIXME PM's probably won't work
 		end
 	end);
+	
+	room:hook("presence", function(ar)
+		local c_modes;
+		local rnick;
+		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")
+			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
+					   not jids[session.full_jid].ar_last[ar.room_jid][ar.nick]["role"] then
+						jids[session.full_jid].ar_last[ar.room_jid][ar.nick]["affiliation"] = xar_item.attr.affiliation
+						jids[session.full_jid].ar_last[ar.room_jid][ar.nick]["role"] = xar_item.attr.role
+						c_modes, rnick = mode_map(xar_item.attr.affiliation, xar_item.attr.role, ar.nick);
+						if c_modes and rnick then session.send((":%s MODE %s +%s"):format(muc_server, channel, c_modes.." "..rnick)); end
+					else
+						c_modes, rnick = mode_map(jids[session.full_jid].ar_last[ar.room_jid][ar.nick]["affiliation"], jids[session.full_jid].ar_last[ar.room_jid][ar.nick]["role"], ar.nick);
+						if c_modes and rnick then session.send((":%s MODE %s -%s"):format(muc_server, channel, c_modes.." "..rnick)); end
+						jids[session.full_jid].ar_last[ar.room_jid][ar.nick]["affiliation"] = xar_item.attr.affiliation
+						jids[session.full_jid].ar_last[ar.room_jid][ar.nick]["role"] = xar_item.attr.role
+						c_modes, rnick = mode_map(xar_item.attr.affiliation, xar_item.attr.role, ar.nick);
+						if c_modes and rnick then session.send((":%s MODE %s +%s"):format(muc_server, channel, c_modes.." "..rnick)); end
+					end
+				end
+			end
+		 end
+	end, -1);
 end
 
 c:hook("groupchat/joined", function(room)
 	local session = room.session or jids[room.opts.source];
-	local channel = room.channel;
+        local channel = "#"..room.jid:match("^(.*)@");
 	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{from=muc_server, 332, room.topic};
 	end
 	commands.NAMES(session, channel)
-	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{from=nick.nick.."!"..nick.nick, "JOIN", channel};
-		if nick.role and modemap[nick.role] then
-			session.send{from=nick.nick.."!"..nick.nick, "MODE", channel, modemap[nick.role], nick.nick};
-		end
 	end);
 	room:hook("occupant-left", function(nick)
-		session.send{from=nick.nick.."!"..nick.nick, "PART", room.channel};
+		jids[session.full_jid].ar_last[nick.room_jid][nick.nick] = nil;
+		session.send{from=nick.nick.."!"..nick.nick, "PART", channel};
 	end);
 end);
 
 function commands.NAMES(session, channel)
 	local nicks = { };
 	local room = session.rooms[channel];
+	local symbols_map = {
+		owner = "~",
+		administrator = "&",
+		moderator = "@",
+		member = "+"
+	}
+		
 	if not room then return end
 	-- TODO Break this out into commands.NAMES
 	for nick, n in pairs(room.occupants) do
-		if n.role and rolemap[n.role] then
-			nick = rolemap[n.role] .. nick;
+                if n.affiliation == "owner" and n.role == "moderator" then
+			nick = symbols_map[n.affiliation]..nick;
+                elseif n.affiliation == "administrator" and n.role == "moderator" then
+			nick = symbols_map[n.affiliation]..nick;
+		elseif n.affiliation == "member" and n.role == "moderator" then
+			nick = symbols_map[n.role]..nick;
+		elseif n.affiliation == "member" and n.role == "partecipant" then
+			nick = symbols_map[n.affiliation]..nick;
+		elseif n.affiliation == "none" and n.role == "moderator" then
+			nick = symbols_map[n.role]..nick;
 		end
 		table.insert(nicks, nick);
 	end
 	nicks = table.concat(nicks, " ");
-	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);
+	session.send((":%s 353 %s = %s :%s"):format(muc_server, session.nick, channel, nicks));
+	session.send((":%s 366 %s %s :End of /NAMES list."):format(muc_server, session.nick, channel));
+	session.send(":"..muc_server.." 353 "..session.nick.." = "..channel.." :"..nicks);
 end
 
 function commands.PART(session, args)
 	local channel, part_message = unpack(args);
+	local room = channel and nodeprep(channel:match("^#(%w+)")) or nil;
+	if not room then return end
 	channel = channel:match("^([%S]*)");
 	session.rooms[channel]:leave(part_message);
+	jids[session.full_jid].ar_last[room.."@"..muc_server] = nil;
 	session.send(":"..session.nick.." PART :"..channel);
 end
 
@@ -359,6 +445,22 @@
 	session.send{from=muc_server, "PONG", args[1]};
 end
 
+function commands.TOPIC(session, message)
+	if not message then return end
+	local channel, topic = message:match("^(%S+) :(.*)$");
+	if not channel then
+		channel = message:match("^(%S+)");
+	end
+	if not channel then return end
+	local room = session.rooms[channel];
+	if topic then
+		room:set_subject(topic)
+		session.send((":%s TOPIC %s :%s"):format(session.nick, channel, room.subject or ""));
+	else
+		session.send((":%s TOPIC %s :%s"):format(session.nick, channel, room.subject or ""));
+	end
+end
+
 function commands.WHO(session, args)
 	local channel = args[1];
 	if session.rooms[channel] then
@@ -412,5 +514,3 @@
 
 --print("Starting loop...")
 --verse.loop()
-
-