comparison mod_ircd/mod_ircd.in.lua @ 465:030404dd7609

mod_ircd: Better nameing, squishy.
author Kim Alvefur <zash@zash.se>
date Tue, 01 Nov 2011 13:52:29 +0100
parents mod_ircd/mod_ircd_broke.lua@bbea8081c865
children 0fcd34ee7301
comparison
equal deleted inserted replaced
463:7d6a05f94941 465:030404dd7609
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(":" .. muc_server .. " 451 " .. command .. " :You have not registered")
105 return true;
106 end
107 end
108 if commands[command] then
109 local ret = commands[command](session, args);
110 if ret then
111 session.send(ret.."\r\n");
112 end
113 else
114 session.send(":" .. muc_server .. " 421 " .. session.nick .. " " .. command .. " :Unknown command")
115 module:log("debug", "Unknown command: %s", command);
116 end
117 end
118 function session.send(data)
119 return conn:write(data.."\r\n");
120 end
121 end
122 if data then
123 session.data(data);
124 end
125 end
126
127 function irc_listener.ondisconnect(conn, error)
128 local session = sessions[conn];
129 for _, room in pairs(session.rooms) do
130 room:leave("Disconnected");
131 end
132 jids[session.full_jid] = nil;
133 nicks[session.nick] = nil;
134 sessions[conn] = nil;
135 end
136
137 function commands.NICK(session, nick)
138 if session.nick then
139 session.send(":"..muc_server.." 484 * "..nick.." :I'm afraid I can't let you do that, "..nick);
140 --TODO Loop throug all rooms and change nick, with help from Verse.
141 return;
142 end
143 nick = nick:match("^[%w_]+");
144 if nicks[nick] then
145 session.send(":"..session.host.." 433 * "..nick.." :The nickname "..nick.." is already in use");
146 return;
147 end
148 local full_jid = jid.join(nick, component_jid, "ircd");
149 jids[full_jid] = session;
150 nicks[nick] = session;
151 session.nick = nick;
152 session.full_jid = full_jid;
153 session.type = "c2s";
154 session.send(":"..session.host.." 001 "..session.nick.." :Welcome to XMPP via the "..session.host.." gateway "..session.nick);
155 end
156
157 function commands.USER(session, params)
158 -- FIXME
159 -- Empty command for now
160 end
161
162 function commands.JOIN(session, channel)
163 local room_jid = irc2muc(channel);
164 print(session.full_jid);
165 local room, err = c:join_room(room_jid, session.nick, { source = session.full_jid } );
166 if not room then
167 return ":"..session.host.." ERR :Could not join room: "..err
168 end
169 session.rooms[channel] = room;
170 room.channel = channel;
171 room.session = session;
172 session.send(":"..session.nick.." JOIN :"..channel);
173 session.send(":"..session.host.." 332 "..session.nick.." "..channel.." :Connection in progress...");
174 room:hook("message", function(event)
175 if not event.body then return end
176 local nick, body = event.nick, event.body;
177 if nick ~= session.nick then
178 if body:sub(1,4) == "/me " then
179 body = "\1ACTION ".. body:sub(5) .. "\1"
180 end
181 session.send(":"..nick.." PRIVMSG "..channel.." :"..body);
182 --FIXME PM's probably won't work
183 end
184 end);
185 end
186
187 c:hook("groupchat/joined", function(room)
188 local session = room.session or jids[room.opts.source];
189 local channel = room.channel;
190 session.send((":%s!%s JOIN %s :"):format(session.nick, session.nick, channel));
191 if room.topic then
192 session.send((":%s 332 %s :%s"):format(session.host, channel, room.topic));
193 end
194 commands.NAMES(session, channel)
195 --FIXME Ones own mode get's lost
196 --session.send((":%s MODE %s +%s %s"):format(session.host, room.channel, modemap[nick.role], nick.nick));
197 room:hook("occupant-joined", function(nick)
198 session.send((":%s!%s JOIN :%s"):format(nick.nick, nick.nick, channel));
199 if nick.role and modemap[nick.role] then
200 session.send((":%s MODE %s +%s %s"):format(session.host, room.channel, modemap[nick.role], nick.nick));
201 end
202 end);
203 room:hook("occupant-left", function(nick)
204 session.send((":%s!%s PART %s :"):format(nick.nick, nick.nick, channel));
205 end);
206 end);
207
208 function commands.NAMES(session, channel)
209 local nicks = { };
210 local room = session.rooms[channel];
211 if not room then return end
212 -- TODO Break this out into commands.NAMES
213 for nick, n in pairs(room.occupants) do
214 if n.role and rolemap[n.role] then
215 nick = rolemap[n.role] .. nick;
216 end
217 table.insert(nicks, nick);
218 end
219 nicks = table.concat(nicks, " ");
220 --: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
221 session.send((":%s 353 %s = %s :%s"):format(session.host, session.nick, channel, nicks));
222 session.send((":%s 366 %s %s :End of /NAMES list."):format(session.host, session.nick, channel));
223 session.send(":"..session.host.." 353 "..session.nick.." = "..channel.." :"..nicks);
224 end
225
226 function commands.PART(session, channel)
227 local channel, part_message = channel:match("^([^:]+):?(.*)$");
228 channel = channel:match("^([%S]*)");
229 session.rooms[channel]:leave(part_message);
230 session.send(":"..session.nick.." PART :"..channel);
231 end
232
233 function commands.PRIVMSG(session, message)
234 local channel, message = message:match("^(%S+) :(.+)$");
235 if message and #message > 0 and session.rooms[channel] then
236 if message:sub(1,8) == "\1ACTION " then
237 message = "/me ".. message:sub(9,-2)
238 end
239 module:log("debug", "%s sending PRIVMSG \"%s\" to %s", session.nick, message, channel);
240 session.rooms[channel]:send_message(message);
241 end
242 end
243
244 function commands.PING(session, server)
245 session.send(":"..session.host..": PONG "..server);
246 end
247
248 function commands.WHO(session, channel)
249 if session.rooms[channel] then
250 local room = session.rooms[channel]
251 for nick in pairs(room.occupants) do
252 --n=MattJ 91.85.191.50 irc.freenode.net MattJ H :0 Matthew Wild
253 session.send(":"..session.host.." 352 "..session.nick.." "..channel.." "..nick.." "..nick.." "..session.host.." "..nick.." H :0 "..nick);
254 end
255 session.send(":"..session.host.." 315 "..session.nick.." "..channel.. " :End of /WHO list");
256 end
257 end
258
259 function commands.MODE(session, channel)
260 session.send(":"..session.host.." 324 "..session.nick.." "..channel.." +J");
261 end
262
263 function commands.QUIT(session, message)
264 session.send("ERROR :Closing Link: "..session.nick);
265 for _, room in pairs(session.rooms) do
266 room:leave(message);
267 end
268 jids[session.full_jid] = nil;
269 nicks[session.nick] = nil;
270 sessions[session.conn] = nil;
271 session:close();
272 end
273
274 function commands.RAW(session, data)
275 --c:send(data)
276 end
277
278 local function desetup()
279 require "net.connlisteners".deregister("irc");
280 end
281
282 --c:hook("ready", function ()
283 require "net.connlisteners".register("irc", irc_listener);
284 require "net.connlisteners".start("irc");
285 --end);
286
287 module:hook("module-unloaded", desetup)
288
289
290 --print("Starting loop...")
291 --verse.loop()
292
293