comparison mod_ircd/mod_ircd_broke.lua @ 447:21cb01de89a8

mod_ircd: few patches from both Zash and myself to make it work again.
author Marco Cirillo <maranda@lightwitch.org>
date Mon, 26 Sep 2011 01:42:18 +0000
parents mod_ircd/mod_ircd.lua@8b81257c9dc5
children 52f2188ec47d
comparison
equal deleted inserted replaced
446:56f1c29ee7f1 447:21cb01de89a8
1 -- README
2 -- Squish verse into this dir, then squish them into one, which you move
3 -- and rename to mod_ircd.lua in your prosody modules/plugins dir.
4 --
5 -- IRC spec:
6 -- http://tools.ietf.org/html/rfc2812
7 local _module = module
8 module = _G.module
9 local module = _module
10 --
11 local component_jid, component_secret, muc_server =
12 module.host, nil, module:get_option("conference_server");
13
14 package.loaded["util.sha1"] = require "util.encodings";
15 local verse = require "verse"
16 require "verse.component"
17 require "socket"
18 c = verse.new();--verse.logger())
19 c:add_plugin("groupchat");
20
21 local function verse2prosody(e)
22 return c:event("stanza", e.stanza) or true;
23 end
24 module:hook("message/bare", verse2prosody);
25 module:hook("message/full", verse2prosody);
26 module:hook("presence/bare", verse2prosody);
27 module:hook("presence/full", verse2prosody);
28 c.type = "component";
29 c.send = core_post_stanza;
30
31 -- This plugin is actually a verse based component, but that mode is currently commented out
32
33 -- Add some hooks for debugging
34 --c:hook("opened", function () print("Stream opened!") end);
35 --c:hook("closed", function () print("Stream closed!") end);
36 --c:hook("stanza", function (stanza) print("Stanza:", stanza) end);
37
38 -- This one prints all received data
39 --c:hook("incoming-raw", print, 1000);
40 --c:hook("stanza", print, 1000);
41 --c:hook("outgoing-raw", print, 1000);
42
43 -- Print a message after authentication
44 --c:hook("authentication-success", function () print("Logged in!"); end);
45 --c:hook("authentication-failure", function (err) print("Failed to log in! Error: "..tostring(err.condition)); end);
46
47 -- Print a message and exit when disconnected
48 --c:hook("disconnected", function () print("Disconnected!"); os.exit(); end);
49
50 -- Now, actually start the connection:
51 --c.connect_host = "127.0.0.1"
52 --c:connect_component(component_jid, component_secret);
53
54 local jid = require "util.jid";
55
56 local function irc2muc(channel, nick)
57 return jid.join(channel:gsub("^#", ""), muc_server, nick)
58 end
59 local function muc2irc(room)
60 local channel, _, nick = jid.split(room);
61 return "#"..channel, nick;
62 end
63 local rolemap = {
64 moderator = "@",
65 participant = "+",
66 }
67 local modemap = {
68 moderator = "o",
69 participant = "v",
70 }
71
72 local irc_listener = { default_port = 6667, default_mode = "*l" };
73
74 local sessions = {};
75 local jids = {};
76 local commands = {};
77
78 local nicks = {};
79
80 local st = require "util.stanza";
81
82 local conference_server = muc_server;
83
84 local function irc_close_session(session)
85 session.conn:close();
86 end
87
88 function irc_listener.onincoming(conn, data)
89 local session = sessions[conn];
90 if not session then
91 session = { conn = conn, host = component_jid, reset_stream = function () end,
92 close = irc_close_session, log = logger.init("irc"..(conn.id or "1")),
93 rooms = {},
94 roster = {} };
95 sessions[conn] = session;
96 function session.data(data)
97 local command, args = data:match("^%s*([^ ]+) *(.*)%s*$");
98 if not command then
99 return;
100 end
101 command = command:upper();
102 if not session.nick then
103 if not (command == "USER" or command == "NICK") then
104 session.send(":" .. session.host .. " 451 " .. command .. " :You have not registered")
105 end
106 end
107 if commands[command] then
108 local ret = commands[command](session, args);
109 if ret then
110 session.send(ret.."\r\n");
111 end
112 else
113 session.send(":" .. session.host .. " 421 " .. session.nick .. " " .. command .. " :Unknown command")
114 module:log("debug", "Unknown command: %s", command);
115 end
116 end
117 function session.send(data)
118 return conn:write(data.."\r\n");
119 end
120 end
121 if data then
122 session.data(data);
123 end
124 end
125
126 function irc_listener.ondisconnect(conn, error)
127 local session = sessions[conn];
128 for _, room in pairs(session.rooms) do
129 room:leave("Disconnected");
130 end
131 jids[session.full_jid] = nil;
132 nicks[session.nick] = nil;
133 sessions[conn] = nil;
134 end
135
136 function commands.NICK(session, nick)
137 if session.nick then
138 session.send(":"..session.host.." 484 * "..nick.." :I'm afraid I can't let you do that, "..nick);
139 --TODO Loop throug all rooms and change nick, with help from Verse.
140 return;
141 end
142 nick = nick:match("^[%w_]+");
143 if nicks[nick] then
144 session.send(":"..session.host.." 433 * "..nick.." :The nickname "..nick.." is already in use");
145 return;
146 end
147 local full_jid = jid.join(nick, component_jid, "ircd");
148 jids[full_jid] = session;
149 nicks[nick] = session;
150 session.nick = nick;
151 session.full_jid = full_jid;
152 session.type = "c2s";
153 session.send(":"..session.host.." 001 "..session.nick.." :Welcome to XMPP via the "..session.host.." gateway "..session.nick);
154 end
155
156 function commands.USER(session, params)
157 -- FIXME
158 -- Empty command for now
159 end
160
161 function commands.JOIN(session, channel)
162 local room_jid = irc2muc(channel);
163 print(session.full_jid);
164 local room, err = c:join_room(room_jid, session.nick, { source = session.full_jid } );
165 if not room then
166 return ":"..session.host.." ERR :Could not join room: "..err
167 end
168 session.rooms[channel] = room;
169 room.channel = channel;
170 room.session = session;
171 session.send(":"..session.nick.." JOIN :"..channel);
172 session.send(":"..session.host.." 332 "..session.nick.." "..channel.." :Connection in progress...");
173 room:hook("message", function(event)
174 if not event.body then return end
175 local nick, body = event.nick, event.body;
176 if nick ~= session.nick then
177 if body:sub(1,4) == "/me " then
178 body = "\1ACTION ".. body:sub(5) .. "\1"
179 end
180 session.send(":"..nick.." PRIVMSG "..channel.." :"..body);
181 --FIXME PM's probably won't work
182 end
183 end);
184 end
185
186 c:hook("groupchat/joined", function(room)
187 local session = room.session or jids[room.opts.source];
188 local channel = room.channel;
189 session.send((":%s!%s JOIN %s :"):format(session.nick, session.nick, channel));
190 if room.topic then
191 session.send((":%s 332 %s :%s"):format(session.host, channel, room.topic));
192 end
193 commands.NAMES(session, channel)
194 --FIXME Ones own mode get's lost
195 --session.send((":%s MODE %s +%s %s"):format(session.host, room.channel, modemap[nick.role], nick.nick));
196 room:hook("occupant-joined", function(nick)
197 session.send((":%s!%s JOIN :%s"):format(nick.nick, nick.nick, channel));
198 if nick.role and modemap[nick.role] then
199 session.send((":%s MODE %s +%s %s"):format(session.host, room.channel, modemap[nick.role], nick.nick));
200 end
201 end);
202 room:hook("occupant-left", function(nick)
203 session.send((":%s!%s PART %s :"):format(nick.nick, nick.nick, channel));
204 end);
205 end);
206
207 function commands.NAMES(session, channel)
208 local nicks = { };
209 local room = session.rooms[channel];
210 if not room then return end
211 -- TODO Break this out into commands.NAMES
212 for nick, n in pairs(room.occupants) do
213 if n.role and rolemap[n.role] then
214 nick = rolemap[n.role] .. nick;
215 end
216 table.insert(nicks, nick);
217 end
218 nicks = table.concat(nicks, " ");
219 --: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
220 session.send((":%s 353 %s = %s :%s"):format(session.host, session.nick, channel, nicks));
221 session.send((":%s 366 %s %s :End of /NAMES list."):format(session.host, session.nick, channel));
222 session.send(":"..session.host.." 353 "..session.nick.." = "..channel.." :"..nicks);
223 end
224
225 function commands.PART(session, channel)
226 local channel, part_message = channel:match("^([^:]+):?(.*)$");
227 channel = channel:match("^([%S]*)");
228 session.rooms[channel]:leave(part_message);
229 session.send(":"..session.nick.." PART :"..channel);
230 end
231
232 function commands.PRIVMSG(session, message)
233 local channel, message = message:match("^(%S+) :(.+)$");
234 if message and #message > 0 and session.rooms[channel] then
235 if message:sub(1,8) == "\1ACTION " then
236 message = "/me ".. message:sub(9,-2)
237 end
238 module:log("debug", "%s sending PRIVMSG \"%s\" to %s", session.nick, message, channel);
239 session.rooms[channel]:send_message(message);
240 end
241 end
242
243 function commands.PING(session, server)
244 session.send(":"..session.host..": PONG "..server);
245 end
246
247 function commands.WHO(session, channel)
248 if session.rooms[channel] then
249 local room = session.rooms[channel]
250 for nick in pairs(room.occupants) do
251 --n=MattJ 91.85.191.50 irc.freenode.net MattJ H :0 Matthew Wild
252 session.send(":"..session.host.." 352 "..session.nick.." "..channel.." "..nick.." "..nick.." "..session.host.." "..nick.." H :0 "..nick);
253 end
254 session.send(":"..session.host.." 315 "..session.nick.." "..channel.. " :End of /WHO list");
255 end
256 end
257
258 function commands.MODE(session, channel)
259 session.send(":"..session.host.." 324 "..session.nick.." "..channel.." +J");
260 end
261
262 function commands.QUIT(session, message)
263 session.send("ERROR :Closing Link: "..session.nick);
264 for _, room in pairs(session.rooms) do
265 room:leave(message);
266 end
267 jids[session.full_jid] = nil;
268 nicks[session.nick] = nil;
269 sessions[session.conn] = nil;
270 session:close();
271 end
272
273 function commands.RAW(session, data)
274 --c:send(data)
275 end
276
277 --c:hook("ready", function ()
278 require "net.connlisteners".register("irc", irc_listener);
279 require "net.connlisteners".start("irc");
280 --end);
281
282 --print("Starting loop...")
283 --verse.loop()
284
285 --[[ TODO
286
287 This is so close to working as a Prosody plugin you know ^^
288 Zash: :D
289 MattJ: That component function can go
290 Prosody fires events now
291 but verse fires "message" where Prosody fires "message/bare"
292 [20:59:50]
293 Easy... don't connect_component
294 hook "message/*" and presence, and whatever
295 and call c:event("message", ...)
296 module:hook("message/bare", function (e) c:event("message", e.stanza) end)
297 as an example
298 That's so bad ^^
299 and override c:send() to core_post_stanza...
300
301 --]]
302