Split user list from Channel into ChannelUserList
[clinton/bobotpp.git] / source / UserCommands.C
CommitLineData
cb21075d 1// UserCommands.C -*- C++ -*-
2// Copyright (c) 1997, 1998 Etienne BERNARD
a6339323 3// Copyright (C) 2002,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
c6e7af05 17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18// 02110-1301, USA.
cb21075d 19
20#ifdef HAVE_CONFIG_H
21#include "config.h"
22#endif
23
cfa82921 24#include "UserCommands.H"
25
cb21075d 26#include <fstream>
f9723c92 27#include <functional>
e07b6b46 28#include <map>
a6339323 29#include <string>
cfa82921 30
a6339323 31#include <cctype>
32#include <cstdlib>
55f2215d 33#include <cstring>
cfa82921 34
cb21075d 35#include <sys/types.h>
36#include <sys/socket.h>
37#include <netinet/in.h>
38#include <arpa/inet.h>
39#include <netdb.h>
55f2215d 40
cb21075d 41#ifndef _X_OPEN_SOURCE
42#define _X_OPEN_SOURCE
43#endif
44#ifndef _X_OPEN_SOURCE_EXTENDED
45#define _X_OPEN_SOURCE_EXTENDED 1
46#endif
47#ifndef __USE_XOPEN
48#define __USE_XOPEN
49#endif
55f2215d 50
cb21075d 51#include <unistd.h>
52
cfa82921 53#include "BanEntry.H"
54#include "Channel.H"
55#include "ChannelList.H"
cb21075d 56#include "Commands.H"
cb21075d 57#include "DCCConnection.H"
6530edbf 58#include "DCCManager.H"
cfa82921 59#include "DCCPerson.H"
cb21075d 60#include "Macros.H"
cfa82921 61#include "Message.H"
62#include "Parser.H"
63#include "Person.H"
64#include "ShitList.H"
65#include "Server.H"
66#include "ServerConnection.H"
67#include "ServerList.H"
68#include "ShitEntry.H"
cb21075d 69#include "StringTokenizer.H"
cfa82921 70#include "User.H"
71#include "UserList.H"
cb21075d 72#include "Utils.H"
cfa82921 73
74#ifdef USESCRIPTS
75#include "Interp.H"
76#endif
cb21075d 77
78#ifdef NOCRYPT
79char * crypt(const char *p, const char *s) { return p; }
80#endif
81
82void
83UserCommands::Action(ServerConnection *cnx, Person *from,
84 String channel, String rest)
85{
86 Message m = Commands::Action(cnx->bot, channel, rest);
87 if (m.getCode() != 0)
88 from->sendNotice(m.getMessage());
89}
90
91void
92UserCommands::AddUser(ServerConnection *cnx, Person *from,
93 String channel, String rest)
94{
95 StringTokenizer st(rest);
96 String mask, who, maskChannel, level, prot,
97 aop, expiration, passwd;
98
a6339323 99 mask = who = st.next_token();
100 maskChannel = st.next_token();
101 level = st.next_token();
102 prot = st.next_token();
103 aop = st.next_token();
104 expiration = st.next_token();
105 passwd = st.next_token();
cb21075d 106
107 if (mask == "" || maskChannel == "" || level == "" ||
108 prot == "" || aop == "") {
109 from->sendNotice("\002Invalid syntax for this command.\002");
110 return;
111 }
112
a6339323 113// if (!Utils::wildcard_p(mask)) {
cb21075d 114// mask = cnx->bot->getUserhost(channel, who);
115// if (mask == "") {
116// from->sendNotice(String("\002I can not find\002 ") + who);
117// return;
118// }
a6339323 119// mask = Utils::make_wildcard(mask);
cb21075d 120// }
121
122// if (cnx->bot->userList->isInUserList(mask, maskChannel)) {
123// from->sendNotice(who + " \002is already in userlist on channel(s)\002 " +
124// maskChannel);
125// return;
126// }
127
128 int l, p;
129 bool a;
130 time_t e;
131
815a1816 132 l = atoi(level.c_str ());
cb21075d 133 if (l < 0 || l > User::FRIEND)
134 return;
a6339323 135 if (l > Utils::get_level(cnx->bot, from->getAddress())) {
cb21075d 136 from->sendNotice("\002You can not give a level greater than yours.\002");
137 return;
138 }
815a1816 139 p = atoi(prot.c_str ());
cb21075d 140 if (p < 0 || p > User::NO_DEOP)
141 return;
815a1816 142 a = (bool)atoi(aop.c_str ());
cb21075d 143 if (a != 0 && a != 1)
144 return;
145
a6339323 146 e = Utils::str2time(expiration);
cb21075d 147
148 if (!e)
149 e = -1;
150
151 // cnx->bot->userList->addUser(mask, maskChannel, l, p, a, e, passwd);
152
153 Message m =
154 Commands::AddUser (cnx->bot, who, maskChannel, l, p, a, e, passwd);
155 if (!m.getCode ())
156 {
157 from->sendNotice(String("\002Added\002 ") + mask +
158 " \002on channels\002 " + maskChannel);
159 from->sendNotice(String("\002Level:\002 ") +
a6339323 160 Utils::level2str(l) +
cb21075d 161 " \002Protection:\002 " +
a6339323 162 Utils::prot2str(p) +
cb21075d 163 " \002Auto-op:\002 " +
a6339323 164 Utils::bool2str(a));
cb21075d 165 }
166 else
167 from->sendNotice(m.getMessage ());
168
169 // cnx->bot->rehash();
170}
171
172void
173UserCommands::AddServer(ServerConnection *cnx, Person *from,
174 String channel, String rest)
175{
176 if (rest.length() == 0) {
177 from->sendNotice("\002You must supply a server name.\002");
178 return;
179 }
180
181 StringTokenizer st(rest);
a6339323 182 String serverName = st.next_token();
cb21075d 183 int port = 6667;
184
a6339323 185 if (st.more_tokens_p()) {
186 String temp = st.next_token();
815a1816 187 port = atoi(temp.c_str ());
cb21075d 188 }
189
190 Message m = Commands::AddServer(cnx->bot, serverName, port);
191 if (m.getCode() != 0)
192 from->sendNotice(m.getMessage());
193 else
194 from->sendNotice(String("\002Server\002 ") +
195 serverName + " \002on port\002 " +
196 String((long)port) + " \002has been added "
197 "to the server list.\002");
198}
199
200// FIXME: does this work now
201void
202UserCommands::AddShit(ServerConnection *cnx, Person *from,
203 String channel, String rest)
204{
205 StringTokenizer st(rest);
206 String mask, who, maskChannel, level, expiration, reason;
207
a6339323 208 mask = who = st.next_token();
209 maskChannel = st.next_token();
210 level = st.next_token();
211 expiration = st.next_token();
212 reason = Utils::trim_str (st.rest());
cb21075d 213
214 /* if (mask == "" || maskChannel == "" || level == "") {
215 from->sendNotice("\002Invalid syntax for this command.\002");
216 return;
217 }
218 */
219
220 /*
221 if (reason == "")
222 reason = "You're on my shitlist, lamer";
223 */
224
225 /*
a6339323 226 if (!Utils::wildcard_p(mask)) {
cb21075d 227 mask = cnx->bot->getUserhost(channel, who);
228 if (mask == "") {
229 from->sendNotice(String("\002I can not find\002 ") + who);
230 return;
231 }
a6339323 232 mask = Utils::make_wildcard(mask);
cb21075d 233 if (cnx->bot->shitList->getShit(mask, maskChannel)) {
234 from->sendNotice(mask + " \002is already in shitlist on channel(s)\002 " +
235 maskChannel);
236 return;
237 }
238 }
239 */
240 int l;
241 time_t e;
242
815a1816 243 l = atoi(level.c_str ());
cb21075d 244 if (l < 0 || l > ShitEntry::SHIT_NODEBAN)
245 return;
246
a6339323 247 e = Utils::str2time(expiration);
cb21075d 248
249 if (!e)
250 e = -1;
251
252 /*
253 if (cnx->bot->userList->getMaxProt(mask, maskChannel) > 0) {
254 from->sendNotice(String("\002I can not add\002 ") + who +
255 " \002into the shitlist (protection).");
256 return;
257 }
258
259 cnx->bot->shitList->addShit(mask, maskChannel, l, e, reason);
260 */
261
262 Message M = Commands::AddShit (cnx->bot, mask, maskChannel, l, e, reason);
263 if (!M.getCode ())
264 from->sendNotice(String("\002Added\002 ") + mask +
265 " \002on channels\002 " + maskChannel +
266 " \002into the shitlist.\002");
267 else
268 from->sendNotice (M.getMessage ());
269}
270
271// FIXME: Convert (and change ?)
272void
273UserCommands::Alias(ServerConnection *cnx, Person *from,
274 String channel, String rest)
275{
276 StringTokenizer st(rest);
a6339323 277 String newF = Utils::to_upper (st.next_token());
278 String oldF = Utils::to_upper (st.next_token());
cb21075d 279
280 if (newF == "" || oldF == "") {
281 from->sendNotice("\002Invalid syntax for this command.\002");
282 return;
283 }
284
285 // First, we check that the "new" function does not exist
e07b6b46 286 if (cnx->bot->userFunctions[newF]) {
cb21075d 287 from->sendNotice(newF + " \002is already an alias.\002");
288 return;
e07b6b46 289 }
cb21075d 290
291 // Next, we check that the "old" function exist
e07b6b46 292 if (!cnx->bot->userFunctions[oldF])
293 {
294 from->sendNotice(String("\002I don't know the\002 ") + oldF +
295 " \002command.");
296 return;
cb21075d 297 }
cb21075d 298
299 // Fine, we do the binding
e07b6b46 300 cnx->bot->userFunctions[newF] =
301 new userFunction (*cnx->bot->userFunctions[oldF]);
cb21075d 302
303 from->sendNotice("\002Alias added.\002");
304}
305
306void
307UserCommands::Ban(ServerConnection *cnx, Person *from,
308 String channel, String rest)
309{
310 if (rest.length() == 0) {
311 if (from)
312 from->sendNotice("\002No nick/mask specified.\002");
313 return;
314 }
315
316 Message m = Commands::Ban(cnx->bot, channel, rest);
317 if (m.getCode() != 0 && from)
318 from->sendNotice(m.getMessage());
319}
320
f9723c92 321namespace
322{
323 void print_ban_list (Person * from, const BanEntry * b)
324 {
325 if (b->getExpirationDate() == -1)
326 from->sendNotice(b->getMask().getMask().pad(30) + " -1");
327 else
328 from->sendNotice(b->getMask().getMask().pad(30) + " " +
329 String((long)(b->getExpirationDate() - std::time (0))));
330 }
331}
332
cb21075d 333void
334UserCommands::BanList(ServerConnection *cnx, Person *from,
335 String channel, String rest)
336{
cb21075d 337 Channel *c = cnx->bot->channelList->getChannel(channel);
f9723c92 338
cb21075d 339 from->sendNotice(String("\002Banlist for channel\002 ") +
340 channel + "\002:\002");
341 from->sendNotice("\002Mask Expires (seconds)\002");
f9723c92 342
343 c->for_each_ban_entry (std::bind1st (std::ptr_fun (print_ban_list),
344 from));
345
cb21075d 346 from->sendNotice("\002End of banlist.\002");
347}
348
349// void
350// UserCommands::ChangeLevel(ServerConnection *cnx, Person *from,
351// String channel, String rest)
352// {
353// StringTokenizer st(rest);
354
355// String who;
a6339323 356// String mask = who = st.next_token();
357// String maskChannel = st.next_token();
358// String level = st.next_token();
cb21075d 359
360// if (mask == "" || maskChannel == "" || level == "") {
361// from->sendNotice("\002Invalid syntax for this command.\002");
362// return;
363// }
364
a6339323 365// if (!Utils::wildcard_p(mask)) {
cb21075d 366// mask = cnx->bot->getUserhost(channel, who);
367// if (mask == "") {
368// from->sendNotice(String("\002I can not find\002 ") + who);
369// return;
370// }
371// mask = from->getNick() + "!" + mask;
372// }
373
374// UserListItem *uli = cnx->bot->userList->getUserListItem(mask, maskChannel);
375
376// if (!uli) {
377// from->sendNotice(String("\002I can not find\002 ") + who +
378// " \002on channel(s)\002 " + maskChannel +
379// " \002in my userlist.\002");
380// return;
381// }
382
383// int l = atoi((const char *)level);
384
385// if (l < User::NONE || l > User::MASTER) {
386// from->sendNotice("\002This is not a valid level.\002");
387// return;
388// }
389
a6339323 390// if (l > Utils::get_level(cnx->bot, from->getAddress())) {
cb21075d 391// from->sendNotice("\002You can not give a level greater than yours.\002");
392// return;
393// }
394
a6339323 395// if (Utils::get_level(cnx->bot, from->getAddress()) < uli->level) {
cb21075d 396// from->sendNotice("\002You can not change the level for a person "
397// "whose level is greater than yours.\002");
398// return;
399// }
400
401// uli->level = l;
402// from->sendNotice("\002Level changed.\002");
403// cnx->bot->rehash();
404// }
405
406void
407UserCommands::Channels(ServerConnection *cnx, Person *from,
408 String channel, String rest)
409{
410 String result = "";
411
412 for (std::map<String, Channel *, std::less<String> >::iterator it =
413 cnx->bot->channelList->begin();
414 it != cnx->bot->channelList->end(); ++it)
415 result = result + (*it).first + " ";
416
417 if (result == "")
418 from->sendNotice("\002I am not on any channel.\002");
419 else
815a1816 420 from->sendNotice(String("\002I am currently on channel(s):\002 ")
cb21075d 421 + result);
422}
423
424void
425UserCommands::Cycle(ServerConnection *cnx, Person *from,
426 String channel, String rest)
427{
428 Message m = Commands::Cycle(cnx->bot, channel);
429 if (m.getCode() != 0)
430 from->sendNotice(m.getMessage());
431}
432
433void
434UserCommands::DCCList(ServerConnection *cnx, Person *from,
435 String channel, String rest)
436{
437 time_t current_time = time(0);
438
439 from->sendNotice("\002DCClist:\002");
440 from->sendNotice("\002Hostname Last used\002");
441
6530edbf 442 for (DCC_MAP::iterator it =
c3ecc559 443 cnx->bot->dccConnections->dcc_map.begin ();
444 it != cnx->bot->dccConnections->dcc_map.end();
cb21075d 445 ++it) {
4edefeb6 446 from->sendNotice(String(it->second->dcc->get_nuh()).pad(32) + " " +
cb21075d 447 String((long)(current_time -
4edefeb6 448 it->second->dcc->get_lastSpoken())));
cb21075d 449 }
450
451 from->sendNotice("\002End of dcclist.\002");
452}
453
454void
455UserCommands::Deban(ServerConnection *cnx, Person *from,
456 String channel, String rest)
457{
458 if (rest.length() == 0) {
459 from->sendNotice("\002No nick/mask specified.\002");
460 return;
461 }
462
463 Message m = Commands::Deban(cnx->bot, channel, rest);
464 if (m.getCode() != 0)
465 from->sendNotice(m.getMessage());
466}
467
468void
469UserCommands::DelServer(ServerConnection *cnx, Person *from,
470 String channel, String rest)
471{
472 if (rest.length() == 0) {
473 from->sendNotice("\002You need to supply a server number"
474 " for this command.\002");
475 return;
476 }
477
815a1816 478 int serverNumber = atoi(rest.c_str ());
cb21075d 479
480 Message m = Commands::DelServer(cnx->bot, serverNumber);
481 if (m.getCode() != 0)
482 from->sendNotice(m.getMessage());
483 else
484 from->sendNotice(String("Deleted server ") +
485 cnx->bot->serverList->get(serverNumber)->getHostName() +
486 " (" + String((long)cnx->bot->serverList->get(serverNumber)->getPort()) +
487 ").");
488}
489
490// FIXME: Convert
491void
492UserCommands::DelUser(ServerConnection *cnx, Person *from,
493 String channel, String rest)
494{
495 StringTokenizer st(rest);
496
497 String who;
a6339323 498 String mask = who = st.next_token();
499 String maskChannel = st.next_token();
cb21075d 500
501 if (mask == "" || maskChannel == "") {
502 from->sendNotice("\002Invalid syntax for this command.\002");
503 return;
504 }
505
a6339323 506 if (!Utils::wildcard_p(mask)) {
cb21075d 507 mask = cnx->bot->getUserhost(channel, who);
508 if (mask == "") {
509 from->sendNotice(String("\002I can not find\002 ") + who);
510 return;
511 }
a6339323 512 mask = Utils::make_wildcard(mask);
cb21075d 513 }
514
515 if (!cnx->bot->userList->isInUserList(mask, maskChannel)) {
516 from->sendNotice(mask + " \002is not in userlist on channel(s)\002 " +
517 maskChannel);
518 return;
519 }
520
521 cnx->bot->userList->removeUser(mask, maskChannel);
522 from->sendNotice(who + " \002has been removed from the userlist.\002");
523 cnx->bot->rehash();
524}
525
526// FIXME: Convert
527void
528UserCommands::DelShit(ServerConnection *cnx, Person *from,
529 String channel, String rest)
530{
531 StringTokenizer st(rest);
532
533 String who;
a6339323 534 String mask = who = st.next_token();
535 String maskChannel = st.next_token();
cb21075d 536
537 if (mask == "" || maskChannel == "") {
538 from->sendNotice("\002Invalid syntax for this command.\002");
539 return;
540 }
541
a6339323 542 if (!Utils::wildcard_p(mask)) {
cb21075d 543 mask = cnx->bot->getUserhost(channel, who);
544 if (mask == "") {
545 from->sendNotice(String("\002I can not find\002 ") + who);
546 return;
547 }
a6339323 548 mask = Utils::make_wildcard(mask);
cb21075d 549 }
550
551 if (!cnx->bot->shitList->getShit(mask, maskChannel)) {
552 from->sendNotice(mask + " \002is not in shitlist on channel(s)\002 " +
553 maskChannel);
554 return;
555 }
556
557 cnx->bot->shitList->delShit(mask, maskChannel);
558 from->sendNotice(who + " \002has been removed from the shitlist.\002");
559}
560
561void
562UserCommands::Deop(ServerConnection *cnx, Person *from,
563 String channel, String rest)
564{
565 String target = rest;
566
567 if (target.length() == 0)
568 target = from->getNick();
569
570 Message m = Commands::Deop(cnx->bot, channel, target);
571 if (m.getCode() != 0)
572 from->sendNotice(m.getMessage());
573}
574
575void
576UserCommands::Die(ServerConnection *cnx, Person *from,
577 String channel, String rest)
578{
579 String reason;
580
581 if (rest.length() == 0)
582 reason = "Leaving";
583 else
584 reason = rest;
585
586 Commands::Die(cnx->bot, reason);
587}
588
589void
590UserCommands::Do(ServerConnection *cnx, Person *from,
591 String channel, String rest)
592{
593 if (rest.length() != 0)
594 Commands::Do(cnx->bot, rest);
595}
596
597#ifdef USESCRIPTS
598void
599UserCommands::Execute(ServerConnection *cnx, Person *from,
600 String channel, String rest)
601{
602 if (rest.length() != 0)
603 Interp::Execute(cnx->bot, rest);
604}
605#endif
606
607void
608UserCommands::Help(ServerConnection *cnx, Person *from,
609 String channel, String rest)
610{
611 if (rest.length() == 0) {
612 from->sendNotice("\002Available topics for you are:\002");
a6339323 613 int level = Utils::get_level(cnx->bot, from->getAddress());
cb21075d 614 String result = "";
615 int length = 0;
7b564711 616 std::map<std::string, class userFunction*,
617 std::less<std::string> >::iterator it;
618
619 for (it = cnx->bot->userFunctions.begin();
620 it != cnx->bot->userFunctions.end(); ++it)
621 {
622 if ((*it).second->minLevel <= level)
623 {
624 result = result + (*it).first + " ";
625 length += (*it).first.length() + 1;
626
627 if (length >= 256)
628 {
629 from->sendNotice(result);
630 result = ""; length = 0;
631 }
632 }
633 }
cb21075d 634 if (result != "")
635 from->sendNotice(result);
636 from->sendNotice("\002Use\002 HELP <command> \002for"
637 " help about\002 <command>");
638 return;
639 }
640
641 StringTokenizer st(rest);
a6339323 642 String command = Utils::to_upper (st.next_token());
815a1816 643 std::ifstream helpFile(cnx->bot->helpFileName.c_str ());
cb21075d 644
645 if (!helpFile) {
646 from->sendNotice(String("\002Error: I can not find the "
647 "help file\002 ") +
648 cnx->bot->helpFileName);
649 return;
650 }
651
652 String buf;
653 while (!helpFile.eof()) {
654 helpFile >> buf;
655 if (buf.subString(0, command.length()) == String(":") + command) {
656 buf = buf.subString(1);
657 from->sendNotice(String("\002Help for\002 ") + command +
658 "\002:\002");
659 while (buf != "") {
660 from->sendNotice(buf);
661 helpFile >> buf;
662 }
663 from->sendNotice("\002End of help.\002");
664 return;
665 }
666 }
667
668 from->sendNotice(String("\002No such topic (\002") +
669 command + "\002).\002");
670}
671
672void
673UserCommands::Ident(ServerConnection *cnx, Person *from,
674 String channel, String rest)
675{
676 Channel *c = cnx->bot->channelList->getChannel(channel);
677
678 if (rest.length() <= 2) {
679 from->sendNotice("\002No password specified or password "
680 "too short.\002");
681 return;
682 }
683
71cf2688 684 try
685 {
686 User u = c->getUser(from->getNick());
687
688 if (u.userListItem && u.userListItem->identified) {
689 from->sendNotice(String("\002You are already identified on"
690 " channel\002 ") + channel);
691 return;
692 }
693
694 if (!u.userListItem) {
695 from->sendNotice("\002You are not in my userlist.\002");
696 return;
697 }
698
699 if (u.userListItem->passwd ==
700 crypt(rest.c_str (), u.userListItem->passwd.c_str ())) {
701 // For each channel, we increment identification counter
702 // fixme: is this logic correct?
703 for (std::map<String, Channel *, std::less<String> >::iterator it =
704 cnx->bot->channelList->begin();
705 it != cnx->bot->channelList->end(); ++it)
706 u.userListItem->identified++;
707
708 from->sendNotice("\002You are now identified.\002");
709 } else
710 from->sendNotice("\002This is a wrong password.\002");
711 }
712 catch (ChannelUserList::user_not_found &e)
713 {
714 from->sendNotice(String("\002You can identify yourself on"
715 " channel\002 ") + channel +
716 " \002only if you are on the channel.\002");
717 return;
718 }
cb21075d 719}
720
721void
722UserCommands::Invite(ServerConnection *cnx, Person *from,
723 String channel, String rest)
724{
725 Message m = Commands::Invite(cnx->bot, channel, rest);
726 if (m.getCode() < 0)
727 from->sendNotice(m.getMessage());
728 from->sendNotice(String("\002Inviting\002 ") + rest + " \002on channel\002 " + channel);
729}
730
731// FIXME: Convert
732void
733UserCommands::Join(ServerConnection *cnx, Person *from,
734 String channel, String rest)
735{
736 StringTokenizer st(rest);
a6339323 737 channel = st.next_token();
cb21075d 738
a6339323 739 if (!Utils::valid_channel_name_p(channel)) {
cb21075d 740 from->sendNotice(String("\002") + channel +
741 " is not a valid channel name\002");
742 return;
743 }
744
745 // We change the key only if we are not on the channel. We don't trust
746 // the user...
747 if (!cnx->bot->channelList->getChannel(channel)) {
748 if (cnx->bot->wantedChannels[channel])
749 cnx->bot->wantedChannels[channel]->key = st.rest();
750 else {
751 cnx->bot->wantedChannels[channel] = new wantedChannel("", "", st.rest());
752 }
753 }
754 cnx->queue->sendJoin(channel, cnx->bot->wantedChannels[channel]->key);
755}
756
757// FIXME: Convert
758void
759UserCommands::Keep(ServerConnection *cnx, Person *from,
760 String channel, String rest)
761{
762 String nick = from->getNick();
763
764 if (rest.length() == 0) {
765 from->sendNotice("\002No channel modes specified.\002");
766 return;
767 }
768
769 cnx->bot->channelList->getChannel(channel)->keepModes = rest;
770 from->sendNotice(String("\002Keeping modes\002 ") +
771 rest + " \002on channel\002 " +
772 channel);
773}
774
cb21075d 775void
776UserCommands::Kick(ServerConnection *cnx, Person *from,
777 String channel, String rest)
778{
cb21075d 779 Channel * c = cnx->bot->channelList->getChannel(channel);
780
781 if (rest.length() == 0) {
782 from->sendNotice("\002No nick specified.\002");
783 return;
784 }
785
786 StringTokenizer st(rest);
a6339323 787 String who = st.next_token();
cb21075d 788
a6339323 789 if (Utils::wildcard_p(who)) {
71cf2688 790 try
791 {
792 User u = c->getUser(from->getNick ());
cb21075d 793
71cf2688 794 if (u.getLevel() < User::TRUSTED_USER) {
795 from->sendNotice("\002You need an higher level to "
796 "use wildcards.\002");
797 return;
798 }
799 }
800 catch (const ChannelUserList::user_not_found &)
801 {
802 return;
803 }
cb21075d 804 }
71cf2688 805
806 Message ret = Commands::Kick (cnx->bot, channel, who, st.rest ());
807 if (ret.getCode () != 0)
808 from->sendNotice (ret.getMessage ());
cb21075d 809}
810
811// FIXME: Convert
812void
813UserCommands::KickBan(ServerConnection *cnx, Person *from,
814 String channel, String rest)
815{
816 StringTokenizer st(rest);
817
a6339323 818 Ban(cnx, 0, channel, st.next_token());
cb21075d 819 Kick(cnx, from, channel, rest);
820}
821
822void
823UserCommands::Load(ServerConnection *cnx, Person *from,
824 String channel, String rest)
825{
826 cnx->bot->shitList->read();
827 cnx->bot->userList->read();
828 cnx->bot->userList->addUserFirst(cnx->bot->nickName + "!" + cnx->bot->userHost, "*", 0, 3, true, -1, "");
829 cnx->bot->rehash();
830 from->sendNotice("\002Userlist and shitlist loaded.\002");
831}
832
833#ifdef USESCRIPTS
834void
835UserCommands::LoadScript(ServerConnection *cnx, Person *from,
836 String channel, String rest)
837{
838 if (rest.length() != 0)
839 Interp::LoadScript(cnx->bot, rest);
840}
841#endif
842
843// FIXME: Convert
844void
845UserCommands::Lock(ServerConnection *cnx, Person *from,
846 String channel, String rest)
847{
848 cnx->bot->channelList->getChannel(channel)->lockedTopic = true;
849 from->sendNotice(String("\002Locking topic for channel\002 ") +
850 channel);
851}
852
853// FIXME: Convert
854void
855UserCommands::Mode(ServerConnection *cnx, Person *from,
856 String channel, String rest)
857{
858 String nick = from->getNick();
859
860 if (rest.length() == 0) {
861 from->sendNotice("\002I need a parameter for this command.\002");
862 return;
863 }
864
865 if (!cnx->bot->iAmOp(channel)) {
866 from->sendNotice(String("\002I am not channel op on\002 ") +
867 channel);
868 return;
869 }
870
871 cnx->queue->sendChannelMode(String("MODE ") + channel + " " + rest);
872}
873
874void
875UserCommands::Msg(ServerConnection *cnx, Person *from,
876 String channel, String rest)
877{
878 StringTokenizer st(rest);
a6339323 879 String who = st.next_token();
cb21075d 880 String message = st.rest();
881
882 Message m = Commands::Msg(cnx->bot, who, message);
883 if (m.getCode() != 0)
884 from->sendNotice(m.getMessage());
885}
886
71cf2688 887UserCommands::map_names::map_names (Person *f, std::string &r)
888 : from (f), result (r), length (0)
889{ }
890
891void
892UserCommands::map_names::operator() (const User &user)
893{
894 result += (user.mode & User::OP_MODE ? "@" :
895 (user.mode & User::VOICE_MODE ? "+" : "")) + user.nick + " ";
896 length += user.nick.length() + 1;
897
898 if (length >= 256) {
899 from->sendNotice(result);
900 result = ""; length = 0;
901 }
902}
903
cb21075d 904void
905UserCommands::Names(ServerConnection *cnx, Person *from,
906 String channel, String rest)
907{
908 String nick = from->getNick();
cb21075d 909 Channel *c = cnx->bot->channelList->getChannel(channel);
71cf2688 910 std::string result;
cb21075d 911
912 from->sendNotice(String("\002Names on ") +
913 channel + ":\002");
914
71cf2688 915 map_names f (from, result);
916 c->for_each_channel_users (f);
cb21075d 917
918 if (result != "")
919 from->sendNotice(result);
920
921 from->sendNotice("\002End of names.\002");
922}
923
924// FIXME: Convert
925void
926UserCommands::NextServer(ServerConnection *cnx, Person *from,
927 String channel, String rest)
928{
929 if (cnx->bot->serverList->size() == 0) {
930 from->sendNotice("\002Server list is empty !\002");
931 return;
932 }
933
934 if (cnx->bot->serverList->size() == 1) {
935 from->sendNotice("\002Server list has only one item. Use"
936 " \"reconnect\" to force reconnection.\002");
937 return;
938 }
939
940 if (cnx->bot->canChangeServer()) {
941 cnx->queue->sendQuit("Changing server");
942 cnx->bot->nextServer();
943 }
944 else
945 from->sendNotice("\002I can not change server without"
946 " losing op on a channel I am on.\002");
947}
948
949// FIXME: Convert
950void
951UserCommands::Nick(ServerConnection *cnx, Person *from,
952 String channel, String rest)
953{
954 // We parse the parameters
955 StringTokenizer st(rest);
a6339323 956 String nick = st.next_token();
cb21075d 957
958 if (rest == "") {
959 from->sendNotice(String("\002No nickname given.\002"));
960 return;
961 }
962
6b7614a8 963 if (!Utils::valid_nickname_p (cnx->bot, nick)) {
cb21075d 964 from->sendNotice(String("\002") + nick +
965 " is not a valid nickname\002");
966 return;
967 }
968
969 cnx->bot->wantedNickName = nick;
970 cnx->queue->sendNick(nick);
971}
972
973void
974UserCommands::NsLookup(ServerConnection *cnx, Person *from,
975 String channel, String rest)
976{
977 String target;
978
979 if (rest.length() == 0) {
980 from->sendNotice("\002You need to supply a nick or an "
981 "host for this command.\002");
982 return;
983 }
984
985 if (rest.find('.') == -1) {
986 StringTokenizer st(cnx->bot->getUserhost("", rest));
a6339323 987 st.next_token('@');
cb21075d 988 target = st.rest();
989 if (target.length() == 0) {
990 from->sendNotice(String("\002I could not find\002 ") +
991 target);
992 return;
993 }
994 } else
995 target = rest;
996
997 struct hostent * host;
998 struct in_addr iaddr;
999
1000 if (isdigit(target[0])) { // An IP ?
71cf2688 1001 iaddr.s_addr = inet_addr(target.c_str ());
cb21075d 1002 host = gethostbyaddr((char *)(&iaddr),
1003 sizeof(struct in_addr),
1004 AF_INET);
1005 if (host) {
1006 from->sendNotice(target +
1007 " \002is the IP address of\002 " +
1008 host->h_name);
1009 return;
1010 }
1011 } else {
71cf2688 1012 host = gethostbyname(target.c_str ());
cb21075d 1013 if (host) {
55f2215d 1014 std::memcpy((char *)&iaddr, (char *)host->h_addr,
cb21075d 1015 host->h_length);
1016 from->sendNotice(target + " \002has\002 " +
1017 inet_ntoa(iaddr) + " \002for IP address.\002");
1018 return;
1019 }
1020 }
1021
1022 from->sendNotice(String("\002I could not find host\002 ") +
1023 target);
1024}
1025
cb21075d 1026void
1027UserCommands::Op(ServerConnection *cnx, Person *from,
1028 String channel, String rest)
1029{
71cf2688 1030 Message ret = Commands::Op (cnx->bot, channel,
1031 rest.length () == 0 ? from->getNick () : rest);
1032
1033 if (ret.getCode () != 0)
1034 from->sendNotice (ret.getMessage ());
cb21075d 1035}
1036
cb21075d 1037void
1038UserCommands::Part(ServerConnection *cnx, Person *from,
1039 String channel, String rest)
1040{
71cf2688 1041 Message ret = Commands::Part (cnx->bot, channel);
1042
1043 if (ret.getCode () != 0)
1044 from->sendNotice (ret.getMessage ());
cb21075d 1045}
1046
1047void
1048UserCommands::Password(ServerConnection *cnx, Person *from,
1049 String channel, String rest)
1050{
cb21075d 1051 if (rest.length() == 0) {
1052 from->sendNotice("\002No password.\002");
1053 return;
1054 }
1055
71cf2688 1056 try
1057 {
1058 Channel *c = cnx->bot->channelList->getChannel(channel);
1059 User u = c->getUser(from->getNick());
1060
1061 if (!u.userListItem) {
1062 from->sendNotice("\002You are not in my userlist.\002");
1063 return;
1064 }
1065
1066 if (rest.toLower() == "none") {
1067 u.userListItem->passwd = "";
1068 from->sendNotice("\002Password cleared.\002");
1069 return;
1070 }
1071
1072 static char saltChars[] = "abcdefghijklmnopqrstuvwxyz"
1073 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
1074 char salt[3];
1075 srand(time(0));
1076 salt[0] = saltChars[rand() % 64];
1077 salt[1] = saltChars[rand() % 64];
1078 salt[2] = '\0';
1079
1080 u.userListItem->passwd = crypt(rest.c_str (), salt);
1081 from->sendNotice("\002Password changed.\002");
1082 }
1083 catch (const ChannelUserList::user_not_found &e)
1084 {
1085 from->sendNotice(String("\002To change your password for\002") +
1086 channel + "\002, you need to be on the "
1087 "channel.\002");
1088 return;
1089 }
cb21075d 1090}
1091
1092void
1093UserCommands::Save(ServerConnection *cnx, Person *from,
1094 String channel, String rest)
1095{
1096 cnx->bot->userList->save();
1097 cnx->bot->shitList->save();
1098 from->sendNotice("\002Userlist and shitlist saved.\002");
1099}
1100
1101// FIXME: Convert
1102void
1103UserCommands::Say(ServerConnection *cnx, Person *from,
1104 String channel, String rest)
1105{
1106 if (rest.length() != 0)
1107 cnx->queue->sendPrivmsg(channel, rest);
1108}
1109
1110// FIXME: Convert
1111void
1112UserCommands::Server(ServerConnection *cnx, Person *from,
1113 String channel, String rest)
1114{
1115 int serverNumber;
1116 String nick = from->getNick();
1117
1118 if (rest.length() == 0) {
1119 from->sendNotice("\002You need to supply a server number for this command.\002");
1120 return;
1121 }
1122
815a1816 1123 serverNumber = atoi(rest.c_str ());
cb21075d 1124
1125 if (serverNumber < 0 || serverNumber >= cnx->bot->serverList->size()) {
1126 from->sendNotice(String((long)serverNumber) +
1127 " \002is an invalid server number (see the serverlist).\002");
1128 return;
1129 }
1130
1131 if (cnx->bot->canChangeServer()) {
1132 cnx->queue->sendQuit("Changing server");
1133 cnx->queue->flush();
1134 cnx->bot->connect(serverNumber);
1135 }
1136 else
1137 from->sendNotice("\002I can not change server without losing op on a channel I am on.\002");
1138}
1139
1140void
1141UserCommands::ServerList(ServerConnection *cnx, Person *from,
1142 String channel, String rest)
1143{
1144 String nick = from->getNick();
1145
1146 from->sendNotice("\002Server list:\002");
1147 long l = 0;
1148 String s;
1149 for (std::vector<class Server *>::iterator it =
1150 cnx->bot->serverList->v.begin();
1151 it != cnx->bot->serverList->v.end();
1152 ++it) {
1153 s = (*it) == cnx->server ? "\026" : "";
1154 from->sendNotice(s + String(l++) + s + " " +
1155 (*it)->getHostName() +
1156 " (" + String((long)((*it)->getPort())) +
1157 ")");
1158 }
1159 from->sendNotice("\002End of server list.\002");
1160}
1161
e171dcce 1162
1163void
1164UserCommands::SetFloodRate(ServerConnection *cnx, Person *from,
1165 String channel, String rest)
1166{
815a1816 1167 Message m = Commands::SetFloodRate (cnx->bot, std::atoi (rest.c_str ()));
e171dcce 1168 if (m.getCode ())
1169 from->sendNotice (m.getMessage ());
1170 else
815a1816 1171 from->sendNotice ("Flood Rate set to:" + String(std::atol(rest.c_str ())));
e171dcce 1172}
1173
cb21075d 1174void
1175UserCommands::SetVersion(ServerConnection *cnx, Person *from,
1176 String channel, String rest)
1177{
1178 Message m = Commands::SetVersion(cnx->bot, rest);
6b7614a8 1179
cb21075d 1180 if (m.getCode() < 0)
6b7614a8 1181 {
1182 Commands::Notice (cnx->bot, from->getNick (), m.getMessage());
1183 }
cb21075d 1184}
1185
1186void
1187UserCommands::ShitList(ServerConnection *cnx, Person *from,
1188 String channel, String rest)
1189{
1190 from->sendNotice("\002Shitlist:\002");
1191 from->sendNotice("\002Mask Channel Level Expires Reason\002");
1192
1193 for (std::list<ShitEntry *>::iterator it = cnx->bot->shitList->l.begin();
1194 it != cnx->bot->shitList->l.end();
1195 it++)
1196 from->sendNotice((*it)->shitMask.getMask().pad(25) + " " +
1197 (*it)->shitChannelMask.getMask().pad(10) + " " +
1198 String((long)(*it)->shitLevel).pad(9) + " " +
1199 String((long)(*it)->expirationDate).pad(9) + " " +
1200 (*it)->shitReason);
1201
1202 from->sendNotice("\002End of shitlist.\002");
1203}
1204
1205void
1206UserCommands::SpyList(ServerConnection *cnx, Person *from,
1207 String channel, String rest)
1208{
1209 String nick = from->getNick();
1210
1211 from->sendNotice("\002Spy list:\002");
1212
1213 for (std::map<String, Person *, std::less<String> >::iterator it =
1214 cnx->bot->spyList.begin(); it != cnx->bot->spyList.end(); ++it)
1215 from->sendNotice((*it).first);
1216
1217 from->sendNotice("\002End of spy list.\002");
1218}
1219
1220void
1221UserCommands::SpyMessage(ServerConnection *cnx, Person *from,
1222 String channel, String rest)
1223{
1224 String nick = from->getNick();
1225
1226 if (cnx->bot->spyList.find(nick) != cnx->bot->spyList.end()) {
1227 from->sendNotice("\002You are already spying messages.\002");
1228 return;
1229 }
1230
1231 Person *f = from->copy();
1232 f->keepAlive();
1233 cnx->bot->spyList[nick.toLower()] = f;
1234 from->sendNotice("\002You have been added to the spy list.\002");
1235}
1236
1237// FIXME: Convert
1238void
1239UserCommands::Reconnect(ServerConnection *cnx, Person *from,
1240 String channel, String rest)
1241{
1242 String nick = from->getNick();
1243
1244 if (cnx->bot->canChangeServer()) {
1245 cnx->queue->sendQuit("Reconnecting");
1246 cnx->bot->reconnect();
1247 }
1248 else
1249 from->sendNotice("\002I can not change server without losing op on a channel I am on.\002");
1250}
1251
1252void
1253UserCommands::RSpyMessage(ServerConnection *cnx, Person *from,
1254 String channel, String rest)
1255{
1256 String nick = from->getNick().toLower();
1257
1258 if (cnx->bot->spyList.find(nick) == cnx->bot->spyList.end()) {
1259 from->sendNotice("\002You are not in the spy list.\002");
1260 return;
1261 }
1262
1263 delete cnx->bot->spyList[nick];
1264 cnx->bot->spyList.erase(nick);
1265 from->sendNotice("\002You have been removed from the "
1266 "spy list.\002");
1267}
1268
1269// FIXME: Convert
1270void
1271UserCommands::Unlock(ServerConnection *cnx, Person *from,
1272 String channel, String rest)
1273{
1274 cnx->bot->channelList->getChannel(channel)->lockedTopic = false;
1275 from->sendNotice(String("\002Unlocking topic for channel\002 ") +
1276 channel);
1277}
1278
1279void
1280UserCommands::Stats(ServerConnection *cnx, Person *from,
1281 String channel, String rest)
1282{
1283 String nick = from->getNick();
1284
1285 from->sendNotice(String("\002Keeping modes\002 ") +
1286 cnx->bot->channelList->getChannel(channel)->keepModes + " \002on channel\002 " +
1287 channel);
1288}
1289
cb21075d 1290void
1291UserCommands::TBan(ServerConnection *cnx, Person *from,
1292 String channel, String rest)
1293{
1294 Channel * c = cnx->bot->channelList->getChannel(channel);
cb21075d 1295 StringTokenizer st(rest);
a6339323 1296 String who = st.next_token();
1297 String t = st.next_token();
cb21075d 1298
1299 if (who == "" || t == "") {
1300 if (from)
1301 from->sendNotice("\002Invalid syntax for this command.\002");
1302 return;
1303 }
1304
a6339323 1305 if (Utils::wildcard_p(who) && from) {
71cf2688 1306 if (c->hasNick (from->getNick ())
1307 && c->getUser(from->getNick()).getLevel() < User::TRUSTED_USER) {
cb21075d 1308 if (from)
1309 from->sendNotice("\002You need an higher level to use"
1310 " wildcards.\002");
1311 return;
1312 }
1313 }
1314
f9723c92 1315 Message ret = Commands::TBan (cnx->bot, channel, who, Utils::str2time (t));
1316 if (ret.getCode () && from)
1317 from->sendNotice ("\002" + ret.getMessage () + "\002");
cb21075d 1318}
1319
1320// FIXME: Convert
1321void
1322UserCommands::TKBan(ServerConnection *cnx, Person *from,
1323 String channel, String rest)
1324{
1325 StringTokenizer st(rest);
a6339323 1326 String who = st.next_token();
1327 String t = st.next_token();
cb21075d 1328
1329 TBan(cnx, 0, channel, who + " " + t);
1330 Kick(cnx, from, channel, who + " " + st.rest());
1331}
1332
1333// FIXME: Convert
1334void
1335UserCommands::Topic(ServerConnection *cnx, Person *from,
1336 String channel, String rest)
1337{
1338 String nick = from->getNick();
1339
1340 if (rest.length() == 0) {
1341 if (cnx->bot->channelList->getChannel(channel)->channelTopic == "")
1342 from->sendNotice(String("\002No topic is set for channel\002 ") +
1343 channel + "\002.\002");
1344 else
1345 from->sendNotice(String("\002Topic for\002 ") +
1346 channel + " \002is:\002 " +
1347 cnx->bot->channelList->getChannel(channel)->channelTopic);
1348 } else {
1349 if (cnx->bot->channelList->getChannel(channel)->lockedTopic)
1350 from->sendNotice(String("\002Topic is locked on channel\002 ") +
1351 channel);
1352 else
1353 cnx->queue->sendTopic(channel, rest);
1354 }
1355}
1356
1357void
1358UserCommands::UserList(ServerConnection *cnx, Person *from,
1359 String channel, String rest)
1360{
1361 from->sendNotice("\002Userlist:\002");
1362 from->sendNotice("\002Mask Channel Level Prot Aop Expires\002");
1363
1364 for (std::list<UserListItem *>::iterator it = cnx->bot->userList->l.begin();
1365 it != cnx->bot->userList->l.end();
1366 it++)
a6339323 1367 from->sendNotice((*it)->mask.getMask().pad(25)
1368 + " "
1369 + (*it)->channelMask.getMask().pad(10)
1370 + " " +
1371 String(Utils::level2str((*it)->level)).pad(12)
1372 + " " +
1373 String(Utils::prot2str((*it)->prot)).pad(7)
1374 + " " +
1375 String(Utils::bool2str((*it)->aop)).pad(5)
1376 + " " +
1377 String(Utils::long2str ((*it)->expirationDate)));
1378
cb21075d 1379 from->sendNotice("\002End of userlist.\002");
1380}
1381
1382void
1383UserCommands::Who(ServerConnection *cnx, Person *from,
c6e7af05 1384 String channel, String rest)
cb21075d 1385{
1386 String nick = from->getNick();
cb21075d 1387 UserListItem * uli;
71cf2688 1388
1389 if (cnx->bot->channelList->getChannel(channel)->hasNick(nick))
1390 uli = cnx->bot->channelList->getChannel(channel)->getUser(nick).userListItem;
cb21075d 1391 else
1392 uli = cnx->bot->userList->getUserListItem(from->getAddress(),
71cf2688 1393 channel);
1394
cb21075d 1395 if (uli) {
1396 from->sendNotice(String("\002You are\002 ") +
71cf2688 1397 uli->mask.getMask() + " \002on\002 " +
1398 uli->channelMask.getMask());
cb21075d 1399 from->sendNotice(String("\002Lvl:\002 ") +
71cf2688 1400 Utils::level2str(uli->level) +
1401 " \002Prot:\002 " +
1402 Utils::prot2str(uli->prot) +
1403 " \002Aop:\002 " +
1404 Utils::bool2str(uli->aop) +
1405 " \002Expired:\002 " +
1406 Utils::bool2str(!uli->isStillValid()) +
1407 " \002Ident:\002 " +
1408 (uli && !uli->identified ? "\026" : "") +
1409 Utils::bool2str(uli && uli->identified) +
1410 (uli && !uli->identified ? "\026" : ""));
cb21075d 1411 } else
1412 from->sendNotice(String("\002You are not in the userlist for\002 ") +
71cf2688 1413 channel);
cb21075d 1414}
1415
1416void
1417UserCommands::Whois(ServerConnection *cnx, Person *from,
1418 String channel, String rest)
1419{
1420 String nick = from->getNick();
1421
1422 if (!rest.length()) {
1423 from->sendNotice("\002No nick specified.\002");
1424 return;
1425 }
1426
1427 StringTokenizer st(rest);
a6339323 1428 String otherNick = st.next_token();
cb21075d 1429
cb21075d 1430 UserListItem * uli;
1431
71cf2688 1432 if (cnx->bot->channelList->getChannel(channel)->hasNick(otherNick))
1433 uli = cnx->bot->channelList->getChannel(channel)->getUser(otherNick).userListItem;
cb21075d 1434 else
1435 uli = cnx->bot->userList->getUserListItem(otherNick + "!" +
1436 cnx->bot->getUserhost(channel,
1437 otherNick),
1438 channel);
1439
1440 if (uli) {
1441 from->sendNotice(otherNick +
1442 " \002is\002 " + uli->mask.getMask() +
1443 " \002on\002 " + uli->channelMask.getMask());
1444 from->sendNotice(String("\002Lvl:\002 ") +
a6339323 1445 Utils::level2str(uli->level) +
cb21075d 1446 " \002Prot:\002 " +
a6339323 1447 Utils::prot2str(uli->prot) +
cb21075d 1448 " \002Aop:\002 " +
a6339323 1449 Utils::bool2str(uli->aop) +
cb21075d 1450 " \002Expired:\002 " +
a6339323 1451 Utils::bool2str(!uli->isStillValid()) +
cb21075d 1452 " \002Ident:\002 " +
a6339323 1453 Utils::bool2str(uli && uli->identified));
cb21075d 1454 } else
1455 from->sendNotice(otherNick +
1456 " \002is not in the userlist for\002 " +
1457 channel);
1458}