Implement `bot:channel-users' Scheme function
[clinton/bobotpp.git] / source / ScriptCommands.C
1 // ScriptCommands.C -*- C++ -*-
2 // Copyright (c) 1998 Etienne BERNARD
3 // Copyright (C) 2002,2005,2008,2009 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 #ifdef USESCRIPTS
25
26 #include "ScriptCommands.H"
27
28 #include <libguile.h>
29
30 #include "Bot.H"
31 #include "BotInterp.H"
32 #include "ChannelList.H"
33 #include "Commands.H"
34 #include "DCCManager.H"
35 #include "DCCPerson.H"
36 #include "Interp.H"
37 #include "Message.H"
38 #include "Parser.H"
39 #include "Server.H"
40 #include "ServerConnection.H"
41 #include "ServerList.H"
42 #include "ServerQueue.H"
43 #include "User.H"
44 #include "Utils.H"
45
46 #define VERIFY_STRING(par) if (!scm_is_string((par))) \
47 return scm_from_int(-17)
48
49 #define VERIFY_NUMBER(par) if (!SCM_NUMBERP((par))) \
50 return scm_from_int(-17)
51
52 SCM
53 ScriptCommands::Action(SCM channel, SCM message)
54 {
55 VERIFY_STRING(channel);
56 VERIFY_STRING(message);
57 Message m = Commands::Action(Interp::bot, Utils::scm2str(channel),
58 Utils::scm2str(message));
59 return scm_from_int(m.getCode());
60 }
61
62 SCM
63 ScriptCommands::AddUser(SCM who, SCM maskChannel, SCM level,
64 SCM prot, SCM aop, SCM expire, SCM password)
65 {
66 // It segfaults when not online, but otherwise appears to work
67 VERIFY_STRING (who);
68 VERIFY_STRING (maskChannel);
69 VERIFY_NUMBER (level);
70
71 String wwho = Utils::scm2str (who);
72 String mask = Utils::scm2str (maskChannel);
73 String passwd;
74 std::time_t eexpire;
75
76 if (SCM_UNBNDP (password))
77 passwd = "";
78 else
79 {
80 VERIFY_STRING (password);
81 passwd = Utils::scm2str (password);
82 }
83 if (SCM_UNBNDP (expire))
84 eexpire = -1;
85 else
86 {
87 VERIFY_STRING (expire);
88 eexpire = Utils::str2time (Utils::scm2str (expire));
89 if (!eexpire) eexpire = -1;
90 }
91
92 int protect = scm_to_int (prot);
93 bool aaop = scm_is_true (aop);
94 int llevel = scm_to_int (level);
95
96 Message m = Commands::AddUser (Interp::bot, wwho, mask, llevel,
97 protect, aaop, eexpire, passwd);
98
99 return scm_from_int(m.getCode ());
100 }
101
102 SCM
103 ScriptCommands::AddServer(SCM servername, SCM port)
104 {
105 int p = 6667;
106 if (SCM_NUMBERP(port))
107 p = scm_to_int (port);
108 Message m = Commands::AddServer(Interp::bot,
109 Utils::scm2str(servername),
110 p);
111 return scm_from_int(m.getCode());
112 }
113
114 SCM
115 ScriptCommands::AddShit(SCM mask, SCM maskChannel, SCM level,
116 SCM expiration, SCM reason)
117 {
118 // This appears to work...not much testing though
119 VERIFY_STRING (mask);
120 VERIFY_STRING (maskChannel);
121 VERIFY_NUMBER (level);
122 String mmask = Utils::scm2str (mask);
123 String mmaskChannel = Utils::scm2str (maskChannel);
124 int llevel = scm_to_int (level);
125 std::time_t expire;
126 String rreason;
127
128 if (SCM_UNBNDP (expiration))
129 expire = -1;
130 else
131 {
132 VERIFY_STRING (expiration);
133 expire = Utils::str2time (Utils::scm2str (expiration));
134 if (!expire) expire = -1;
135 }
136 if (SCM_UNBNDP (reason))
137 rreason = "You're on my shitlist, lamer";
138 else
139 {
140 VERIFY_STRING (reason);
141 rreason = Utils::scm2str (reason);
142 }
143 Message m = Commands::AddShit (Interp::bot, mmask, mmaskChannel,
144 llevel, expire, rreason);
145
146 return scm_from_int(m.getCode ());
147 }
148
149 SCM
150 ScriptCommands::Ban(SCM channel, SCM who)
151 {
152 VERIFY_STRING(channel);
153 VERIFY_STRING(who);
154 Message m = Commands::Ban(Interp::bot, Utils::scm2str(channel),
155 Utils::scm2str(who));
156 return scm_from_int(m.getCode());
157 }
158
159 SCM
160 ScriptCommands::ChangeCommandLevel(SCM command, SCM level)
161 {
162 VERIFY_STRING (command);
163 VERIFY_NUMBER (level);
164
165 std::string ccommand = scm_to_locale_string (command);
166 unsigned int llevel = scm_to_uint (level);
167
168 if (llevel > 4)
169 return SCM_BOOL_F;
170
171 std::map<std::string, class userFunction*,
172 std::less<std::string> >::const_iterator uf_iter
173 = Interp::bot->userFunctions.find (ccommand);
174 userFunction * f = 0;
175
176 if (uf_iter != Interp::bot->userFunctions.end ())
177 f = uf_iter->second;
178 else
179 return SCM_BOOL_F;
180
181 f->minLevel = llevel;
182 return SCM_BOOL_T;
183 }
184
185
186 void
187 ScriptCommands::collect_channel_users::operator() (SCM *list, User user)
188 const
189 {
190 *list = scm_cons (scm_list_n (Utils::str2scm (user.get_nick()),
191 Utils::str2scm (user.get_userhost ()),
192 scm_from_int (user.get_mode ()),
193 SCM_UNDEFINED),
194 *list);
195 }
196
197 SCM
198 ScriptCommands::ChannelUsers (SCM channel_name)
199 {
200 VERIFY_STRING (channel_name);
201
202 Channel *channel = Interp::bot->channelList->getChannel (Utils::scm2str (channel_name));
203
204 if (!channel)
205 return SCM_BOOL_F;
206
207 SCM* list = (SCM*)scm_gc_malloc (sizeof (SCM), "ScriptCommands::ChannelUsers");
208 *list = SCM_EOL;
209
210 collect_channel_users c;
211
212 channel->for_each_channel_users (std::bind1st (c, list));
213
214 scm_remember_upto_here_1 (list);
215 return scm_reverse_x (*list, SCM_UNDEFINED);
216 }
217
218 SCM
219 ScriptCommands::CTCP(SCM to, SCM command , SCM message)
220 {
221 VERIFY_STRING(to);
222 VERIFY_STRING(command);
223 VERIFY_STRING(message);
224
225 Commands::CTCP (Interp::bot, Utils::scm2str (to),
226 Utils::scm2str (command),
227 Utils::scm2str (message));
228
229 return SCM_UNSPECIFIED;
230 }
231
232 SCM
233 ScriptCommands::CTCPReply (SCM to, SCM command , SCM message)
234 {
235 VERIFY_STRING(to);
236 VERIFY_STRING(command);
237 VERIFY_STRING(message);
238
239 Commands::CTCPReply (Interp::bot, Utils::scm2str (to),
240 Utils::scm2str (command),
241 Utils::scm2str (message));
242
243 return SCM_UNSPECIFIED;
244 }
245
246 SCM
247 ScriptCommands::Cycle(SCM channel)
248 {
249 VERIFY_STRING(channel);
250 Message m = Commands::Cycle(Interp::bot, Utils::scm2str(channel));
251 return scm_from_int(m.getCode());
252 }
253
254 SCM
255 ScriptCommands::Deban(SCM channel, SCM who)
256 {
257 VERIFY_STRING(channel);
258 VERIFY_STRING(who);
259 Message m = Commands::Deban(Interp::bot, Utils::scm2str(channel),
260 Utils::scm2str(who));
261 return scm_from_int(m.getCode());
262 }
263
264 SCM
265 ScriptCommands::DelServer(SCM number)
266 {
267 VERIFY_NUMBER(number);
268 Message m = Commands::DelServer(Interp::bot, scm_to_int (number));
269 return scm_from_int(m.getCode());
270 }
271
272 SCM
273 ScriptCommands::DelUser(SCM who, SCM maskChannel)
274 {
275 VERIFY_STRING(who);
276 VERIFY_STRING(maskChannel);
277 Message m = Commands::DelUser(Interp::bot, Utils::scm2str(who),
278 Utils::scm2str(maskChannel));
279 return scm_from_int(m.getCode());
280 }
281
282 SCM
283 ScriptCommands::DelShit(SCM who, SCM maskChannel)
284 {
285 VERIFY_STRING(who);
286 VERIFY_STRING(maskChannel);
287 Message m = Commands::DelShit(Interp::bot, Utils::scm2str(who),
288 Utils::scm2str(maskChannel));
289 return scm_from_int(m.getCode());
290 }
291
292 SCM
293 ScriptCommands::Deop(SCM channel, SCM who)
294 {
295 VERIFY_STRING(channel);
296 VERIFY_STRING(who);
297 Message m = Commands::Deop(Interp::bot, Utils::scm2str(channel),
298 Utils::scm2str(who));
299 return scm_from_int(m.getCode());
300 }
301
302 SCM
303 ScriptCommands::Die(SCM reason)
304 {
305 String r = "Leaving";
306 if (scm_is_string(reason))
307 r = Utils::scm2str(reason);
308 Message m = Commands::Die(Interp::bot, r);
309 return scm_from_int(m.getCode());
310 }
311
312 SCM
313 ScriptCommands::Do(SCM command)
314 {
315 VERIFY_STRING(command);
316 Message m = Commands::Do(Interp::bot, Utils::scm2str(command));
317 return scm_from_int(m.getCode());
318 }
319
320 SCM
321 ScriptCommands::Invite(SCM channel, SCM who)
322 {
323 VERIFY_STRING(channel);
324 VERIFY_STRING(who);
325 Message m = Commands::Invite(Interp::bot, Utils::scm2str(channel),
326 Utils::scm2str(who));
327 return scm_from_int(m.getCode());
328 }
329
330 SCM
331 ScriptCommands::Join(SCM channel, SCM key)
332 {
333 VERIFY_STRING(channel);
334 String k = "";
335 if (scm_is_string(key))
336 k = Utils::scm2str(key);
337 Message m = Commands::Join(Interp::bot, Utils::scm2str(channel),
338 k);
339 return scm_from_int(m.getCode());
340 }
341
342 SCM
343 ScriptCommands::Keep(SCM channel, SCM modes)
344 {
345 VERIFY_STRING(channel);
346 VERIFY_STRING(modes);
347 Message m = Commands::Keep(Interp::bot, Utils::scm2str(channel),
348 Utils::scm2str(modes));
349 return scm_from_int(m.getCode());
350 }
351
352 SCM
353 ScriptCommands::Kick(SCM channel, SCM who, SCM reason)
354 {
355 VERIFY_STRING(channel);
356 VERIFY_STRING(who);
357
358 String r = "";
359 if (scm_is_string(reason))
360 r = Utils::scm2str(reason);
361
362 Message m = Commands::Kick(Interp::bot, Utils::scm2str(channel),
363 Utils::scm2str(who), r);
364 return scm_from_int(m.getCode());
365 }
366
367 SCM
368 ScriptCommands::KickBan(SCM channel, SCM who, SCM reason)
369 {
370 VERIFY_STRING(channel);
371 VERIFY_STRING(who);
372 String r = "";
373 if (scm_is_string(reason))
374 r = Utils::scm2str(reason);
375 Message m = Commands::KickBan(Interp::bot, Utils::scm2str(channel),
376 Utils::scm2str(who), r);
377 return scm_from_int(m.getCode());
378 }
379
380 SCM
381 ScriptCommands::Lock(SCM channel)
382 {
383 VERIFY_STRING(channel);
384 Message m = Commands::Lock(Interp::bot, Utils::scm2str(channel));
385 return scm_from_int(m.getCode());
386 }
387
388 SCM
389 ScriptCommands::LogPort(void)
390 {
391 return Interp::bot->botInterp->logPort;
392 }
393
394 SCM
395 ScriptCommands::Mode(SCM channel, SCM mode)
396 {
397 VERIFY_STRING(channel);
398 VERIFY_STRING(mode);
399 Message m = Commands::Mode(Interp::bot, Utils::scm2str(channel),
400 Utils::scm2str(mode));
401 return scm_from_int(m.getCode());
402 }
403
404 SCM
405 ScriptCommands::Msg(SCM nick, SCM message)
406 {
407 VERIFY_STRING(nick);
408 VERIFY_STRING(message);
409 Message m = Commands::Msg(Interp::bot, Utils::scm2str(nick),
410 Utils::scm2str(message));
411 return scm_from_int(m.getCode());
412
413 }
414
415 SCM
416 ScriptCommands::NextServer(void)
417 {
418 Message m = Commands::NextServer(Interp::bot);
419 return scm_from_int(m.getCode());
420 }
421
422 SCM
423 ScriptCommands::Nick(SCM nick)
424 {
425 VERIFY_STRING(nick);
426 Message m = Commands::Nick(Interp::bot, Utils::scm2str(nick));
427 return scm_from_int(m.getCode());
428 }
429
430 SCM
431 ScriptCommands::Notice (SCM to, SCM message)
432 {
433 VERIFY_STRING (to);
434 VERIFY_STRING (message);
435
436 return (scm_from_int
437 (Commands::Notice (Interp::bot,
438 Utils::scm2str (to),
439 Utils::scm2str (message)).getCode ()));
440
441 }
442
443 SCM
444 ScriptCommands::Op(SCM channel, SCM who)
445 {
446 VERIFY_STRING(channel);
447 VERIFY_STRING(who);
448 Message m = Commands::Op(Interp::bot, Utils::scm2str(channel),
449 Utils::scm2str(who));
450 return scm_from_int(m.getCode());
451 }
452
453 SCM
454 ScriptCommands::Part(SCM channel)
455 {
456 VERIFY_STRING(channel);
457 Message m = Commands::Part(Interp::bot, Utils::scm2str(channel));
458 return scm_from_int(m.getCode());
459 }
460
461 SCM
462 ScriptCommands::Reconnect(void)
463 {
464 Message m = Commands::Reconnect(Interp::bot);
465 return scm_from_int(m.getCode());
466 }
467
468 SCM
469 ScriptCommands::Say(SCM channel, SCM message)
470 {
471 VERIFY_STRING(channel);
472 VERIFY_STRING(message);
473 Message m = Commands::Say(Interp::bot, Utils::scm2str(channel),
474 Utils::scm2str(message));
475 return scm_from_int(m.getCode());
476 }
477
478 SCM
479 ScriptCommands::Server(SCM number)
480 {
481 VERIFY_NUMBER(number);
482 Message m = Commands::Server(Interp::bot, scm_to_int(number));
483 return scm_from_int(m.getCode());
484 }
485
486 SCM
487 ScriptCommands::SetFloodRate(SCM rate)
488 {
489 VERIFY_NUMBER(rate);
490 Message m = Commands::SetFloodRate(Interp::bot, scm_to_uint (rate));
491 return scm_from_int(m.getCode());
492 }
493
494 SCM
495 ScriptCommands::SetVersion(SCM version)
496 {
497 Message m = Commands::SetVersion(Interp::bot, Utils::scm2str(version));
498 return scm_from_int(m.getCode());
499 }
500
501 SCM
502 ScriptCommands::TBan(SCM channel, SCM who, SCM seconds)
503 {
504 VERIFY_STRING(channel);
505 VERIFY_STRING(who);
506 VERIFY_NUMBER(seconds);
507 Message m = Commands::TBan(Interp::bot, Utils::scm2str(channel),
508 Utils::scm2str(who), scm_to_int(seconds));
509 return scm_from_int(m.getCode());
510 }
511
512 SCM
513 ScriptCommands::TKBan(SCM channel, SCM who, SCM seconds, SCM reason)
514 {
515 VERIFY_STRING(channel);
516 VERIFY_STRING(who);
517 VERIFY_NUMBER(seconds);
518 String r = "";
519 if (scm_is_string(reason))
520 r = Utils::scm2str(reason);
521 Message m = Commands::TKBan(Interp::bot, Utils::scm2str(channel),
522 Utils::scm2str(who),
523 scm_to_int(seconds), r);
524 return scm_from_int(m.getCode());
525 }
526
527 SCM
528 ScriptCommands::Topic(SCM channel, SCM topic)
529 {
530 VERIFY_STRING(channel);
531 VERIFY_STRING(topic);
532 Message m = Commands::Topic(Interp::bot, Utils::scm2str(channel),
533 Utils::scm2str(topic));
534 return scm_from_int(m.getCode());
535 }
536
537 SCM
538 ScriptCommands::Unlock(SCM channel)
539 {
540 VERIFY_STRING(channel);
541 Message m = Commands::Unlock(Interp::bot, Utils::scm2str(channel));
542 return scm_from_int(m.getCode());
543 }
544
545 SCM
546 ScriptCommands::Who (SCM target)
547 {
548 VERIFY_STRING (target);
549
550 Message m = Commands::Who (Interp::bot, Utils::scm2str (target));
551
552 return scm_from_int (m.getCode ());
553 }
554
555 SCM
556 ScriptCommands::Whois (SCM nick)
557 {
558 VERIFY_STRING (nick);
559
560 Message m = Commands::Whois (Interp::bot, Utils::scm2str (nick));
561
562 return scm_from_int (m.getCode ());
563 }
564
565 SCM
566 ScriptCommands::getNickname(void)
567 {
568 return Utils::str2scm(Interp::bot->nickName);
569 }
570
571 SCM
572 ScriptCommands::getServer(void)
573 {
574 ::Server *serv = Interp::bot->serverList->currentServer();
575 int serverNumber = Interp::bot->serverList->currentNumber;
576
577 return scm_list_n(scm_from_int(serverNumber),
578 Utils::str2scm(serv->getHostName()),
579 scm_from_int(serv->getPort()),
580 Utils::str2scm(serv->getPassword()),
581 SCM_UNDEFINED);
582 }
583
584 SCM
585 ScriptCommands::getServerList(void)
586 {
587 SCM res = scm_list_n(SCM_UNDEFINED);
588 ::Server *s;
589 int i = 0;
590 std::vector<class Server *>::iterator it =
591 Interp::bot->serverList->begin();
592
593 for ( ; it != Interp::bot->serverList->end(); ++it) {
594 s = (*it);
595 res =
596 scm_append
597 (scm_list_2 (res,
598 scm_list_n(scm_list_n(scm_from_int(i++),
599 Utils::str2scm(s->getHostName()),
600 scm_from_int(s->getPort()),
601 Utils::str2scm(s->getPassword()),
602 SCM_UNDEFINED), SCM_UNDEFINED)));
603 }
604 return res;
605 }
606
607 SCM
608 ScriptCommands::flushQueue(void)
609 {
610 if (!Interp::bot->serverConnection)
611 return SCM_BOOL_F;
612 Interp::bot->serverConnection->queue->flush();
613 return SCM_BOOL_T;
614 }
615
616 SCM
617 ScriptCommands::flushPort(void)
618 {
619 scm_flush(Interp::bot->botInterp->logPort);
620 return SCM_BOOL_T;
621 }
622
623 SCM
624 ScriptCommands::random(SCM scm_max)
625 {
626 int max = 0;
627 //srand(time(NULL));
628 if (SCM_NUMBERP(scm_max))
629 max = scm_to_int(scm_max);
630 return scm_from_int(max ? rand() % max : 0);
631 }
632
633 SCM
634 ScriptCommands::addCommand(SCM scm_commandName, SCM scm_function,
635 SCM scm_needsChannel, SCM scm_args,
636 SCM scm_minLevel)
637 {
638 // We check that commandName is a string
639 if (!scm_is_string(scm_commandName))
640 return SCM_BOOL_F;
641
642 // We check that the command does not exist
643 String commandName = Utils::to_upper (Utils::scm2str(scm_commandName));
644 if (Interp::bot->userFunctions[commandName])
645 return SCM_BOOL_F;
646
647 // Next we check that needsChannel is a boolean
648 if (!scm_is_bool (scm_needsChannel))
649 return SCM_BOOL_F;
650 bool needsChannel = scm_to_bool(scm_needsChannel);
651
652 // We check that minLevel is an integer and that it's
653 // a valid level
654 if (!SCM_NUMBERP(scm_minLevel))
655 return SCM_BOOL_F;
656
657 int minLevel = scm_to_int(scm_minLevel);
658 if (minLevel < User::NONE || minLevel > User::MASTER)
659 return SCM_BOOL_F;
660
661 // We check that "scm_function" is a Scheme procedure
662 if (!scm_is_true (scm_procedure_p(scm_function)))
663 return SCM_BOOL_F;
664
665 // We check that args is an integer and is between 0 and 20 (arbitrary limit)
666 if (!SCM_NUMBERP(scm_args))
667 return SCM_BOOL_F;
668
669 int args = scm_to_int(scm_args);
670 if (args < 0 || args > 20)
671 return SCM_BOOL_F;
672
673 // We add the command in the commands list
674 Interp::bot->userFunctions[commandName] =
675 new userFunction(0, minLevel, needsChannel, args, scm_function);
676
677 return SCM_BOOL_T;
678 }
679
680 SCM
681 ScriptCommands::delCommand(SCM scm_commandName)
682 {
683 // We check that commandName is a string
684 if (!scm_is_string(scm_commandName))
685 return SCM_BOOL_F;
686
687 // We check that the command does exist
688 String commandName = Utils::to_upper (Utils::scm2str(scm_commandName));
689 if (!Interp::bot->userFunctions[commandName])
690 return SCM_BOOL_F;
691
692 // We delete the command
693 Interp::bot->userFunctions.erase(commandName);
694
695 return SCM_BOOL_T;
696 }
697
698 SCM
699 ScriptCommands::AddHook(SCM type, SCM regex, SCM function, SCM pri, SCM fall,
700 SCM name)
701 {
702 int priority = 0;
703 bool fallt = true; // does this hook fall through?
704 String rname = "DEFAULT";
705
706 if (!SCM_UNBNDP (pri))
707 priority = scm_to_int (pri);
708 if (!SCM_UNBNDP (fall))
709 fallt = scm_is_true (fall);
710 if (!SCM_UNBNDP (name))
711 rname = Utils::scm2str (name);
712 return scm_from_bool (Interp::bot->botInterp->AddHook(scm_to_int(type),
713 regex, function,
714 priority, fallt, rname));
715 }
716
717 SCM
718 ScriptCommands::AddTimer(SCM when, SCM function)
719 {
720 return Interp::bot->botInterp->AddTimer(scm_to_int(when), function);
721 }
722
723 SCM
724 ScriptCommands::DelTimer(SCM timer)
725 {
726 return scm_from_bool (Interp::bot->botInterp->DelTimer(timer));
727 }
728
729 SCM
730 ScriptCommands::sendDCCChatMessage (SCM to, SCM message)
731 {
732
733 return scm_from_bool (Interp::bot->dccConnections->sendMessage
734 (Utils::scm2str (to),
735 Utils::scm2str (message)));
736 }
737
738
739
740
741
742
743 #endif