2 # UserDCC.pl: User Commands, DCC CHAT.
4 # Version: v0.2 (20010119)
5 # Created: 20000707 (from UserExtra.pl)
10 use vars qw(%users %ignore %sched %bans %mask %cache %channels %param
12 use vars qw($who $chan $message $msgType $user $chnick $conn $ident
13 $verifyUser $ucount_userfile $utime_userfile $lobotomized
14 $utime_chanfile $ucount_chanfile);
15 use vars qw(@backlog);
23 if ($message =~ /^(exit|quit)$/i) {
24 # do ircII clients support remote close? if so, cool!
25 &FIXME("userDCC: quit called.");
27 &status("userDCC: after dcc_close!");
33 if ($message =~ /^who$/) {
34 my $count = scalar(keys %{ $dcc{'CHAT'} });
35 my $dccCHAT = $message;
37 &performStrictReply("Start of who ($count users).");
38 foreach (keys %{ $dcc{'CHAT'} }) {
39 &performStrictReply("=> $_");
41 &performStrictReply("End of who.");
46 ### for those users with enough flags.
48 if ($message =~ /^tellme(\s+(.*))?$/i) {
50 if ($args =~ /^\s*$/) {
55 my $result = &doQuestion($args);
56 &performStrictReply($result);
62 if ($message =~ /^4op(\s+($mask{chan}))?$/i) {
63 return unless (&hasFlag("o"));
72 if (!$channels{$chan}{'o'}{$ident}) {
73 &msg($who, "i don't have ops on $chan to do that.");
77 # on non-4mode(<4) servers, this may be exploited.
78 if ($channels{$chan}{'o'}{$who}) {
79 rawout("MODE $chan -o+o-o+o". (" $who" x 4));
81 rawout("MODE $chan +o-o+o-o". (" $who" x 4));
88 if ($message =~ /^opme(\s+($mask{chan}))?$/i) {
89 return unless (&hasFlag("o"));
90 return unless (&hasFlag("A"));
99 # can this be exploited?
100 rawout("MODE $chan +o $who");
106 if ($message =~ /^backlog(\s+(.*))?$/i) {
107 return unless (&hasFlag("o"));
108 return unless (&IsParam("backlog"));
110 my $max = $param{'backlog'};
115 } elsif ($num !~ /^\d+/) {
116 &msg($who, "error: argument is not positive integer.");
118 } elsif ($num > $max or $num < 0) {
119 &msg($who, "error: argument is out of range (max $max).");
123 &msg($who, "Start of backlog...");
125 sleep 1 if ($_ % 4 == 0 and $_ != 0);
126 $conn->privmsg($who, "[".($_+1)."]: $backlog[$max-$num+$_]");
128 &msg($who, "End of backlog.");
134 if ($message =~ /^dumpvars$/i) {
135 return unless (&hasFlag("o"));
136 return unless (&IsParam("DumpVars"));
138 &status("Dumping all variables...");
145 if ($message =~ /^symdump$/i) {
146 return unless (&hasFlag('o'));
147 return unless (&IsParam('DumpVars2'));
149 &status("Dumping all variables...");
156 if ($message =~ /^kick(\s+(.*?))$/) {
157 return unless (&hasFlag("o"));
165 my @args = split(/\s+/, $arg);
166 my ($nick,$chan,$reason) = @args;
168 if (&validChan($chan) == 0) {
169 &msg($who,"error: invalid channel \002$chan\002");
173 if (&IsNickInChan($nick,$chan) == 0) {
174 &msg($who,"$nick is not in $chan.");
178 &kick($nick,$chan,$reason);
184 if ($message =~ /^mode(\s+(.*))?$/) {
185 return unless (&hasFlag("n"));
186 my ($chan,$mode) = split /\s+/,$2,2;
193 if (&validChan($chan) == 0) {
194 &msg($who,"error: invalid channel \002$chan\002");
198 if (!$channels{$chan}{o}{$ident}) {
199 &msg($who,"error: don't have ops on \002$chan\002");
209 if ($message =~ /^part(\s+(\S+))?$/i) {
210 return unless (&hasFlag("o"));
213 if ($jchan !~ /^$mask{chan}$/) {
214 &msg($who, "error, invalid chan.");
219 if (!&validChan($jchan)) {
220 &msg($who, "error, I'm not on that chan.");
224 &msg($jchan, "Leaving. (courtesy of $who).");
229 # lobotomy. sometimes we want the bot to be _QUIET_.
230 if ($message =~ /^(lobotomy|bequiet)$/i) {
231 return unless (&hasFlag("o"));
234 &performReply("i'm already lobotomized");
236 &performReply("i have been lobotomized");
244 if ($message =~ /^(unlobotomy|benoisy)$/i) {
245 return unless (&hasFlag("o"));
248 &performReply("i have been unlobotomized, woohoo");
250 delete $cache{lobotomy};
251 # undef $cache{lobotomy}; # ??
253 &performReply("i'm not lobotomized");
260 if ($message =~ /^op(\s+(.*))?$/i) {
261 return unless (&hasFlag("o"));
266 if ($opee =~ /^(\S+)\s+(\S+)$/) {
269 if (!&validChan($2)) {
270 &msg($who,"error: invalid chan ($2).");
274 &msg($who,"error: invalid params.");
278 @chans = keys %channels;
284 next unless (&IsNickInChan($opee,$_));
286 if ($channels{$_}{'o'}{$opee}) {
287 &performStrictReply("op: $opee already has ops on $_");
292 &performStrictReply("opping $opee on $_");
297 &performStrictReply("op: opped on all possible channels.");
299 &DEBUG("op: found => '$found'.");
300 &DEBUG("op: op => '$op'.");
307 if ($message =~ /^deop(\s+(.*))?$/i) {
308 return unless (&hasFlag("o"));
313 if ($opee =~ /^(\S+)\s+(\S+)$/) {
316 if (!&validChan($2)) {
317 &msg($who,"error: invalid chan ($2).");
321 &msg($who,"error: invalid params.");
325 @chans = keys %channels;
331 next unless (&IsNickInChan($opee,$_));
333 if (!exists $channels{$_}{'o'}{$opee}) {
334 &status("deop: $opee already has no ops on $_");
339 &status("deopping $opee on $_ at ${who}'s request");
344 &status("deop: deopped on all possible channels.");
346 &DEBUG("deop: found => '$found'.");
347 &DEBUG("deop: op => '$op'.");
354 if ($message =~ s/^say\s+(\S+)\s+(.*)//) {
355 return unless (&hasFlag("o"));
356 my ($chan,$msg) = (lc $1, $2);
358 &DEBUG("chan => '$1', msg => '$msg'.");
360 # TODO: add nick destination.
361 if (&validChan($chan)) {
364 &msg($who,"i'm not on \002$chan\002, sorry.");
371 if ($message =~ s/^do\s+(\S+)\s+(.*)//) {
372 return unless (&hasFlag("o"));
373 my ($chan,$msg) = (lc $1, $2);
375 &DEBUG("chan => '$1', msg => '$msg'.");
377 # TODO: add nick destination.
378 if (&validChan($chan)) {
379 &action($chan, $msg);
381 &msg($who,"i'm not on \002$chan\002, sorry.");
388 if ($message =~ /^die$/) {
389 return unless (&hasFlag("n"));
393 &status("Dying by $who\'s request");
397 # global factoid substitution.
398 if ($message =~ m|^s([/,#])(.+?)\1(.*?)\1;?\s*$|) {
399 my ($delim,$op,$np) = ($1, $2, $3);
400 return unless (&hasFlag("n"));
401 ### TODO: support flags to do full-on global.
404 if ($np =~ /$delim/) {
405 &performReply("looks like you used the delimiter too many times. You may want to use a different delimiter, like ':' or '#'.");
409 ### TODO: fix up $op to support mysql/sqlite/pgsql
410 ### TODO: => add db/sql specific function to fix this.
411 my @list = &searchTable("factoids", "factoid_key",
412 "factoid_value", $op);
415 &performReply("Expression didn't match anything.");
419 if (scalar @list > 100) {
420 &performReply("regex found more than 100 matches... not doing.");
424 &status("gsubst: going to alter ".scalar(@list)." factoids.");
425 &performReply("going to alter ".scalar(@list)." factoids.");
431 next if (&IsLocked($faqtoid) == 1);
432 my $result = &getFactoid($faqtoid);
434 &DEBUG("was($faqtoid) => '$was'.");
437 # we could support global local (once off).
438 if ($result =~ s/\Q$op/$np/gi) {
439 if (length $result > $param{'maxDataSize'}) {
440 &performReply("that's too long (or was long)");
443 &setFactInfo($faqtoid, "factoid_value", $result);
444 &status("update: '$faqtoid' =is=> '$result'; was '$was'");
446 &WARN("subst: that's weird... thought we found the string ($op) in '$faqtoid'.");
452 &ERROR("Some warnings/errors?");
455 &performReply("Ok... did s/$op/$np/ for ".
456 (scalar(@list) - $error)." factoids");
462 if ($message =~ /^jump(\s+(\S+))?$/i) {
463 return unless (&hasFlag("n"));
471 if ($2 =~ /^(\S+)(:(\d+))?$/) {
475 &msg($who,"invalid format.");
479 &status("jumping servers... $server...");
480 $conn->quit("jumping to $server");
482 if (&irc($server,$port) == 0) {
488 if ($message =~ /^reload$/i) {
489 return unless (&hasFlag("n"));
491 &status("USER reload $who");
492 &performStrictReply("reloading...");
494 &performStrictReply("reloaded.");
500 if ($message =~ /^reset$/i) {
501 return unless (&hasFlag("n"));
503 &msg($who,"resetting...");
505 foreach ( keys %channels, keys %chanconf ) {
507 next if (grep /^\Q$c\E$/i, @done);
514 &DEBUG("before clearircvars");
516 &DEBUG("before joinnextchan");
518 &DEBUG("after joinnextchan");
520 &status("USER reset $who");
521 &msg($who,"reset complete");
527 if ($message =~ /^rehash$/) {
528 return unless (&hasFlag("n"));
530 &msg($who,"rehashing...");
532 &status("USER rehash $who");
533 &msg($who,"rehashed");
539 ##### USER//CHAN SPECIFIC CONFIGURATION COMMANDS
542 if ($message =~ /^chaninfo(\s+(.*))?$/) {
543 my @args = split /[\s\t]+/, $2; # hrm.
545 if (scalar @args != 1) {
550 if (!exists $chanconf{$args[0]}) {
551 &performStrictReply("no such channel $args[0]");
555 &performStrictReply("showing channel conf.");
556 foreach (sort keys %{ $chanconf{$args[0]} }) {
557 &performStrictReply("$chan: $_ => $chanconf{$args[0]}{$_}");
559 &performStrictReply("End of chaninfo.");
565 if ($message =~ /^(chanset|\+chan)(\s+(.*?))?$/) {
570 if (!defined $args) {
576 while ($args =~ s/^($mask{chan})\s*//) {
577 push(@chans, lc($1));
580 if (!scalar @chans) {
581 push(@chans, "_default");
585 my($what,$val) = split /[\s\t]+/, $args, 2;
587 ### TODO: "cannot set values without +m".
588 return unless (&hasFlag("n"));
591 if (defined $what and $what !~ /^[-+]/ and !defined $val and $no_chan) {
592 &performStrictReply("Showing $what values on all channels...");
595 foreach (keys %chanconf) {
597 if (defined $chanconf{$_}{$what}) {
598 $val = $chanconf{$_}{$what};
605 foreach (keys %vals) {
606 &performStrictReply(" $what = $_(" . scalar(keys %{$vals{$_}}) . "): ".join(' ', sort keys %{ $vals{$_} } ) );
609 &performStrictReply("End of list.");
614 ### TODO: move to UserDCC again.
615 if ($cmd eq "chanset" and !defined $what) {
616 &DEBUG("showing channel conf.");
618 foreach $chan (@chans) {
619 if ($chan eq '_default') {
620 &performStrictReply("Default channel settings");
622 &performStrictReply("chan: $chan (see _default also)");
626 foreach (sort keys %{ $chanconf{$chan} }) {
627 my $newstr = join(', ', @items);
628 ### TODO: make length use channel line limit?
629 if (length $newstr > 370) {
630 &performStrictReply(" $str");
634 push(@items, "$_ => $chanconf{$chan}{$_}");
636 &performStrictReply(" $str") if (@items);
641 $cache{confvars}{$what} = $val;
645 &chanSet($cmd, $_, $what, $val);
651 if ($message =~ /^(chanunset|\-chan)(\s+(.*))?$/) {
652 return unless (&hasFlag("n"));
656 if (!defined $args) {
663 if ($args =~ s/^(\-)?($mask{chan})\s*//) {
665 $delete = ($1) ? 1 : 0;
667 &VERB("no chan arg; setting to default.",2);
672 if (!exists $chanconf{$chan}) {
673 &performStrictReply("no such channel $chan");
679 if (!&getChanConf($args,$chan)) {
680 &performStrictReply("$args does not exist for $chan");
684 my @chans = &ChanConfList($args);
685 &DEBUG("scalar chans => ".scalar(@chans) );
686 if (scalar @chans == 1 and $chans[0] eq "_default" and !$no_chan) {
687 &performStrictReply("ok, $args was set only for _default; unsetting for _defaul but setting for other chans.");
689 my $val = $chanconf{$_}{_default};
690 foreach (keys %chanconf) {
691 $chanconf{$_}{$args} = $val;
693 delete $chanconf{_default}{$args};
694 $cache{confvars}{$args} = 0;
700 if ($no_chan and !exists($chanconf{_default}{$args})) {
701 &performStrictReply("ok, $args for _default does not exist, removing from all chans.");
703 foreach (keys %chanconf) {
704 next unless (exists $chanconf{$_}{$args});
705 &DEBUG("delete chanconf{$_}{$args};");
706 delete $chanconf{$_}{$args};
708 $cache{confvars}{$args} = 0;
714 &performStrictReply("Unsetting channel ($chan) option $args. (was $chanconf{$chan}{$args})");
715 delete $chanconf{$chan}{$args};
721 &performStrictReply("Deleting channel $chan for sure!");
722 $utime_chanfile = time();
726 &performStrictReply("Leaving $chan...");
728 delete $chanconf{$chan};
730 &performStrictReply("Prefix channel with '-' to delete for sure.");
736 if ($message =~ /^newpass(\s+(.*))?$/) {
737 my(@args) = split /[\s\t]+/, $2 || '';
739 if (scalar @args != 1) {
744 my $u = &getUser($who);
745 my $crypt = &mkcrypt($args[0]);
747 &performStrictReply("Set your passwd to '$crypt'");
748 $users{$u}{PASS} = $crypt;
750 $utime_userfile = time();
756 if ($message =~ /^chpass(\s+(.*))?$/) {
757 my(@args) = split /[\s\t]+/, $2 || '';
764 if (!&IsUser($args[0])) {
765 &performStrictReply("user $args[0] is not valid.");
769 my $u = &getUser($args[0]);
771 &performStrictReply("Internal error, u = NULL.");
775 if (scalar @args == 1) {
777 if (!&IsFlag("n") and $who !~ /^\Q$verifyUser\E$/i) {
778 &performStrictReply("cannot remove passwd of others.");
782 if (!exists $users{$u}{PASS}) {
783 &performStrictReply("$u does not have pass set anyway.");
787 &performStrictReply("Deleted pass from $u.");
789 $utime_userfile = time();
792 delete $users{$u}{PASS};
797 my $crypt = &mkcrypt($args[1]);
798 &performStrictReply("Set $u's passwd to '$crypt'");
799 $users{$u}{PASS} = $crypt;
801 $utime_userfile = time();
807 if ($message =~ /^chattr(\s+(.*))?$/) {
808 my(@args) = split /[\s\t]+/, $2 || '';
817 if ($args[0] =~ /^$mask{nick}$/i) {
819 $user = &getUser($args[0]);
823 $user = &getUser($who);
824 &DEBUG("user $who... nope.") unless (defined $user);
825 $user = &getUser($verifyUser);
829 if (!defined $user) {
830 &performStrictReply("user does not exist.");
834 my $flags = $users{$user}{FLAGS};
835 if (!defined $chflag) {
836 &performStrictReply("Flags for $user: $flags");
840 &DEBUG("who => $who");
841 &DEBUG("verifyUser => $verifyUser");
842 if (!&IsFlag("n") and $who !~ /^\Q$verifyUser\E$/i) {
843 &performStrictReply("cannto change attributes of others.");
849 foreach (split //, $chflag) {
850 if ($_ eq "+") { $state = 1; next; }
851 if ($_ eq "-") { $state = 0; next; }
853 if (!defined $state) {
854 &performStrictReply("no initial + or - was found in attr.");
859 next if ($flags =~ /\Q$_\E/);
862 if (&IsParam("owner")
863 and $param{owner} =~ /^\Q$user\E$/i
864 and $flags =~ /[nmo]/
866 &performStrictReply("not removing flag $_ for $user.");
869 next unless ($flags =~ s/\Q$_\E//);
876 $utime_userfile = time();
879 $flags = join('', sort split('', $flags));
880 &performStrictReply("Current flags: $flags");
881 $users{$user}{FLAGS} = $flags;
883 &performStrictReply("No flags changed: $flags");
889 if ($message =~ /^chnick(\s+(.*))?$/) {
890 my(@args) = split /[\s\t]+/, $2 || '';
892 if ($who eq "_default") {
893 &WARN("$who or verifyuser tried to run chnick.");
897 if (!scalar @args or scalar @args > 2) {
902 if (scalar @args == 1) { # 1
903 $user = &getUser($who);
904 &DEBUG("nope, not $who.") unless (defined $user);
905 $user ||= &getUser($verifyUser);
908 $user = &getUser($args[0]);
912 if (!defined $user) {
913 &performStrictReply("user $who or $args[0] does not exist.");
917 if ($user =~ /^\Q$chnick\E$/i) {
918 &performStrictReply("user == chnick. why should I do that?");
922 if (&getUser($chnick)) {
923 &performStrictReply("user $chnick is already used!");
927 if (!&IsFlag("n") and $who !~ /^\Q$verifyUser\E$/i) {
928 &performStrictReply("cannto change nick of others.");
929 return "REPLY" if ($who eq "_default");
933 foreach (keys %{ $users{$user} }) {
934 $users{$chnick}{$_} = $users{$user}{$_};
935 delete $users{$user}{$_};
937 undef $users{$user}; # ???
939 $utime_userfile = time();
942 &performStrictReply("Changed '$user' to '$chnick' successfully.");
947 if ($message =~ /^([-+])host(\s+(.*))?$/) {
949 my(@args) = split /[\s\t]+/, $3 || '';
950 my $state = ($1 eq "+") ? 1 : 0;
957 if ($who eq "_default") {
958 &WARN("$who or verifyuser tried to run $cmd.");
963 if ($args[0] =~ /^$mask{nick}$/i) { # <nick>
964 return unless (&hasFlag("n"));
965 $user = &getUser($args[0]);
968 # FIXME: who or verifyUser. (don't remember why)
969 $user = &getUser($who);
973 if (!defined $user) {
974 &performStrictReply("user $user does not exist.");
978 if (!defined $mask) {
979 &performStrictReply("Hostmasks for $user: " . join(" ", keys %{$users{$user}{HOSTS}}));
983 if (!&IsFlag("n") and $who !~ /^\Q$verifyUser\E$/i) {
984 &performStrictReply("cannto change masks of others.");
988 my $count = scalar keys %{ $users{$user}{HOSTS} };
991 if ($mask !~ /^$mask{nuh}$/) {
992 &performStrictReply("error: mask ($mask) is not a real hostmask.");
996 if (exists $users{$user}{HOSTS}{$mask}) {
997 &performStrictReply("mask $mask already exists.");
1001 ### TODO: override support.
1002 $users{$user}{HOSTS}{$mask} = 1;
1004 &performStrictReply("Added $mask to list of masks.");
1008 if (!exists $users{$user}{HOSTS}{$mask}) {
1009 &performStrictReply("mask $mask does not exist.");
1013 ### TODO: wildcard support. ?
1014 delete $users{$user}{HOSTS}{$mask};
1016 if (scalar keys %{ $users{$user}{HOSTS} } != $count) {
1017 &performStrictReply("Removed $mask from list of masks.");
1019 &performStrictReply("error: could not find $mask in list of masks.");
1024 $utime_userfile = time();
1030 if ($message =~ /^([-+])ban(\s+(.*))?$/) {
1033 my(@args) = split /[\s\t]+/, $3 || '';
1034 my $state = ($1 eq "+") ? 1 : 0;
1036 if (!scalar @args) {
1041 my($mask,$chan,$time,$reason);
1043 if ($flatarg =~ s/^($mask{nuh})\s*//) {
1046 &DEBUG("arg does not contain nuh mask?");
1049 if ($flatarg =~ s/^($mask{chan})\s*//) {
1052 $chan = "*"; # _default instead?
1055 if ($state == 0) { # delete.
1056 my @c = &banDel($mask);
1063 &performStrictReply("Removed $mask from chans: @c");
1065 &performStrictReply("$mask was not found in ban list.");
1076 if ($flatarg =~ s/^(\d+)\s*//) {
1078 &DEBUG("time = $time.");
1080 &performStrictReply("error: time cannot be negatime?");
1087 if ($flatarg =~ s/^(.*)$//) { # need length?
1091 if (!&IsFlag("n") and $who !~ /^\Q$verifyUser\E$/i) {
1092 &performStrictReply("cannto change masks of others.");
1096 if ($mask !~ /^$mask{nuh}$/) {
1097 &performStrictReply("error: mask ($mask) is not a real hostmask.");
1101 if ( &banAdd($mask,$chan,$time,$reason) == 2) {
1102 &performStrictReply("ban already exists; overwriting.");
1104 &performStrictReply("Added $mask for $chan (time => $time, reason => $reason)");
1109 if ($message =~ /^whois(\s+(.*))?$/) {
1112 if (!defined $arg) {
1117 my $user = &getUser($arg);
1118 if (!defined $user) {
1119 &performStrictReply("whois: user $user does not exist.");
1123 ### TODO: better (eggdrop-like) output.
1124 &performStrictReply("user: $user");
1125 foreach (keys %{ $users{$user} }) {
1126 my $ref = ref $users{$user}{$_};
1128 if ($ref eq "HASH") {
1130 ### DOES NOT WORK???
1131 foreach (keys %{ $users{$user}{$type} }) {
1132 &performStrictReply(" $type => $_");
1137 &performStrictReply(" $_ => $users{$user}{$_}");
1139 &performStrictReply("End of USER whois.");
1144 if ($message =~ /^bans(\s+(.*))?$/) {
1148 if ($arg ne "_default" and !&validChan($arg) ) {
1149 &performStrictReply("error: chan $chan is invalid.");
1154 if (!scalar keys %bans) {
1155 &performStrictReply("Ban list is empty.");
1160 &performStrictReply(" mask: expire, time-added, count, who-by, reason");
1161 foreach $c (keys %bans) {
1162 next unless (!defined $arg or $arg =~ /^\Q$c\E$/i);
1163 &performStrictReply(" $c:");
1165 foreach (keys %{ $bans{$c} }) {
1166 my $val = $bans{$c}{$_};
1168 if (ref $val eq "ARRAY") {
1169 my @array = @{ $val };
1170 &performStrictReply(" $_: @array");
1172 &DEBUG("unknown ban: $val");
1176 &performStrictReply("END of bans.");
1181 if ($message =~ /^banlist(\s+(.*))?$/) {
1184 if (defined $arg and $arg !~ /^$mask{chan}$/) {
1185 &performStrictReply("error: chan $chan is invalid.");
1189 &DEBUG("bans for global or arg => $arg.");
1190 foreach (keys %bans) { #CHANGE!!!
1191 &DEBUG(" $_ => $bans{$_}.");
1194 &DEBUG("End of bans.");
1195 &performStrictReply("END of bans.");
1200 if ($message =~ /^save$/) {
1201 return unless (&hasFlag("o"));
1205 &performStrictReply("saved user and chan files");
1211 $message =~ s/^addignore/+ignore/;
1212 $message =~ s/^(del|un)ignore/-ignore/;
1215 if ($message =~ /^(\+|\-)ignore(\s+(.*))?$/i) {
1216 return unless (&hasFlag("o"));
1217 my $state = ($1 eq "+") ? 1 : 0;
1218 my $str = $1."ignore";
1226 my($mask,$chan,$time,$comment);
1229 if ($args =~ s/^($mask{nuh})\s*//) {
1232 &ERROR("no NUH mask?");
1236 if (!$state) { # delignore.
1237 if ( &ignoreDel($mask) ) {
1238 &performStrictReply("ok, deleted ignores for $mask.");
1240 &performStrictReply("could not find $mask in ignore list.");
1250 if ($args =~ s/^($mask{chan}|\*)\s*//) {
1257 if ($args =~ s/^(\d+)\s*//) {
1258 $time = $1; # time is in minutes
1267 $comment = "added by $who";
1270 if ( &ignoreAdd($mask, $chan, $time, $comment) > 1) {
1271 &performStrictReply("FIXME: $mask already in ignore list; written over anyway.");
1273 &performStrictReply("added $mask to ignore list.");
1279 if ($message =~ /^ignore(\s+(.*))?$/) {
1283 if ($arg !~ /^$mask{chan}$/) {
1284 &performStrictReply("error: chan $chan is invalid.");
1288 if (!&validChan($arg)) {
1289 &performStrictReply("error: chan $arg is invalid.");
1293 &performStrictReply("Showing bans for $arg only.");
1296 if (!scalar keys %ignore) {
1297 &performStrictReply("Ignore list is empty.");
1301 ### TODO: proper (eggdrop-like) formatting.
1303 &performStrictReply(" mask: expire, time-added, who, comment");
1304 foreach $c (keys %ignore) {
1305 next unless (!defined $arg or $arg =~ /^\Q$c\E$/i);
1306 &performStrictReply(" $c:");
1308 foreach (keys %{ $ignore{$c} }) {
1309 my $ref = ref $ignore{$c}{$_};
1310 if ($ref eq "ARRAY") {
1311 my @array = @{ $ignore{$c}{$_} };
1312 &performStrictReply(" $_: @array");
1314 &DEBUG("unknown ignore line?");
1318 &performStrictReply("END of ignore.");
1324 if ($message =~ /^(add|del)user(\s+(.*))?$/i) {
1326 my $strstr = $1."user";
1327 my @args = split /\s+/, $3 || '';
1329 my $state = ($str =~ /^(add)$/) ? 1 : 0;
1331 if (!scalar @args) {
1336 if ($str eq 'add') {
1337 if (scalar @args != 2) {
1338 &performStrictReply('adduser requires hostmask argument.');
1341 } elsif (scalar @args != 1) {
1342 &performStrictReply('too many arguments.');
1348 if (scalar @args == 1) {
1349 $args[1] = &getHostMask($args[0]);
1350 &performStrictReply("Attemping to guess $args[0]'s hostmask...");
1352 # crude hack... crappy Net::IRC
1353 $conn->schedule(5, sub {
1354 # hopefully this is right.
1355 my $nick = (keys %{ $cache{nuhInfo} })[0];
1356 if (!defined $nick) {
1357 &performStrictReply("couldn't get nuhinfo... adding user without a hostmask.");
1361 my $mask = &makeHostMask( $cache{nuhInfo}{$nick}{NUH} );
1363 if ( &userAdd($nick, $mask) ) {
1365 &performStrictReply("Added $nick with flags $users{$nick}{FLAGS}");
1366 my @hosts = keys %{ $users{$nick}{HOSTS} };
1367 &performStrictReply("hosts: @hosts");
1373 &DEBUG("args => @args");
1374 if ( &userAdd(@args) ) { # success.
1375 &performStrictReply("Added $args[0] with flags $users{$args[0]}{FLAGS}");
1376 my @hosts = keys %{ $users{$args[0]}{HOSTS} };
1377 &performStrictReply("hosts: @hosts");
1380 &performStrictReply("User $args[0] already exists");
1385 if ( &userDel($args[0]) ) { # success.
1386 &performStrictReply("Deleted $args[0] successfully.");
1389 &performStrictReply("User $args[0] does not exist.");
1396 if ($message =~ /^sched$/) {
1401 foreach (keys %sched) {
1402 next unless (exists $sched{$_}{TIME});
1403 $time{ $sched{$_}{TIME}-time() }{$_} = 1;
1406 next unless (exists $sched{$_}{RUNNING});
1411 foreach (sort { $a <=> $b } keys %time) {
1412 my $str = join(", ", sort keys %{ $time{$_} });
1413 &DEBUG("time => $_, str => $str");
1414 push(@time, "$str (".&Time2String($_).")");
1417 &performStrictReply( &formListReply(0, "Schedulers: ", @time ) );
1418 &performStrictReply( &formListReply(0, "Scheds to run: ", sort @list ) );
1419 &performStrictReply( &formListReply(0, "Scheds running(should not happen?) ", sort @run ) );
1424 # quite a cool hack: reply in DCC CHAT.
1425 $msgType = "chat" if (exists $dcc{'CHAT'}{$who});
1428 $done++ if &parseCmdHook($message);
1429 $done++ unless (&Modules());
1432 &DEBUG("running non DCC CHAT command inside DCC CHAT!");