]> git.donarmstrong.com Git - infobot.git/blob - src/Modules/UserDCC.pl
- ".op" fixed. found by Rev
[infobot.git] / src / Modules / UserDCC.pl
1 #
2 #  UserDCC.pl: User Commands, DCC CHAT.
3 #      Author: dms
4 #     Version: v0.2 (20010119)
5 #     Created: 20000707 (from UserExtra.pl)
6 #
7
8 if (&IsParam("useStrict")) { use strict; }
9
10 sub userDCC {
11     # hrm...
12     $message =~ s/\s+$//;
13
14     ### for all users.
15     # quit.
16     if ($message =~ /^(exit|quit)$/i) {
17         # do ircII clients support remote close? if so, cool!
18         &status("userDCC: quit called. FIXME");
19         &dcc_close($who);
20         &status("userDCC: after dcc_close!");
21
22         return;
23     }
24
25     # who.
26     if ($message =~ /^who$/) {
27         my $count = scalar(keys %{$dcc{'CHAT'}});
28         my $dccCHAT = $message;
29
30         &pSReply("Start of who ($count users).");
31         foreach (keys %{$dcc{'CHAT'}}) {
32             &pSReply("=> $_");
33         }
34         &pSReply("End of who.");
35
36         return;
37     }
38
39     ### for those users with enough flags.
40
41     # 4op.
42     if ($message =~ /^4op(\s+($mask{chan}))?$/i) {
43         return unless (&hasFlag("o"));
44
45         my $chan = $2;
46
47         if ($chan eq "") {
48             &help("4op");
49             return;
50         }
51
52         if (!$channels{$chan}{'o'}{$ident}) {
53             &msg($who, "i don't have ops on $chan to do that.");
54             return;
55         }
56
57         # on non-4mode(<4) servers, this may be exploited.
58         if ($channels{$chan}{'o'}{$who}) {
59             rawout("MODE $chan -o+o-o+o". (" $who" x 4));
60         } else {
61             rawout("MODE $chan +o-o+o-o". (" $who" x 4));
62         }
63
64         return;
65     }
66
67     # backlog.
68     if ($message =~ /^backlog(\s+(.*))?$/i) {
69         return unless (&hasFlag("o"));
70         return unless (&hasParam("backlog"));
71         my $num = $2;
72         my $max = $param{'backlog'};
73
74         if (!defined $num) {
75             &help("backlog");
76             return;
77         } elsif ($num !~ /^\d+/) {
78             &msg($who, "error: argument is not positive integer.");
79             return;
80         } elsif ($num > $max or $num < 0) {
81             &msg($who, "error: argument is out of range (max $max).");
82             return;
83         }
84
85         &msg($who, "Start of backlog...");
86         for (0..$num-1) {
87             sleep 1 if ($_ % 4 == 0 and $_ != 0);
88             $conn->privmsg($who, "[".($_+1)."]: $backlog[$max-$num+$_]");
89         }
90         &msg($who, "End of backlog.");
91
92         return;
93     }
94
95     # dump variables.
96     if ($message =~ /^dumpvars$/i) {
97         return unless (&hasFlag("o"));
98         return unless (&IsParam("dumpvars"));
99
100         &status("Dumping all variables...");
101         &dumpallvars();
102
103         return;
104     }
105
106     # kick.
107     if ($message =~ /^kick(\s+(\S+)(\s+(\S+))?)?/) {
108         return unless (&hasFlag("o"));
109         my ($nick,$chan) = (lc $2,lc $4);
110
111         if ($nick eq "") {
112             &help("kick");
113             return;
114         }
115
116         if (&validChan($chan) == 0) {
117             &msg($who,"error: invalid channel \002$chan\002");
118             return;
119         }
120
121         if (&IsNickInChan($nick,$chan) == 0) {
122             &msg($who,"$nick is not in $chan.");
123             return;
124         }
125
126         &kick($nick,$chan);
127
128         return;
129     }
130
131     # kick.
132     if ($message =~ /^mode(\s+(.*))?$/) {
133         return unless (&hasFlag("m"));
134         my ($chan,$mode) = split /\s+/,$2,2;
135
136         if ($chan eq "") {
137             &help("mode");
138             return;
139         }
140
141         if (&validChan($chan) == 0) {
142             &msg($who,"error: invalid channel \002$chan\002");
143             return;
144         }
145
146         if (!$channels{$chan}{o}{$ident}) {
147             &msg($who,"error: don't have ops on \002$chan\002");
148             return;
149         }
150
151         &mode($chan, $mode);
152
153         return;
154     }
155
156     # part.
157     if ($message =~ /^part(\s+(\S+))?$/i) {
158         return unless (&hasFlag("o"));
159         my $jchan = $2;
160
161         if ($jchan !~ /^$mask{chan}$/) {
162             &msg($who, "error, invalid chan.");
163             &help("part");
164             return;
165         }
166
167         if (!&validChan($jchan)) {
168             &msg($who, "error, I'm not on that chan.");
169             return;
170         }
171
172         &msg($jchan, "Leaving. (courtesy of $who).");
173         &part($jchan);
174         return;
175     }
176
177     # lobotomy. sometimes we want the bot to be _QUIET_.
178     if ($message =~ /^(lobotomy|bequiet)$/i) {
179         return unless (&hasFlag("o"));
180
181         if ($lobotomized) {
182             &performReply("i'm already lobotomized");
183         } else {
184             &performReply("i have been lobotomized");
185             $lobotomized = 1;
186         }
187
188         return;
189     }
190
191     # unlobotomy.
192     if ($message =~ /^(unlobotomy|benoisy)$/i) {
193         return unless (&hasFlag("o"));
194         if ($lobotomized) {
195             &performReply("i have been unlobotomized, woohoo");
196             $lobotomized = 0;
197         } else {
198             &performReply("i'm not lobotomized");
199         }
200         return;
201     }
202
203     # op.
204     if ($message =~ /^op(\s+(.*))?$/i) {
205         return unless (&hasFlag("o"));
206         my ($opee) = lc $2;
207         my @chans;
208
209         if ($opee =~ / /) {
210             if ($opee =~ /^(\S+)\s+(\S+)$/) {
211                 $opee  = $1;
212                 @chans = ($2);
213                 if (!&validChan($2)) {
214                     &msg($who,"error: invalid chan ($2).");
215                     return;
216                 }
217             } else {
218                 &msg($who,"error: invalid params.");
219                 return;
220             }
221         } else {
222             @chans = keys %channels;
223         }
224
225         my $found = 0;
226         my $op = 0;
227         foreach (@chans) {
228             next unless (&IsNickInChan($opee,$_));
229             $found++;
230             if ($channels{$_}{'o'}{$opee}) {
231                 &pSReply("op: $opee already has ops on $_");
232                 next;
233             }
234             $op++;
235
236             &pSReply("opping $opee on $_");
237             &op($_, $opee);
238         }
239
240         if ($found != $op) {
241             &pSReply("op: opped on all possible channels.");
242         } else {
243             &DEBUG("op: found => '$found'.");
244             &DEBUG("op:    op => '$op'.");
245         }
246
247         return;
248     }
249
250     # deop.
251     if ($message =~ /^deop(\s+(.*))?$/i) {
252         return unless (&hasFlag("o"));
253         my ($opee) = lc $2;
254         my @chans;
255
256         if ($opee =~ / /) {
257             if ($opee =~ /^(\S+)\s+(\S+)$/) {
258                 $opee  = $1;
259                 @chans = ($2);
260                 if (!&validChan($2)) {
261                     &msg($who,"error: invalid chan ($2).");
262                     return;
263                 }
264             } else {
265                 &msg($who,"error: invalid params.");
266                 return;
267             }
268         } else {
269             @chans = keys %channels;
270         }
271
272         my $found = 0;
273         my $op = 0;
274         foreach (@chans) {
275             next unless (&IsNickInChan($opee,$_));
276             $found++;
277             if (!exists $channels{$_}{'o'}{$opee}) {
278                 &status("deop: $opee already has no ops on $_");
279                 next;
280             }
281             $op++;
282
283             &status("deopping $opee on $_ at ${who}'s request");
284             &deop($_, $opee);
285         }
286
287         if ($found != $op) {
288             &status("deop: deopped on all possible channels.");
289         } else {
290             &DEBUG("deop: found => '$found'.");
291             &DEBUG("deop: op => '$op'.");
292         }
293
294         return;
295     }
296
297     # say.
298     if ($message =~ s/^say\s+(\S+)\s+(.*)//) {
299         return unless (&hasFlag("o"));
300         my ($chan,$msg) = (lc $1, $2);
301         &DEBUG("chan => '$1', msg => '$msg'.");
302
303         if (&validChan($chan)) {
304             &msg($chan, $2);
305         } else {
306             &msg($who,"i'm not on \002$1\002, sorry.");
307         }
308         return;
309     }
310
311     # die.
312     if ($message =~ /^die$/) {
313         return unless (&hasFlag("n"));
314
315         &doExit();
316
317         &status("Dying by $who\'s request");
318         exit 0;
319     }
320
321     # global factoid substitution.
322     if ($message =~ m|^s([/,#])(.+?)\1(.*?)\1;?\s*$|) {
323         my ($delim,$op,$np) = ($1, $2, $3);
324         return unless (&hasFlag("n"));
325         ### TODO: support flags to do full-on global.
326
327         # incorrect format.
328         if ($np =~ /$delim/) {
329             &performReply("looks like you used the delimiter too many times. You may want to use a different delimiter, like ':' or '#'.");
330             return;
331         }
332
333         ### TODO: fix up $op to support mysql/pgsql/dbm(perl)
334         ### TODO: => add db/sql specific function to fix this.
335         my @list = &searchTable("factoids", "factoid_key",
336                         "factoid_value", $op);
337
338         if (!scalar @list) {
339             &performReply("Expression didn't match anything.");
340             return;
341         }
342
343         if (scalar @list > 100) {
344             &performReply("regex found more than 100 matches... not doing.");
345             return;
346         }
347
348         &status("gsubst: going to alter ".scalar(@list)." factoids.");
349         &performReply("going to alter ".scalar(@list)." factoids.");
350
351         my $error = 0;
352         foreach (@list) {
353             my $faqtoid = $_;
354
355             next if (&IsLocked($faqtoid) == 1);
356             my $result = &getFactoid($faqtoid);
357             my $was = $result;
358             &DEBUG("was($faqtoid) => '$was'.");
359
360             # global global
361             # we could support global local (once off).
362             if ($result =~ s/\Q$op/$np/gi) {
363                 if (length $result > $param{'maxDataSize'}) {
364                     &performReply("that's too long (or was long)");
365                     return;
366                 }
367                 &setFactInfo($faqtoid, "factoid_value", $result);
368                 &status("update: '$faqtoid' =is=> '$result'; was '$was'");
369             } else {
370                 &WARN("subst: that's weird... thought we found the string ($op) in '$faqtoid'.");
371                 $error++;
372             }
373         }
374
375         if ($error) {
376             &ERROR("Some warnings/errors?");
377         }
378
379         &performReply("Ok... did s/$op/$np/ for ".
380                                 (scalar(@list) - $error)." factoids");
381
382         return;
383     }
384
385     # jump.
386     if ($message =~ /^jump(\s+(\S+))?$/i) {
387         return unless (&hasFlag("n"));
388
389         if ($2 eq "") {
390             &help("jump");
391             return;
392         }
393
394         my ($server,$port);
395         if ($2 =~ /^(\S+)(:(\d+))?$/) {
396             $server = $1;
397             $port   = $3 || 6667;
398         } else {
399             &msg($who,"invalid format.");
400             return;
401         }
402
403         &status("jumping servers... $server...");
404         &rawout("QUIT :jumping to $server");
405
406         if (&irc($server,$port) == 0) {
407             &ircloop();
408         }
409     }
410
411     # reload.
412     if ($message =~ /^reload$/i) {
413         return unless (&hasFlag("n"));
414
415         &status("USER reload $who");
416         &pSReply("reloading...");
417         &reloadAllModules();
418         &pSReply("reloaded.");
419
420         return;
421     }
422
423     # rehash.
424     if ($message =~ /^rehash$/) {
425         return unless (&hasFlag("n"));
426
427         &msg($who,"rehashing...");
428         &restart("REHASH");
429         &status("USER rehash $who");
430         &msg($who,"rehashed");
431
432         return;
433     }
434
435     #####
436     ##### USER//CHAN SPECIFIC CONFIGURATION COMMANDS
437     #####
438
439     if ($message =~ /^chaninfo(\s+(.*))?$/) {
440         my @args = split /[\s\t]+/, $2; # hrm.
441
442         if (scalar @args != 1) {
443             &help("chaninfo");
444             return;
445         }
446
447         if (!exists $chanconf{$args[0]}) {
448             &pSReply("no such channel $args[0]");
449             return;
450         }
451
452         &pSReply("showing channel conf.");
453         foreach (sort keys %{ $chanconf{$args[0]} }) {
454             &pSReply("$chan: $_ => $chanconf{$args[0]}{$_}");
455         }
456         &pSReply("End of chaninfo.");
457
458         return;
459     }
460
461     # +chan.
462     if ($message =~ /^(chanset|\+chan)(\s+(.*?))?$/) {
463         my $cmd         = $1;
464         my $args        = $3;
465         my $no_chan     = 0;
466
467         if (!defined $args) {
468             &help($cmd);
469             return;
470         }
471
472         my @chans;
473         while ($args =~ s/^($mask{chan})\s*//) {
474             push(@chans, $1);
475         }
476
477         if (!scalar @chans) {
478             push(@chans, "_default");
479             $no_chan    = 1;
480         }
481
482         my($what,$val) = split /[\s\t]+/, $args, 2;
483
484         ### TODO: "cannot set values without +m".
485         return unless (&hasFlag("m"));
486
487         # READ ONLY.
488         if (defined $what and $what !~ /^[-+]/ and !defined $val and $no_chan) {
489             &pSReply("Showing $what values on all channels...");
490
491             my %vals;
492             foreach (keys %chanconf) {
493                 my $val = $chanconf{$_}{$what} || "NOT-SET";
494                 $vals{$val}{$_} = 1;
495             }
496
497             foreach (keys %vals) {
498                 &pSReply("  $what = $_: ".join(' ', keys %{ $vals{$_} } ) );
499             }
500
501             &pSReply("End of list.");
502
503             return;
504         }
505
506         ### TODO: move to UserDCC again.
507         if ($cmd eq "chanset" and !defined $what) {
508             &DEBUG("showing channel conf.");
509
510             foreach $chan ($chan, "_default") {
511                 &pSReply("chan: $chan");
512                 ### TODO: merge 2 or 3 per line.
513                 my @items;
514                 my $str = "";
515                 foreach (sort keys %{ $chanconf{$chan} }) {
516                     my $newstr = join(', ', @items);
517                     if (length $newstr > 60) {
518                         &pSReply("    $str");
519                         @items = ();
520                     }
521                     $str = $newstr;
522                     push(@items, "$_ => $chanconf{$chan}{$_}");
523                 }
524                 &pSReply("    $str") if (@items);
525             }
526             return;
527         }
528
529         foreach (@chans) {
530             &chanSet($cmd, $_, $what, $val);
531         }
532
533         return;
534     }
535
536     if ($message =~ /^(chanunset|\-chan)(\s+(.*))?$/) {
537         return unless (&hasFlag("m"));
538         my $args        = $3;
539         my $no_chan     = 0;
540
541         if (!defined $args) {
542             &help("chanunset");
543             return;
544         }
545
546         my ($chan);
547         my $delete      = 0;
548         if ($args =~ s/^(\-)?($mask{chan})\s*//) {
549             $chan       = $2;
550             $delete     = ($1) ? 1 : 0;
551             &DEBUG("chan => $chan.");
552         } else {
553             &VERB("no chan arg; setting to default.",2);
554             $chan       = "_default";
555             $no_chan    = 1;
556         }
557
558         if (!exists $chanconf{$chan}) {
559             &pSReply("no such channel $chan");
560             return;
561         }
562
563         if ($args ne "") {
564
565             if (!&getChanConf($args,$chan)) {
566                 &pSReply("$args does not exist for $chan");
567                 return;
568             }
569
570             my @chans = &ChanConfList($args);
571             &DEBUG("scalar chans => ".scalar(@chans) );
572             if (scalar @chans == 1 and $chans[0] eq "_default" and !$no_chan) {
573                 &psReply("ok, $args was set only for _default; unsetting for _defaul but setting for other chans.");
574
575                 my $val = $chanconf{$_}{_default};
576                 foreach (keys %chanconf) {
577                     $chanconf{$_}{$args} = $val;
578                 }
579                 delete $chanconf{_default}{$args};
580
581                 return;
582             }
583
584             if ($no_chan and !exists($chanconf{_default}{$args})) {
585                 &pSReply("ok, $args for _default does not exist, removing from all chans.");
586
587                 foreach (keys %chanconf) {
588                     next unless (exists $chanconf{$_}{$args});
589                     &DEBUG("delete chanconf{$_}{$args};");
590                     delete $chanconf{$_}{$args};
591                 }
592
593                 return;
594             }
595
596             &pSReply("Unsetting channel ($chan) option $args. (was $chanconf{$chan}{$args})");
597             delete $chanconf{$chan}{$args};
598
599             return;
600         }
601
602         if ($delete) {
603             &pSReply("Deleting channel $chan for sure!");
604             $utime_chanfile = time();
605             $ucount_chanfile++;
606
607             &part($chan);
608             &pSReply("Leaving $chan...");
609
610             delete $chanconf{$chan};
611         } else {
612             &pSReply("Prefix channel with '-' to delete for sure.");
613         }
614
615         return;
616     }
617
618     if ($message =~ /^newpass(\s+(.*))?$/) {
619         my(@args) = split /[\s\t]+/, $2 || '';
620
621         if (scalar @args != 1) {
622             &help("newpass");
623             return;
624         }
625
626         my $u = &getUser($who);
627
628         my $salt = join '',('.','/',0..9,'A'..'Z','a'..'z')[rand 64, rand 64];
629         my $crypt = crypt($args[0], $salt);
630         &pSReply("Set your passwd to '$crypt'");
631         $users{$u}{PASS} = $crypt;
632
633         $utime_userfile = time();
634         $ucount_userfile++;
635
636         return;
637     }
638
639     if ($message =~ /^chpass(\s+(.*))?$/) {
640         my(@args) = split /[\s\t]+/, $2 || '';
641
642         if (!scalar @args) {
643             &help("chpass");
644             return;
645         }
646
647         if (!&IsUser($args[0])) {
648             &pSReply("user $args[0] is not valid.");
649             return;
650         }
651
652         my $u = &getUser($args[0]);
653         if (!defined $u) {
654             &pSReply("Internal error, u = NULL.");
655             return;
656         }
657
658         if (scalar @args == 1) {        # del pass.
659             if (!&IsFlag("m") and $who !~ /^\Q$verifyUser\E$/i) {
660                 &pSReply("cannto remove passwd of others.");
661                 return;
662             }
663
664             if (!exists $users{$u}{PASS}) {
665                 &pSReply("$u does not have pass set anyway.");
666                 return;
667             }
668
669             &pSReply("Deleted pass from $u.");
670
671             $utime_userfile = time();
672             $ucount_userfile++;
673
674             delete $users{$u}{PASS};
675
676             return;
677         }
678
679         my $salt = join '',('.','/',0..9,'A'..'Z','a'..'z')[rand 64, rand 64];
680         my $crypt = crypt($args[1], $salt);
681         &pSReply("Set $u's passwd to '$crypt'");
682         $users{$u}{PASS} = $crypt;
683
684         $utime_userfile = time();
685         $ucount_userfile++;
686
687         return;
688     }
689
690     if ($message =~ /^chattr(\s+(.*))?$/) {
691         my(@args) = split /[\s\t]+/, $2 || '';
692
693         if (!scalar @args) {
694             &help("chattr");
695             return;
696         }
697
698         my $user;
699         if ($args[0] =~ /^$mask{nick}$/i) {     # <nick>
700             $user       = &getUser($args[0]);
701             $chflag     = $args[1];
702         } else {                                # <flags>
703             $user       = &getUser($who);
704             &DEBUG("user $who... nope.") unless (defined $user);
705             $user       = &getUser($verifyUser);
706             $chflag     = $args[0];
707         }
708
709         if (!defined $user) {
710             &pSReply("user $user does not exist.");
711             return;
712         }
713
714         my $flags = $users{$user}{FLAGS};
715         if (!defined $chflag) {
716             &pSReply("Flags for $user: $flags");
717             return;
718         }
719
720         &DEBUG("who => $who");
721         &DEBUG("verifyUser => $verifyUser");
722         if (!&IsFlag("m") and $who !~ /^\Q$verifyUser\E$/i) {
723             &pSReply("cannto change attributes of others.");
724             return "REPLY";
725         }
726
727         my $state;
728         my $change      = 0;
729         foreach (split //, $chflag) {
730             if ($_ eq "+") { $state = 1; next; }
731             if ($_ eq "-") { $state = 0; next; }
732
733             if (!defined $state) {
734                 &pSReply("no initial + or - was found in attr.");
735                 return;
736             }
737
738             if ($state) {
739                 next if ($flags =~ /\Q$_\E/);
740                 $flags .= $_;
741             } else {
742                 if (&IsParam("owner")
743                         and $param{owner} =~ /^\Q$user\E$/i
744                         and $flags =~ /[nmo]/
745                 ) {
746                     &pSReply("not removing flag $_ for $user.");
747                     next;
748                 }
749                 next unless ($flags =~ s/\Q$_\E//);
750             }
751
752             $change++;
753         }
754
755         if ($change) {
756             $utime_userfile = time();
757             $ucount_userfile++;
758             &pSReply("Current flags: $flags");
759             $users{$user}{FLAGS} = $flags;
760         } else {
761             &pSReply("No flags changed: $flags");
762         }
763
764         return;
765     }
766
767     if ($message =~ /^chnick(\s+(.*))?$/) {
768         my(@args) = split /[\s\t]+/, $2 || '';
769
770         if ($who eq "_default") {
771             &WARN("$who or verifyuser tried to run chnick.");
772             return "REPLY";
773         }
774
775         if (!scalar @args or scalar @args > 2) {
776             &help("chnick");
777             return;
778         }
779
780         if (scalar @args == 1) {        # 1
781             $user       = &getUser($who);
782             &DEBUG("nope, not $who.") unless (defined $user);
783             $user       ||= &getUser($verifyUser);
784             $chnick     = $args[0];
785         } else {                        # 2
786             $user       = &getUser($args[0]);
787             $chnick     = $args[1];
788         }
789
790         if (!defined $user) {
791             &pSReply("user $who or $args[0] does not exist.");
792             return;
793         }
794
795         if ($user =~ /^\Q$chnick\E$/i) {
796             &pSReply("user == chnick. why should I do that?");
797             return;
798         }
799
800         if (&getUser($chnick)) {
801             &pSReply("user $chnick is already used!");
802             return;
803         }
804
805         if (!&IsFlag("m") and $who !~ /^\Q$verifyUser\E$/i) {
806             &pSReply("cannto change nick of others.");
807             return "REPLY" if ($who eq "_default");
808             return;
809         }
810
811         foreach (keys %{ $users{$user} }) {
812             $users{$chnick}{$_} = $users{$user}{$_};
813             delete $users{$user}{$_};
814         }
815         undef $users{$user};    # ???
816
817         $utime_userfile = time();
818         $ucount_userfile++;
819
820         &pSReply("Changed '$user' to '$chnick' successfully.");
821
822         return;
823     }
824
825     if ($message =~ /^([-+])host(\s+(.*))?$/) {
826         my $cmd         = $1."host";
827         my(@args)       = split /[\s\t]+/, $3 || '';
828         my $state       = ($1 eq "+") ? 1 : 0;
829
830         if (!scalar @args) {
831             &help($cmd);
832             return;
833         }
834
835         if ($who eq "_default") {
836             &WARN("$who or verifyuser tried to run $cmd.");
837             return "REPLY";
838         }
839
840         my ($user,$mask);
841         if ($args[0] =~ /^$mask{nick}$/i) {     # <nick>
842             return unless (&hasFlag("m"));
843             $user       = &getUser($args[0]);
844             $mask       = $args[1];
845         } else {                                # <mask>
846             # who or verifyUser. FIXME!!!
847             $user       = &getUser($who);
848             $mask       = $args[0];
849         }
850
851         if (!defined $user) {
852             &pSReply("user $user does not exist.");
853             return;
854         }
855
856         if (!defined $mask) {
857             ### FIXME.
858             &pSReply("Hostmasks for $user: $users{$user}{HOSTS}");
859
860             return;
861         }
862
863         if (!&IsFlag("m") and $who !~ /^\Q$verifyUser\E$/i) {
864             &pSReply("cannto change masks of others.");
865             return;
866         }
867
868         if ($mask !~ /^$mask{nuh}$/) {
869             &pSReply("error: mask ($mask) is not a real hostmask.");
870             return;
871         }
872
873         my $count = scalar keys %{ $users{$user}{HOSTS} };
874
875         if ($state) {                           # add.
876             if (exists $users{$user}{HOSTS}{$mask}) {
877                 &pSReply("mask $mask already exists.");
878                 return;
879             }
880
881             ### TODO: override support.
882             $users{$user}{HOSTS}{$mask} = 1;
883
884             &pSReply("Added $mask to list of masks.");
885
886         } else {                                # delete.
887
888             if (!exists $users{$user}{HOSTS}{$mask}) {
889                 &pSReply("mask $mask does not exist.");
890                 return;
891             }
892
893             ### TODO: wildcard support. ?
894             delete $users{$user}{HOSTS}{$mask};
895
896             if (scalar keys %{ $users{$user}{HOSTS} } != $count) {
897                 &pSReply("Removed $mask from list of masks.");
898             } else {
899                 &pSReply("error: could not find $mask in list of masks.");
900                 return;
901             }
902         }
903
904         $utime_userfile = time();
905         $ucount_userfile++;
906
907         return;
908     }
909
910     if ($message =~ /^([-+])ban(\s+(.*))?$/) {
911         my $cmd         = $1."ban";
912         my $flatarg     = $3;
913         my(@args)       = split /[\s\t]+/, $3 || '';
914         my $state       = ($1 eq "+") ? 1 : 0;
915
916         if (!scalar @args) {
917             &help($cmd);
918             return;
919         }
920
921         my($mask,$chan,$time,$reason);
922
923         if ($flatarg =~ s/^($mask{nuh})\s*//) {
924             $mask = $1;
925         } else {
926             &DEBUG("arg does not contain nuh mask?");
927         }
928
929         if ($flatarg =~ s/^($mask{chan})\s*//) {
930             $chan = $1;
931         } else {
932             $chan = "*";        # _default instead?
933         }
934
935         if ($state == 0) {              # delete.
936             my @c = &banDel($mask);
937
938             foreach (@c) {
939                 &unban($mask, $_);
940             }
941
942             if ($c) {
943                 &pSReply("Removed $mask from chans: @c");
944             } else {
945                 &pSReply("$mask was not found in ban list.");
946             }
947
948             return;
949         }
950
951         ###
952         # add ban.
953         ###
954
955         # time.
956         if ($flatarg =~ s/^(\d+)\s*//) {
957             $time = $1;
958             &DEBUG("time = $time.");
959             if ($time < 0) {
960                 &pSReply("error: time cannot be negatime?");
961                 return;
962             }
963         } else {
964             $time = 0;
965         }
966
967         if ($flatarg =~ s/^(.*)$//) {   # need length?
968             $reason     = $1;
969         }
970
971         if (!&IsFlag("m") and $who !~ /^\Q$verifyUser\E$/i) {
972             &pSReply("cannto change masks of others.");
973             return;
974         }
975
976         if ($mask !~ /^$mask{nuh}$/) {
977             &pSReply("error: mask ($mask) is not a real hostmask.");
978             return;
979         }
980
981         if ( &banAdd($mask,$chan,$time,$reason) == 2) {
982             &pSReply("ban already exists; overwriting.");
983         }
984         &pSReply("Added $mask for $chan (time => $time, reason => $reason)");
985
986         return;
987     }
988
989     if ($message =~ /^whois(\s+(.*))?$/) {
990         my $arg = $2;
991
992         if (!defined $arg) {
993             &help("whois");
994             return;
995         }
996
997         my $user = &getUser($arg);
998         if (!defined $user) {
999             &pSReply("whois: user $user does not exist.");
1000             return;
1001         }
1002
1003         ### TODO: better (eggdrop-like) output.
1004         &pSReply("user: $user");
1005         foreach (keys %{ $users{$user} }) {
1006             my $ref = ref $users{$user}{$_};
1007
1008             if ($ref eq "HASH") {
1009                 my $type = $_;
1010                 ### DOES NOT WORK???
1011                 foreach (keys %{ $users{$user}{$type} }) {
1012                     &pSReply("    $type => $_");
1013                 }
1014                 next;
1015             }
1016
1017             &pSReply("    $_ => $users{$user}{$_}");
1018         }
1019         &pSReply("End of USER whois.");
1020
1021         return;
1022     }
1023
1024     if ($message =~ /^bans(\s+(.*))?$/) {
1025         my $arg = $2;
1026
1027         if (defined $arg) {
1028             if ($arg ne "_default" and !&validChan($arg) ) {
1029                 &pSReply("error: chan $chan is invalid.");
1030                 return;
1031             }
1032         }
1033
1034         if (!scalar keys %bans) {
1035             &pSReply("Ban list is empty.");
1036             return;
1037         }
1038
1039         my $c;
1040         &pSReply("     mask: expire, time-added, count, who-by, reason");
1041         foreach $c (keys %bans) {
1042             next unless (!defined $arg or $arg =~ /^\Q$c\E$/i);
1043             &pSReply("  $c:");
1044
1045             foreach (keys %{ $bans{$c} }) {
1046                 my $val = $bans{$c}{$_};
1047
1048                 if (ref $val eq "ARRAY") {
1049                     my @array = @{ $val };
1050                     &pSReply("    $_: @array");
1051                 } else {
1052                     &DEBUG("unknown ban: $val");
1053                 }
1054             }
1055         }
1056         &pSReply("END of bans.");
1057
1058         return;
1059     }
1060
1061     if ($message =~ /^banlist(\s+(.*))?$/) {
1062         my $arg = $2;
1063
1064         if (defined $arg and $arg !~ /^$mask_chan$/) {
1065             &pSReply("error: chan $chan is invalid.");
1066             return;
1067         }
1068
1069         &DEBUG("bans for global or arg => $arg.");
1070         foreach (keys %bans) {                  #CHANGE!!!
1071             &DEBUG("  $_ => $bans{$_}.");
1072         }
1073
1074         &DEBUG("End of bans.");
1075         &pSReply("END of bans.");
1076
1077         return;
1078     }
1079
1080     if ($message =~ /^save$/) {
1081         return unless (&hasFlag("o"));
1082
1083         &writeUserFile();
1084         &writeChanFile();
1085
1086         return;
1087     }
1088
1089     ### ALIASES.
1090     $message =~ s/^addignore/+ignore/;
1091     $message =~ s/^(del|un)ignore/-ignore/;
1092
1093     # ignore.
1094     if ($message =~ /^(\+|\-)ignore(\s+(.*))?$/i) {
1095         return unless (&hasFlag("o"));
1096         my $state       = ($1 eq "+") ? 1 : 0;
1097         my $str         = $1."ignore";
1098         my $args        = $3;
1099
1100         if (!$args) {
1101             &help($str);
1102             return;
1103         }
1104
1105         my($mask,$chan,$time,$comment);
1106
1107         # mask.
1108         if ($args =~ s/^($mask{nuh})\s*//) {
1109             $mask = $1;
1110         } else {
1111             &ERROR("no NUH mask?");
1112             return;
1113         }
1114
1115         if (!$state) {                  # delignore.
1116             if ( &ignoreDel($mask) ) {
1117                 &pSReply("ok, deleted X ignores.");
1118             } else {
1119                 &pSReply("could not find $mask in ignore list.");
1120             }
1121             return;
1122         }
1123
1124         ###
1125         # addignore.
1126         ###
1127
1128         # chan.
1129         if ($args =~ s/^($mask{chan}|\*)\s*//) {
1130             $chan = $1;
1131         } else {
1132             $chan = "*";
1133         }
1134
1135         # time.
1136         if ($args =~ s/^(\d+)\s*//) {
1137             $time = $1*60;      # ??
1138         } else {
1139             $time = 0;
1140         }
1141
1142         # time.
1143         if ($args) {
1144             $comment = $args;
1145         } else {
1146             $comment = "added by $who";
1147         }
1148
1149         if ( &ignoreAdd($mask, $chan, $time, $comment) > 1) {
1150             &pSReply("warn: $mask already in ignore list; written over anyway. FIXME");
1151         } else {
1152             &pSReply("added $mask to ignore list.");
1153         }
1154
1155         return;
1156     }
1157
1158     if ($message =~ /^ignore(\s+(.*))?$/) {
1159         my $arg = $2;
1160
1161         if (defined $arg) {
1162             if ($arg !~ /^$mask{chan}$/) {
1163                 &pSReply("error: chan $chan is invalid.");
1164                 return;
1165             }
1166
1167             if (!&validChan($arg)) {
1168                 &pSReply("error: chan $arg is invalid.");
1169                 return;
1170             }
1171
1172             &pSReply("Showing bans for $arg only.");
1173         }
1174
1175         if (!scalar keys %ignore) {
1176             &pSReply("Ignore list is empty.");
1177             return;
1178         }
1179
1180         ### TODO: proper (eggdrop-like) formatting.
1181         my $c;
1182         &pSReply("    mask: expire, time-added, who, comment");
1183         foreach $c (keys %ignore) {
1184             next unless (!defined $arg or $arg =~ /^\Q$c\E$/i);
1185             &pSReply("  $c:");
1186
1187             foreach (keys %{ $ignore{$c} }) {
1188                 my $ref = ref $ignore{$c}{$_};
1189                 if ($ref eq "ARRAY") {
1190                     my @array = @{ $ignore{$c}{$_} };
1191                     &pSReply("      $_: @array");
1192                 } else {
1193                     &DEBUG("unknown ignore line?");
1194                 }
1195             }
1196         }
1197         &pSReply("END of ignore.");
1198
1199         return;
1200     }
1201
1202     # adduser/deluser.
1203     if ($message =~ /^(\+|\-|add|del)user(\s+(.*))?$/i) {
1204         my $str         = $1;
1205         my $strstr      = $1."user";
1206         my @args        = split /\s+/, $3 || '';
1207         my $args        = $3;
1208         my $state       = ($str =~ /^(\+|add)$/) ? 1 : 0;
1209
1210         if (!scalar @args) {
1211             &help($strstr);
1212             return;
1213         }
1214
1215         if ($str eq "+") {
1216             if (scalar @args != 2) {
1217                 &pSReply(".+host requires hostmask argument.");
1218                 return;
1219             }
1220         } elsif (scalar @args != 1) {
1221             &pSReply("too many arguments.");
1222             return;
1223         }
1224
1225         if ($state) {                   # adduser.
1226             if (scalar @args == 1) {
1227                 $args[1]        = &getHostMask($args[0]);
1228                 if (!defined $args[1]) {
1229                     &ERROR("could not get hostmask?");
1230                     return;
1231                 }
1232             }
1233
1234             if ( &userAdd(@args) ) {    # success.
1235                 &pSReply("Added $args[0]...");
1236
1237             } else {                    # failure.
1238                 &pSReply("User $args[0] already exists");
1239             }
1240
1241         } else {                        # deluser.
1242
1243             if ( &userDel($args[0]) ) { # success.
1244                 &pSReply("Deleted $args[0] successfully.");
1245
1246             } else {                    # failure.
1247                 &pSReply("User $args[0] does not exist.");
1248             }
1249
1250         }
1251         return;
1252     }
1253
1254     if ($message =~ /^sched$/) {
1255         my @list;
1256         my @run;
1257
1258         my %time;
1259         foreach (keys %sched) {
1260             next unless (exists $sched{$_}{TIME});
1261             $time{ $sched{$_}{TIME}-time() }{$_} = 1;
1262             push(@list,$_);
1263
1264             next unless (exists $sched{$_}{RUNNING});
1265             push(@run,$_);
1266         }
1267
1268         my @time;
1269         foreach (sort { $a <=> $b } keys %time) {
1270             my $str = join(", ", sort keys %{ $time{$_} });
1271             &DEBUG("time => $_, str => $str");
1272             push(@time, "$str (".&Time2String($_).")");
1273         }
1274
1275         &pSReply( &formListReply(0, "Schedulers: ", @time ) );
1276         &pSReply( &formListReply(0, "Scheds to run: ", sort @list ) );
1277         &pSReply( &formListReply(0, "Scheds running(should not happen?) ", sort @run ) );
1278
1279         return;
1280     }
1281
1282     return "REPLY";
1283 }
1284
1285 1;