1 // Parser.C -*- C++ -*-
2 // Copyright (c) 1997, 1998 Etienne BERNARD
3 // Copyright (C) 2002,2003,2005 Clinton Ebadi
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
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <sys/types.h>
24 #include <netinet/in.h>
26 #include "StringTokenizer.H"
28 #include "UserCommands.H"
33 typedef void (*fptr) (ServerConnection *, Person *, String);
34 std::map < std::string, fptr, std::less < std::string > >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 */
57 Parser::functions["ERROR"] = Parser::parseError;
58 Parser::functions["INVITE"] = Parser::parseInvite;
59 Parser::functions["JOIN"] = Parser::parseJoin;
60 Parser::functions["KICK"] = Parser::parseKick;
61 Parser::functions["MODE"] = Parser::parseMode;
62 Parser::functions["NICK"] = Parser::parseNick;
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;
75 Parser::parseLine (ServerConnection * cnx, String line)
77 StringTokenizer st (line);
80 cnx->bot->botInterp->RunHooks (Hook::RAW, line,
87 String fromMask = st.next_token ().substr (1);
88 if (fromMask.find ('!') != -1)
89 from = new Person (cnx->bot, fromMask);
92 String command = st.next_token ();
93 String rest = st.rest ();
95 // We must use map<>::find or else a new entry will be created in
96 // the map which will cause another lookup of the same invalid
97 // command to segfault the bot
98 std::map<std::string, fptr, std::less<std::string> >::const_iterator cit
99 = functions.find (command);
101 if (cit != functions.end ())
103 fptr temp_func = cit->second;
104 temp_func (cnx, from, rest);
111 Parser::parse001 (ServerConnection * cnx, Person * from, String rest)
114 StringTokenizer st (rest);
115 String realNick = st.next_token ();
116 if ((cnx->bot->nickName).toLower () != realNick.toLower ())
118 // Yes, this can happen, and it was a very subtle bug
119 cnx->bot->nickName = realNick;
120 cnx->bot->userList->removeFirst ();
121 cnx->bot->userList->addUserFirst (realNick + "!" +
122 cnx->bot->userHost, "*", 0,
124 cnx->bot->lastNickNameChange = time (0);
128 cnx->bot->connected = true;
129 cnx->queue->sendUserMode (cnx->bot->nickName, "+i");
130 cnx->queue->sendWhois (cnx->bot->nickName);
131 for (std::map < String, wantedChannel *,
132 std::less < String > >::iterator it =
133 cnx->bot->wantedChannels.begin ();
134 it != cnx->bot->wantedChannels.end (); ++it)
135 cnx->queue->sendJoin ((*it).first, (*it).second->key);
136 cnx->bot->logLine (String ("Connected to server ") +
137 cnx->bot->serverList->currentServer ()->
138 getHostName () + " (" +
139 String ((long) cnx->bot->serverList->
140 currentServer ()->getPort ()) + ").");
144 Parser::parse302 (ServerConnection * cnx, Person * from, String rest)
146 unsigned long num = cnx->bot->receivedUserhostID++;
147 StringTokenizer st (rest);
149 if (st.rest ().length ())
152 String parameters = st.rest ();
153 parameters = parameters.substr (1);
154 cnx->bot->userhostMap[num] = parameters;
157 cnx->bot->userhostMap[num] = "";
161 Parser::parse311 (ServerConnection * cnx, Person * from, String rest)
163 StringTokenizer st (rest);
165 String nuh = st.next_token () + "!";
166 String uh = st.next_token () + "@";
167 uh = uh + st.next_token ();
169 cnx->bot->userList->addUserFirst (nuh, "*", 0, 3, true, -1, "");
170 cnx->bot->userHost = uh;
174 Parser::parse315 (ServerConnection * cnx, Person * from, String rest)
176 StringTokenizer st (rest);
178 String channel = st.next_token ();
179 Channel *c = cnx->bot->channelList->getChannel (channel);
186 Parser::parse324 (ServerConnection * cnx, Person * from, String rest)
188 StringTokenizer st (rest);
190 String channel = st.next_token ();
191 if (Channel * c = cnx->bot->channelList->getChannel (channel))
193 c->parseMode (from, st.rest ());
197 Parser::parse332 (ServerConnection * cnx, Person * from, String rest)
199 StringTokenizer st (rest);
201 String channel = st.next_token ();
202 if (Channel * c = cnx->bot->channelList->getChannel (channel))
204 c->channelTopic = st.rest ().substr (1);
208 Parser::parse352 (ServerConnection * cnx, Person * from, String rest)
210 StringTokenizer st (rest);
212 String ch = st.next_token ();
213 String uh = st.next_token () + "@";
214 uh = uh + st.next_token ();
216 String n = st.next_token ();
217 String m = st.next_token ();
219 for (int i = 0; i < m.length (); i++)
225 mode |= User::AWAY_MODE;
228 mode |= User::IRCOP_MODE;
231 mode |= User::OP_MODE;
234 mode |= User::VOICE_MODE;
237 if (Channel * c = cnx->bot->channelList->getChannel (ch))
239 c->addNick (n, uh, mode, cnx->bot->userList);
243 Parser::parse353 (ServerConnection * cnx, Person * from, String rest)
247 StringTokenizer st (rest);
250 Channel *c = cnx->bot->channelList->getChannel (st.next_token ());
253 StringTokenizer st2 (st.next_token (':'));
254 while (st2.more_tokens_p ())
256 nick = st2.next_token ();
259 mode = User::OP_MODE;
260 nick = nick.substr (1);
262 else if (nick[0] == '+')
264 mode = User::VOICE_MODE;
265 nick = nick.substr (1);
267 c->addNick (nick, "", mode, 0, true);
272 Parser::parse366 (ServerConnection * cnx, Person * from, String rest)
274 StringTokenizer st (rest);
276 String ch = st.next_token ();
277 if (Channel * c = cnx->bot->channelList->getChannel (ch))
282 Parser::parse367 (ServerConnection * cnx, Person * from, String rest)
284 StringTokenizer st (rest);
286 String ch = st.next_token ();
287 if (Channel * c = cnx->bot->channelList->getChannel (ch))
288 c->addBan (st.next_token (), -1);
292 Parser::parse401 (ServerConnection * cnx, Person * from, String rest)
294 StringTokenizer st (rest);
296 String nick = st.next_token ();
297 if (cnx->bot->spyList.find (nick) != cnx->bot->spyList.end ())
299 delete cnx->bot->spyList[nick];
300 cnx->bot->spyList.erase (nick);
305 Parser::parse433 (ServerConnection * cnx, Person * from, String rest)
307 if (cnx->bot->connected)
309 if (cnx->bot->nickName.length () == 9)
313 i < cnx->bot->nickName.length ()
314 && cnx->bot->nickName[i] == '_'; i++);
315 if (i < cnx->bot->nickName.length ())
317 cnx->bot->nickName.substr (0,
319 cnx->bot->nickName.substr (i + 1);
321 cnx->bot->nickName = cnx->bot->nickName.substr (0, 4) +
322 String ((long) (rand () % 10000));
325 cnx->bot->nickName = cnx->bot->nickName + "_";
326 cnx->queue->sendNick (cnx->bot->nickName);
330 Parser::parse473 (ServerConnection * cnx, Person * from, String rest)
332 StringTokenizer st (rest);
334 cnx->bot->logLine (String ("Unable to join channel ") +
335 st.next_token () + ".");
339 Parser::parseError (ServerConnection * cnx, Person * from, String rest)
341 cnx->bot->logLine (String ("Error from server ") +
342 cnx->bot->serverList->currentServer ()->
343 getHostName () + " (" +
344 String ((long) cnx->bot->serverList->
345 currentServer ()->getPort ()) + ").");
346 cnx->bot->nextServer ();
350 Parser::parseInvite (ServerConnection * cnx, Person * from, String rest)
352 String nick = from->getNick ();
353 StringTokenizer st (rest);
355 String channel = st.rest ();
357 cnx->bot->botInterp->RunHooks (Hook::INVITE,
358 nick + " " + channel,
363 (channel), SCM_UNDEFINED));
365 if (cnx->bot->wantedChannels.find (channel) !=
366 cnx->bot->wantedChannels.end ())
367 cnx->queue->sendJoin (channel, cnx->bot->wantedChannels[channel]->key);
371 Parser::parseJoin (ServerConnection * cnx, Person * from, String rest)
373 StringTokenizer st (from->getAddress ());
374 String n = st.next_token ('!');
375 String uh = st.next_token ();
376 StringTokenizer st2 (rest);
377 String c = st2.next_token (':');
379 bool joinAndMode = false;
381 cnx->bot->botInterp->RunHooks (Hook::JOIN, n + " " + c,
385 str2scm (c), SCM_UNDEFINED));
387 // This part of code is for the combined JOIN & MODE of ircd 2.9
388 if (c.find ('\007') >= 0)
391 StringTokenizer st3 (c);
392 c = st3.next_token ('\007');
393 String m = st3.rest ();
395 for (int i = 0; i < m.length (); i++)
396 mode = mode + " " + n;
399 if (n == cnx->bot->nickName)
401 cnx->bot->logLine (String ("Joined channel ") + c + ".");
402 if (cnx->bot->wantedChannels.find (c) !=
403 cnx->bot->wantedChannels.end ())
404 cnx->bot->channelList->
405 addChannel (cnx, c, cnx->bot->wantedChannels[c]->keep);
407 cnx->bot->channelList->addChannel (cnx, c);
408 cnx->queue->sendWho (c);
409 cnx->queue->sendChannelMode (String ("MODE ") + c + " b");
410 cnx->queue->sendChannelMode (String ("MODE ") + c);
414 Channel *ch = cnx->bot->channelList->getChannel (c);
417 ShitEntry *se = cnx->bot->shitList->getShit (n + "!" + uh, c);
418 if (se && se->isStillValid () &&
419 se->getShitLevel () >= ShitEntry::SHIT_NOJOIN)
421 cnx->queue->sendChannelMode (c, "+b", se->getMask ());
422 cnx->queue->sendKick (c, n, se->getShitReason ());
425 ch->addNick (n, uh, 0, cnx->bot->userList);
426 if (ch->getUser (n)->getAop ()
427 && !(ch->getUser (n)->mode & User::OP_MODE) && cnx->bot->iAmOp (c))
429 // This is a part of the antispoof code
430 ch->getUser (n)->userkey = Utils::get_key ();
431 Commands::CTCP (cnx->bot, n, "PING",
432 ch->getUser (n)->userkey + " " + c);
437 parseMode (cnx, 0, mode);
441 Parser::parseKick (ServerConnection * cnx, Person * from, String rest)
443 StringTokenizer st (rest);
444 String channel = st.next_token ();
445 String target = st.next_token ();
446 String reason = st.rest ().substr (1);
448 cnx->bot->botInterp->RunHooks (Hook::KICK,
450 from->getNick () + " " +
451 channel + " " + reason,
464 (reason), SCM_UNDEFINED));
466 if (target == cnx->bot->nickName)
468 cnx->bot->logLine (from->getAddress () +
469 " kicked me out of channel " + channel +
470 " (" + reason + ").");
471 cnx->queue->sendJoin (channel,
472 cnx->bot->channelList->
473 getChannel (channel)->channelKey);
474 cnx->bot->channelList->delChannel (channel);
478 if (!cnx->bot->channelList->getChannel (channel))
480 User *u = cnx->bot->channelList->getChannel (channel)->getUser (target);
481 if (u && u->getProt () >= User::NO_KICK)
483 String fromNick = from->getNick ();
485 cnx->bot->channelList->getChannel (channel)->getUser (fromNick);
486 if (v->getProt () < User::NO_KICK)
488 cnx->bot->logLine (from->getAddress () + " kicked " + target +
489 " (protected) out of channel " + channel +
490 " (" + reason + ").");
491 cnx->queue->sendKick (channel, fromNick,
492 target + " \002is protected !\002");
495 cnx->bot->channelList->getChannel (channel)->delNick (target);
500 Parser::parseMode (ServerConnection * cnx, Person * from, String rest)
502 StringTokenizer st (rest);
503 String ch = st.next_token ();
504 String modes = st.rest ();
507 cnx->bot->botInterp->RunHooks (Hook::MODE,
508 from->getNick () + " " + ch +
520 if (Utils::channel_p (ch))
522 Channel *c = cnx->bot->channelList->getChannel (ch);
526 c->parseMode (from, modes);
528 c->parseMode (0, modes);
533 Parser::parseNick (ServerConnection * cnx, Person * from, String rest)
535 String on_orig = from->getNick ();
536 String on = on_orig.toLower ();
537 String nn = rest.substr (1);
538 String nn_lower = nn.toLower ();
540 cnx->bot->botInterp->RunHooks (Hook::NICKNAME,
549 if ((cnx->bot->nickName).toLower () == on)
551 cnx->bot->userList->removeFirst ();
552 cnx->bot->userList->addUserFirst (nn + "!" +
553 cnx->bot->userHost, "*", 0,
555 cnx->bot->lastNickNameChange = time (0);
556 cnx->bot->nickName = nn;
560 if (cnx->bot->spyList.find (on) != cnx->bot->spyList.end ())
562 cnx->bot->spyList[nn_lower] = cnx->bot->spyList[on];
563 cnx->bot->spyList.erase (on);
566 for (std::map < String, Channel *,
567 std::less < String > >::iterator it =
568 cnx->bot->channelList->begin ();
569 it != cnx->bot->channelList->end (); ++it)
570 if ((*it).second->hasNick (on))
571 (*it).second->changeNick (on, nn_lower);
575 Parser::parseNotice (ServerConnection * cnx, Person * from, String rest)
579 nick = from->getNick ();
580 StringTokenizer st (rest);
581 String to = st.next_token ();
582 rest = st.rest ().substr (1);
583 if (rest[0] != '\001')
586 if (Utils::channel_p (to))
587 cnx->bot->botInterp->RunHooks (Hook::PUBLIC_NOTICE,
588 nick + " " + to + " " + rest,
597 cnx->bot->botInterp->RunHooks (Hook::NOTICE, nick + " " + rest,
607 rest = rest.substr (1, rest.length () - 2);
608 StringTokenizer st2 (rest);
609 String command = st2.next_token ();
612 cnx->bot->botInterp->RunHooks (Hook::CTCP_REPLY,
613 nick + " " + command + " " +
624 if (command == "PING")
626 StringTokenizer st3 (rest);
627 rest = st3.next_token ();
628 String c = st3.rest ();
629 if (cnx->bot->channelList->getChannel (c) &&
630 cnx->bot->channelList->getChannel (c)->getUser (nick) &&
631 cnx->bot->channelList->getChannel (c)->getUser (nick)->
633 && !(cnx->bot->channelList->getChannel (c)->
634 getUser (nick)->mode & User::OP_MODE)
635 && cnx->bot->channelList->getChannel (c)->getUser (nick)->
637 cnx->queue->sendChannelMode (c, "+o", nick);
642 Parser::parsePrivmsg (ServerConnection * cnx, Person * from, String rest)
644 String nick = from->getNick ();
645 StringTokenizer st (rest);
646 String to = st.next_token ();
647 String fromUserhost = Utils::get_userhost (from->getAddress ());
648 rest = st.rest ().substr (1);
649 if (++(cnx->bot->ignoredUserhosts[fromUserhost]) > Bot::MAX_MESSAGES)
651 if (cnx->bot->ignoredUserhosts[fromUserhost] == Bot::MAX_MESSAGES + 1)
654 cnx->bot->botInterp->RunHooks (Hook::FLOOD, nick,
659 cnx->bot->ignoredUserhosts[fromUserhost] += Bot::IGNORE_DELAY;
660 cnx->bot->logLine (from->getAddress () +
661 " is flooding me. We will ignore him/her/it.");
662 if (!Utils::channel_p (to))
664 sendNotice (String ("\002You are now being ignored for ") +
665 String ((long) Bot::IGNORE_DELAY) +
668 // The following lines reset the counter if you use the
669 // command "!sorry" (if '!' is your command char).
670 // This is not documented, I know. But one probably does
671 // not want that every users can bypass the flood control
672 // Of course, if you want this feature to remain 'secret',
673 // do not use it in public.
674 if (rest.toUpper () == String (cnx->bot->commandChar) + "SORRY")
676 cnx->bot->ignoredUserhosts[fromUserhost] = 0;
677 from->sendNotice ("\002Don't do it again!\002");
682 if (rest[0] == '\001')
684 rest = rest.substr (1, rest.length () - 2);
685 if (!Utils::channel_p (to))
686 for (std::map < String, Person *,
687 std::less < String > >::iterator it =
688 cnx->bot->spyList.begin (); it != cnx->bot->spyList.end (); ++it)
689 (*it).second->sendNotice (String ("CTCP From ") +
691 Parser::parseCTCP (cnx, from, to, rest);
695 if ((rest.length () < 5 ||
696 rest.substr (1, 5).toUpper () != "IDENT") &&
697 (rest.length () < 8 ||
698 rest.substr (1, 8).toUpper () != "PASSWORD") &&
699 !Utils::channel_p (to))
700 for (std::map < String, Person *,
701 std::less < String > >::iterator it =
702 cnx->bot->spyList.begin (); it != cnx->bot->spyList.end (); ++it)
703 (*it).second->sendNotice (String ("*") + nick + "* " + rest);
704 Parser::parseMessage (cnx, from, to, rest);
709 Parser::parsePart (ServerConnection * cnx, Person * from, String rest)
711 String n = from->getNick ();
712 StringTokenizer st (rest);
713 String channel = st.next_token ();
715 cnx->bot->botInterp->RunHooks (Hook::LEAVE, n + " " + channel,
720 (channel), SCM_UNDEFINED));
722 if (n.toLower () == cnx->bot->nickName.toLower ())
724 cnx->bot->logLine (String ("Leaved channel ") + channel + ".");
725 cnx->bot->channelList->delChannel (channel);
729 Channel *c = cnx->bot->channelList->getChannel (channel);
733 if (c->countOp == 0 && c->count == 1)
735 cnx->queue->sendPart (channel);
736 cnx->queue->sendJoin (channel,
737 cnx->bot->wantedChannels[channel]->key);
743 Parser::parsePing (ServerConnection * cnx, Person * from, String rest)
745 cnx->queue->sendPong (rest);
749 Parser::parsePong (ServerConnection * cnx, Person * from, String rest)
751 cnx->lag = (cnx->lag + 2 * (time (NULL) - cnx->pingTime)) / 3;
752 cnx->bot->sentPing = false;
756 Parser::parseQuit (ServerConnection * cnx, Person * from, String rest)
758 String n = from->getNick ();
760 cnx->bot->botInterp->RunHooks (Hook::SIGNOFF, n + " " + rest,
767 if (n == cnx->bot->nickName)
768 cnx->bot->stop = true;
769 for (std::map < String, Channel *,
770 std::less < String > >::iterator it =
771 cnx->bot->channelList->begin ();
772 it != cnx->bot->channelList->end (); ++it)
773 (*it).second->delNick (n);
777 Parser::parseTopic (ServerConnection * cnx, Person * from, String rest)
779 StringTokenizer st (rest);
780 String channel = st.next_token ();
781 String newTopic = st.rest ().substr (1);
782 Channel *c = cnx->bot->channelList->getChannel (channel);
784 cnx->bot->botInterp->RunHooks (Hook::TOPIC,
785 from->getNick () + " " +
786 channel + " " + newTopic,
796 (newTopic), SCM_UNDEFINED));
800 if (c->lockedTopic && from->getNick () != cnx->bot->nickName)
801 cnx->queue->sendTopic (channel, c->channelTopic);
802 c->channelTopic = newTopic;
806 Parser::parseCTCP (ServerConnection * cnx,
807 Person * from, String to, String parameters)
809 StringTokenizer st (parameters);
810 String command = Utils::to_upper (st.next_token ());
811 String nick = from->getNick ();
813 if (st.more_tokens_p ())
818 cnx->bot->botInterp->RunHooks (Hook::CTCP,
819 nick + " " + to + " " +
820 command + " " + rest,
832 if (command == "PING")
834 Commands::CTCPReply (cnx->bot, nick, "PING", rest);
836 else if (command == "VERSION")
838 Commands::CTCPReply (cnx->bot, nick, "VERSION",
839 cnx->bot->versionString);
841 else if (command == "CLOCK")
843 time_t diff = time (NULL) - cnx->bot->startTime;
844 Commands::CTCPReply (cnx->bot, nick, "CLOCK",
845 String ("elapsed time: ") +
846 String ((long) (diff / 86400)) +
848 String ((long) (diff % 86400) /
850 String ((long) (diff % 3600) / 60) +
851 "m" + String ((long) (diff % 60)) + "s");
853 else if (command == "COMMAND")
855 Commands::CTCPReply (cnx->bot, nick,
856 "COMMAND", String (cnx->bot->commandChar));
858 else if (command == "LAG")
860 Commands::CTCPReply (cnx->bot, nick, "LAG",
861 String ((long) cnx->lag) + " second(s)");
863 else if (command == "DCC")
865 StringTokenizer st2 (rest);
866 command = Utils::to_upper (st2.next_token ());
867 if (command == "CHAT")
871 unsigned long address =
872 std::strtoul (st2.next_token ().c_str(), 0, 0);
873 int port = std::atoi (st2.next_token().c_str());
874 if (port >= 1024 && Utils::get_level (cnx->bot, from->getAddress ()))
875 cnx->bot->addDCC (from, address, port, Bot::CHAT);
877 cnx->bot->logLine ("DCC Chat Failed in Parser");
881 else if (command == "ACTION")
883 cnx->bot->botInterp->RunHooks (Hook::ACTION,
884 // FIXME: from->getAddress should
885 // be nick. MAYBE, depending on
886 // whether this could be
887 // considered a bug or a feature
888 // change to normalize
889 // hooks/action with the other
890 // hooks. Maybe a 3.0 change?
891 from->getAddress () + " " + to +
907 Parser::parseMessage (ServerConnection * cnx,
908 Person * from, String to, String parameters)
911 if (Utils::channel_p (to))
912 cnx->bot->botInterp->RunHooks (Hook::PUBLIC,
913 from->getNick () + " " + to +
923 (parameters), SCM_UNDEFINED));
925 cnx->bot->botInterp->RunHooks (Hook::MESSAGE,
926 from->getNick () + " " +
934 (parameters), SCM_UNDEFINED));
936 if (parameters[0] != cnx->bot->commandChar)
939 StringTokenizer st (parameters);
940 String command = Utils::to_upper (st.next_token ().substr (1));
941 String rest = Utils::trim_str (st.rest ());
943 bool identified = false;
944 std::map<std::string, class userFunction*,
945 std::less<std::string> >::const_iterator uf_iter
946 = cnx->bot->userFunctions.find (command);
947 userFunction * f = 0;
949 if (uf_iter != cnx->bot->userFunctions.end ())
956 if (f->needsChannelName)
958 if (Utils::channel_p (rest))
960 StringTokenizer st2 (rest);
961 to = st.next_token ();
964 if (!Utils::channel_p (to))
966 from->sendNotice ("\002You need to supply a channel name"
967 " for this command\002");
970 if (!cnx->bot->channelList->getChannel (to))
972 from->sendNotice (String ("\002I am not on channel\002 ") +
976 level = Utils::get_level (cnx->bot, from->getAddress (), to);
978 if (Channel * c = cnx->bot->channelList->getChannel (to))
979 u = c->getUser (from->getNick ());
980 if (!u || !u->userListItem)
983 identified = u->userListItem->passwd == ""
984 || u->userListItem->identified > 0;
988 level = Utils::get_level (cnx->bot, from->getAddress ());
991 if (level >= f->minLevel)
993 cnx->bot->logLine (from->getAddress () + " did " + command +
996 if (f->argsCount != -1)
998 Parser::parseScriptFunction (cnx, to, f->needsChannelName,
999 f->scmFunc, f->argsCount,
1004 f->function (cnx, from, to, rest);
1007 f->function (cnx, from, to, rest);
1015 ("\002You are not identified on channel\002 ") +
1023 Parser::parseScriptFunction (ServerConnection * cnx,
1025 bool needsChannelName,
1026 SCM scmFunc, int argsCount, String parameters)
1029 SCM args_list = scm_listify (SCM_UNDEFINED);
1030 if (needsChannelName)
1032 args_list = gh_append2 (args_list,
1033 scm_listify (Utils::
1039 StringTokenizer st (parameters);
1040 for (int i = argsCount; i > 0; i--)
1045 param = st.next_token ();
1046 args_list = gh_append2 (args_list,
1047 scm_listify (Utils::str2scm (param),
1051 struct wrapper_data wd;
1053 wd.args = args_list;
1054 scm_internal_catch (SCM_BOOL_T,
1055 (scm_t_catch_body) lazy_apply_wrapper, (void *) &wd,
1056 (scm_t_catch_handler) empty_handler, 0);