comparison mod_ircd/mod_ircd.in.lua @ 468:640e6c0b563d

mod_ircd: Scrub invalid UTF-8 sequences, welcome message
author Kim Alvefur <zash@zash.se>
date Tue, 01 Nov 2011 19:18:30 +0100
parents 0fcd34ee7301
children ff03a325aa41
comparison
equal deleted inserted replaced
467:266bf13729ae 468:640e6c0b563d
51 --c.connect_host = "127.0.0.1" 51 --c.connect_host = "127.0.0.1"
52 --c:connect_component(component_jid, component_secret); 52 --c:connect_component(component_jid, component_secret);
53 53
54 local jid = require "util.jid"; 54 local jid = require "util.jid";
55 local nodeprep = require "util.encodings".stringprep.nodeprep; 55 local nodeprep = require "util.encodings".stringprep.nodeprep;
56
57 local function utf8_clean (s)
58 local push, join = table.insert, table.concat;
59 local r, i = {}, 1;
60 if not(s and #s > 0) then
61 return ""
62 end
63 while true do
64 local c = s:sub(i,i)
65 local b = c:byte();
66 local w = (
67 (b >= 9 and b <= 10 and 0) or
68 (b >= 32 and b <= 126 and 0) or
69 (b >= 192 and b <= 223 and 1) or
70 (b >= 224 and b <= 239 and 2) or
71 (b >= 240 and b <= 247 and 3) or
72 (b >= 248 and b <= 251 and 4) or
73 (b >= 251 and b <= 252 and 5) or nil
74 )
75 if not w then
76 push(r, "?")
77 else
78 local n = i + w;
79 if w == 0 then
80 push(r, c);
81 elseif n > #s then
82 push(r, ("?"):format(b));
83 else
84 local e = s:sub(i+1,n);
85 if e:match('^[\128-\191]*$') then
86 push(r, c);
87 push(r, e);
88 i = n;
89 else
90 push(r, ("?"):format(b));
91 end
92 end
93 end
94 i = i + 1;
95 if i > #s then
96 break
97 end
98 end
99 return join(r);
100 end
56 101
57 local function parse_line(line) 102 local function parse_line(line)
58 local ret = {}; 103 local ret = {};
59 if line:sub(1,1) == ":" then 104 if line:sub(1,1) == ":" then
60 ret.from, line = line:match("^:(%w+)%s+(.*)$"); 105 ret.from, line = line:match("^:(%w+)%s+(.*)$");
126 end 171 end
127 command = command:upper(); 172 command = command:upper();
128 if not session.nick then 173 if not session.nick then
129 if not (command == "USER" or command == "NICK") then 174 if not (command == "USER" or command == "NICK") then
130 module:log("debug", "Client tried to send command %s before registering", command); 175 module:log("debug", "Client tried to send command %s before registering", command);
131 return session.send{from=muc_server, 451, command, "You have not registered"} 176 return session.send{from=muc_server, "451", command, "You have not registered"}
132 end 177 end
133 end 178 end
134 if commands[command] then 179 if commands[command] then
135 local ret = commands[command](session, parts); 180 local ret = commands[command](session, parts);
136 if ret then 181 if ret then
137 return session.send(ret); 182 return session.send(ret);
138 end 183 end
139 else 184 else
140 session.send{from=muc_server, 421, session.nick, command, "Unknown command"}; 185 session.send{from=muc_server, "421", session.nick, command, "Unknown command"};
141 return module:log("debug", "Unknown command: %s", command); 186 return module:log("debug", "Unknown command: %s", command);
142 end 187 end
143 end 188 end
144 function session.send(data) 189 function session.send(data)
145 if type(data) == "string" then 190 if type(data) == "string" then
172 sessions[conn] = nil; 217 sessions[conn] = nil;
173 end 218 end
174 219
175 function commands.NICK(session, args) 220 function commands.NICK(session, args)
176 if session.nick then 221 if session.nick then
177 session.send(":"..muc_server.." 484 * "..nick.." :I'm afraid I can't let you do that, "..session.nick); 222 session.send{from = muc_server, "484", "*", nick, "I'm afraid I can't let you do that"};
178 --TODO Loop throug all rooms and change nick, with help from Verse. 223 --TODO Loop throug all rooms and change nick, with help from Verse.
179 return; 224 return;
180 end 225 end
181 local nick = args[1]; 226 local nick = args[1];
182 nick = nick:gsub("[^%w_]",""); 227 nick = nick:gsub("[^%w_]","");
183 if nicks[nick] then 228 if nicks[nick] then
184 session.send{from=muc_server, 433, nick, "The nickname "..nick.." is already in use"}; 229 session.send{from=muc_server, "433", nick, "The nickname "..nick.." is already in use"};
185 return; 230 return;
186 end 231 end
187 local full_jid = jid.join(nick, component_jid, "ircd"); 232 local full_jid = jid.join(nick, component_jid, "ircd");
188 jids[full_jid] = session; 233 jids[full_jid] = session;
189 nicks[nick] = session; 234 nicks[nick] = session;
190 session.nick = nick; 235 session.nick = nick;
191 session.full_jid = full_jid; 236 session.full_jid = full_jid;
192 session.type = "c2s"; 237 session.type = "c2s";
193 session.send{from = muc_server, 001, nick, "Welcome to XMPP via the "..session.host.." gateway "..session.nick}; 238 session.send{from = muc_server, "001", nick, "Welcome to IRC gateway to XMPP!"};
194 session.send{from=nick, "MODE", nick, "+i"}; -- why 239 session.send{from = muc_server, "002", nick, module.host.." running Prosody "..prosody.version};
240 session.send{from = muc_server, "003", nick, os.date(nil, prosody.start_time)}
241 session.send{from = muc_server, "004", table.concat({muc_server, "alpha", "i", "ov"}, " ")};
242 session.send{from = nick, "MODE", nick, "+i"}; -- why
195 end 243 end
196 244
197 function commands.USER(session, params) 245 function commands.USER(session, params)
198 -- FIXME 246 -- FIXME
199 -- Empty command for now 247 -- Empty command for now
278 local channel, message = unpack(args); 326 local channel, message = unpack(args);
279 if message and #message > 0 then 327 if message and #message > 0 then
280 if message:sub(1,8) == "\1ACTION " then 328 if message:sub(1,8) == "\1ACTION " then
281 message = "/me ".. message:sub(9,-2) 329 message = "/me ".. message:sub(9,-2)
282 end 330 end
283 -- TODO clean out invalid chars 331 message = utf8_clean(message);
284 if channel:sub(1,1) == "#" then 332 if channel:sub(1,1) == "#" then
285 if session.rooms[channel] then 333 if session.rooms[channel] then
286 module:log("debug", "%s sending PRIVMSG \"%s\" to %s", session.nick, message, channel); 334 module:log("debug", "%s sending PRIVMSG \"%s\" to %s", session.nick, message, channel);
287 session.rooms[channel]:send_message(message); 335 session.rooms[channel]:send_message(message);
288 end 336 end
320 end 368 end
321 session.send{from=muc_server, 315, session.nick, channel, "End of /WHO list"}; 369 session.send{from=muc_server, 315, session.nick, channel, "End of /WHO list"};
322 end 370 end
323 end 371 end
324 372
325 function commands._MODE(session, args) -- FIXME 373 function commands.MODE(session, args) -- FIXME
326 local channel, target = unpack(args); 374 local channel, target = unpack(args);
327 if target then 375 if target then
328 -- do stuff? 376 -- do stuff?
329 --room:set_affiliation(...) 377 --room:set_affiliation(...)
378 session.send{from=muc_server, "324", session.nick, channel, "+i"}
330 else 379 else
331 -- What's 324? And +J ? 380 -- What's 324? And +J ?
332 session.send{from=muc_server, 324, session.nick, channel, "+J"} 381 session.send{from=muc_server, "324", session.nick, channel, "+J"}
333 end 382 end
334 end 383 end
335 384
336 function commands.QUIT(session, args) 385 function commands.QUIT(session, args)
337 session.send{"ERROR", "Closing Link: "..session.nick}; 386 session.send{"ERROR", "Closing Link: "..session.nick};