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 &pSReply("Start of who ($count users).");
38 foreach (keys %{ $dcc{'CHAT'} }) {
41 &pSReply("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);
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 =~ /^backlog(\s+(.*))?$/i) {
89 return unless (&hasFlag("o"));
90 return unless (&hasParam("backlog"));
92 my $max = $param{'backlog'};
97 } elsif ($num !~ /^\d+/) {
98 &msg($who, "error: argument is not positive integer.");
100 } elsif ($num > $max or $num < 0) {
101 &msg($who, "error: argument is out of range (max $max).");
105 &msg($who, "Start of backlog...");
107 sleep 1 if ($_ % 4 == 0 and $_ != 0);
108 $conn->privmsg($who, "[".($_+1)."]: $backlog[$max-$num+$_]");
110 &msg($who, "End of backlog.");
116 if ($message =~ /^dumpvars$/i) {
117 return unless (&hasFlag("o"));
118 return unless (&IsParam("dumpvars"));
120 &status("Dumping all variables...");
127 if ($message =~ /^symdump$/i) {
128 return unless (&hasFlag("o"));
129 return unless (&IsParam("symdump"));
131 &status("Dumping all variables...");
138 if ($message =~ /^kick(\s+(.*?))$/) {
139 return unless (&hasFlag("o"));
147 my @args = split(/\s+/, $arg);
148 my ($nick,$chan,$reason) = @args;
150 if (&validChan($chan) == 0) {
151 &msg($who,"error: invalid channel \002$chan\002");
155 if (&IsNickInChan($nick,$chan) == 0) {
156 &msg($who,"$nick is not in $chan.");
160 &kick($nick,$chan,$reason);
166 if ($message =~ /^mode(\s+(.*))?$/) {
167 return unless (&hasFlag("n"));
168 my ($chan,$mode) = split /\s+/,$2,2;
175 if (&validChan($chan) == 0) {
176 &msg($who,"error: invalid channel \002$chan\002");
180 if (!$channels{$chan}{o}{$ident}) {
181 &msg($who,"error: don't have ops on \002$chan\002");
191 if ($message =~ /^part(\s+(\S+))?$/i) {
192 return unless (&hasFlag("o"));
195 if ($jchan !~ /^$mask{chan}$/) {
196 &msg($who, "error, invalid chan.");
201 if (!&validChan($jchan)) {
202 &msg($who, "error, I'm not on that chan.");
206 &msg($jchan, "Leaving. (courtesy of $who).");
211 # lobotomy. sometimes we want the bot to be _QUIET_.
212 if ($message =~ /^(lobotomy|bequiet)$/i) {
213 return unless (&hasFlag("o"));
216 &performReply("i'm already lobotomized");
218 &performReply("i have been lobotomized");
226 if ($message =~ /^(unlobotomy|benoisy)$/i) {
227 return unless (&hasFlag("o"));
230 &performReply("i have been unlobotomized, woohoo");
232 delete $cache{lobotomy};
233 # undef $cache{lobotomy}; # ??
235 &performReply("i'm not lobotomized");
242 if ($message =~ /^op(\s+(.*))?$/i) {
243 return unless (&hasFlag("o"));
248 if ($opee =~ /^(\S+)\s+(\S+)$/) {
251 if (!&validChan($2)) {
252 &msg($who,"error: invalid chan ($2).");
256 &msg($who,"error: invalid params.");
260 @chans = keys %channels;
266 next unless (&IsNickInChan($opee,$_));
268 if ($channels{$_}{'o'}{$opee}) {
269 &pSReply("op: $opee already has ops on $_");
274 &pSReply("opping $opee on $_");
279 &pSReply("op: opped on all possible channels.");
281 &DEBUG("op: found => '$found'.");
282 &DEBUG("op: op => '$op'.");
289 if ($message =~ /^deop(\s+(.*))?$/i) {
290 return unless (&hasFlag("o"));
295 if ($opee =~ /^(\S+)\s+(\S+)$/) {
298 if (!&validChan($2)) {
299 &msg($who,"error: invalid chan ($2).");
303 &msg($who,"error: invalid params.");
307 @chans = keys %channels;
313 next unless (&IsNickInChan($opee,$_));
315 if (!exists $channels{$_}{'o'}{$opee}) {
316 &status("deop: $opee already has no ops on $_");
321 &status("deopping $opee on $_ at ${who}'s request");
326 &status("deop: deopped on all possible channels.");
328 &DEBUG("deop: found => '$found'.");
329 &DEBUG("deop: op => '$op'.");
336 if ($message =~ s/^say\s+(\S+)\s+(.*)//) {
337 return unless (&hasFlag("o"));
338 my ($chan,$msg) = (lc $1, $2);
340 &DEBUG("chan => '$1', msg => '$msg'.");
342 # TODO: add nick destination.
343 if (&validChan($chan)) {
346 &msg($who,"i'm not on \002$chan\002, sorry.");
353 if ($message =~ s/^do\s+(\S+)\s+(.*)//) {
354 return unless (&hasFlag("o"));
355 my ($chan,$msg) = (lc $1, $2);
357 &DEBUG("chan => '$1', msg => '$msg'.");
359 # TODO: add nick destination.
360 if (&validChan($chan)) {
361 &action($chan, $msg);
363 &msg($who,"i'm not on \002$chan\002, sorry.");
370 if ($message =~ /^die$/) {
371 return unless (&hasFlag("n"));
375 &status("Dying by $who\'s request");
379 # global factoid substitution.
380 if ($message =~ m|^s([/,#])(.+?)\1(.*?)\1;?\s*$|) {
381 my ($delim,$op,$np) = ($1, $2, $3);
382 return unless (&hasFlag("n"));
383 ### TODO: support flags to do full-on global.
386 if ($np =~ /$delim/) {
387 &performReply("looks like you used the delimiter too many times. You may want to use a different delimiter, like ':' or '#'.");
391 ### TODO: fix up $op to support mysql/sqlite/pgsql
392 ### TODO: => add db/sql specific function to fix this.
393 my @list = &searchTable("factoids", "factoid_key",
394 "factoid_value", $op);
397 &performReply("Expression didn't match anything.");
401 if (scalar @list > 100) {
402 &performReply("regex found more than 100 matches... not doing.");
406 &status("gsubst: going to alter ".scalar(@list)." factoids.");
407 &performReply("going to alter ".scalar(@list)." factoids.");
413 next if (&IsLocked($faqtoid) == 1);
414 my $result = &getFactoid($faqtoid);
416 &DEBUG("was($faqtoid) => '$was'.");
419 # we could support global local (once off).
420 if ($result =~ s/\Q$op/$np/gi) {
421 if (length $result > $param{'maxDataSize'}) {
422 &performReply("that's too long (or was long)");
425 &setFactInfo($faqtoid, "factoid_value", $result);
426 &status("update: '$faqtoid' =is=> '$result'; was '$was'");
428 &WARN("subst: that's weird... thought we found the string ($op) in '$faqtoid'.");
434 &ERROR("Some warnings/errors?");
437 &performReply("Ok... did s/$op/$np/ for ".
438 (scalar(@list) - $error)." factoids");
444 if ($message =~ /^jump(\s+(\S+))?$/i) {
445 return unless (&hasFlag("n"));
453 if ($2 =~ /^(\S+)(:(\d+))?$/) {
457 &msg($who,"invalid format.");
461 &status("jumping servers... $server...");
462 $conn->quit("jumping to $server");
464 if (&irc($server,$port) == 0) {
470 if ($message =~ /^reload$/i) {
471 return unless (&hasFlag("n"));
473 &status("USER reload $who");
474 &pSReply("reloading...");
476 &pSReply("reloaded.");
482 if ($message =~ /^reset$/i) {
483 return unless (&hasFlag("n"));
485 &msg($who,"resetting...");
487 foreach ( keys %channels, keys %chanconf ) {
489 next if (grep /^\Q$c\E$/i, @done);
496 &DEBUG("before clearircvars");
498 &DEBUG("before joinnextchan");
500 &DEBUG("after joinnextchan");
502 &status("USER reset $who");
503 &msg($who,"reset complete");
509 if ($message =~ /^rehash$/) {
510 return unless (&hasFlag("n"));
512 &msg($who,"rehashing...");
514 &status("USER rehash $who");
515 &msg($who,"rehashed");
521 ##### USER//CHAN SPECIFIC CONFIGURATION COMMANDS
524 if ($message =~ /^chaninfo(\s+(.*))?$/) {
525 my @args = split /[\s\t]+/, $2; # hrm.
527 if (scalar @args != 1) {
532 if (!exists $chanconf{$args[0]}) {
533 &pSReply("no such channel $args[0]");
537 &pSReply("showing channel conf.");
538 foreach (sort keys %{ $chanconf{$args[0]} }) {
539 &pSReply("$chan: $_ => $chanconf{$args[0]}{$_}");
541 &pSReply("End of chaninfo.");
547 if ($message =~ /^(chanset|\+chan)(\s+(.*?))?$/) {
552 if (!defined $args) {
558 while ($args =~ s/^($mask{chan})\s*//) {
559 push(@chans, lc($1));
562 if (!scalar @chans) {
563 push(@chans, "_default");
567 my($what,$val) = split /[\s\t]+/, $args, 2;
569 ### TODO: "cannot set values without +m".
570 return unless (&hasFlag("n"));
573 if (defined $what and $what !~ /^[-+]/ and !defined $val and $no_chan) {
574 &pSReply("Showing $what values on all channels...");
577 foreach (keys %chanconf) {
579 if (defined $chanconf{$_}{$what}) {
580 $val = $chanconf{$_}{$what};
587 foreach (keys %vals) {
588 &pSReply(" $what = $_(" . scalar(keys %{$vals{$_}}) . "): ".join(' ', keys %{ $vals{$_} } ) );
591 &pSReply("End of list.");
596 ### TODO: move to UserDCC again.
597 if ($cmd eq "chanset" and !defined $what) {
598 &DEBUG("showing channel conf.");
600 foreach $chan (@chans) {
601 if ($chan eq '_default') {
602 &pSReply("Default channel settings");
604 &pSReply("chan: $chan (see _default also)");
608 foreach (sort keys %{ $chanconf{$chan} }) {
609 my $newstr = join(', ', @items);
610 ### TODO: make length use channel line limit?
611 if (length $newstr > 370) {
616 push(@items, "$_ => $chanconf{$chan}{$_}");
618 &pSReply(" $str") if (@items);
623 $cache{confvars}{$what} = $val;
627 &chanSet($cmd, $_, $what, $val);
633 if ($message =~ /^(chanunset|\-chan)(\s+(.*))?$/) {
634 return unless (&hasFlag("n"));
638 if (!defined $args) {
645 if ($args =~ s/^(\-)?($mask{chan})\s*//) {
647 $delete = ($1) ? 1 : 0;
649 &VERB("no chan arg; setting to default.",2);
654 if (!exists $chanconf{$chan}) {
655 &pSReply("no such channel $chan");
661 if (!&getChanConf($args,$chan)) {
662 &pSReply("$args does not exist for $chan");
666 my @chans = &ChanConfList($args);
667 &DEBUG("scalar chans => ".scalar(@chans) );
668 if (scalar @chans == 1 and $chans[0] eq "_default" and !$no_chan) {
669 &psReply("ok, $args was set only for _default; unsetting for _defaul but setting for other chans.");
671 my $val = $chanconf{$_}{_default};
672 foreach (keys %chanconf) {
673 $chanconf{$_}{$args} = $val;
675 delete $chanconf{_default}{$args};
676 $cache{confvars}{$args} = 0;
682 if ($no_chan and !exists($chanconf{_default}{$args})) {
683 &pSReply("ok, $args for _default does not exist, removing from all chans.");
685 foreach (keys %chanconf) {
686 next unless (exists $chanconf{$_}{$args});
687 &DEBUG("delete chanconf{$_}{$args};");
688 delete $chanconf{$_}{$args};
690 $cache{confvars}{$args} = 0;
696 &pSReply("Unsetting channel ($chan) option $args. (was $chanconf{$chan}{$args})");
697 delete $chanconf{$chan}{$args};
703 &pSReply("Deleting channel $chan for sure!");
704 $utime_chanfile = time();
708 &pSReply("Leaving $chan...");
710 delete $chanconf{$chan};
712 &pSReply("Prefix channel with '-' to delete for sure.");
718 if ($message =~ /^newpass(\s+(.*))?$/) {
719 my(@args) = split /[\s\t]+/, $2 || '';
721 if (scalar @args != 1) {
726 my $u = &getUser($who);
727 my $crypt = &mkcrypt($args[0]);
729 &pSReply("Set your passwd to '$crypt'");
730 $users{$u}{PASS} = $crypt;
732 $utime_userfile = time();
738 if ($message =~ /^chpass(\s+(.*))?$/) {
739 my(@args) = split /[\s\t]+/, $2 || '';
746 if (!&IsUser($args[0])) {
747 &pSReply("user $args[0] is not valid.");
751 my $u = &getUser($args[0]);
753 &pSReply("Internal error, u = NULL.");
757 if (scalar @args == 1) { # del pass.
758 if (!&IsFlag("n") and $who !~ /^\Q$verifyUser\E$/i) {
759 &pSReply("cannot remove passwd of others.");
763 if (!exists $users{$u}{PASS}) {
764 &pSReply("$u does not have pass set anyway.");
768 &pSReply("Deleted pass from $u.");
770 $utime_userfile = time();
773 delete $users{$u}{PASS};
778 my $crypt = &mkcrypt($args[1]);
779 &pSReply("Set $u's passwd to '$crypt'");
780 $users{$u}{PASS} = $crypt;
782 $utime_userfile = time();
788 if ($message =~ /^chattr(\s+(.*))?$/) {
789 my(@args) = split /[\s\t]+/, $2 || '';
798 if ($args[0] =~ /^$mask{nick}$/i) { # <nick>
799 $user = &getUser($args[0]);
802 $user = &getUser($who);
803 &DEBUG("user $who... nope.") unless (defined $user);
804 $user = &getUser($verifyUser);
808 if (!defined $user) {
809 &pSReply("user does not exist.");
813 my $flags = $users{$user}{FLAGS};
814 if (!defined $chflag) {
815 &pSReply("Flags for $user: $flags");
819 &DEBUG("who => $who");
820 &DEBUG("verifyUser => $verifyUser");
821 if (!&IsFlag("n") and $who !~ /^\Q$verifyUser\E$/i) {
822 &pSReply("cannto change attributes of others.");
828 foreach (split //, $chflag) {
829 if ($_ eq "+") { $state = 1; next; }
830 if ($_ eq "-") { $state = 0; next; }
832 if (!defined $state) {
833 &pSReply("no initial + or - was found in attr.");
838 next if ($flags =~ /\Q$_\E/);
841 if (&IsParam("owner")
842 and $param{owner} =~ /^\Q$user\E$/i
843 and $flags =~ /[nmo]/
845 &pSReply("not removing flag $_ for $user.");
848 next unless ($flags =~ s/\Q$_\E//);
855 $utime_userfile = time();
857 &pSReply("Current flags: $flags");
858 $users{$user}{FLAGS} = $flags;
860 &pSReply("No flags changed: $flags");
866 if ($message =~ /^chnick(\s+(.*))?$/) {
867 my(@args) = split /[\s\t]+/, $2 || '';
869 if ($who eq "_default") {
870 &WARN("$who or verifyuser tried to run chnick.");
874 if (!scalar @args or scalar @args > 2) {
879 if (scalar @args == 1) { # 1
880 $user = &getUser($who);
881 &DEBUG("nope, not $who.") unless (defined $user);
882 $user ||= &getUser($verifyUser);
885 $user = &getUser($args[0]);
889 if (!defined $user) {
890 &pSReply("user $who or $args[0] does not exist.");
894 if ($user =~ /^\Q$chnick\E$/i) {
895 &pSReply("user == chnick. why should I do that?");
899 if (&getUser($chnick)) {
900 &pSReply("user $chnick is already used!");
904 if (!&IsFlag("n") and $who !~ /^\Q$verifyUser\E$/i) {
905 &pSReply("cannto change nick of others.");
906 return "REPLY" if ($who eq "_default");
910 foreach (keys %{ $users{$user} }) {
911 $users{$chnick}{$_} = $users{$user}{$_};
912 delete $users{$user}{$_};
914 undef $users{$user}; # ???
916 $utime_userfile = time();
919 &pSReply("Changed '$user' to '$chnick' successfully.");
924 if ($message =~ /^([-+])host(\s+(.*))?$/) {
926 my(@args) = split /[\s\t]+/, $3 || '';
927 my $state = ($1 eq "+") ? 1 : 0;
934 if ($who eq "_default") {
935 &WARN("$who or verifyuser tried to run $cmd.");
940 if ($args[0] =~ /^$mask{nick}$/i) { # <nick>
941 return unless (&hasFlag("n"));
942 $user = &getUser($args[0]);
945 # FIXME: who or verifyUser. (don't remember why)
946 $user = &getUser($who);
950 if (!defined $user) {
951 &pSReply("user $user does not exist.");
955 if (!defined $mask) {
956 &pSReply("Hostmasks for $user: " . join(" ", keys %{$users{$user}{HOSTS}}));
960 if (!&IsFlag("n") and $who !~ /^\Q$verifyUser\E$/i) {
961 &pSReply("cannto change masks of others.");
965 if ($mask !~ /^$mask{nuh}$/) {
966 &pSReply("error: mask ($mask) is not a real hostmask.");
970 my $count = scalar keys %{ $users{$user}{HOSTS} };
973 if (exists $users{$user}{HOSTS}{$mask}) {
974 &pSReply("mask $mask already exists.");
978 ### TODO: override support.
979 $users{$user}{HOSTS}{$mask} = 1;
981 &pSReply("Added $mask to list of masks.");
985 if (!exists $users{$user}{HOSTS}{$mask}) {
986 &pSReply("mask $mask does not exist.");
990 ### TODO: wildcard support. ?
991 delete $users{$user}{HOSTS}{$mask};
993 if (scalar keys %{ $users{$user}{HOSTS} } != $count) {
994 &pSReply("Removed $mask from list of masks.");
996 &pSReply("error: could not find $mask in list of masks.");
1001 $utime_userfile = time();
1007 if ($message =~ /^([-+])ban(\s+(.*))?$/) {
1010 my(@args) = split /[\s\t]+/, $3 || '';
1011 my $state = ($1 eq "+") ? 1 : 0;
1013 if (!scalar @args) {
1018 my($mask,$chan,$time,$reason);
1020 if ($flatarg =~ s/^($mask{nuh})\s*//) {
1023 &DEBUG("arg does not contain nuh mask?");
1026 if ($flatarg =~ s/^($mask{chan})\s*//) {
1029 $chan = "*"; # _default instead?
1032 if ($state == 0) { # delete.
1033 my @c = &banDel($mask);
1040 &pSReply("Removed $mask from chans: @c");
1042 &pSReply("$mask was not found in ban list.");
1053 if ($flatarg =~ s/^(\d+)\s*//) {
1055 &DEBUG("time = $time.");
1057 &pSReply("error: time cannot be negatime?");
1064 if ($flatarg =~ s/^(.*)$//) { # need length?
1068 if (!&IsFlag("n") and $who !~ /^\Q$verifyUser\E$/i) {
1069 &pSReply("cannto change masks of others.");
1073 if ($mask !~ /^$mask{nuh}$/) {
1074 &pSReply("error: mask ($mask) is not a real hostmask.");
1078 if ( &banAdd($mask,$chan,$time,$reason) == 2) {
1079 &pSReply("ban already exists; overwriting.");
1081 &pSReply("Added $mask for $chan (time => $time, reason => $reason)");
1086 if ($message =~ /^whois(\s+(.*))?$/) {
1089 if (!defined $arg) {
1094 my $user = &getUser($arg);
1095 if (!defined $user) {
1096 &pSReply("whois: user $user does not exist.");
1100 ### TODO: better (eggdrop-like) output.
1101 &pSReply("user: $user");
1102 foreach (keys %{ $users{$user} }) {
1103 my $ref = ref $users{$user}{$_};
1105 if ($ref eq "HASH") {
1107 ### DOES NOT WORK???
1108 foreach (keys %{ $users{$user}{$type} }) {
1109 &pSReply(" $type => $_");
1114 &pSReply(" $_ => $users{$user}{$_}");
1116 &pSReply("End of USER whois.");
1121 if ($message =~ /^bans(\s+(.*))?$/) {
1125 if ($arg ne "_default" and !&validChan($arg) ) {
1126 &pSReply("error: chan $chan is invalid.");
1131 if (!scalar keys %bans) {
1132 &pSReply("Ban list is empty.");
1137 &pSReply(" mask: expire, time-added, count, who-by, reason");
1138 foreach $c (keys %bans) {
1139 next unless (!defined $arg or $arg =~ /^\Q$c\E$/i);
1142 foreach (keys %{ $bans{$c} }) {
1143 my $val = $bans{$c}{$_};
1145 if (ref $val eq "ARRAY") {
1146 my @array = @{ $val };
1147 &pSReply(" $_: @array");
1149 &DEBUG("unknown ban: $val");
1153 &pSReply("END of bans.");
1158 if ($message =~ /^banlist(\s+(.*))?$/) {
1161 if (defined $arg and $arg !~ /^$mask{chan}$/) {
1162 &pSReply("error: chan $chan is invalid.");
1166 &DEBUG("bans for global or arg => $arg.");
1167 foreach (keys %bans) { #CHANGE!!!
1168 &DEBUG(" $_ => $bans{$_}.");
1171 &DEBUG("End of bans.");
1172 &pSReply("END of bans.");
1177 if ($message =~ /^save$/) {
1178 return unless (&hasFlag("o"));
1182 &pSReply("saved user and chan files");
1188 $message =~ s/^addignore/+ignore/;
1189 $message =~ s/^(del|un)ignore/-ignore/;
1192 if ($message =~ /^(\+|\-)ignore(\s+(.*))?$/i) {
1193 return unless (&hasFlag("o"));
1194 my $state = ($1 eq "+") ? 1 : 0;
1195 my $str = $1."ignore";
1203 my($mask,$chan,$time,$comment);
1206 if ($args =~ s/^($mask{nuh})\s*//) {
1209 &ERROR("no NUH mask?");
1213 if (!$state) { # delignore.
1214 if ( &ignoreDel($mask) ) {
1215 &pSReply("ok, deleted ignores for $mask.");
1217 &pSReply("could not find $mask in ignore list.");
1227 if ($args =~ s/^($mask{chan}|\*)\s*//) {
1234 if ($args =~ s/^(\d+)\s*//) {
1235 $time = $1; # time is in minutes
1244 $comment = "added by $who";
1247 if ( &ignoreAdd($mask, $chan, $time, $comment) > 1) {
1248 &pSReply("FIXME: $mask already in ignore list; written over anyway.");
1250 &pSReply("added $mask to ignore list.");
1256 if ($message =~ /^ignore(\s+(.*))?$/) {
1260 if ($arg !~ /^$mask{chan}$/) {
1261 &pSReply("error: chan $chan is invalid.");
1265 if (!&validChan($arg)) {
1266 &pSReply("error: chan $arg is invalid.");
1270 &pSReply("Showing bans for $arg only.");
1273 if (!scalar keys %ignore) {
1274 &pSReply("Ignore list is empty.");
1278 ### TODO: proper (eggdrop-like) formatting.
1280 &pSReply(" mask: expire, time-added, who, comment");
1281 foreach $c (keys %ignore) {
1282 next unless (!defined $arg or $arg =~ /^\Q$c\E$/i);
1285 foreach (keys %{ $ignore{$c} }) {
1286 my $ref = ref $ignore{$c}{$_};
1287 if ($ref eq "ARRAY") {
1288 my @array = @{ $ignore{$c}{$_} };
1289 &pSReply(" $_: @array");
1291 &DEBUG("unknown ignore line?");
1295 &pSReply("END of ignore.");
1301 if ($message =~ /^(\+|\-|add|del)user(\s+(.*))?$/i) {
1303 my $strstr = $1."user";
1304 my @args = split /\s+/, $3 || '';
1306 my $state = ($str =~ /^(\+|add)$/) ? 1 : 0;
1308 if (!scalar @args) {
1314 if (scalar @args != 2) {
1315 &pSReply(".+host requires hostmask argument.");
1318 } elsif (scalar @args != 1) {
1319 &pSReply("too many arguments.");
1323 if ($state) { # adduser.
1324 if (scalar @args == 1) {
1325 $args[1] = &getHostMask($args[0]);
1326 &pSReply("Attemping to guess $args[0]'s hostmask...");
1328 # crude hack... crappy Net::IRC
1329 $conn->schedule(5, sub {
1330 # hopefully this is right.
1331 my $nick = (keys %{ $cache{nuhInfo} })[0];
1332 if (!defined $nick) {
1333 &pSReply("couldn't get nuhinfo... adding user without a hostmask.");
1338 my $mask = &makeHostMask( $cache{nuhInfo}{$nick}{NUH} );
1340 if ( &userAdd($nick, $mask) ) { # success.
1341 &pSReply("Added $nick with flags $users{$nick}{FLAGS}");
1342 my @hosts = keys %{ $users{$nick}{HOSTS} };
1343 &pSReply("hosts: @hosts");
1349 &DEBUG("args => @args");
1350 if ( &userAdd(@args) ) { # success.
1351 &pSReply("Added $args[0] with flags $users{$args[0]}{FLAGS}");
1352 my @hosts = keys %{ $users{$args[0]}{HOSTS} };
1353 &pSReply("hosts: @hosts");
1356 &pSReply("User $args[0] already exists");
1361 if ( &userDel($args[0]) ) { # success.
1362 &pSReply("Deleted $args[0] successfully.");
1365 &pSReply("User $args[0] does not exist.");
1372 if ($message =~ /^sched$/) {
1377 foreach (keys %sched) {
1378 next unless (exists $sched{$_}{TIME});
1379 $time{ $sched{$_}{TIME}-time() }{$_} = 1;
1382 next unless (exists $sched{$_}{RUNNING});
1387 foreach (sort { $a <=> $b } keys %time) {
1388 my $str = join(", ", sort keys %{ $time{$_} });
1389 &DEBUG("time => $_, str => $str");
1390 push(@time, "$str (".&Time2String($_).")");
1393 &pSReply( &formListReply(0, "Schedulers: ", @time ) );
1394 &pSReply( &formListReply(0, "Scheds to run: ", sort @list ) );
1395 &pSReply( &formListReply(0, "Scheds running(should not happen?) ", sort @run ) );
1400 # quite a cool hack: reply in DCC CHAT.
1401 $msgType = "chat" if (exists $dcc{'CHAT'}{$who});
1404 $done++ if &parseCmdHook("main", $message);
1405 $done++ if &parseCmdHook("extra", $message);
1406 $done++ unless (&Modules());
1409 &DEBUG("running non DCC CHAT command inside DCC CHAT!");