c60b91ef4734d38e6e8489d918393df838cd25bf
[clinton/bobotpp.git] / source / UserCommands.C
1 // UserCommands.C -*- C++ -*-
2 // Copyright (c) 1997, 1998 Etienne BERNARD
3 // Copyright (C) 2002,2005 Clinton Ebadi
4
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // any later version.
9
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301, USA.
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "UserCommands.H"
25
26 #include <fstream>
27 #include <functional>
28 #include <map>
29 #include <string>
30
31 #include <cctype>
32 #include <cstdlib>
33 #include <cstring>
34
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
39 #include <netdb.h>
40
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
50
51 #include <unistd.h>
52
53 #include "BanEntry.H"
54 #include "Channel.H"
55 #include "ChannelList.H"
56 #include "Commands.H"
57 #include "DCCConnection.H"
58 #include "DCCManager.H"
59 #include "DCCPerson.H"
60 #include "Macros.H"
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"
69 #include "StringTokenizer.H"
70 #include "User.H"
71 #include "UserList.H"
72 #include "Utils.H"
73
74 #ifdef USESCRIPTS
75 #include "Interp.H"
76 #endif
77
78 #ifdef NOCRYPT
79 char * crypt(const char *p, const char *s) { return p; }
80 #endif
81
82 void
83 UserCommands::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
91 void
92 UserCommands::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
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();
106
107 if (mask == "" || maskChannel == "" || level == "" ||
108 prot == "" || aop == "") {
109 from->sendNotice("\002Invalid syntax for this command.\002");
110 return;
111 }
112
113 // if (!Utils::wildcard_p(mask)) {
114 // mask = cnx->bot->getUserhost(channel, who);
115 // if (mask == "") {
116 // from->sendNotice(String("\002I can not find\002 ") + who);
117 // return;
118 // }
119 // mask = Utils::make_wildcard(mask);
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
132 l = atoi((const char *)level);
133 if (l < 0 || l > User::FRIEND)
134 return;
135 if (l > Utils::get_level(cnx->bot, from->getAddress())) {
136 from->sendNotice("\002You can not give a level greater than yours.\002");
137 return;
138 }
139 p = atoi((const char *)prot);
140 if (p < 0 || p > User::NO_DEOP)
141 return;
142 a = (bool)atoi((const char *)aop);
143 if (a != 0 && a != 1)
144 return;
145
146 e = Utils::str2time(expiration);
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 ") +
160 Utils::level2str(l) +
161 " \002Protection:\002 " +
162 Utils::prot2str(p) +
163 " \002Auto-op:\002 " +
164 Utils::bool2str(a));
165 }
166 else
167 from->sendNotice(m.getMessage ());
168
169 // cnx->bot->rehash();
170 }
171
172 void
173 UserCommands::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);
182 String serverName = st.next_token();
183 int port = 6667;
184
185 if (st.more_tokens_p()) {
186 String temp = st.next_token();
187 port = atoi((const char *)temp);
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
201 void
202 UserCommands::AddShit(ServerConnection *cnx, Person *from,
203 String channel, String rest)
204 {
205 StringTokenizer st(rest);
206 String mask, who, maskChannel, level, expiration, reason;
207
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());
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 /*
226 if (!Utils::wildcard_p(mask)) {
227 mask = cnx->bot->getUserhost(channel, who);
228 if (mask == "") {
229 from->sendNotice(String("\002I can not find\002 ") + who);
230 return;
231 }
232 mask = Utils::make_wildcard(mask);
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
243 l = atoi((const char *)level);
244 if (l < 0 || l > ShitEntry::SHIT_NODEBAN)
245 return;
246
247 e = Utils::str2time(expiration);
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 ?)
272 void
273 UserCommands::Alias(ServerConnection *cnx, Person *from,
274 String channel, String rest)
275 {
276 StringTokenizer st(rest);
277 String newF = Utils::to_upper (st.next_token());
278 String oldF = Utils::to_upper (st.next_token());
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
286 if (cnx->bot->userFunctions[newF]) {
287 from->sendNotice(newF + " \002is already an alias.\002");
288 return;
289 }
290
291 // Next, we check that the "old" function exist
292 if (!cnx->bot->userFunctions[oldF])
293 {
294 from->sendNotice(String("\002I don't know the\002 ") + oldF +
295 " \002command.");
296 return;
297 }
298
299 // Fine, we do the binding
300 cnx->bot->userFunctions[newF] =
301 new userFunction (*cnx->bot->userFunctions[oldF]);
302
303 from->sendNotice("\002Alias added.\002");
304 }
305
306 void
307 UserCommands::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
321 namespace
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
333 void
334 UserCommands::BanList(ServerConnection *cnx, Person *from,
335 String channel, String rest)
336 {
337 Channel *c = cnx->bot->channelList->getChannel(channel);
338
339 from->sendNotice(String("\002Banlist for channel\002 ") +
340 channel + "\002:\002");
341 from->sendNotice("\002Mask Expires (seconds)\002");
342
343 c->for_each_ban_entry (std::bind1st (std::ptr_fun (print_ban_list),
344 from));
345
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;
356 // String mask = who = st.next_token();
357 // String maskChannel = st.next_token();
358 // String level = st.next_token();
359
360 // if (mask == "" || maskChannel == "" || level == "") {
361 // from->sendNotice("\002Invalid syntax for this command.\002");
362 // return;
363 // }
364
365 // if (!Utils::wildcard_p(mask)) {
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
390 // if (l > Utils::get_level(cnx->bot, from->getAddress())) {
391 // from->sendNotice("\002You can not give a level greater than yours.\002");
392 // return;
393 // }
394
395 // if (Utils::get_level(cnx->bot, from->getAddress()) < uli->level) {
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
406 void
407 UserCommands::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
420 from->sendNotice(String("\002I am currently on channel(s):\002 ") +
421 + result);
422 }
423
424 void
425 UserCommands::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
433 void
434 UserCommands::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
442 for (DCC_MAP::iterator it =
443 cnx->bot->dccConnections->dcc_map.begin ();
444 it != cnx->bot->dccConnections->dcc_map.end();
445 ++it) {
446 from->sendNotice(String(it->second->dcc->get_nuh()).pad(32) + " " +
447 String((long)(current_time -
448 it->second->dcc->get_lastSpoken())));
449 }
450
451 from->sendNotice("\002End of dcclist.\002");
452 }
453
454 void
455 UserCommands::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
468 void
469 UserCommands::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
478 int serverNumber = atoi(rest);
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
491 void
492 UserCommands::DelUser(ServerConnection *cnx, Person *from,
493 String channel, String rest)
494 {
495 StringTokenizer st(rest);
496
497 String who;
498 String mask = who = st.next_token();
499 String maskChannel = st.next_token();
500
501 if (mask == "" || maskChannel == "") {
502 from->sendNotice("\002Invalid syntax for this command.\002");
503 return;
504 }
505
506 if (!Utils::wildcard_p(mask)) {
507 mask = cnx->bot->getUserhost(channel, who);
508 if (mask == "") {
509 from->sendNotice(String("\002I can not find\002 ") + who);
510 return;
511 }
512 mask = Utils::make_wildcard(mask);
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
527 void
528 UserCommands::DelShit(ServerConnection *cnx, Person *from,
529 String channel, String rest)
530 {
531 StringTokenizer st(rest);
532
533 String who;
534 String mask = who = st.next_token();
535 String maskChannel = st.next_token();
536
537 if (mask == "" || maskChannel == "") {
538 from->sendNotice("\002Invalid syntax for this command.\002");
539 return;
540 }
541
542 if (!Utils::wildcard_p(mask)) {
543 mask = cnx->bot->getUserhost(channel, who);
544 if (mask == "") {
545 from->sendNotice(String("\002I can not find\002 ") + who);
546 return;
547 }
548 mask = Utils::make_wildcard(mask);
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
561 void
562 UserCommands::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
575 void
576 UserCommands::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
589 void
590 UserCommands::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
598 void
599 UserCommands::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
607 void
608 UserCommands::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");
613 int level = Utils::get_level(cnx->bot, from->getAddress());
614 String result = "";
615 int length = 0;
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 }
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);
642 String command = Utils::to_upper (st.next_token());
643 std::ifstream helpFile(cnx->bot->helpFileName);
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
672 void
673 UserCommands::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
684 User * u = c->getUser(from->getNick());
685 if (!u) {
686 from->sendNotice(String("\002You can identify yourself on"
687 " channel\002 ") + channel +
688 " \002only if you are on the channel.\002");
689 return;
690 }
691
692 if (u->userListItem && u->userListItem->identified) {
693 from->sendNotice(String("\002You are already identified on"
694 " channel\002 ") + channel);
695 return;
696 }
697
698 if (!u->userListItem) {
699 from->sendNotice("\002You are not in my userlist.\002");
700 return;
701 }
702
703 if (u->userListItem->passwd ==
704 crypt((const char *)rest, (const char *)u->userListItem->passwd)) {
705 // For each channel, we increment identification counter
706 for (std::map<String, Channel *, std::less<String> >::iterator it =
707 cnx->bot->channelList->begin();
708 it != cnx->bot->channelList->end(); ++it)
709 u->userListItem->identified++;
710
711 from->sendNotice("\002You are now identified.\002");
712 } else
713 from->sendNotice("\002This is a wrong password.\002");
714 }
715
716 void
717 UserCommands::Invite(ServerConnection *cnx, Person *from,
718 String channel, String rest)
719 {
720 Message m = Commands::Invite(cnx->bot, channel, rest);
721 if (m.getCode() < 0)
722 from->sendNotice(m.getMessage());
723 from->sendNotice(String("\002Inviting\002 ") + rest + " \002on channel\002 " + channel);
724 }
725
726 // FIXME: Convert
727 void
728 UserCommands::Join(ServerConnection *cnx, Person *from,
729 String channel, String rest)
730 {
731 StringTokenizer st(rest);
732 channel = st.next_token();
733
734 if (!Utils::valid_channel_name_p(channel)) {
735 from->sendNotice(String("\002") + channel +
736 " is not a valid channel name\002");
737 return;
738 }
739
740 // We change the key only if we are not on the channel. We don't trust
741 // the user...
742 if (!cnx->bot->channelList->getChannel(channel)) {
743 if (cnx->bot->wantedChannels[channel])
744 cnx->bot->wantedChannels[channel]->key = st.rest();
745 else {
746 cnx->bot->wantedChannels[channel] = new wantedChannel("", "", st.rest());
747 }
748 }
749 cnx->queue->sendJoin(channel, cnx->bot->wantedChannels[channel]->key);
750 }
751
752 // FIXME: Convert
753 void
754 UserCommands::Keep(ServerConnection *cnx, Person *from,
755 String channel, String rest)
756 {
757 String nick = from->getNick();
758
759 if (rest.length() == 0) {
760 from->sendNotice("\002No channel modes specified.\002");
761 return;
762 }
763
764 cnx->bot->channelList->getChannel(channel)->keepModes = rest;
765 from->sendNotice(String("\002Keeping modes\002 ") +
766 rest + " \002on channel\002 " +
767 channel);
768 }
769
770 // FIXME: Convert
771 void
772 UserCommands::Kick(ServerConnection *cnx, Person *from,
773 String channel, String rest)
774 {
775 String nick = from->getNick();
776
777 Channel * c = cnx->bot->channelList->getChannel(channel);
778
779 if (rest.length() == 0) {
780 from->sendNotice("\002No nick specified.\002");
781 return;
782 }
783
784 StringTokenizer st(rest);
785 String who = st.next_token();
786
787 if (Utils::wildcard_p(who)) {
788 User * u = c->getUser(nick);
789 if (!u)
790 return;
791 if (u->getLevel() < User::TRUSTED_USER) {
792 from->sendNotice("\002You need an higher level to "
793 "use wildcards.\002");
794 return;
795 }
796 }
797
798 if (!cnx->bot->iAmOp(channel)) {
799 from->sendNotice(String("\002I am not channel op on\002 ") +
800 channel);
801 return;
802 }
803
804 if (Utils::wildcard_p(who)) {
805 Mask m(who);
806 for (std::map<String, User *, std::less<String> >::iterator it =
807 c->channelMemory.begin();
808 it != c->channelMemory.end();
809 ++it)
810 if (m.matches((*it).second->nick + "!" +
811 (*it).second->userhost) &&
812 (*it).second->getProt() < User::NO_KICK)
813 cnx->queue->sendKick(channel, (*it).second->nick, st.rest());
814 } else {
815 User * u = c->getUser(who);
816 if (!u) {
817 from->sendNotice(String("\002I can not find\002 ") +
818 who + " \002on\002 " + channel);
819 return;
820 }
821 if (u->getProt() < User::NO_KICK)
822 cnx->queue->sendKick(channel, who, st.rest());
823 else
824 from->sendNotice(String("\002I can not kick\002 ") +
825 who + " \002on\002 " + channel +
826 " \002(protected).\002");
827 }
828 }
829
830 // FIXME: Convert
831 void
832 UserCommands::KickBan(ServerConnection *cnx, Person *from,
833 String channel, String rest)
834 {
835 StringTokenizer st(rest);
836
837 Ban(cnx, 0, channel, st.next_token());
838 Kick(cnx, from, channel, rest);
839 }
840
841 void
842 UserCommands::Load(ServerConnection *cnx, Person *from,
843 String channel, String rest)
844 {
845 cnx->bot->shitList->read();
846 cnx->bot->userList->read();
847 cnx->bot->userList->addUserFirst(cnx->bot->nickName + "!" + cnx->bot->userHost, "*", 0, 3, true, -1, "");
848 cnx->bot->rehash();
849 from->sendNotice("\002Userlist and shitlist loaded.\002");
850 }
851
852 #ifdef USESCRIPTS
853 void
854 UserCommands::LoadScript(ServerConnection *cnx, Person *from,
855 String channel, String rest)
856 {
857 if (rest.length() != 0)
858 Interp::LoadScript(cnx->bot, rest);
859 }
860 #endif
861
862 // FIXME: Convert
863 void
864 UserCommands::Lock(ServerConnection *cnx, Person *from,
865 String channel, String rest)
866 {
867 cnx->bot->channelList->getChannel(channel)->lockedTopic = true;
868 from->sendNotice(String("\002Locking topic for channel\002 ") +
869 channel);
870 }
871
872 // FIXME: Convert
873 void
874 UserCommands::Mode(ServerConnection *cnx, Person *from,
875 String channel, String rest)
876 {
877 String nick = from->getNick();
878
879 if (rest.length() == 0) {
880 from->sendNotice("\002I need a parameter for this command.\002");
881 return;
882 }
883
884 if (!cnx->bot->iAmOp(channel)) {
885 from->sendNotice(String("\002I am not channel op on\002 ") +
886 channel);
887 return;
888 }
889
890 cnx->queue->sendChannelMode(String("MODE ") + channel + " " + rest);
891 }
892
893 void
894 UserCommands::Msg(ServerConnection *cnx, Person *from,
895 String channel, String rest)
896 {
897 StringTokenizer st(rest);
898 String who = st.next_token();
899 String message = st.rest();
900
901 Message m = Commands::Msg(cnx->bot, who, message);
902 if (m.getCode() != 0)
903 from->sendNotice(m.getMessage());
904 }
905
906 void
907 UserCommands::Names(ServerConnection *cnx, Person *from,
908 String channel, String rest)
909 {
910 String nick = from->getNick();
911 String result = "";
912 int length = 0;
913 Channel *c = cnx->bot->channelList->getChannel(channel);
914 std::map<String, User *, std::less<String> >::iterator it;
915
916 from->sendNotice(String("\002Names on ") +
917 channel + ":\002");
918
919 for (it = c->channelMemory.begin();
920 it != c->channelMemory.end(); ++it) {
921 result = result +
922 ((*it).second->mode & User::OP_MODE ? "@" :
923 ((*it).second->mode & User::VOICE_MODE ? "+" : "")) +
924 (*it).second->nick + " ";
925 length += (*it).first.length() + 1;
926 if (length >= 256) {
927 from->sendNotice(result);
928 result = ""; length = 0;
929 }
930 }
931
932 if (result != "")
933 from->sendNotice(result);
934
935 from->sendNotice("\002End of names.\002");
936 }
937
938 // FIXME: Convert
939 void
940 UserCommands::NextServer(ServerConnection *cnx, Person *from,
941 String channel, String rest)
942 {
943 if (cnx->bot->serverList->size() == 0) {
944 from->sendNotice("\002Server list is empty !\002");
945 return;
946 }
947
948 if (cnx->bot->serverList->size() == 1) {
949 from->sendNotice("\002Server list has only one item. Use"
950 " \"reconnect\" to force reconnection.\002");
951 return;
952 }
953
954 if (cnx->bot->canChangeServer()) {
955 cnx->queue->sendQuit("Changing server");
956 cnx->bot->nextServer();
957 }
958 else
959 from->sendNotice("\002I can not change server without"
960 " losing op on a channel I am on.\002");
961 }
962
963 // FIXME: Convert
964 void
965 UserCommands::Nick(ServerConnection *cnx, Person *from,
966 String channel, String rest)
967 {
968 // We parse the parameters
969 StringTokenizer st(rest);
970 String nick = st.next_token();
971
972 if (rest == "") {
973 from->sendNotice(String("\002No nickname given.\002"));
974 return;
975 }
976
977 if (!Utils::valid_nickname_p (cnx->bot, nick)) {
978 from->sendNotice(String("\002") + nick +
979 " is not a valid nickname\002");
980 return;
981 }
982
983 cnx->bot->wantedNickName = nick;
984 cnx->queue->sendNick(nick);
985 }
986
987 void
988 UserCommands::NsLookup(ServerConnection *cnx, Person *from,
989 String channel, String rest)
990 {
991 String target;
992
993 if (rest.length() == 0) {
994 from->sendNotice("\002You need to supply a nick or an "
995 "host for this command.\002");
996 return;
997 }
998
999 if (rest.find('.') == -1) {
1000 StringTokenizer st(cnx->bot->getUserhost("", rest));
1001 st.next_token('@');
1002 target = st.rest();
1003 if (target.length() == 0) {
1004 from->sendNotice(String("\002I could not find\002 ") +
1005 target);
1006 return;
1007 }
1008 } else
1009 target = rest;
1010
1011 struct hostent * host;
1012 struct in_addr iaddr;
1013
1014 if (isdigit(target[0])) { // An IP ?
1015 iaddr.s_addr = inet_addr((const char *)target);
1016 host = gethostbyaddr((char *)(&iaddr),
1017 sizeof(struct in_addr),
1018 AF_INET);
1019 if (host) {
1020 from->sendNotice(target +
1021 " \002is the IP address of\002 " +
1022 host->h_name);
1023 return;
1024 }
1025 } else {
1026 host = gethostbyname((const char *)target);
1027 if (host) {
1028 std::memcpy((char *)&iaddr, (char *)host->h_addr,
1029 host->h_length);
1030 from->sendNotice(target + " \002has\002 " +
1031 inet_ntoa(iaddr) + " \002for IP address.\002");
1032 return;
1033 }
1034 }
1035
1036 from->sendNotice(String("\002I could not find host\002 ") +
1037 target);
1038 }
1039
1040 // FIXME: Convert
1041 void
1042 UserCommands::Op(ServerConnection *cnx, Person *from,
1043 String channel, String rest)
1044 {
1045 String nick = from->getNick();
1046
1047 if (!cnx->bot->iAmOp(channel)) {
1048 from->sendNotice(String("\002I am not channel op on\002 ") +
1049 channel);
1050 return;
1051 }
1052
1053 if (Utils::wildcard_p(rest)) {
1054 from->sendNotice("\002Mass op is not allowed.\002");
1055 return;
1056 }
1057
1058 String target;
1059
1060 if (rest.length() == 0)
1061 target = nick;
1062 else
1063 target = rest;
1064
1065 User *u = cnx->bot->channelList->getChannel(channel)->getUser(target);
1066 if (!u) {
1067 from->sendNotice(String("\002I cannot find\002 ") + target + " \002on channel\002 " + channel);
1068 return;
1069 }
1070
1071 ShitEntry *se = cnx->bot->shitList->getShit(target, channel);
1072 if (se && se->isStillValid() && se->getShitLevel() >= ShitEntry::SHIT_NOOP) {
1073 from->sendNotice(String("\002I can not op\002 ")+target+" \002on channel\002 "+channel+" \002(shitlist).\002");
1074 return;
1075 }
1076
1077 if (!(u->mode & User::OP_MODE))
1078 cnx->queue->sendChannelMode(channel, "+o", target);
1079 else {
1080 if (target == nick)
1081 from->sendNotice(String("\002You are already channel "
1082 "operator on\002 ") + channel);
1083 else
1084 from->sendNotice(target + " \002is already channel "
1085 "operator on\002 " + channel);
1086 }
1087 }
1088
1089 // FIXME: Convert
1090 void
1091 UserCommands::Part(ServerConnection *cnx, Person *from,
1092 String channel, String rest)
1093 {
1094 wantedChannel *w = cnx->bot->wantedChannels[channel];
1095 cnx->bot->wantedChannels.erase(channel);
1096 delete w;
1097 cnx->queue->sendPart(channel);
1098 }
1099
1100 void
1101 UserCommands::Password(ServerConnection *cnx, Person *from,
1102 String channel, String rest)
1103 {
1104 Channel *c = cnx->bot->channelList->getChannel(channel);
1105
1106 if (rest.length() == 0) {
1107 from->sendNotice("\002No password.\002");
1108 return;
1109 }
1110
1111 User * u = c->getUser(from->getNick());
1112 if (!u) {
1113 from->sendNotice(String("\002To change your password for\002") +
1114 channel + "\002, you need to be on the "
1115 "channel.\002");
1116 return;
1117 }
1118
1119 if (!u->userListItem) {
1120 from->sendNotice("\002You are not in my userlist.\002");
1121 return;
1122 }
1123
1124 if (rest.toLower() == "none") {
1125 u->userListItem->passwd = "";
1126 from->sendNotice("\002Password cleared.\002");
1127 return;
1128 }
1129
1130 static char saltChars[] = "abcdefghijklmnopqrstuvwxyz"
1131 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
1132 char salt[3];
1133 srand(time(0));
1134 salt[0] = saltChars[rand() % 64];
1135 salt[1] = saltChars[rand() % 64];
1136 salt[2] = '\0';
1137
1138 u->userListItem->passwd = crypt((const char *)rest, salt);
1139 from->sendNotice("\002Password changed.\002");
1140 }
1141
1142 void
1143 UserCommands::Save(ServerConnection *cnx, Person *from,
1144 String channel, String rest)
1145 {
1146 cnx->bot->userList->save();
1147 cnx->bot->shitList->save();
1148 from->sendNotice("\002Userlist and shitlist saved.\002");
1149 }
1150
1151 // FIXME: Convert
1152 void
1153 UserCommands::Say(ServerConnection *cnx, Person *from,
1154 String channel, String rest)
1155 {
1156 if (rest.length() != 0)
1157 cnx->queue->sendPrivmsg(channel, rest);
1158 }
1159
1160 // FIXME: Convert
1161 void
1162 UserCommands::Server(ServerConnection *cnx, Person *from,
1163 String channel, String rest)
1164 {
1165 int serverNumber;
1166 String nick = from->getNick();
1167
1168 if (rest.length() == 0) {
1169 from->sendNotice("\002You need to supply a server number for this command.\002");
1170 return;
1171 }
1172
1173 serverNumber = atoi(rest);
1174
1175 if (serverNumber < 0 || serverNumber >= cnx->bot->serverList->size()) {
1176 from->sendNotice(String((long)serverNumber) +
1177 " \002is an invalid server number (see the serverlist).\002");
1178 return;
1179 }
1180
1181 if (cnx->bot->canChangeServer()) {
1182 cnx->queue->sendQuit("Changing server");
1183 cnx->queue->flush();
1184 cnx->bot->connect(serverNumber);
1185 }
1186 else
1187 from->sendNotice("\002I can not change server without losing op on a channel I am on.\002");
1188 }
1189
1190 void
1191 UserCommands::ServerList(ServerConnection *cnx, Person *from,
1192 String channel, String rest)
1193 {
1194 String nick = from->getNick();
1195
1196 from->sendNotice("\002Server list:\002");
1197 long l = 0;
1198 String s;
1199 for (std::vector<class Server *>::iterator it =
1200 cnx->bot->serverList->v.begin();
1201 it != cnx->bot->serverList->v.end();
1202 ++it) {
1203 s = (*it) == cnx->server ? "\026" : "";
1204 from->sendNotice(s + String(l++) + s + " " +
1205 (*it)->getHostName() +
1206 " (" + String((long)((*it)->getPort())) +
1207 ")");
1208 }
1209 from->sendNotice("\002End of server list.\002");
1210 }
1211
1212
1213 void
1214 UserCommands::SetFloodRate(ServerConnection *cnx, Person *from,
1215 String channel, String rest)
1216 {
1217 Message m = Commands::SetFloodRate (cnx->bot, std::atoi (rest));
1218 if (m.getCode ())
1219 from->sendNotice (m.getMessage ());
1220 else
1221 from->sendNotice ("Flood Rate set to:" + String(std::atol(rest)));
1222 }
1223
1224 void
1225 UserCommands::SetVersion(ServerConnection *cnx, Person *from,
1226 String channel, String rest)
1227 {
1228 Message m = Commands::SetVersion(cnx->bot, rest);
1229
1230 if (m.getCode() < 0)
1231 {
1232 Commands::Notice (cnx->bot, from->getNick (), m.getMessage());
1233 }
1234 }
1235
1236 void
1237 UserCommands::ShitList(ServerConnection *cnx, Person *from,
1238 String channel, String rest)
1239 {
1240 from->sendNotice("\002Shitlist:\002");
1241 from->sendNotice("\002Mask Channel Level Expires Reason\002");
1242
1243 for (std::list<ShitEntry *>::iterator it = cnx->bot->shitList->l.begin();
1244 it != cnx->bot->shitList->l.end();
1245 it++)
1246 from->sendNotice((*it)->shitMask.getMask().pad(25) + " " +
1247 (*it)->shitChannelMask.getMask().pad(10) + " " +
1248 String((long)(*it)->shitLevel).pad(9) + " " +
1249 String((long)(*it)->expirationDate).pad(9) + " " +
1250 (*it)->shitReason);
1251
1252 from->sendNotice("\002End of shitlist.\002");
1253 }
1254
1255 void
1256 UserCommands::SpyList(ServerConnection *cnx, Person *from,
1257 String channel, String rest)
1258 {
1259 String nick = from->getNick();
1260
1261 from->sendNotice("\002Spy list:\002");
1262
1263 for (std::map<String, Person *, std::less<String> >::iterator it =
1264 cnx->bot->spyList.begin(); it != cnx->bot->spyList.end(); ++it)
1265 from->sendNotice((*it).first);
1266
1267 from->sendNotice("\002End of spy list.\002");
1268 }
1269
1270 void
1271 UserCommands::SpyMessage(ServerConnection *cnx, Person *from,
1272 String channel, String rest)
1273 {
1274 String nick = from->getNick();
1275
1276 if (cnx->bot->spyList.find(nick) != cnx->bot->spyList.end()) {
1277 from->sendNotice("\002You are already spying messages.\002");
1278 return;
1279 }
1280
1281 Person *f = from->copy();
1282 f->keepAlive();
1283 cnx->bot->spyList[nick.toLower()] = f;
1284 from->sendNotice("\002You have been added to the spy list.\002");
1285 }
1286
1287 // FIXME: Convert
1288 void
1289 UserCommands::Reconnect(ServerConnection *cnx, Person *from,
1290 String channel, String rest)
1291 {
1292 String nick = from->getNick();
1293
1294 if (cnx->bot->canChangeServer()) {
1295 cnx->queue->sendQuit("Reconnecting");
1296 cnx->bot->reconnect();
1297 }
1298 else
1299 from->sendNotice("\002I can not change server without losing op on a channel I am on.\002");
1300 }
1301
1302 void
1303 UserCommands::RSpyMessage(ServerConnection *cnx, Person *from,
1304 String channel, String rest)
1305 {
1306 String nick = from->getNick().toLower();
1307
1308 if (cnx->bot->spyList.find(nick) == cnx->bot->spyList.end()) {
1309 from->sendNotice("\002You are not in the spy list.\002");
1310 return;
1311 }
1312
1313 delete cnx->bot->spyList[nick];
1314 cnx->bot->spyList.erase(nick);
1315 from->sendNotice("\002You have been removed from the "
1316 "spy list.\002");
1317 }
1318
1319 // FIXME: Convert
1320 void
1321 UserCommands::Unlock(ServerConnection *cnx, Person *from,
1322 String channel, String rest)
1323 {
1324 cnx->bot->channelList->getChannel(channel)->lockedTopic = false;
1325 from->sendNotice(String("\002Unlocking topic for channel\002 ") +
1326 channel);
1327 }
1328
1329 void
1330 UserCommands::Stats(ServerConnection *cnx, Person *from,
1331 String channel, String rest)
1332 {
1333 String nick = from->getNick();
1334
1335 from->sendNotice(String("\002Keeping modes\002 ") +
1336 cnx->bot->channelList->getChannel(channel)->keepModes + " \002on channel\002 " +
1337 channel);
1338 }
1339
1340 void
1341 UserCommands::TBan(ServerConnection *cnx, Person *from,
1342 String channel, String rest)
1343 {
1344 Channel * c = cnx->bot->channelList->getChannel(channel);
1345 StringTokenizer st(rest);
1346 String who = st.next_token();
1347 String t = st.next_token();
1348
1349 if (who == "" || t == "") {
1350 if (from)
1351 from->sendNotice("\002Invalid syntax for this command.\002");
1352 return;
1353 }
1354
1355 if (Utils::wildcard_p(who) && from) {
1356 User * u = c->getUser(from->getNick());
1357 if (u && u->getLevel() < User::TRUSTED_USER) {
1358 if (from)
1359 from->sendNotice("\002You need an higher level to use"
1360 " wildcards.\002");
1361 return;
1362 }
1363 }
1364
1365 Message ret = Commands::TBan (cnx->bot, channel, who, Utils::str2time (t));
1366 if (ret.getCode () && from)
1367 from->sendNotice ("\002" + ret.getMessage () + "\002");
1368 }
1369
1370 // FIXME: Convert
1371 void
1372 UserCommands::TKBan(ServerConnection *cnx, Person *from,
1373 String channel, String rest)
1374 {
1375 StringTokenizer st(rest);
1376 String who = st.next_token();
1377 String t = st.next_token();
1378
1379 TBan(cnx, 0, channel, who + " " + t);
1380 Kick(cnx, from, channel, who + " " + st.rest());
1381 }
1382
1383 // FIXME: Convert
1384 void
1385 UserCommands::Topic(ServerConnection *cnx, Person *from,
1386 String channel, String rest)
1387 {
1388 String nick = from->getNick();
1389
1390 if (rest.length() == 0) {
1391 if (cnx->bot->channelList->getChannel(channel)->channelTopic == "")
1392 from->sendNotice(String("\002No topic is set for channel\002 ") +
1393 channel + "\002.\002");
1394 else
1395 from->sendNotice(String("\002Topic for\002 ") +
1396 channel + " \002is:\002 " +
1397 cnx->bot->channelList->getChannel(channel)->channelTopic);
1398 } else {
1399 if (cnx->bot->channelList->getChannel(channel)->lockedTopic)
1400 from->sendNotice(String("\002Topic is locked on channel\002 ") +
1401 channel);
1402 else
1403 cnx->queue->sendTopic(channel, rest);
1404 }
1405 }
1406
1407 void
1408 UserCommands::UserList(ServerConnection *cnx, Person *from,
1409 String channel, String rest)
1410 {
1411 from->sendNotice("\002Userlist:\002");
1412 from->sendNotice("\002Mask Channel Level Prot Aop Expires\002");
1413
1414 for (std::list<UserListItem *>::iterator it = cnx->bot->userList->l.begin();
1415 it != cnx->bot->userList->l.end();
1416 it++)
1417 from->sendNotice((*it)->mask.getMask().pad(25)
1418 + " "
1419 + (*it)->channelMask.getMask().pad(10)
1420 + " " +
1421 String(Utils::level2str((*it)->level)).pad(12)
1422 + " " +
1423 String(Utils::prot2str((*it)->prot)).pad(7)
1424 + " " +
1425 String(Utils::bool2str((*it)->aop)).pad(5)
1426 + " " +
1427 String(Utils::long2str ((*it)->expirationDate)));
1428
1429 from->sendNotice("\002End of userlist.\002");
1430 }
1431
1432 void
1433 UserCommands::Who(ServerConnection *cnx, Person *from,
1434 String channel, String rest)
1435 {
1436 String nick = from->getNick();
1437 User * u = cnx->bot->channelList->getChannel(channel)->getUser(nick);
1438 UserListItem * uli;
1439
1440 if (u)
1441 uli = u->userListItem;
1442 else
1443 uli = cnx->bot->userList->getUserListItem(from->getAddress(),
1444 channel);
1445
1446 if (uli) {
1447 from->sendNotice(String("\002You are\002 ") +
1448 uli->mask.getMask() + " \002on\002 " +
1449 uli->channelMask.getMask());
1450 from->sendNotice(String("\002Lvl:\002 ") +
1451 Utils::level2str(uli->level) +
1452 " \002Prot:\002 " +
1453 Utils::prot2str(uli->prot) +
1454 " \002Aop:\002 " +
1455 Utils::bool2str(uli->aop) +
1456 " \002Expired:\002 " +
1457 Utils::bool2str(!uli->isStillValid()) +
1458 " \002Ident:\002 " +
1459 (uli && !uli->identified ? "\026" : "") +
1460 Utils::bool2str(uli && uli->identified) +
1461 (uli && !uli->identified ? "\026" : ""));
1462 } else
1463 from->sendNotice(String("\002You are not in the userlist for\002 ") +
1464 channel);
1465 }
1466
1467 void
1468 UserCommands::Whois(ServerConnection *cnx, Person *from,
1469 String channel, String rest)
1470 {
1471 String nick = from->getNick();
1472
1473 if (!rest.length()) {
1474 from->sendNotice("\002No nick specified.\002");
1475 return;
1476 }
1477
1478 StringTokenizer st(rest);
1479 String otherNick = st.next_token();
1480
1481 User * u = cnx->bot->channelList->getChannel(channel)->getUser(otherNick);
1482 UserListItem * uli;
1483
1484 if (u)
1485 uli = u->userListItem;
1486 else
1487 uli = cnx->bot->userList->getUserListItem(otherNick + "!" +
1488 cnx->bot->getUserhost(channel,
1489 otherNick),
1490 channel);
1491
1492 if (uli) {
1493 from->sendNotice(otherNick +
1494 " \002is\002 " + uli->mask.getMask() +
1495 " \002on\002 " + uli->channelMask.getMask());
1496 from->sendNotice(String("\002Lvl:\002 ") +
1497 Utils::level2str(uli->level) +
1498 " \002Prot:\002 " +
1499 Utils::prot2str(uli->prot) +
1500 " \002Aop:\002 " +
1501 Utils::bool2str(uli->aop) +
1502 " \002Expired:\002 " +
1503 Utils::bool2str(!uli->isStillValid()) +
1504 " \002Ident:\002 " +
1505 Utils::bool2str(uli && uli->identified));
1506 } else
1507 from->sendNotice(otherNick +
1508 " \002is not in the userlist for\002 " +
1509 channel);
1510 }