summaryrefslogtreecommitdiff
path: root/noncore/net/opieirc/ircmessageparser.cpp
Unidiff
Diffstat (limited to 'noncore/net/opieirc/ircmessageparser.cpp') (more/less context) (show whitespace changes)
-rw-r--r--noncore/net/opieirc/ircmessageparser.cpp478
1 files changed, 478 insertions, 0 deletions
diff --git a/noncore/net/opieirc/ircmessageparser.cpp b/noncore/net/opieirc/ircmessageparser.cpp
new file mode 100644
index 0000000..a2be5a4
--- a/dev/null
+++ b/noncore/net/opieirc/ircmessageparser.cpp
@@ -0,0 +1,478 @@
1#include <qtextstream.h>
2#include "ircmessageparser.h"
3#include "ircversion.h"
4#include <stdio.h>
5
6/* Lookup table for literal commands */
7IRCLiteralMessageParserStruct IRCMessageParser::literalParserProcTable[] = {
8 { "PING", FUNC(parseLiteralPing) },
9 { "NOTICE", FUNC(parseLiteralNotice) },
10 { "JOIN", FUNC(parseLiteralJoin) },
11 { "PRIVMSG", FUNC(parseLiteralPrivMsg) },
12 { "NICK", FUNC(parseLiteralNick) },
13 { "PART", FUNC(parseLiteralPart) },
14 { "QUIT", FUNC(parseLiteralQuit) },
15 { "ERROR", FUNC(parseLiteralError) },
16 { "ERROR:", FUNC(parseLiteralError) },
17 { "MODE", FUNC(parseLiteralMode) },
18 { "KICK", FUNC(parseLiteralKick) },
19 { 0 , 0 }
20};
21
22/* Lookup table for literal commands */
23IRCCTCPMessageParserStruct IRCMessageParser::ctcpParserProcTable[] = {
24 { "PING", FUNC(parseCTCPPing) },
25 { "VERSION", FUNC(parseCTCPVersion) },
26 { "ACTION", FUNC(parseCTCPAction) },
27 { 0 , 0 }
28};
29/* Lookup table for numerical commands */
30IRCNumericalMessageParserStruct IRCMessageParser::numericalParserProcTable[] = {
31 { 1, FUNC(parseNumerical001) }, // RPL_WELCOME
32 { 2, FUNC(parseNumerical002) }, // RPL_YOURHOST
33 { 3, FUNC(parseNumerical003) }, // RPL_CREATED
34 { 4, FUNC(parseNumerical004) }, // RPL_MYINFO
35 { 5, FUNC(parseNumerical005) }, // RPL_BOUNCE, RPL_PROTOCTL
36 { 251, FUNC(parseNumericalStats) }, // RPL_LUSERCLIENT
37 { 254, FUNC(nullFunc)}, // RPL_LUSERCHANNELS
38 { 255, FUNC(parseNumericalStats) }, // RPL_LUSERNAME
39 { 353, FUNC(parseNumericalNames) }, // RPL_NAMREPLY
40 { 366, FUNC(parseNumericalEndOfNames) }, // RPL_ENDOFNAMES
41 { 375, FUNC(parseNumericalStats) }, // RPL_MOTDSTART
42 { 372, FUNC(parseNumericalStats) }, // RPL_MOTD
43 { 376, FUNC(parseNumericalStats) }, // RPL_ENDOFMOTD
44 { 377, FUNC(parseNumericalStats) }, // RPL_MOTD2
45 { 378, FUNC(parseNumericalStats) }, // RPL_MOTD3
46 { 412, FUNC(parseNumericalStats) }, // ERNOTEXTTOSEND
47 { 433, FUNC(parseNumericalNicknameInUse) }, // ERR_NICKNAMEINUSE
48 { 0, 0 }
49};
50
51IRCMessageParser::IRCMessageParser(IRCSession *session) {
52 m_session = session;
53}
54
55void IRCMessageParser::parse(IRCMessage *message) {
56 /* Find out what kind of message we have here and call the appropriate handler using
57 the parser tables. If no handler can be found, print out an error message */
58 if (message->isNumerical()) {
59 for (int i=0; i<numericalParserProcTable[i].commandNumber; i++) {
60 if (message->commandNumber() == numericalParserProcTable[i].commandNumber) {
61 (this->*(numericalParserProcTable[i].proc))(message);
62 return;
63 }
64 }
65 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Received unhandled numeric command : ")+QString::number(message->commandNumber())));
66 } else if (message->isCTCP()) {
67 for (int i=0; ctcpParserProcTable[i].commandName; i++) {
68 if (message->ctcpCommand() == ctcpParserProcTable[i].commandName) {
69 (this->*(ctcpParserProcTable[i].proc))(message);
70 return;
71 }
72 }
73 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Received unhandled ctcp command : ")+message->ctcpCommand()));
74 } else {
75 for (int i=0; literalParserProcTable[i].commandName; i++) {
76 if (message->command() == literalParserProcTable[i].commandName) {
77 (this->*(literalParserProcTable[i].proc))(message);
78 return;
79 }
80 }
81 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Received unhandled literal command : ")+message->command()));
82 }
83}
84
85void IRCMessageParser::nullFunc(IRCMessage *) {
86 /* Do nothing */
87}
88
89void IRCMessageParser::parseLiteralPing(IRCMessage *message) {
90 m_session->m_connection->sendLine("PONG " + message->allParameters());
91}
92
93void IRCMessageParser::parseLiteralNotice(IRCMessage *message) {
94 emit outputReady(IRCOutput(OUTPUT_SERVERMESSAGE, message->allParameters()));
95}
96
97void IRCMessageParser::parseLiteralJoin(IRCMessage *message) {
98 QString channelName = message->param(0);
99 IRCPerson mask(message->prefix());
100 IRCChannel *channel = m_session->getChannel(channelName);
101 if (!channel) {
102 /* We joined */
103 if (mask.nick() == m_session->m_server->nick()) {
104 channel = new IRCChannel(channelName);
105 m_session->addChannel(channel);
106 } else {
107 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Nonexistant channel join - desynchronized?")));
108 }
109 } else {
110 /* Someone else joined */
111 if (mask.nick() != m_session->m_server->nick()) {
112 if (!channel->getPerson(mask.nick())) {
113 IRCChannelPerson *chanperson = new IRCChannelPerson();
114 IRCPerson *person = m_session->getPerson(mask.nick());
115 if (!person) {
116 person = new IRCPerson(message->prefix());
117 m_session->addPerson(person);
118 }
119 chanperson->flags = 0;
120 chanperson->person = person;
121 channel->addPerson(chanperson);
122 IRCOutput output(OUTPUT_OTHERJOIN, mask.nick() + tr(" joined channel ") + channelName);
123 output.addParam(channel);
124 output.addParam(chanperson);
125 emit outputReady(output);
126 } else {
127 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Person has already joined the channel - desynchronized?")));
128 }
129 } else {
130 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("You already joined the channel - desynchronized?")));
131 }
132 }
133}
134
135void IRCMessageParser::parseLiteralPart(IRCMessage *message) {
136 QString channelName = message->param(0);
137 IRCChannel *channel = m_session->getChannel(channelName);
138 IRCPerson mask(message->prefix());
139 if (channel) {
140 if (mask.nick() == m_session->m_server->nick()) {
141 m_session->removeChannel(channel);
142 IRCOutput output(OUTPUT_SELFPART, tr("You left channel ") + channelName);
143 output.addParam(channel);
144 emit outputReady(output);
145 delete channel;
146 } else {
147 IRCChannelPerson *person = channel->getPerson(mask.nick());
148 if (person) {
149 channel->removePerson(person);
150 IRCOutput output(OUTPUT_OTHERPART, mask.nick() + tr(" left channel ") + channelName);
151 output.addParam(channel);
152 output.addParam(person);
153 emit outputReady(output);
154 delete person;
155 } else {
156 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Parting person not found - desynchronized?")));
157 }
158 }
159 } else {
160 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Channel for part not found - desynchronized?")));
161 }
162}
163
164void IRCMessageParser::parseLiteralPrivMsg(IRCMessage *message) {
165 if (m_session->m_server->nick() == message->param(0)) {
166 /* IRC Query message detected, verify sender and display it */
167 IRCPerson mask(message->prefix());
168 IRCPerson *person = m_session->getPerson(mask.nick());
169 if (!person) {
170 /* Person not yet known, create and add to the current session */
171 person = new IRCPerson(message->prefix());
172 m_session->addPerson(person);
173 }
174 IRCOutput output(OUTPUT_CHANPRIVMSG, message->param(1));
175 output.addParam(person);
176 emit outputReady(output);
177 } else if (message->param(0).at(0) == '#') {
178 /* IRC Channel message detected, verify sender, channel and display it */
179 IRCChannel *channel = m_session->getChannel(message->param(0));
180 if (channel) {
181 IRCPerson mask(message->prefix());
182 IRCChannelPerson *person = channel->getPerson(mask.nick());
183 if (person) {
184 IRCOutput output(OUTPUT_CHANPRIVMSG, message->param(1));
185 output.addParam(channel);
186 output.addParam(person);
187 emit outputReady(output);
188 } else {
189 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Channel message with unknown sender")));
190 }
191 } else {
192 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Channel message with unknown channel")));
193 }
194 } else {
195 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Received PRIVMSG of unknown type")));
196 }
197}
198
199void IRCMessageParser::parseLiteralNick(IRCMessage *message) {
200 IRCPerson mask(message->prefix());
201
202 if (mask.nick() == m_session->m_server->nick()) {
203 /* We are changing our nickname */
204 m_session->m_server->setNick(message->param(0));
205 IRCOutput output(OUTPUT_NICKCHANGE, tr("You are now known as ")+message->param(0));
206 output.addParam(0);
207 emit outputReady(output);
208 } else {
209 /* Someone else is */
210 IRCPerson *person = m_session->getPerson(mask.nick());
211 if (person) {
212 IRCOutput output(OUTPUT_NICKCHANGE, mask.nick() + tr(" is now known as ") + message->param(0));
213 output.addParam(person);
214 emit outputReady(output);
215 } else {
216 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Nickname change of an unknown person")));
217 }
218 }
219}
220
221void IRCMessageParser::parseLiteralQuit(IRCMessage *message) {
222 IRCPerson mask(message->prefix());
223 IRCPerson *person = m_session->getPerson(mask.nick());
224 if (person) {
225 QList<IRCChannel> channels;
226 m_session->getChannelsByPerson(person, channels);
227 QListIterator<IRCChannel> it(channels);
228 for (;it.current(); ++it) {
229 IRCChannelPerson *chanperson = it.current()->getPerson(mask.nick());
230 it.current()->removePerson(chanperson);
231 }
232 m_session->removePerson(person);
233 IRCOutput output(OUTPUT_QUIT, mask.nick() + tr(" has quit ") + "(" + message->param(0) + ")");
234 output.addParam(person);
235 emit outputReady(output);
236 } else {
237 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Unknown person quit - desynchronized?")));
238 }
239}
240
241void IRCMessageParser::parseLiteralError(IRCMessage *message) {
242 emit outputReady(IRCOutput(OUTPUT_ERROR, message->allParameters()));
243}
244
245void IRCMessageParser::parseCTCPPing(IRCMessage *message) {
246 IRCPerson mask(message->prefix());
247 m_session->m_connection->sendCTCP(mask.nick(), "PING " + message->allParameters());
248 emit outputReady(IRCOutput(OUTPUT_CTCP, tr("Received a CTCP PING from ")+mask.nick()));
249}
250
251void IRCMessageParser::parseCTCPVersion(IRCMessage *message) {
252 IRCPerson mask(message->prefix());
253 m_session->m_connection->sendCTCP(mask.nick(), APP_VERSION " " APP_COPYSTR);
254 emit outputReady(IRCOutput(OUTPUT_CTCP, tr("Received a CTCP VERSION from ")+mask.nick()));
255}
256
257void IRCMessageParser::parseCTCPAction(IRCMessage *message) {
258 IRCPerson mask(message->prefix());
259 QString dest = message->ctcpDestination();
260 if (dest.startsWith("#")) {
261 IRCChannel *channel = m_session->getChannel(dest);
262 if (channel) {
263 IRCChannelPerson *person = channel->getPerson(mask.nick());
264 if (person) {
265 IRCOutput output(OUTPUT_CHANACTION, "*" + mask.nick() + message->param(0));
266 output.addParam(channel);
267 output.addParam(person);
268 emit outputReady(output);
269 } else {
270 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("CTCP ACTION with unknown person - Desynchronized?")));
271 }
272 } else {
273 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("CTCP ACTION with unknown channel - Desynchronized?")));
274 }
275 } else {
276 if (message->ctcpDestination() == m_session->m_server->nick()) {
277 IRCPerson *person = m_session->getPerson(mask.nick());
278 if (!person) {
279 /* Person not yet known, create and add to the current session */
280 person = new IRCPerson(message->prefix());
281 m_session->addPerson(person);
282 }
283 IRCOutput output(OUTPUT_QUERYACTION, "*" + mask.nick() + message->param(0));
284 output.addParam(person);
285 emit outputReady(output);
286 } else {
287 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("CTCP ACTION with bad recipient")));
288 }
289 }
290}
291
292void IRCMessageParser::parseLiteralMode(IRCMessage *message) {
293 IRCPerson mask(message->prefix());
294
295 if (message->param(0).startsWith("#")) {
296 IRCChannel *channel = m_session->getChannel(message->param(0));
297 if (channel) {
298 QString temp, parameters = message->allParameters().right(message->allParameters().length() - channel->channelname().length() - 1);
299 QTextIStream stream(&parameters);
300 bool set = FALSE;
301 while (!stream.atEnd()) {
302 stream >> temp;
303 if (temp.startsWith("+")) {
304 set = TRUE;
305 temp = temp.right(1);
306 } else if (temp.startsWith("-")) {
307 set = FALSE;
308 temp = temp.right(1);
309 } else {
310 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Mode change has unknown type")));
311 return;
312 }
313 if (temp == "o") {
314 stream >> temp;
315 IRCChannelPerson *person = channel->getPerson(temp);
316 if (person) {
317 if (set) {
318 person->flags |= PERSON_FLAG_OP;
319 IRCOutput output(OUTPUT_CHANPERSONMODE, mask.nick() + tr(" gives channel operator status to " + person->person->nick()));
320 output.addParam(channel);
321 output.addParam(person);
322 emit outputReady(output);
323 } else {
324 person->flags &= 0xFFFF - PERSON_FLAG_OP;
325 IRCOutput output(OUTPUT_CHANPERSONMODE, mask.nick() + tr(" removes channel operator status from " + person->person->nick()));
326 output.addParam(channel);
327 output.addParam(person);
328 emit outputReady(output);
329 }
330 } else {
331 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Mode change with unknown person - Desynchronized?")));
332 }
333 } else if (temp == "v") {
334 stream >> temp;
335 IRCChannelPerson *person = channel->getPerson(temp);
336 if (person) {
337 if (set) {
338 person->flags |= PERSON_FLAG_VOICE;
339 IRCOutput output(OUTPUT_CHANPERSONMODE, mask.nick() + tr(" gives voice to " + person->person->nick()));
340 output.addParam(channel);
341 output.addParam(person);
342 emit outputReady(output);
343 } else {
344 person->flags &= 0xFFFF - PERSON_FLAG_VOICE;
345 IRCOutput output(OUTPUT_CHANPERSONMODE, mask.nick() + tr(" removes voice from " + person->person->nick()));
346 output.addParam(channel);
347 output.addParam(person);
348 emit outputReady(output);
349 }
350 } else {
351 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Mode change with unknown person - Desynchronized?")));
352 }
353 } else {
354 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Mode change with unknown flag")));
355 }
356 }
357 } else {
358 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Mode change with unknown kannel - Desynchronized?")));
359 }
360 } else {
361 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("User modes not supported yet")));
362 }
363}
364
365void IRCMessageParser::parseLiteralKick(IRCMessage *message) {
366 IRCPerson mask(message->prefix());
367 IRCChannel *channel = m_session->getChannel(message->param(0));
368 if (channel) {
369 IRCChannelPerson *person = channel->getPerson(message->param(1));
370 if (person) {
371 if (person->person->nick() == m_session->m_server->nick()) {
372 m_session->removeChannel(channel);
373 IRCOutput output(OUTPUT_SELFKICK, tr("You were kicked from ") + channel->channelname() + tr(" by ") + mask.nick() + " (" + message->param(2) + ")");
374 output.addParam(channel);
375 emit outputReady(output);
376 } else {
377 channel->removePerson(person);
378 IRCOutput output(OUTPUT_OTHERKICK, person->person->nick() + tr(" was kicked from ") + channel->channelname() + tr(" by ") + mask.nick()+ " (" + message->param(2) + ")");
379 output.addParam(channel);
380 output.addParam(person);
381 emit outputReady(output);
382 }
383 } else {
384 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Unknown person kick - desynchronized?")));
385 }
386 } else {
387 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Unknown channel kick - desynchronized?")));
388 }
389}
390
391void IRCMessageParser::parseNumerical001(IRCMessage *message) {
392 /* Welcome to IRC message, display */
393 emit outputReady(IRCOutput(OUTPUT_SERVERMESSAGE, message->param(1)));
394}
395
396void IRCMessageParser::parseNumerical002(IRCMessage *message) {
397 emit outputReady(IRCOutput(OUTPUT_SERVERMESSAGE, message->param(1)));
398}
399
400void IRCMessageParser::parseNumerical003(IRCMessage *message) {
401 emit outputReady(IRCOutput(OUTPUT_SERVERMESSAGE, message->param(1)));
402}
403
404void IRCMessageParser::parseNumerical004(IRCMessage *message) {
405 emit outputReady(IRCOutput(OUTPUT_SERVERMESSAGE, message->allParameters()));
406}
407
408void IRCMessageParser::parseNumerical005(IRCMessage *message) {
409 emit outputReady(IRCOutput(OUTPUT_SERVERMESSAGE, message->allParameters()));
410}
411
412void IRCMessageParser::parseNumericalStats(IRCMessage *message) {
413 emit outputReady(IRCOutput(OUTPUT_SERVERMESSAGE, message->param(1)));
414}
415
416void IRCMessageParser::parseNumericalNames(IRCMessage *message) {
417 /* Name list sent when joining a channel */
418 IRCChannel *channel = m_session->getChannel(message->param(2));
419 if (channel != 0) {
420 QString people = message->param(3);
421 QTextIStream stream(&people);
422 QString temp;
423
424 while (!stream.atEnd()) {
425 stream >> temp;
426
427 char flagch = temp.at(0).latin1();
428 int flag = 0;
429 QString nick;
430 /* Parse person flags */
431 if (flagch == '@' || flagch == '+' || flagch=='%' || flagch == '*') {
432
433 nick = temp.right(temp.length()-1);
434 switch (flagch) {
435 case '@': flag = PERSON_FLAG_OP; break;
436 case '+': flag = PERSON_FLAG_VOICE; break;
437 case '%': flag = PERSON_FLAG_HALFOP; break;
438 default : flag = 0; break;
439 }
440 } else {
441 nick = temp;
442 }
443
444 IRCChannelPerson *chan_person = new IRCChannelPerson();
445 IRCPerson *person = m_session->getPerson(nick);
446 if (person == 0) {
447 person = new IRCPerson();
448 person->setNick(nick);
449 m_session->addPerson(person);
450 }
451 chan_person->person = person;
452 chan_person->flags = flag;
453 channel->addPerson(chan_person);
454 }
455 } else {
456 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Server message with unknown channel")));
457 }
458}
459
460void IRCMessageParser::parseNumericalEndOfNames(IRCMessage *message) {
461 /* Done syncing to channel */
462 IRCChannel *channel = m_session->getChannel(message->param(1));
463 if (channel) {
464 channel->setHasPeople(TRUE);
465 /* Yes, we want the names before anything happens inside the GUI */
466 IRCOutput output(OUTPUT_SELFJOIN, tr("You joined channel ") + channel->channelname());
467 output.addParam(channel);
468 emit outputReady(output);
469 } else {
470 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Server message with unknown channel")));
471 }
472}
473
474
475void IRCMessageParser::parseNumericalNicknameInUse(IRCMessage *) {
476 emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Nickname is in use, please reconnect with a different nickname")));
477 m_session->endSession();
478}