1 /*
2 * tclirc.c -- part of irc.mod
3 */
4 /*
5 * Copyright (C) 1997 Robey Pointer
6 * Copyright (C) 1999 - 2021 Eggheads Development Team
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 */
22
23 /* Streamlined by answer.
24 */
25 static int tcl_chanlist STDVAR
26 {
27 char nuh[1024];
28 int f;
29 memberlist *m;
30 struct chanset_t *chan;
31 struct flag_record plus = { FR_CHAN | FR_GLOBAL | FR_BOT, 0, 0, 0, 0, 0 },
32 minus = { FR_CHAN | FR_GLOBAL | FR_BOT, 0, 0, 0, 0, 0},
33 user = { FR_CHAN | FR_GLOBAL | FR_BOT, 0, 0, 0, 0, 0 };
34
35 BADARGS(2, 3, " channel ?flags?");
36
37 chan = findchan_by_dname(argv[1]);
38 if (!chan) {
39 Tcl_AppendResult(irp, "invalid channel: ", argv[1], NULL);
40 return TCL_ERROR;
41 }
42 if (argc == 2) {
43 /* No flag restrictions so just whiz it thru quick */
44 for (m = chan->channel.member; m && m->nick[0]; m = m->next)
45 Tcl_AppendElement(irp, m->nick);
46 return TCL_OK;
47 }
48 break_down_flags(argv[2], &plus, &minus);
49 f = (minus.global || minus.udef_global || minus.chan || minus.udef_chan ||
50 minus.bot);
51 /* Return empty set if asked for flags but flags don't exist */
52 if (!plus.global && !plus.udef_global && !plus.chan && !plus.udef_chan &&
53 !plus.bot && !f)
54 return TCL_OK;
55 minus.match = plus.match ^ (FR_AND | FR_OR);
56
57 for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
58 if (!m->user) {
59 egg_snprintf(nuh, sizeof nuh, "%s!%s", m->nick, m->userhost);
60 m->user = get_user_by_host(nuh);
61 }
62 get_user_flagrec(m->user, &user, argv[1]);
63 user.match = plus.match;
64 if (flagrec_eq(&plus, &user)) {
65 if (!f || !flagrec_eq(&minus, &user))
66 Tcl_AppendElement(irp, m->nick);
67 }
68 }
69 return TCL_OK;
70 }
71
72 static int tcl_botisop STDVAR
73 {
74 struct chanset_t *chan, *thechan = NULL;
75
76 BADARGS(1, 2, " ?channel?");
77
78 if (argc > 1) {
79 chan = findchan_by_dname(argv[1]);
80 thechan = chan;
81 if (!thechan) {
82 Tcl_AppendResult(irp, "illegal channel: ", argv[1], NULL);
83 return TCL_ERROR;
84 }
85 } else
86 chan = chanset;
87
88 while (chan && (thechan == NULL || thechan == chan)) {
89 if (me_op(chan)) {
90 Tcl_AppendResult(irp, "1", NULL);
91 return TCL_OK;
92 }
93 chan = chan->next;
94 }
95 Tcl_AppendResult(irp, "0", NULL);
96 return TCL_OK;
97 }
98
99 static int tcl_botishalfop STDVAR
100 {
101 struct chanset_t *chan, *thechan = NULL;
102
103 BADARGS(1, 2, " ?channel?");
104
105 if (argc > 1) {
106 chan = findchan_by_dname(argv[1]);
107 thechan = chan;
108 if (!thechan) {
109 Tcl_AppendResult(irp, "illegal channel: ", argv[1], NULL);
110 return TCL_ERROR;
111 }
112 } else
113 chan = chanset;
114
115 while (chan && (thechan == NULL || thechan == chan)) {
116 if (me_halfop(chan)) {
117 Tcl_AppendResult(irp, "1", NULL);
118 return TCL_OK;
119 }
120 chan = chan->next;
121 }
122 Tcl_AppendResult(irp, "0", NULL);
123 return TCL_OK;
124 }
125
126 static int tcl_ischanjuped STDVAR
127 {
128 struct chanset_t *chan;
129
130 BADARGS(2, 2, " channel");
131
132 chan = findchan_by_dname(argv[1]);
133 if (chan == NULL) {
134 Tcl_AppendResult(irp, "illegal channel: ", argv[1], NULL);
135 return TCL_ERROR;
136 }
137 if (channel_juped(chan))
138 Tcl_AppendResult(irp, "1", NULL);
139 else
140 Tcl_AppendResult(irp, "0", NULL);
141 return TCL_OK;
142 }
143
144 static int tcl_botisvoice STDVAR
145 {
146 struct chanset_t *chan, *thechan = NULL;
147 memberlist *mx;
148
149 BADARGS(1, 2, " ?channel?");
150
151 if (argc > 1) {
152 chan = findchan_by_dname(argv[1]);
153 thechan = chan;
154 if (!thechan) {
155 Tcl_AppendResult(irp, "illegal channel: ", argv[1], NULL);
156 return TCL_ERROR;
157 }
158 } else
159 chan = chanset;
160
161 while (chan && (thechan == NULL || thechan == chan)) {
162 if ((mx = ismember(chan, botname)) && chan_hasvoice(mx)) {
163 Tcl_AppendResult(irp, "1", NULL);
164 return TCL_OK;
165 }
166 chan = chan->next;
167 }
168 Tcl_AppendResult(irp, "0", NULL);
169 return TCL_OK;
170 }
171
172 static int tcl_botonchan STDVAR
173 {
174 struct chanset_t *chan, *thechan = NULL;
175
176 BADARGS(1, 2, " ?channel?");
177
178 if (argc > 1) {
179 chan = findchan_by_dname(argv[1]);
180 thechan = chan;
181 if (!thechan) {
182 Tcl_AppendResult(irp, "illegal channel: ", argv[1], NULL);
183 return TCL_ERROR;
184 }
185 } else
186 chan = chanset;
187
188 while (chan && (thechan == NULL || thechan == chan)) {
189 if (ismember(chan, botname)) {
190 Tcl_AppendResult(irp, "1", NULL);
191 return TCL_OK;
192 }
193 chan = chan->next;
194 }
195 Tcl_AppendResult(irp, "0", NULL);
196 return TCL_OK;
197 }
198
199 static int tcl_isop STDVAR
200 {
201 struct chanset_t *chan, *thechan = NULL;
202 memberlist *mx;
203
204 BADARGS(2, 3, " nick ?channel?");
205
206 if (argc > 2) {
207 chan = findchan_by_dname(argv[2]);
208 thechan = chan;
209 if (!thechan) {
210 Tcl_AppendResult(irp, "illegal channel: ", argv[2], NULL);
211 return TCL_ERROR;
212 }
213 } else
214 chan = chanset;
215
216 while (chan && (thechan == NULL || thechan == chan)) {
217 if ((mx = ismember(chan, argv[1])) && chan_hasop(mx)) {
218 Tcl_AppendResult(irp, "1", NULL);
219 return TCL_OK;
220 }
221 chan = chan->next;
222 }
223 Tcl_AppendResult(irp, "0", NULL);
224 return TCL_OK;
225 }
226
227 static int tcl_ishalfop STDVAR
228 {
229 struct chanset_t *chan, *thechan = NULL;
230 memberlist *mx;
231
232 BADARGS(2, 3, " nick ?channel?");
233
234 if (argc > 2) {
235 chan = findchan_by_dname(argv[2]);
236 thechan = chan;
237 if (!thechan) {
238 Tcl_AppendResult(irp, "illegal channel: ", argv[2], NULL);
239 return TCL_ERROR;
240 }
241 } else
242 chan = chanset;
243
244 while (chan && (thechan == NULL || thechan == chan)) {
245 if ((mx = ismember(chan, argv[1])) && chan_hashalfop(mx)) {
246 Tcl_AppendResult(irp, "1", NULL);
247 return TCL_OK;
248 }
249 chan = chan->next;
250 }
251 Tcl_AppendResult(irp, "0", NULL);
252 return TCL_OK;
253 }
254
255 static int tcl_isvoice STDVAR
256 {
257 struct chanset_t *chan, *thechan = NULL;
258 memberlist *mx;
259
260 BADARGS(2, 3, " nick ?channel?");
261
262 if (argc > 2) {
263 chan = findchan_by_dname(argv[2]);
264 thechan = chan;
265 if (!thechan) {
266 Tcl_AppendResult(irp, "illegal channel: ", argv[2], NULL);
267 return TCL_ERROR;
268 }
269 } else
270 chan = chanset;
271
272 while (chan && (thechan == NULL || thechan == chan)) {
273 if ((mx = ismember(chan, argv[1])) && chan_hasvoice(mx)) {
274 Tcl_AppendResult(irp, "1", NULL);
275 return TCL_OK;
276 }
277 chan = chan->next;
278 }
279 Tcl_AppendResult(irp, "0", NULL);
280 return TCL_OK;
281 }
282
283 static int tcl_wasop STDVAR
284 {
285 struct chanset_t *chan;
286 memberlist *mx;
287
288 BADARGS(3, 3, " nick channel");
289
290 chan = findchan_by_dname(argv[2]);
291 if (chan == NULL) {
292 Tcl_AppendResult(irp, "illegal channel: ", argv[2], NULL);
293 return TCL_ERROR;
294 }
295 if ((mx = ismember(chan, argv[1])) && chan_wasop(mx))
296 Tcl_AppendResult(irp, "1", NULL);
297 else
298 Tcl_AppendResult(irp, "0", NULL);
299 return TCL_OK;
300 }
301
302 static int tcl_washalfop STDVAR
303 {
304 struct chanset_t *chan;
305 memberlist *mx;
306
307 BADARGS(3, 3, " nick channel");
308
309 chan = findchan_by_dname(argv[2]);
310 if (chan == NULL) {
311 Tcl_AppendResult(irp, "illegal channel: ", argv[2], NULL);
312 return TCL_ERROR;
313 }
314 if ((mx = ismember(chan, argv[1])) && chan_washalfop(mx))
315 Tcl_AppendResult(irp, "1", NULL);
316 else
317 Tcl_AppendResult(irp, "0", NULL);
318 return TCL_OK;
319 }
320
321 static int tcl_onchan STDVAR
322 {
323 struct chanset_t *chan, *thechan = NULL;
324
325 BADARGS(2, 3, " nickname ?channel?");
326
327 if (argc > 2) {
328 chan = findchan_by_dname(argv[2]);
329 thechan = chan;
330 if (!thechan) {
331 Tcl_AppendResult(irp, "illegal channel: ", argv[2], NULL);
332 return TCL_ERROR;
333 }
334 } else
335 chan = chanset;
336
337 while (chan && (thechan == NULL || thechan == chan)) {
338 if (ismember(chan, argv[1])) {
339 Tcl_AppendResult(irp, "1", NULL);
340 return TCL_OK;
341 }
342 chan = chan->next;
343 }
344 Tcl_AppendResult(irp, "0", NULL);
345 return TCL_OK;
346 }
347
348 static int tcl_handonchan STDVAR
349 {
350 char nuh[1024];
351 struct chanset_t *chan, *thechan = NULL;
352 memberlist *m;
353
354 BADARGS(2, 3, " handle ?channel?");
355
356 if (argc > 2) {
357 chan = findchan_by_dname(argv[2]);
358 thechan = chan;
359 if (!thechan) {
360 Tcl_AppendResult(irp, "illegal channel: ", argv[2], NULL);
361 return TCL_ERROR;
362 }
363 } else
364 chan = chanset;
365
366 while (chan && (thechan == NULL || thechan == chan)) {
367 for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
368 if (!m->user) {
369 egg_snprintf(nuh, sizeof nuh, "%s!%s", m->nick, m->userhost);
370 m->user = get_user_by_host(nuh);
371 }
372 if (m->user && !rfc_casecmp(m->user->handle, argv[1])) {
373 Tcl_AppendResult(irp, "1", NULL);
374 return TCL_OK;
375 }
376 }
377 chan = chan->next;
378 }
379 Tcl_AppendResult(irp, "0", NULL);
380 return TCL_OK;
381 }
382
383 static int tcl_ischanban STDVAR
384 {
385 struct chanset_t *chan;
386
387 BADARGS(3, 3, " ban channel");
388
389 chan = findchan_by_dname(argv[2]);
390 if (chan == NULL) {
391 Tcl_AppendResult(irp, "illegal channel: ", argv[2], NULL);
392 return TCL_ERROR;
393 }
394 if (ischanban(chan, argv[1]))
395 Tcl_AppendResult(irp, "1", NULL);
396 else
397 Tcl_AppendResult(irp, "0", NULL);
398 return TCL_OK;
399 }
400
401 static int tcl_ischanexempt STDVAR
402 {
403 struct chanset_t *chan;
404
405 BADARGS(3, 3, " exempt channel");
406
407 chan = findchan_by_dname(argv[2]);
408 if (chan == NULL) {
409 Tcl_AppendResult(irp, "illegal channel: ", argv[2], NULL);
410 return TCL_ERROR;
411 }
412 if (ischanexempt(chan, argv[1]))
413 Tcl_AppendResult(irp, "1", NULL);
414 else
415 Tcl_AppendResult(irp, "0", NULL);
416 return TCL_OK;
417 }
418
419 static int tcl_ischaninvite STDVAR
420 {
421 struct chanset_t *chan;
422
423 BADARGS(3, 3, " invite channel");
424
425 chan = findchan_by_dname(argv[2]);
426 if (chan == NULL) {
427 Tcl_AppendResult(irp, "illegal channel: ", argv[2], NULL);
428 return TCL_ERROR;
429 }
430 if (ischaninvite(chan, argv[1]))
431 Tcl_AppendResult(irp, "1", NULL);
432 else
433 Tcl_AppendResult(irp, "0", NULL);
434 return TCL_OK;
435 }
436
437 /* Checks internal tracking of IRC server away status, as updated by IRC
438 * server 352 and AWAY messages. Meant mostly for use with the IRCv3 away-notify
439 * capability, it may not be accurate using only 352s.
440 */
441 static int tcl_isaway STDVAR
442 {
443 struct chanset_t *chan, *thechan = NULL;
444 memberlist *m;
445
446 BADARGS(2, 3, " nick ?channel?");
447
448 if (argc > 2) { /* If channel specified, does it exist? */
449 chan = findchan_by_dname(argv[2]);
450 thechan = chan;
451 if (!thechan) {
452 Tcl_AppendResult(irp, "illegal channel: ", argv[2], NULL);
453 return TCL_ERROR;
454 }
455 } else {
456 chan = chanset;
457 }
458 while (chan && (thechan == NULL || thechan == chan)) {
459 if ((m = ismember(chan, argv[1])) && chan_ircaway(m)) {
460 Tcl_AppendResult(irp, "1", NULL);
461 return TCL_OK;
462 }
463 chan = chan->next;
464 }
465 Tcl_AppendResult(irp, "0", NULL);
466 return TCL_OK;
467 }
468
469 static int tcl_getchanhost STDVAR
470 {
471 struct chanset_t *chan, *thechan = NULL;
472 memberlist *m;
473
474 BADARGS(2, 3, " nickname ?channel?");
475
476 if (argc > 2) {
477 chan = findchan_by_dname(argv[2]);
478 thechan = chan;
479 if (!thechan) {
480 Tcl_AppendResult(irp, "illegal channel: ", argv[2], NULL);
481 return TCL_ERROR;
482 }
483 } else
484 chan = chanset;
485
486 while (chan && (thechan == NULL || thechan == chan)) {
487 m = ismember(chan, argv[1]);
488 if (m) {
489 Tcl_AppendResult(irp, m->userhost, NULL);
490 return TCL_OK;
491 }
492 chan = chan->next;
493 }
494 return TCL_OK;
495 }
496
497 static int tcl_onchansplit STDVAR
498 {
499 struct chanset_t *chan, *thechan = NULL;
500 memberlist *m;
501
502 BADARGS(2, 3, " nickname ?channel?");
503
504 if (argc > 2) {
505 chan = findchan_by_dname(argv[2]);
506 thechan = chan;
507 if (!thechan) {
508 Tcl_AppendResult(irp, "illegal channel: ", argv[2], NULL);
509 return TCL_ERROR;
510 }
511 } else
512 chan = chanset;
513
514 while (chan && (thechan == NULL || thechan == chan)) {
515 m = ismember(chan, argv[1]);
516 if (m && chan_issplit(m)) {
517 Tcl_AppendResult(irp, "1", NULL);
518 return TCL_OK;
519 }
520 chan = chan->next;
521 }
522 Tcl_AppendResult(irp, "0", NULL);
523 return TCL_OK;
524 }
525
526 static int tcl_maskhost STDVAR
527 {
528 char *new;
529
530 BADARGS(2, 3, " nick!user@host ?type?");
531
532 new = nmalloc(strlen(argv[1]) + 5);
533 if (argc == 3)
534 maskaddr(argv[1], new, atoi(argv[2]));
535 else
536 maskban(argv[1], new);
537 Tcl_AppendResult(irp, new, NULL);
538 nfree(new);
539 return TCL_OK;
540 }
541
542 static int tcl_getchanidle STDVAR
543 {
544 memberlist *m;
545 struct chanset_t *chan;
546 char s[20];
547 int x;
548
549 BADARGS(3, 3, " nickname channel");
550
551 if (!(chan = findchan_by_dname(argv[2]))) {
552 Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
553 return TCL_ERROR;
554 }
555 m = ismember(chan, argv[1]);
556
557 if (m) {
558 x = (now - (m->last)) / 60;
559 simple_sprintf(s, "%d", x);
560 Tcl_AppendResult(irp, s, NULL);
561 return TCL_OK;
562 }
563 Tcl_AppendResult(irp, "-1", NULL);
564 return TCL_OK;
565 }
566
tcl_chanmasks(masklist * m,Tcl_Interp * irp)567 static int tcl_chanmasks(masklist *m, Tcl_Interp *irp)
568 {
569 char work[20], *p;
570 EGG_CONST char *list[3];
571
572 for (; m && m->mask && m->mask[0]; m = m->next) {
573 list[0] = m->mask;
574 list[1] = m->who;
575 simple_sprintf(work, "%d", now - m->timer);
576 list[2] = work;
577 p = Tcl_Merge(3, list);
578 Tcl_AppendElement(irp, p);
579 Tcl_Free((char *) p);
580 }
581 return TCL_OK;
582 }
583
584 static int tcl_chanbans STDVAR
585 {
586 struct chanset_t *chan;
587
588 BADARGS(2, 2, " channel");
589
590 chan = findchan_by_dname(argv[1]);
591 if (chan == NULL) {
592 Tcl_AppendResult(irp, "illegal channel: ", argv[2], NULL);
593 return TCL_ERROR;
594 }
595 return tcl_chanmasks(chan->channel.ban, irp);
596 }
597
598 static int tcl_chanexempts STDVAR
599 {
600 struct chanset_t *chan;
601
602 BADARGS(2, 2, " channel");
603
604 chan = findchan_by_dname(argv[1]);
605 if (chan == NULL) {
606 Tcl_AppendResult(irp, "illegal channel: ", argv[2], NULL);
607 return TCL_ERROR;
608 }
609 return tcl_chanmasks(chan->channel.exempt, irp);
610 }
611
612 static int tcl_chaninvites STDVAR
613 {
614 struct chanset_t *chan;
615
616 BADARGS(2, 2, " channel");
617
618 chan = findchan_by_dname(argv[1]);
619 if (chan == NULL) {
620 Tcl_AppendResult(irp, "illegal channel: ", argv[2], NULL);
621 return TCL_ERROR;
622 }
623 return tcl_chanmasks(chan->channel.invite, irp);
624 }
625
626 static int tcl_getchanmode STDVAR
627 {
628 struct chanset_t *chan;
629
630 BADARGS(2, 2, " channel");
631
632 chan = findchan_by_dname(argv[1]);
633 if (chan == NULL) {
634 Tcl_AppendResult(irp, "invalid channel: ", argv[1], NULL);
635 return TCL_ERROR;
636 }
637 Tcl_AppendResult(irp, getchanmode(chan), NULL);
638 return TCL_OK;
639 }
640
641 static int tcl_getchanjoin STDVAR
642 {
643 struct chanset_t *chan;
644 char s[21];
645 memberlist *m;
646
647 BADARGS(3, 3, " nick channel");
648
649 chan = findchan_by_dname(argv[2]);
650 if (chan == NULL) {
651 Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
652 return TCL_ERROR;
653 }
654 m = ismember(chan, argv[1]);
655
656 if (m == NULL) {
657 Tcl_AppendResult(irp, argv[1], " is not on ", argv[2], NULL);
658 return TCL_ERROR;
659 }
660 sprintf(s, "%lu", (unsigned long) m->joined);
661 Tcl_AppendResult(irp, s, NULL);
662 return TCL_OK;
663 }
664
665 static int tcl_channame2dname STDVAR
666 {
667 struct chanset_t *chan;
668
669 BADARGS(2, 2, " channel-name");
670
671 chan = findchan(argv[1]);
672 if (chan) {
673 Tcl_AppendResult(irp, chan->dname, NULL);
674 return TCL_OK;
675 } else {
676 Tcl_AppendResult(irp, "invalid channel-name: ", argv[1], NULL);
677 return TCL_ERROR;
678 }
679 }
680
681 static int tcl_chandname2name STDVAR
682 {
683 struct chanset_t *chan;
684
685 BADARGS(2, 2, " channel-dname");
686
687 chan = findchan_by_dname(argv[1]);
688 if (chan) {
689 Tcl_AppendResult(irp, chan->name, NULL);
690 return TCL_OK;
691 } else {
692 Tcl_AppendResult(irp, "invalid channel-dname: ", argv[1], NULL);
693 return TCL_ERROR;
694 }
695 }
696
697 static int tcl_flushmode STDVAR
698 {
699 struct chanset_t *chan;
700
701 BADARGS(2, 2, " channel");
702
703 chan = findchan_by_dname(argv[1]);
704 if (chan == NULL) {
705 Tcl_AppendResult(irp, "invalid channel: ", argv[1], NULL);
706 return TCL_ERROR;
707 }
708 flush_mode(chan, NORMAL);
709 return TCL_OK;
710 }
711
712 static int tcl_pushmode STDVAR
713 {
714 struct chanset_t *chan;
715 char plus, mode;
716
717 BADARGS(3, 4, " channel mode ?arg?");
718
719 chan = findchan_by_dname(argv[1]);
720 if (chan == NULL) {
721 Tcl_AppendResult(irp, "invalid channel: ", argv[1], NULL);
722 return TCL_ERROR;
723 }
724 plus = argv[2][0];
725
726 mode = argv[2][1];
727 if ((plus != '+') && (plus != '-')) {
728 mode = plus;
729 plus = '+';
730 }
731 if (argc == 4)
732 add_mode(chan, plus, mode, argv[3]);
733 else
734 add_mode(chan, plus, mode, "");
735 return TCL_OK;
736 }
737
738 static int tcl_resetbans STDVAR
739 {
740 struct chanset_t *chan;
741
742 BADARGS(2, 2, " channel");
743
744 chan = findchan_by_dname(argv[1]);
745 if (chan == NULL) {
746 Tcl_AppendResult(irp, "invalid channel ", argv[1], NULL);
747 return TCL_ERROR;
748 }
749 resetbans(chan);
750 return TCL_OK;
751 }
752
753 static int tcl_resetexempts STDVAR
754 {
755 struct chanset_t *chan;
756
757 BADARGS(2, 2, " channel");
758
759 chan = findchan_by_dname(argv[1]);
760 if (chan == NULL) {
761 Tcl_AppendResult(irp, "invalid channel ", argv[1], NULL);
762 return TCL_ERROR;
763 }
764 resetexempts(chan);
765 return TCL_OK;
766 }
767
768 static int tcl_resetinvites STDVAR
769 {
770 struct chanset_t *chan;
771
772 BADARGS(2, 2, " channel");
773
774 chan = findchan_by_dname(argv[1]);
775 if (chan == NULL) {
776 Tcl_AppendResult(irp, "invalid channel ", argv[1], NULL);
777 return TCL_ERROR;
778 }
779 resetinvites(chan);
780 return TCL_OK;
781 }
782
783 static int tcl_resetchanidle STDVAR
784 {
785 memberlist *m;
786 struct chanset_t *chan;
787
788 BADARGS(2, 3, " ?nick? channel");
789
790 chan = findchan_by_dname((argc == 2) ? argv[1] : argv[2]);
791 if (chan == NULL) {
792 Tcl_AppendResult(irp, "invalid channel ",
793 (argc == 2) ? argv[1] : argv[2], NULL);
794 return TCL_ERROR;
795 }
796
797 if (argc == 2)
798 for (m = chan->channel.member; m; m = m->next)
799 m->last = now;
800 else {
801 if (!(m = ismember(chan, argv[1]))) {
802 Tcl_AppendResult(irp, argv[1], " is not on ", argv[2], NULL);
803 return TCL_ERROR;
804 }
805 m->last = now;
806 }
807 return TCL_OK;
808 }
809
810 static int tcl_resetchanjoin STDVAR
811 {
812 memberlist *m;
813 struct chanset_t *chan;
814
815 BADARGS(2, 3, " ?nick? channel");
816
817 chan = findchan_by_dname((argc == 2) ? argv[1] : argv[2]);
818 if (chan == NULL) {
819 Tcl_AppendResult(irp, "invalid channel ",
820 (argc == 2) ? argv[1] : argv[2], NULL);
821 return TCL_ERROR;
822 }
823
824 if (argc == 2)
825 for (m = chan->channel.member; m; m = m->next)
826 m->joined = now;
827 else {
828 if (!(m = ismember(chan, argv[1]))) {
829 Tcl_AppendResult(irp, argv[1], " is not on ", argv[2], NULL);
830 return TCL_ERROR;
831 }
832 m->joined = now;
833 }
834 return TCL_OK;
835 }
836
setflags(int * flags,char * argflags)837 static int setflags(int *flags, char *argflags) {
838 char *c;
839
840 for (c = argflags; *c; c++) {
841 switch(*c) {
842 case 'w':
843 *flags |= CHAN_RESETWHO;
844 break;
845 case 'm':
846 *flags |= CHAN_RESETMODES;
847 break;
848 case 'b':
849 *flags |= CHAN_RESETBANS;
850 break;
851 case 'e':
852 *flags |= CHAN_RESETEXEMPTS;
853 break;
854 case 'I':
855 *flags |= CHAN_RESETINVITED;
856 break;
857 case 't':
858 *flags |= CHAN_RESETTOPIC;
859 break;
860 default:
861 return 1; /* Found a flag we don't support, return an error */
862 }
863 }
864 return 0;
865 }
866
867 static int tcl_refreshchan STDVAR
868 {
869 int flags = 0;
870 struct chanset_t *chan;
871
872 BADARGS(2, 3, " channel ?flags?");
873
874 chan = findchan_by_dname(argv[1]);
875 if (chan == NULL) {
876 Tcl_AppendResult(irp, "invalid channel ", argv[1], NULL);
877 return TCL_ERROR;
878 }
879
880 if (argc == 2) {
881 reset_chan_info(chan, CHAN_RESETALL, 0);
882 return TCL_OK;
883 }
884 if (setflags(&flags, argv[2])) { /* Set flags to refresh */
885 Tcl_AppendResult(irp, "invalid refresh flags: ", argv[2], NULL);
886 return TCL_ERROR;
887 } else {
888 reset_chan_info(chan, flags, 0);
889 }
890 return TCL_OK;
891 }
892
893 static int tcl_resetchan STDVAR
894 {
895 int flags = 0;
896 struct chanset_t *chan;
897
898 BADARGS(2, 3, " channel ?flags?");
899
900 chan = findchan_by_dname(argv[1]);
901 if (chan == NULL) {
902 Tcl_AppendResult(irp, "invalid channel ", argv[1], NULL);
903 return TCL_ERROR;
904 }
905
906 if (argc == 2) {
907 reset_chan_info(chan, CHAN_RESETALL, 1);
908 return TCL_OK;
909 }
910 if (setflags(&flags, argv[2])) { /* Set flags to refresh */
911 Tcl_AppendResult(irp, "invalid reset flags: ", argv[2], NULL);
912 return TCL_ERROR;
913 } else {
914 reset_chan_info(chan, flags, 1);
915 }
916 return TCL_OK;
917 }
918
919 static int tcl_topic STDVAR
920 {
921 struct chanset_t *chan;
922
923 BADARGS(2, 2, " channel");
924
925 chan = findchan_by_dname(argv[1]);
926 if (chan == NULL) {
927 Tcl_AppendResult(irp, "invalid channel ", argv[1], NULL);
928 return TCL_ERROR;
929 }
930 Tcl_AppendResult(irp, chan->channel.topic, NULL);
931 return TCL_OK;
932 }
933
934 static int tcl_account2nicks STDVAR
935 {
936 memberlist *m;
937 struct chanset_t *chan, *thechan = NULL;
938 Tcl_Obj *nicks;
939 Tcl_Obj **nicksv = NULL;
940 int nicksc = 0, i, found;
941
942 BADARGS(2, 3, " account ?channel?");
943
944 if (argc > 2) {
945 chan = findchan_by_dname(argv[2]);
946 thechan = chan;
947 if (chan == NULL) {
948 Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
949 return TCL_ERROR;
950 }
951 } else
952 chan = chanset;
953
954 nicks = Tcl_NewListObj(0, NULL);
955 while (chan && (thechan == NULL || thechan == chan)) {
956 for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
957 found = 0;
958 /* Does this user have the account we're looking for? */
959 if (!rfc_casecmp(m->account, argv[1])) {
960 /* Is the nick of the user already in the list? */
961 Tcl_ListObjGetElements(irp, nicks, &nicksc, &nicksv);
962 for (i = 0; i < nicksc; i++) {
963 if (!rfc_casecmp(m->nick, Tcl_GetString(nicksv[i]))) {
964 found = 1;
965 break;
966 }
967 }
968 if (!found) {
969 Tcl_ListObjAppendElement(irp, nicks, Tcl_NewStringObj(m->nick, -1));
970 }
971 }
972 }
973 chan = chan->next;
974 }
975 Tcl_SetObjResult(irp, nicks);
976 return TCL_OK;
977 }
978
979 static int tcl_hand2nicks STDVAR
980 {
981 char nuh[1024];
982 memberlist *m;
983 struct chanset_t *chan, *thechan = NULL;
984 Tcl_Obj *nicks;
985 Tcl_Obj **nicksv = NULL;
986 int nicksc = 0, i, found;
987
988 BADARGS(2, 3, " handle ?channel?");
989
990 if (argc > 2) {
991 chan = findchan_by_dname(argv[2]);
992 thechan = chan;
993 if (chan == NULL) {
994 Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
995 return TCL_ERROR;
996 }
997 } else
998 chan = chanset;
999
1000 nicks = Tcl_NewListObj(0, NULL);
1001 while (chan && (thechan == NULL || thechan == chan)) {
1002 for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
1003 found = 0;
1004 /* Does this user have the account we're looking for? */
1005 if (!m->user && !m->tried_getuser) {
1006 egg_snprintf(nuh, sizeof nuh, "%s!%s", m->nick, m->userhost);
1007 m->tried_getuser = 1;
1008 m->user = get_user_by_host(nuh);
1009 }
1010 if (m->user && !rfc_casecmp(m->user->handle, argv[1])) {
1011 /* Is the nick of the user already in the list? */
1012 Tcl_ListObjGetElements(irp, nicks, &nicksc, &nicksv);
1013 for (i = 0; i < nicksc; i++) {
1014 if (!rfc_casecmp(m->nick, Tcl_GetString(nicksv[i]))) {
1015 found = 1;
1016 break;
1017 }
1018 }
1019 if (!found) {
1020 Tcl_ListObjAppendElement(irp, nicks, Tcl_NewStringObj(m->nick, -1));
1021 }
1022 }
1023 }
1024 chan = chan->next;
1025 }
1026 Tcl_SetObjResult(irp, nicks);
1027 return TCL_OK;
1028 }
1029
1030 static int tcl_hand2nick STDVAR
1031 {
1032 char nuh[1024];
1033 memberlist *m;
1034 struct chanset_t *chan, *thechan = NULL;
1035
1036 BADARGS(2, 3, " handle ?channel?");
1037
1038 if (argc > 2) {
1039 chan = findchan_by_dname(argv[2]);
1040 thechan = chan;
1041 if (chan == NULL) {
1042 Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
1043 return TCL_ERROR;
1044 }
1045 } else
1046 chan = chanset;
1047
1048 while (chan && (thechan == NULL || thechan == chan)) {
1049 for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
1050 if (!m->user && !m->tried_getuser) {
1051 egg_snprintf(nuh, sizeof nuh, "%s!%s", m->nick, m->userhost);
1052 m->tried_getuser = 1;
1053 m->user = get_user_by_host(nuh);
1054 }
1055 if (m->user && !rfc_casecmp(m->user->handle, argv[1])) {
1056 Tcl_AppendResult(irp, m->nick, NULL);
1057 return TCL_OK;
1058 }
1059 }
1060 chan = chan->next;
1061 }
1062 return TCL_OK;
1063 }
1064
1065 static int tcl_nick2hand STDVAR
1066 {
1067 char nuh[1024];
1068 memberlist *m;
1069 struct chanset_t *chan, *thechan = NULL;
1070
1071 BADARGS(2, 3, " nick ?channel?");
1072
1073 if (argc > 2) {
1074 chan = findchan_by_dname(argv[2]);
1075 thechan = chan;
1076 if (chan == NULL) {
1077 Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
1078 return TCL_ERROR;
1079 }
1080 } else
1081 chan = chanset;
1082
1083 while (chan && (thechan == NULL || thechan == chan)) {
1084 m = ismember(chan, argv[1]);
1085 if (m) {
1086 if (!m->user) {
1087 egg_snprintf(nuh, sizeof nuh, "%s!%s", m->nick, m->userhost);
1088 m->user = get_user_by_host(nuh);
1089 }
1090 Tcl_AppendResult(irp, m->user ? m->user->handle : "*", NULL);
1091 return TCL_OK;
1092 }
1093 chan = chan->next;
1094 }
1095 return TCL_OK;
1096 }
1097
1098 static int tcl_putkick STDVAR
1099 {
1100 struct chanset_t *chan;
1101 int k = 0, l;
1102 char kicknick[512], *nick, *p, *comment = NULL;
1103 memberlist *m;
1104
1105 BADARGS(3, 4, " channel nick?s? ?comment?");
1106
1107 chan = findchan_by_dname(argv[1]);
1108 if (chan == NULL) {
1109 Tcl_AppendResult(irp, "illegal channel: ", argv[1], NULL);
1110 return TCL_ERROR;
1111 }
1112 if (argc == 4)
1113 comment = argv[3];
1114 else
1115 comment = "";
1116 if (!me_op(chan) && !me_halfop(chan)) {
1117 Tcl_AppendResult(irp, "need op or halfop", NULL);
1118 return TCL_ERROR;
1119 }
1120
1121 kicknick[0] = 0;
1122 p = argv[2];
1123 /* Loop through all given nicks */
1124 while (p) {
1125 nick = p;
1126 p = strchr(nick, ','); /* Search for beginning of next nick */
1127 if (p) {
1128 *p = 0;
1129 p++;
1130 }
1131
1132 m = ismember(chan, nick);
1133 if (!me_op(chan) && !(me_halfop(chan) && !chan_hasop(m))) {
1134 Tcl_AppendResult(irp, "need op", NULL);
1135 return TCL_ERROR;
1136 }
1137 if (!m)
1138 continue; /* Skip non-existent nicks */
1139 m->flags |= SENTKICK; /* Mark as pending kick */
1140 if (kicknick[0])
1141 strncat(kicknick, ",", sizeof kicknick - strlen(kicknick) - 1);
1142 strncat(kicknick, nick, sizeof kicknick - strlen(kicknick) - 1); /* Add to local queue */
1143 k++;
1144
1145 /* Check if we should send the kick command yet */
1146 l = strlen(chan->name) + strlen(kicknick) + strlen(comment);
1147 if (((kick_method != 0) && (k == kick_method)) || (l > 480)) {
1148 dprintf(DP_SERVER, "KICK %s %s :%s\n", chan->name, kicknick, comment);
1149 k = 0;
1150 kicknick[0] = 0;
1151 }
1152 }
1153 /* Clear out all pending kicks in our local kick queue */
1154 if (k > 0)
1155 dprintf(DP_SERVER, "KICK %s %s :%s\n", chan->name, kicknick, comment);
1156 return TCL_OK;
1157 }
1158
1159 static tcl_cmds tclchan_cmds[] = {
1160 {"chanlist", tcl_chanlist},
1161 {"botisop", tcl_botisop},
1162 {"botishalfop", tcl_botishalfop},
1163 {"botisvoice", tcl_botisvoice},
1164 {"isop", tcl_isop},
1165 {"wasop", tcl_wasop},
1166 {"ishalfop", tcl_ishalfop},
1167 {"washalfop", tcl_washalfop},
1168 {"isvoice", tcl_isvoice},
1169 {"onchan", tcl_onchan},
1170 {"handonchan", tcl_handonchan},
1171 {"ischanban", tcl_ischanban},
1172 {"ischanexempt", tcl_ischanexempt},
1173 {"ischaninvite", tcl_ischaninvite},
1174 {"ischanjuped", tcl_ischanjuped},
1175 {"getchanhost", tcl_getchanhost},
1176 {"onchansplit", tcl_onchansplit},
1177 {"maskhost", tcl_maskhost},
1178 {"getchanidle", tcl_getchanidle},
1179 {"isaway", tcl_isaway},
1180 {"chanbans", tcl_chanbans},
1181 {"chanexempts", tcl_chanexempts},
1182 {"chaninvites", tcl_chaninvites},
1183 {"account2nicks", tcl_account2nicks},
1184 {"hand2nicks", tcl_hand2nicks},
1185 {"hand2nick", tcl_hand2nick},
1186 {"nick2hand", tcl_nick2hand},
1187 {"getchanmode", tcl_getchanmode},
1188 {"getchanjoin", tcl_getchanjoin},
1189 {"flushmode", tcl_flushmode},
1190 {"pushmode", tcl_pushmode},
1191 {"resetbans", tcl_resetbans},
1192 {"resetexempts", tcl_resetexempts},
1193 {"resetinvites", tcl_resetinvites},
1194 {"resetchanidle", tcl_resetchanidle},
1195 {"resetchanjoin", tcl_resetchanjoin},
1196 {"resetchan", tcl_resetchan},
1197 {"refreshchan", tcl_refreshchan},
1198 {"topic", tcl_topic},
1199 {"botonchan", tcl_botonchan},
1200 {"putkick", tcl_putkick},
1201 {"channame2dname", tcl_channame2dname},
1202 {"chandname2name", tcl_chandname2name},
1203 {NULL, NULL}
1204 };
1205