[project @ 2002-07-12 03:27:05 by unknown_lamer]
[clinton/bobotpp.git] / source / Parser.C
CommitLineData
cb21075d 1// Parser.C -*- C++ -*-
2// Copyright (c) 1997, 1998 Etienne BERNARD
3// Copyright (C) 2002 Clinton Ebadi
4
5// This program is free software; you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation; either version 2 of the License, or
8// any later version.
9
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14
15// You should have received a copy of the GNU General Public License
16// along with this program; if not, write to the Free Software
17// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
18
19#ifdef HAVE_CONFIG_H
20#include "config.h"
21#endif
22
23#include <sys/types.h>
24#include <netinet/in.h>
25
26#include "StringTokenizer.H"
27#include "Parser.H"
28#include "UserCommands.H"
29#include "Macros.H"
30#include "Utils.H"
31#include "ShitList.H"
32
439869bf 33typedef void (*fptr)(ServerConnection *, Person *, String);
34std::map<std::string, fptr, std::less<std::string> > Parser::functions;
35
36void Parser::init ()
37{
38 Parser::functions["001"] = Parser::parse001; /* RPL_WELCOME */
39 Parser::functions["302"] = Parser::parse302; /* RPL_USERHOST */
40 Parser::functions["311"] = Parser::parse311; /* RPL_WHOISUSER */
41 Parser::functions["315"] = Parser::parse315; /* RPL_ENDOFWHO */
42 Parser::functions["324"] = Parser::parse324; /* RPL_CHANNELMODEIS */
43 Parser::functions["332"] = Parser::parse332; /* RPL_TOPIC */
44 Parser::functions["352"] = Parser::parse352; /* RPL_WHOREPLY */
45 Parser::functions["353"] = Parser::parse353; /* RPL_NAMESREPLY */
46 Parser::functions["366"] = Parser::parse366; /* RPL_ENDOFNAMES */
47 Parser::functions["367"] = Parser::parse367; /* RPL_BANLIST */
48 Parser::functions["401"] = Parser::parse401; /* ERR_NOSUCHNICK */
49 Parser::functions["433"] = Parser::parse433; /* ERR_NICKNAMEINUSE */
50 Parser::functions["437"] = Parser::parse433; /* ERR_UNAVAILRESOURCE */
51 Parser::functions["471"] = Parser::parse473; /* ERR_CHANNELISFULL */
52 Parser::functions["473"] = Parser::parse473; /* ERR_INVITEONLYCHAN */
53 Parser::functions["474"] = Parser::parse473; /* ERR_BANNEDFROMCHAN */
54 Parser::functions["475"] = Parser::parse473; /* ERR_BADCHANNELKEY */
55 Parser::functions["ERROR"] = Parser::parseError;
56 Parser::functions["INVITE"] = Parser::parseInvite;
57 Parser::functions["JOIN"] = Parser::parseJoin;
58 Parser::functions["KICK"] = Parser::parseKick ;
59 Parser::functions["MODE"] = Parser::parseMode ;
60 Parser::functions["NICK"] = Parser::parseNick ;
61 Parser::functions["NOTICE"] = Parser::parseNotice;
62 Parser::functions["PART"] = Parser::parsePart;
63 Parser::functions["PING"] = Parser::parsePing;
64 Parser::functions["PONG"] = Parser::parsePong;
65 Parser::functions["PRIVMSG"] = Parser::parsePrivmsg;
66 Parser::functions["QUIT"] = Parser::parseQuit;
67 Parser::functions["TOPIC"] = Parser::parseTopic;
68 Parser::functions[""] = Parser::parseError;
69}
cb21075d 70
71
72void
73Parser::parseLine(ServerConnection * cnx, String line)
74{
75 StringTokenizer st(line);
76 Person * from = 0;
77
78#ifdef USESCRIPTS
79 cnx->bot->botInterp->RunHooks(Hook::RAW, line,
80 scm_listify (Utils::string2SCM(line),
81 SCM_UNDEFINED));
82#endif
83
84 if (line[0] == ':') {
85 String fromMask = st.nextToken().subString(1);
86 if (fromMask.find('!') != -1)
87 from = new Person(cnx->bot, fromMask);
88 }
89
90 String command = st.nextToken();
91 String rest = st.rest();
92
439869bf 93 /* for (int i = 0; functions[i].name != 0; i++)
cb21075d 94 if (command == functions[i].name) {
95 functions[i].function(cnx, from, rest);
96 break;
97 }
439869bf 98 */
99 if (fptr temp_func = functions[command])
100 temp_func (cnx, from, rest);
cb21075d 101
102 delete from;
103}
104
105void
106Parser::parse001(ServerConnection * cnx,
107 Person *from, String rest)
108{
109 String temp = "";
110 StringTokenizer st(rest);
111 String realNick = st.nextToken();
112
113 if ((cnx->bot->nickName).toLower() != realNick) {
114 // Yes, this can happen, and it was a very subtle bug
115 cnx->bot->nickName = realNick;
116 cnx->bot->userList->removeFirst();
117 cnx->bot->userList->addUserFirst(realNick + "!" + cnx->bot->userHost, "*", 0, 3, true, -1, "");
118 cnx->bot->lastNickNameChange = time(0);
119 cnx->bot->rehash();
120 }
121
122 cnx->bot->connected = true;
123
124 cnx->queue->sendUserMode(cnx->bot->nickName, "+i");
125 cnx->queue->sendWhois(cnx->bot->nickName);
126
127 for (std::map<String, wantedChannel *, std::less<String> >::iterator
128 it = cnx->bot->wantedChannels.begin();
129 it != cnx->bot->wantedChannels.end(); ++it)
130 cnx->queue->sendJoin((*it).first, (*it).second->key);
131
132 cnx->bot->logLine(String("Connected to server ") +
133 cnx->bot->serverList->currentServer()->getHostName() +
134 " (" + String((long)cnx->bot->serverList->currentServer()->getPort()) +
135 ").");
136}
137
138void
139Parser::parse302(ServerConnection *cnx,
140 Person *from, String rest)
141{
142 unsigned long num = cnx->bot->receivedUserhostID++;
143 StringTokenizer st(rest);
144
145 st.nextToken(':');
146
147 if (st.rest().length()) {
148 st.nextToken('=');
149 String parameters = st.rest();
150 parameters = parameters.subString(1);
151 cnx->bot->userhostMap[num] = parameters;
152 } else
153 cnx->bot->userhostMap[num] = "";
154}
155
156void
157Parser::parse311(ServerConnection *cnx,
158 Person *from, String rest)
159{
160 StringTokenizer st(rest);
161 st.nextToken();
162 String nuh = st.nextToken() + "!";
163 String uh = st.nextToken() + "@";
164 uh = uh + st.nextToken();
165 nuh = nuh + uh;
166 cnx->bot->userList->addUserFirst(nuh, "*", 0, 3, true, -1, "");
167 cnx->bot->userHost = uh;
168}
169
170void
171Parser::parse315(ServerConnection *cnx,
172 Person *from, String rest)
173{
174 StringTokenizer st(rest);
175 st.nextToken();
176 String channel = st.nextToken();
177 Channel *c = cnx->bot->channelList->getChannel(channel);
178 if (!c)
179 return;
180 c->gotWho = true;
181}
182
183void
184Parser::parse324(ServerConnection *cnx,
185 Person *from, String rest)
186{
187 StringTokenizer st(rest);
188 st.nextToken();
189 String channel = st.nextToken();
190 if (Channel *c = cnx->bot->channelList->getChannel(channel))
191 if (c) c->parseMode(from, st.rest());
192}
193
194void
195Parser::parse332(ServerConnection *cnx,
196 Person *from, String rest)
197{
198 StringTokenizer st(rest);
199 st.nextToken();
200 String channel = st.nextToken();
201 if (Channel *c = cnx->bot->channelList->getChannel(channel))
202 if (c) c->channelTopic = st.rest().subString(1);
203}
204
205void
206Parser::parse352(ServerConnection *cnx,
207 Person *from, String rest)
208{
209 StringTokenizer st(rest);
210 st.nextToken();
211 String ch = st.nextToken();
212 String uh = st.nextToken() + "@";
213 uh = uh + st.nextToken();
214 st.nextToken();
215 String n = st.nextToken();
216 String m = st.nextToken();
217 int mode = 0;
218
219 for (int i = 0; i < m.length(); i++)
220 switch (m[i]) {
221 case 'H': break;
222 case 'G': mode |= User::AWAY_MODE; break;
223 case '*': mode |= User::IRCOP_MODE; break;
224 case '@': mode |= User::OP_MODE; break;
225 case '+': mode |= User::VOICE_MODE; break;
226 }
227 if (Channel *c = cnx->bot->channelList->getChannel(ch))
228 if (c) c->addNick(n, uh, mode, cnx->bot->userList);
229}
230
231void
232Parser::parse353(ServerConnection *cnx,
233 Person *from, String rest)
234{
235 int mode = 0;
236 String nick;
237
238 StringTokenizer st(rest);
239 st.nextToken(); st.nextToken();
240
241 Channel * c = cnx->bot->channelList->getChannel(st.nextToken());
242 if (!c) return;
243 StringTokenizer st2(st.nextToken(':'));
244
245 while (st2.hasMoreTokens()) {
246 nick = st2.nextToken();
247 if (nick[0] == '@') {
248 mode = User::OP_MODE;
249 nick = nick.subString(1);
250 } else if (nick[0] == '+') {
251 mode = User::VOICE_MODE;
252 nick = nick.subString(1);
253 }
254 c->addNick(nick, "", mode, 0, true);
255 }
256}
257
258void
259Parser::parse366(ServerConnection *cnx,
260 Person *from, String rest)
261{
262 StringTokenizer st(rest);
263 st.nextToken();
264 String ch = st.nextToken();
265 if (Channel *c = cnx->bot->channelList->getChannel(ch))
266 c->joined = true;
267}
268
269void
270Parser::parse367(ServerConnection *cnx,
271 Person *from, String rest)
272{
273 StringTokenizer st(rest);
274 st.nextToken();
275 String ch = st.nextToken();
276 if (Channel *c = cnx->bot->channelList->getChannel(ch))
277 c->addBan(st.nextToken(), -1);
278}
279
280void
281Parser::parse401(ServerConnection *cnx,
282 Person *from, String rest)
283{
284 StringTokenizer st(rest);
285 st.nextToken();
286 String nick = st.nextToken();
287
288 if (cnx->bot->spyList.find(nick) != cnx->bot->spyList.end()) {
289 delete cnx->bot->spyList[nick];
290 cnx->bot->spyList.erase(nick);
291 }
292}
293
294void
295Parser::parse433(ServerConnection *cnx,
296 Person *from, String rest)
297{
298 if (cnx->bot->connected)
299 return;
300
301 if (cnx->bot->nickName.length() == 9) {
302 int i;
303 for (i = 0; i < cnx->bot->nickName.length() && cnx->bot->nickName[i] == '_'; i++)
304 ;
305 if (i < cnx->bot->nickName.length())
306 cnx->bot->nickName = cnx->bot->nickName.subString(0, i-1) + "_" + cnx->bot->nickName.subString(i+1);
307 else
308 cnx->bot->nickName = cnx->bot->nickName.subString(0, 4) +
309 String((long)(rand() % 10000));
310 }
311 else
312 cnx->bot->nickName = cnx->bot->nickName + "_";
313
314 cnx->queue->sendNick(cnx->bot->nickName);
315}
316
317void
318Parser::parse473(ServerConnection *cnx,
319 Person *from, String rest)
320{
321 StringTokenizer st(rest);
322 st.nextToken();
323
324 cnx->bot->logLine(String("Unable to join channel ") +
325 st.nextToken() + ".");
326}
327
328void
329Parser::parseError(ServerConnection *cnx,
330 Person *from, String rest)
331{
332 cnx->bot->logLine(String("Error from server ") +
333 cnx->bot->serverList->currentServer()->getHostName() +
334 " (" + String((long)cnx->bot->serverList->currentServer()->getPort()) +
335 ").");
336 cnx->bot->nextServer();
337}
338
339void
340Parser::parseInvite(ServerConnection *cnx,
341 Person *from, String rest)
342{
343 String nick = from->getNick();
344 StringTokenizer st(rest);
345 st.nextToken(':');
346 String channel = st.rest();
347
348#ifdef USESCRIPTS
349 cnx->bot->botInterp->RunHooks(Hook::INVITE, nick + " " + channel,
350 scm_listify (Utils::string2SCM(nick),
351 Utils::string2SCM(channel),
352 SCM_UNDEFINED));
353#endif
354
355 if (cnx->bot->wantedChannels.find(channel) !=
356 cnx->bot->wantedChannels.end())
357 cnx->queue->sendJoin(channel, cnx->bot->wantedChannels[channel]->key);
358}
359
360void
361Parser::parseJoin(ServerConnection *cnx,
362 Person *from, String rest)
363{
364 StringTokenizer st(from->getAddress());
365 String n = st.nextToken('!');
366 String uh = st.nextToken();
367 StringTokenizer st2(rest);
368 String c = st2.nextToken(':');
369 String mode;
370 bool joinAndMode = false;
371
372#ifdef USESCRIPTS
373 cnx->bot->botInterp->RunHooks(Hook::JOIN, n + " " + c,
374 scm_listify (Utils::string2SCM(n),
375 Utils::string2SCM(c),
376 SCM_UNDEFINED));
377#endif
378
379 // This part of code is for the combined JOIN & MODE of ircd 2.9
380 if (c.find('\007') >= 0) {
381 joinAndMode = true;
382 StringTokenizer st3(c);
383 c = st3.nextToken('\007');
384 String m = st3.rest();
385 mode = c + " +" + m;
386 for (int i = 0; i < m.length(); i++)
387 mode = mode + " " + n;
388 }
389
390 if (n == cnx->bot->nickName) {
391 cnx->bot->logLine(String("Joined channel ") + c + ".");
392 if (cnx->bot->wantedChannels.find(c) != cnx->bot->wantedChannels.end())
393 cnx->bot->channelList->addChannel(cnx, c, cnx->bot->wantedChannels[c]->keep);
394 else
395 cnx->bot->channelList->addChannel(cnx, c);
396 cnx->queue->sendWho(c);
397 cnx->queue->sendChannelMode(String("MODE ") + c + " b");
398 cnx->queue->sendChannelMode(String("MODE ") + c);
399 } else {
400 Channel * ch = cnx->bot->channelList->getChannel(c);
401 if (!ch)
402 return;
403 ShitEntry * se = cnx->bot->shitList->getShit(n+"!"+uh, c);
404 if (se && se->isStillValid() &&
405 se->getShitLevel() >= ShitEntry::SHIT_NOJOIN) {
406 cnx->queue->sendChannelMode(c, "+b", se->getMask());
407 cnx->queue->sendKick(c, n, se->getShitReason());
408 return;
409 }
410 ch->addNick(n, uh, 0, cnx->bot->userList);
411 if (ch->getUser(n)->getAop() && !(ch->getUser(n)->mode & User::OP_MODE) && cnx->bot->iAmOp(c)) {
412 // This is a part of the antispoof code
413 ch->getUser(n)->userkey = Utils::getKey();
414 cnx->queue->sendCTCP(n, "PING", ch->getUser(n)->userkey + " " + c);
415 }
416 }
417
418 if (joinAndMode)
419 parseMode(cnx, 0, mode);
420}
421
422void
423Parser::parseKick(ServerConnection *cnx,
424 Person *from, String rest)
425{
426 StringTokenizer st(rest);
427 String channel = st.nextToken();
428 String target = st.nextToken();
429 String reason = st.rest().subString(1);
430
431#ifdef USESCRIPTS
432 cnx->bot->botInterp->RunHooks(Hook::KICK, target + " " + from->getNick() + " "
433 + channel + " " + reason,
434 scm_listify (Utils::string2SCM(target),
435 Utils::string2SCM(from->getNick()),
436 Utils::string2SCM(channel),
437 Utils::string2SCM(reason),
438 SCM_UNDEFINED));
439#endif
440
441 if (target == cnx->bot->nickName) {
442 cnx->bot->logLine(from->getAddress() + " kicked me out of channel " +
443 channel + " (" + reason + ").");
444 cnx->queue->sendJoin(channel, cnx->bot->channelList->getChannel(channel)->channelKey);
445 cnx->bot->channelList->delChannel(channel);
446 } else {
447 if (!cnx->bot->channelList->getChannel(channel)) return;
448 User *u = cnx->bot->channelList->getChannel(channel)->getUser(target);
449 if (u && u->getProt() >= User::NO_KICK) {
450 String fromNick = from->getNick();
451 User *v = cnx->bot->channelList->getChannel(channel)->getUser(fromNick);
452 if (v->getProt() < User::NO_KICK) {
453 cnx->bot->logLine(from->getAddress() + " kicked " + target +
454 " (protected) out of channel " + channel +
455 " (" + reason + ").");
456 cnx->queue->sendKick(channel, fromNick,
457 target + " \002is protected !\002");
458 }
459 }
460 cnx->bot->channelList->getChannel(channel)->delNick(target);
461 }
462}
463
464void
465Parser::parseMode(ServerConnection *cnx,
466 Person *from, String rest)
467{
468 StringTokenizer st(rest);
469 String ch = st.nextToken();
470 String modes = st.rest();
471
472#ifdef USESCRIPTS
473 if (from)
474 cnx->bot->botInterp->RunHooks(Hook::MODE, from->getNick() + " " + ch +
475 " " + modes,
476 scm_listify (Utils::string2SCM(from->getNick()),
477 Utils::string2SCM(ch),
478 Utils::string2SCM(modes),
479 SCM_UNDEFINED));
480#endif
481
482
483 if (Utils::isChannel(ch)) {
484 Channel *c = cnx->bot->channelList->getChannel(ch);
485 if (!c)
486 return;
487 if (from)
488 c->parseMode(from, modes);
489 else
490 c->parseMode(0, modes);
491 }
492}
493
494void
495Parser::parseNick(ServerConnection *cnx,
496 Person *from, String rest)
497{
498 String on_orig = from->getNick();
499 String on = on_orig.toLower();
500 String nn = rest.subString(1);
501 String nn_lower = nn.toLower();
502
503#ifdef USESCRIPTS
504 cnx->bot->botInterp->RunHooks(Hook::NICKNAME, on_orig + " " + nn,
505 scm_listify (Utils::string2SCM(on_orig),
506 Utils::string2SCM(nn),
507 SCM_UNDEFINED));
508#endif
509
510 if ((cnx->bot->nickName).toLower() == on) {
511 cnx->bot->userList->removeFirst();
512 cnx->bot->userList->addUserFirst(nn + "!" + cnx->bot->userHost, "*", 0, 3, true, -1, "");
513 cnx->bot->lastNickNameChange = time(0);
514 cnx->bot->nickName = nn;
515 cnx->bot->rehash();
516 }
517
518 if (cnx->bot->spyList.find(on) != cnx->bot->spyList.end()) {
519 cnx->bot->spyList[nn_lower] = cnx->bot->spyList[on];
520 cnx->bot->spyList.erase(on);
521 }
522
523 for (std::map<String, Channel *, std::less<String> >::iterator it =
524 cnx->bot->channelList->begin();
525 it != cnx->bot->channelList->end();
526 ++it)
527 if ((*it).second->hasNick(on))
528 (*it).second->changeNick(on, nn_lower);
529}
530
531void
532Parser::parseNotice(ServerConnection *cnx,
533 Person *from, String rest)
534{
535 String nick = "";
536
537 if (from)
538 nick = from->getNick();
539
540 StringTokenizer st(rest);
541 String to = st.nextToken();
542
543 rest = st.rest().subString(1);
544
545 if (rest[0] != '\001') {
546#ifdef USESCRIPTS
547 if (Utils::isChannel(to))
548 cnx->bot->botInterp->RunHooks(Hook::PUBLIC_NOTICE, nick + " " +
549 to + " " + rest,
550 scm_listify (Utils::string2SCM(nick),
551 Utils::string2SCM(to),
552 Utils::string2SCM(rest),
553 SCM_UNDEFINED));
554 else
555 cnx->bot->botInterp->RunHooks(Hook::NOTICE, nick + " " + rest,
556 scm_listify (Utils::string2SCM(nick),
557 Utils::string2SCM(rest),
558 SCM_UNDEFINED));
559#endif
560 return;
561 }
562
563 rest = rest.subString(1, rest.length() - 2);
564 StringTokenizer st2(rest);
565 String command = st2.nextToken();
566 rest = st2.rest();
567
568#ifdef USESCRIPTS
569 cnx->bot->botInterp->RunHooks(Hook::CTCP_REPLY, nick + " " + command +
570 " " + rest,
571 scm_listify (Utils::string2SCM(nick),
572 Utils::string2SCM(command),
573 Utils::string2SCM(rest),
574 SCM_UNDEFINED));
575#endif
576
577 if (command == "PING") {
578 StringTokenizer st3(rest);
579 rest = st3.nextToken();
580 String c = st3.rest();
581 if (cnx->bot->channelList->getChannel(c) &&
582 cnx->bot->channelList->getChannel(c)->getUser(nick) &&
583 cnx->bot->channelList->getChannel(c)->getUser(nick)->getAop() &&
584 !(cnx->bot->channelList->getChannel(c)->getUser(nick)->mode & User::OP_MODE)
585 && cnx->bot->channelList->getChannel(c)->getUser(nick)->userkey == rest)
586 cnx->queue->sendChannelMode(c, "+o", nick);
587 }
588}
589
590void
591Parser::parsePrivmsg(ServerConnection *cnx,
592 Person *from, String rest)
593{
594 String nick = from->getNick();
595
596 StringTokenizer st(rest);
597 String to = st.nextToken();
598 String fromUserhost = Utils::getUserhost(from->getAddress());
599
600 rest = st.rest().subString(1);
601
602 if (++(cnx->bot->ignoredUserhosts[fromUserhost])
603 > Bot::MAX_MESSAGES) {
604 if (cnx->bot->ignoredUserhosts[fromUserhost]
605 == Bot::MAX_MESSAGES+1) {
606#ifdef USESCRIPTS
607 cnx->bot->botInterp->RunHooks(Hook::FLOOD, nick,
608 scm_listify (Utils::string2SCM(nick),
609 SCM_UNDEFINED));
610#endif
611 cnx->bot->ignoredUserhosts[fromUserhost] += Bot::IGNORE_DELAY;
612 cnx->bot->logLine(from->getAddress() +
613 " is flooding me. We will ignore him/her/it.");
614 if (!Utils::isChannel(to))
615 from->sendNotice(String("\002You are now being ignored for ") +
616 String((long)Bot::IGNORE_DELAY) + " seconds.\002");
617 }
618 // The following lines reset the counter if you use the
619 // command "!sorry" (if '!' is your command char).
620 // This is not documented, I know. But one probably does
621 // not want that every users can bypass the flood control
622 // Of course, if you want this feature to remain 'secret',
623 // do not use it in public.
624 if (rest.toUpper() == String(cnx->bot->commandChar) + "SORRY") {
625 cnx->bot->ignoredUserhosts[fromUserhost] = 0;
626 from->sendNotice("\002Don't do it again!\002");
627 }
628 return;
629 }
630
631 if (rest[0] == '\001') {
632 rest = rest.subString(1, rest.length() - 2);
633 if (!Utils::isChannel(to))
634 for (std::map<String, Person *, std::less<String> >::iterator it =
635 cnx->bot->spyList.begin(); it != cnx->bot->spyList.end(); ++it)
636 (*it).second->sendNotice(String("CTCP From ") + nick +
637 ": " + rest);
638 Parser::parseCTCP(cnx, from, to, rest);
639 }
640 else {
641 if ((rest.length() < 5 ||
642 rest.subString(1, 5).toUpper() != "IDENT") &&
643 (rest.length() < 8 ||
644 rest.subString(1, 8).toUpper() != "PASSWORD") &&
645 !Utils::isChannel(to))
646 for (std::map<String, Person *, std::less<String> >::iterator it =
647 cnx->bot->spyList.begin(); it != cnx->bot->spyList.end(); ++it)
648 (*it).second->sendNotice(String("*") + nick + "* " + rest);
649 Parser::parseMessage(cnx, from, to, rest);
650 }
651}
652
653void
654Parser::parsePart(ServerConnection *cnx,
655 Person *from, String rest)
656{
657 String n = from->getNick();
658 StringTokenizer st(rest);
659 String channel = st.nextToken();
660
661#ifdef USESCRIPTS
662 cnx->bot->botInterp->RunHooks(Hook::LEAVE, n + " " + channel,
663 scm_listify (Utils::string2SCM(n),
664 Utils::string2SCM(channel),
665 SCM_UNDEFINED));
666#endif
667
668 if (n.toLower() == cnx->bot->nickName.toLower()) {
669 cnx->bot->logLine(String("Leaved channel ") + channel + ".");
670 cnx->bot->channelList->delChannel(channel);
671 } else {
672 Channel * c = cnx->bot->channelList->getChannel(channel);
673 if (!c) return;
674 c->delNick(n);
675 if (c->countOp == 0 && c->count == 1) {
676 cnx->queue->sendPart(channel);
677 cnx->queue->sendJoin(channel, cnx->bot->wantedChannels[channel]->key);
678 }
679 }
680}
681
682void
683Parser::parsePing(ServerConnection * cnx,
684 Person *from, String rest)
685{
686 cnx->queue->sendPong(rest);
687}
688
689void
690Parser::parsePong(ServerConnection *cnx,
691 Person *from, String rest)
692{
693 cnx->lag = (cnx->lag + 2 * (time(NULL) - cnx->pingTime)) / 3;
694 cnx->bot->sentPing = false;
695}
696
697void
698Parser::parseQuit(ServerConnection *cnx,
699 Person *from, String rest)
700{
701 String n = from->getNick();
702
703#ifdef USESCRIPTS
704 cnx->bot->botInterp->RunHooks(Hook::SIGNOFF, n + " " + rest,
705 scm_listify (Utils::string2SCM(n),
706 Utils::string2SCM(rest),
707 SCM_UNDEFINED));
708#endif
709
710 if (n == cnx->bot->nickName)
711 cnx->bot->stop = true;
712
713 for (std::map<String, Channel *, std::less<String> >::iterator it =
714 cnx->bot->channelList->begin();
715 it != cnx->bot->channelList->end();
716 ++it)
717 (*it).second->delNick(n);
718}
719
720void
721Parser::parseTopic(ServerConnection *cnx,
722 Person *from, String rest)
723{
724 StringTokenizer st(rest);
725 String channel = st.nextToken();
726 String newTopic = st.rest().subString(1);
727 Channel *c = cnx->bot->channelList->getChannel(channel);
728
729#ifdef USESCRIPTS
730 cnx->bot->botInterp->RunHooks(Hook::TOPIC, from->getNick() + " " + channel +
731 " " + newTopic,
732 scm_listify (Utils::string2SCM(from->getNick()),
733 Utils::string2SCM(channel),
734 Utils::string2SCM(newTopic),
735 SCM_UNDEFINED));
736#endif
737
738 if (!c) return;
739
740 if (c->lockedTopic && from->getNick() != cnx->bot->nickName)
741 cnx->queue->sendTopic(channel, c->channelTopic);
742
743 c->channelTopic = newTopic;
744}
745
746void
747Parser::parseCTCP(ServerConnection *cnx,
748 Person *from, String to,
749 String parameters)
750{
751 StringTokenizer st(parameters);
752 String command = st.nextToken().toUpper();
753 String nick = from->getNick();
754 String rest;
755
756 if (st.hasMoreTokens())
757 rest = st.rest();
758 else
759 rest = "";
760
761#ifdef USESCRIPTS
762 cnx->bot->botInterp->RunHooks(Hook::CTCP, nick + " " + to + " " +
763 command + " " + rest,
764 scm_listify (Utils::string2SCM(nick),
765 Utils::string2SCM(to),
766 Utils::string2SCM(command),
767 Utils::string2SCM(rest),
768 SCM_UNDEFINED));
769#endif
770
771 if (command == "PING")
772 cnx->queue->sendCTCPReply(nick, "PING", rest);
773 else if (command == "VERSION")
774 cnx->queue->sendCTCPReply(nick, "VERSION", cnx->bot->versionString);
775
776 else if (command == "CLOCK") {
777 time_t diff = time(NULL) - cnx->bot->startTime;
778 cnx->queue->sendCTCPReply(nick, "CLOCK", String("elapsed time: ") +
779 String((long)(diff / 86400)) + "d" +
780 String((long)(diff % 86400) / 3600) +
781 "h" + String((long)(diff % 3600) / 60) +
782 "m" + String((long)(diff % 60)) + "s");
783 } else if (command == "COMMAND")
784 cnx->queue->sendCTCPReply(nick,
785 "COMMAND",
786 String(cnx->bot->commandChar));
787 else if (command == "LAG")
788 cnx->queue->sendCTCPReply(nick, "LAG",
789 String((long)cnx->lag) + " second(s)");
790 else if (command == "DCC") {
791 StringTokenizer st2(rest);
792 command = st2.nextToken().toUpper();
793 if (command == "CHAT") {
794 // FIXME: Re-activate and debug DCC
439869bf 795 st2.nextToken();
796 unsigned long address =
797 ntohl (strtoul((const char *)st2.nextToken(), 0, 0));
798 int port = atoi((const char *)st2.nextToken ());
799 if (port >= 1024 && Utils::getLevel(cnx->bot, from->getAddress()))
800 cnx->bot->addDCC(from, address, port);
cb21075d 801 }
802 }
803#ifdef USESCRIPTS
804 else if (command == "ACTION") {
805 cnx->bot->botInterp->RunHooks(Hook::ACTION, from->getAddress() + " " +
806 to + " " + rest,
807 scm_listify (Utils::string2SCM(from->getAddress()),
808 Utils::string2SCM(to),
809 Utils::string2SCM(rest),
810 SCM_UNDEFINED));
811 }
812#endif
813}
814
815struct userFunctionsStruct userFunctionsInit[] =
816
817{
818 { "ACTION", UserCommands::Action, User::USER, true },
819 { "ADDUSER", UserCommands::AddUser, User::FRIEND, false },
820 { "ADDSERVER", UserCommands::AddServer, User::FRIEND, false },
821 { "ADDSHIT", UserCommands::AddShit, User::FRIEND, false },
822 { "ALIAS", UserCommands::Alias, User::MASTER, false },
823 { "BAN", UserCommands::Ban, User::USER, true },
824 { "BANLIST", UserCommands::BanList, User::USER, true },
825 // { "CHANGELEVEL", UserCommands::ChangeLevel, User::FRIEND, false },
826 { "CHANNELS", UserCommands::Channels, User::FRIEND, false },
827 { "CYCLE", UserCommands::Cycle, User::FRIEND, true },
828 { "DCCLIST", UserCommands::DCCList, User::FRIEND, false },
829 { "DEBAN", UserCommands::Deban, User::USER, true },
830 { "DELSERVER", UserCommands::DelServer, User::FRIEND, false },
831 { "DELUSER", UserCommands::DelUser, User::FRIEND, false },
832 { "DELSHIT", UserCommands::DelShit, User::FRIEND, false },
833 { "DEOP", UserCommands::Deop, User::TRUSTED_USER, true },
834 { "DIE", UserCommands::Die, User::MASTER, false },
835 { "DO", UserCommands::Do, User::MASTER, false },
836#ifdef USESCRIPTS
837 { "EXECUTE", UserCommands::Execute, User::MASTER, false },
838#endif
839 { "HELP", UserCommands::Help, User::NONE, false },
840 { "IDENT", UserCommands::Ident, User::NONE, true },
841 { "INVITE", UserCommands::Invite, User::USER, true },
842 { "JOIN", UserCommands::Join, User::FRIEND, false },
843 { "KEEP", UserCommands::Keep, User::FRIEND, true },
844 { "KICK", UserCommands::Kick, User::USER, true },
845 { "KICKBAN", UserCommands::KickBan, User::USER, true },
846 { "LOAD", UserCommands::Load, User::FRIEND, false },
847#ifdef USESCRIPTS
848 { "LOADSCRIPT", UserCommands::LoadScript, User::MASTER, false },
849#endif
850 { "LOCK", UserCommands::Lock, User::FRIEND, true },
851 { "MODE", UserCommands::Mode, User::FRIEND, true },
852 { "MSG", UserCommands::Msg, User::USER, false },
853 { "NAMES", UserCommands::Names, User::USER, true },
854 { "NEXTSERVER", UserCommands::NextServer, User::FRIEND, false },
855 { "NICK", UserCommands::Nick, User::FRIEND, false },
856 { "NSLOOKUP", UserCommands::NsLookup, User::USER, false },
857 { "OP", UserCommands::Op, User::TRUSTED_USER, true },
858 { "PART", UserCommands::Part, User::FRIEND, true },
859 { "PASSWORD", UserCommands::Password, User::USER, true },
860 { "RECONNECT", UserCommands::Reconnect, User::FRIEND, false },
861 { "RSPYMESSAGE", UserCommands::RSpyMessage, User::USER, false },
862 { "SAVE", UserCommands::Save, User::FRIEND, false },
863 { "SAY", UserCommands::Say, User::USER, true },
864 { "SERVER", UserCommands::Server, User::FRIEND, false },
865 { "SERVERLIST", UserCommands::ServerList, User::FRIEND, false },
866 { "SETVERSION", UserCommands::SetVersion, User::MASTER, false },
867 { "SHITLIST", UserCommands::ShitList, User::FRIEND, false },
868 { "SPYLIST", UserCommands::SpyList, User::USER, false },
869 { "SPYMESSAGE", UserCommands::SpyMessage, User::USER, false },
870 { "STATS", UserCommands::Stats, User::FRIEND, true },
871 { "TBAN", UserCommands::TBan, User::USER, true },
872 { "TKBAN", UserCommands::TKBan, User::USER, true },
873 { "TOPIC", UserCommands::Topic, User::USER, true },
874 { "UNLOCK", UserCommands::Unlock, User::FRIEND, true },
875 { "USERLIST", UserCommands::UserList, User::FRIEND, false },
876 { "WHO", UserCommands::Who, User::NONE, true },
877 { "WHOIS", UserCommands::Whois, User::FRIEND, true },
878 { "", 0, 0, false }
879};
880
881void
882Parser::parseMessage(ServerConnection *cnx,
883 Person *from, String to,
884 String parameters)
885{
886#ifdef USESCRIPTS
887 if (Utils::isChannel(to))
888 cnx->bot->botInterp->RunHooks(Hook::PUBLIC, from->getNick() + " " +
889 to + " " + parameters,
890 scm_listify (Utils::string2SCM(from->getNick()),
891 Utils::string2SCM(to),
892 Utils::string2SCM(parameters),
893 SCM_UNDEFINED));
894 else
895 cnx->bot->botInterp->RunHooks(Hook::MESSAGE, from->getNick() + " " + parameters,
896 scm_listify (Utils::string2SCM(from->getNick()),
897 Utils::string2SCM(parameters),
898 SCM_UNDEFINED));
899#endif
900
901 if (parameters[0] != cnx->bot->commandChar)
902 return;
903
904 StringTokenizer st(parameters);
905
906 String command = st.nextToken().subString(1).toUpper();
907 String rest = st.rest().trim();
908 int level;
909 bool identified = false;
910
911 std::list<userFunction *>::iterator it;
912 for (it = cnx->bot->userFunctions.begin();
913 it != cnx->bot->userFunctions.end();
914 ++it)
915 if (command == (*it)->name) {
916 if ((*it)->needsChannelName) {
917 if (Utils::isChannel(rest)) {
918 StringTokenizer st2(rest);
919 to = st.nextToken();
920 rest = st.rest();
921 }
922 if (!Utils::isChannel(to)) {
923 from->sendNotice("\002You need to supply a channel name"
924 " for this command\002");
925 return;
926 }
927 if (!cnx->bot->channelList->getChannel(to)) {
928 from->sendNotice(String("\002I am not on channel\002 ") +
929 to);
930 return;
931 }
932 level = Utils::getLevel(cnx->bot, from->getAddress(), to);
933 User * u = 0;
934 if (Channel *c = cnx->bot->channelList->getChannel(to))
935 u = c->getUser(from->getNick());
936 if (!u || !u->userListItem)
937 identified = true;
938 else
939 identified = u->userListItem->passwd == "" || u->userListItem->identified > 0;
940 } else {
941 level = Utils::getLevel(cnx->bot, from->getAddress());
942 identified = true;
943 }
944 if (level >= (*it)->minLevel) {
945 cnx->bot->logLine(from->getAddress() + " did " + command +
946 " " + rest);
947#ifdef USESCRIPTS
948 if ((*it)->argsCount != -1) {
949 Parser::parseScriptFunction(cnx, to, (*it)->needsChannelName,
950 (*it)->scmFunc, (*it)->argsCount, rest);
951 } else {
952 (*it)->function(cnx, from, to, rest);
953 }
954#else
955 (*it)->function(cnx, from, to, rest);
956#endif
957 break;
958 } else {
959 if (!identified)
960 from->sendNotice(String("\002You are not identified on channel\002 ")+to);
961 }
962 }
963}
964
965#ifdef USESCRIPTS
966void
967Parser::parseScriptFunction(ServerConnection *cnx, String channel,
968 bool needsChannelName, SCM scmFunc,
969 int argsCount, String parameters)
970{
971 String param;
972 SCM args_list = scm_listify (SCM_UNDEFINED);
973
974 if (needsChannelName) {
975 args_list = gh_append2(args_list,
976 scm_listify (Utils::string2SCM(channel),
977 SCM_UNDEFINED));
978 argsCount--;
979 }
980
981 StringTokenizer st(parameters);
982 for (int i = argsCount; i > 0; i--) {
983 if (i == 1)
984 param = st.rest();
985 else
986 param = st.nextToken();
987 args_list = gh_append2(args_list,
988 scm_listify (Utils::string2SCM(param),
989 SCM_UNDEFINED));
990 }
991
992 struct wrapper_data wd;
993 wd.func = scmFunc;
994 wd.args = args_list;
995
439869bf 996 gh_catch(SCM_BOOL_T, (scm_t_catch_body) scm_apply_wrapper,
997 (void *)&wd, (scm_t_catch_handler) Interp::ErrorHandler,
cb21075d 998 0);
999}
1000#endif