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