2 # DynaConfig.pl: Read/Write configuration files dynamically.
4 # Version: v0.1 (20010120)
6 # NOTE: Merged from User.pl
9 if (&IsParam("useStrict")) { use strict; }
12 ##### USERFILE CONFIGURATION READER/WRITER
16 if (!open IN,"$bot_misc_dir/blootbot.users") {
17 &ERROR("cannot read userfile.");
24 &ERROR("old or invalid user file found.");
36 if (/^--(\S+)[\s\t]+(.*)$/) { # user: middle entry.
37 my ($what,$val) = ($1,$2);
40 if ($what eq "HOSTS") {
41 $users{$nick}{$1}{$2} = 1;
43 $users{$nick}{$1} = $2;
46 } elsif (/^(\S+)$/) { # user: start entry.
49 } elsif (/^::(\S+) ignore$/) { # ignore: start entry.
52 } elsif (/^- (\S+):+(\d+):(\S+):(\d+):(.*)$/) {
53 ### ignore: middle entry.
54 # $mask, $count?, $whoby, $atime, $comment.
55 my(@array) = ($2,$3,$4,$5);
56 $ignore{$chan}{$1} = \@array;
58 } elsif (/^::(\S+) bans$/) { # bans: start entry.
61 } elsif (/^- (\S+):+(\d+):+(\d+):(\d+):(\S+):(.*)$/) {
62 ### bans: middle entry.
63 # $btime, $atime, $count, $whoby, $reason.
64 my(@array) = ($2,$3,$4,$5,$6);
65 $bans{$chan}{$1} = \@array;
68 &WARN("unknown line: $_");
73 &status( sprintf("USERFILE: Loaded: %d users, %d bans, %d ignore",
74 scalar(keys %users)-1,
82 if (!open OUT,">$bot_misc_dir/blootbot.users") {
83 &ERROR("cannot write to userfile.");
87 my $time = scalar(localtime);
89 print OUT "#v1: blootbot -- $ident -- written $time\n\n";
93 foreach (sort keys %users) {
96 my $count = scalar keys %{ $users{$user} };
98 &WARN("user $user has no other attributes; skipping.");
104 foreach (sort keys %{ $users{$user} }) {
106 my $val = $users{$user}{$_};
108 if (ref($val) eq "HASH") {
109 foreach (sort keys %{ $users{$user}{$_} }) {
110 print OUT "--$what\t\t$_\n";
114 print OUT "--$_\t\t$val\n";
122 foreach (keys %bans) {
126 my $count = scalar keys %{ $bans{$chan} };
128 &WARN("bans: chan $chan has no other attributes; skipping.");
132 print OUT "::$chan bans\n";
133 &DEBUG("::$chan bans");
134 foreach (keys %{ $bans{$chan} }) {
135 printf OUT "- %s:+%d:+%d:%d:%s:%s\n",
136 $_, @{ $bans{$chan}{$_} };
137 &DEBUG( sprintf("- %s:+%d:+%d:%d:%s:%s\n",
138 $_, @{ $bans{$chan}{$_} } ));
141 print OUT "\n" if ($cbans);
145 foreach (keys %ignore) {
149 my $count = scalar keys %{ $ignore{$chan} };
151 &WARN("ignore: chan $chan has no other attributes; skipping.");
155 print OUT "::$chan ignore\n";
156 &DEBUG("::$chan ignore");
157 foreach (keys %{ $ignore{$chan} }) {
158 printf OUT "- %s:+%d:%s:%d:%s\n",
159 $_, @{ $bans{$chan}{$_} };
160 &DEBUG( sprintf("- %s:+%d:%s:%d:%s\n",
161 $_, @{ $bans{$chan}{$_} } ));
167 $wtime_userfile = time();
168 &status("--- Saved USERFILE ($cusers users; $cbans bans; $cignore ignore) at $time");
169 if (defined $msgType and $msgType =~ /^chat$/) {
170 &performStrictReply("--- Writing user file...");
175 ##### CHANNEL CONFIGURATION READER/WRITER
179 if (!open IN,"$bot_misc_dir/blootbot.chan") {
180 &ERROR("cannot erad chanfile.");
184 $_ = <IN>; # version string.
196 next unless (defined $chan);
198 if (/^[\s\t]+\+(\S+)$/) { # bool, true.
199 $chanconf{$chan}{$1} = 1;
201 } elsif (/^[\s\t]+\-(\S+)$/) { # bool, false.
202 $chanconf{$chan}{$1} = 0;
204 } elsif (/^[\s\t]+(\S+)[\ss\t]+(.*)$/) {# what = val.
205 $chanconf{$chan}{$1} = $2;
208 &WARN("unknown line: $_") unless (/^#/);
213 &status("CHANFILE: Loaded: ".(scalar(keys %chanconf)-1)." chans");
217 if (!open OUT,">$bot_misc_dir/blootbot.chan") {
218 &ERROR("cannot write chanfile.");
222 my $time = scalar(localtime);
223 print OUT "#v1: blootbot -- $ident -- written $time\n\n";
227 ### Process 1: if defined in _default, remove same definition
228 ### from non-default channels.
229 foreach (keys %{ $chanconf{_default} }) {
231 my $val = $chanconf{_default}{$opt};
234 foreach (keys %chanconf) {
237 next if ($chan eq "_default");
238 next unless (exists $chanconf{$chan}{$opt});
239 next unless ($val eq $chanconf{$chan}{$opt});
241 delete $chanconf{$chan}{$opt};
245 &DEBUG("Removed config $opt to @chans since it's defiend in '_default'");
249 ### Process 2: if defined in all chans but _default, set in
250 ### _default and remove all others.
251 my (%optsval, %opts);
252 foreach (keys %chanconf) {
254 next if ($chan eq "_default");
257 foreach (keys %{ $chanconf{$chan} }) {
259 if (exists $optsval{$opt} and $optsval{$opt} eq $chanconf{$chan}{$opt}) {
263 $optsval{$opt} = $chanconf{$chan}{$opt};
268 &DEBUG("chans => ".scalar(keys %chanconf)." - 1");
269 foreach (keys %opts) {
270 &DEBUG(" opts{$_} => $opts{$_}");
273 ### other optimizations are in UserDCC.pl
277 foreach (sort keys %chanconf) {
282 foreach (sort keys %{ $chanconf{$chan} }) {
283 my $val = $chanconf{$chan}{$_};
285 if ($val =~ /^0$/) { # bool, false.
288 } elsif ($val =~ /^1$/) { # bool, true.
291 } else { # what = val.
292 print OUT " $_ $val\n";
302 $wtime_chanfile = time();
303 &status("--- Saved CHANFILE (".scalar(keys %chanconf).
306 if (defined $msgType and $msgType =~ /^chat$/) {
307 &performStrictReply("--- Writing chan file...");
317 my ($ret, $f, $o) = "";
319 if (!defined $userHandle) {
320 &DEBUG("Dyna: line 320: add verifyUser");
323 foreach $f (split //, $users{$userHandle}{FLAGS}) {
324 foreach $o ( split //, $flags ) {
325 next unless ($f eq $o);
336 my ($nick, $lnuh) = @_;
341 foreach $user (keys %users) {
342 next if ($user eq "_default");
344 foreach $m (keys %{$users{$user}{HOSTS}}) {
347 $m =~ s/([\@\(\)\[\]])/\\$1/g;
349 next unless ($lnuh =~ /^$m$/i);
351 if ($user !~ /^\Q$nick\E$/i) {
352 &status("vU: host matched but diff nick ($nick != $user).");
359 last if ($userHandle ne "");
361 if ($user =~ /^\Q$nick\E$/i and !exists $cache{VUSERWARN}{$user}) {
362 &status("vU: nick matched but host is not in list ($lnuh).");
363 $cache{VUSERWARN}{$user} = 1;
367 $userHandle ||= "_default";
368 $talkWho{$talkchannel} = $who if (defined $talkchannel);
375 # returns true if arg1 encrypts to arg2
376 my ($plain, $encrypted) = @_;
377 if ($encrypted eq "") {
378 ($plain, $encrypted) = split(/\s+/, $plain, 2);
380 return 0 unless ($plain ne "" and $encrypted ne "");
382 # MD5 // DES. Bobby Billingsley++.
383 my $salt = substr($encrypted, 0, 2);
384 if ($encrypted =~ /^\$\d\$(\w\w)\$/) {
388 return ($encrypted eq crypt($plain, $salt));
391 # mainly for dcc chat... hrm.
395 if (&IsFlag($flag) eq $flag) {
398 &status("DCC CHAT: <$who> $message -- not enough flags.");
399 &performStrictReply("error: you do not have enough flags for that. ($flag required)");
405 my($mask,$chan,$expire,$comment) = @_;
407 $chan ||= "*"; # global if undefined.
408 $comment ||= ""; # optional.
409 $expire ||= 0; # permament.
413 $expire = $expire*60 + time();
419 $exist++ if (exists $ignore{$chan}{$mask});
421 $ignore{$chan}{$mask} = [$expire, $count, $who, time(), $comment];
424 $utime_userfile = time();
437 ### TODO: support wildcards.
438 foreach (keys %ignore) {
441 foreach (grep /^\Q$mask\E$/i, keys %{ $ignore{$chan} }) {
442 delete $ignore{$chan}{$mask};
446 &DEBUG("iD: scalar => ".scalar(keys %{ $ignore{$chan} }) );
450 $utime_userfile = time();
458 my($nick,$mask) = @_;
460 if (exists $users{$nick}) {
464 $utime_userfile = time();
467 $users{$nick}{HOSTS}{$mask} = 1;
468 $users{$nick}{FLAGS} = $users{_default}{FLAGS};
476 if (!exists $users{$nick}) {
480 $utime_userfile = time();
483 delete $users{$nick};
489 my($mask,$chan,$expire,$reason) = @_;
495 $expire = $expire*60 + time();
499 $exist++ if (exists $bans{$chan}{$mask} or
500 exists $bans{_default}{$mask});
501 $bans{$chan}{$mask} = [$expire, 0, $who, time(), $reason];
504 $utime_userfile = time();
515 foreach (keys %bans) {
518 foreach (grep /^\Q$mask\E$/i, keys %{ $bans{$chan} }) {
519 delete $bans{$chan}{$_};
523 &DEBUG("bans: scalar => ".scalar(keys %{ $bans{$chan} }) );
527 $utime_userfile = time();
537 if ( &getUser($user) ) {
547 if (!defined $user) {
548 &WARN("getUser: user == NULL.");
552 if (my @retval = grep /^\Q$user\E$/i, keys %users) {
553 if ($retval[0] ne $user) {
554 &WARN("getUser: retval[0] ne user ($retval[0] ne $user)");
556 my $count = scalar keys %{ $users{$retval[0]} };
557 &DEBUG("count => $count.");
568 "limitcheckInterval",
572 ### TODO: finish off this list.
575 my @regFlagsUser = ("mno"); # todo...