]> git.donarmstrong.com Git - infobot.git/blob - src/DynaConfig.pl
* Merged r1666:1760 from src-cleanup branch
[infobot.git] / src / DynaConfig.pl
1 #
2 # DynaConfig.pl: Read/Write configuration files dynamically.
3 #        Author: dms
4 #       Version: v0.1 (20010120)
5 #       Created: 20010119
6 #          NOTE: Merged from User.pl
7 #
8
9 use strict;
10
11 use vars qw(%chanconf %cache %bans %channels %nuh %users %ignore
12   %talkWho %dcc %mask);
13 use vars qw($utime_userfile $ucount_userfile $utime_chanfile $who
14   $ucount_chanfile $userHandle $chan $msgType $talkchannel
15   $ident $bot_state_dir $talkWho $flag_quit $wtime_userfile
16   $wcount_userfile $wtime_chanfile $nuh $message);
17
18 my @regFlagsUser = (
19
20     # possible chars to include in FLAG
21     'A',    # bot administration over /msg
22             # default is only via DCC CHAT
23     'O',    # dynamic ops (as on channel). (automatic +o)
24     'T',    # add topics.
25     'a',    # ask/request factoid.
26     'm',    # modify factoid. (includes renaming)
27     'n',    # bot owner, can 'reload'
28     'o',    # master of bot (automatic +amrt)
29             # can search on factoid strings shorter than 2 chars
30             # can tell bot to join new channels
31             # can [un]lock factoids
32     'r',    # remove factoid.
33     't',    # teach/add factoid.
34     's',    # Bypass +silent on channels
35 );
36
37 #####
38 ##### USERFILE CONFIGURATION READER/WRITER
39 #####
40
41 sub readUserFile {
42     my $f = "$bot_state_dir/infobot.users";
43
44     if ( !-f $f ) {
45         &DEBUG("userfile not found; new fresh run detected.");
46         return;
47     }
48
49     if ( -f $f and -f "$f~" ) {
50         my $s1 = -s $f;
51         my $s2 = -s "$f~";
52
53         if ( $s2 > $s1 * 3 ) {
54             &FIXME("rUF: backup file bigger than current file.");
55         }
56     }
57
58     if ( !open IN, $f ) {
59         &ERROR("Cannot read userfile ($f): $!");
60         &closeLog();
61         exit 1;
62     }
63
64     undef %users;     # clear on reload.
65     undef %bans;      # reset.
66     undef %ignore;    # reset.
67
68     my $ver = <IN>;
69     if ( $ver !~ /^#v1/ ) {
70         &ERROR("old or invalid user file found.");
71         &closeLog();
72         exit 1;       # correct?
73     }
74
75     my $nick;
76     my $type;
77     while (<IN>) {
78         chop;
79
80         next if /^$/;
81         next if /^#/;
82
83         if (/^--(\S+)[\s\t]+(.*)$/) {    # user: middle entry.
84             my ( $what, $val ) = ( $1, $2 );
85
86             if ( !defined $val or $val eq '' ) {
87                 &WARN("$what: val == NULL.");
88                 next;
89             }
90
91             if ( !defined $nick ) {
92                 &WARN("DynaConfig: invalid line: $_");
93                 next;
94             }
95
96             # nice little hack.
97             if ( $what eq 'HOSTS' ) {
98                 $users{$nick}{$what}{$val} = 1;
99             }
100             else {
101                 $users{$nick}{$what} = $val;
102             }
103
104         }
105         elsif (/^(\S+)$/) {    # user: start entry.
106             $nick = $1;
107
108         }
109         elsif (/^::(\S+) ignore$/) {    # ignore: start entry.
110             $chan = $1;
111             $type = 'ignore';
112
113         }
114         elsif ( /^- (\S+):\+(\d+):\+(\d+):(\S+):(.*)$/ and $type eq 'ignore' ) {
115             ### ignore: middle entry.
116             my $mask = $1;
117             my (@array) = ( $2, $3, $4, $5 );
118             ### DEBUG purposes only!
119             if ( $mask !~ /^$mask{nuh}$/ ) {
120                 &WARN("ignore: mask $mask is invalid.");
121                 next;
122             }
123             $ignore{$chan}{$mask} = \@array;
124
125         }
126         elsif (/^::(\S+) bans$/) {    # bans: start entry.
127             $chan = $1;
128             $type = 'bans';
129
130         }
131         elsif ( /^- (\S+):\+(\d+):\+(\d+):(\d+):(\S+):(.*)$/
132             and $type eq 'bans' )
133         {
134             ### bans: middle entry.
135             # $btime, $atime, $count, $whoby, $reason.
136             my (@array) = ( $2, $3, $4, $5, $6 );
137             $bans{$chan}{$1} = \@array;
138
139         }
140         else {    # unknown.
141             &WARN("unknown line: $_");
142         }
143     }
144     close IN;
145
146     &status(
147         sprintf(
148             "USERFILE: Loaded: %d users, %d bans, %d ignore",
149             scalar( keys %users ) - 1,
150             scalar( keys %bans ),      # ??
151             scalar( keys %ignore ),    # ??
152         )
153     );
154 }
155
156 sub writeUserFile {
157     if ( !scalar keys %users ) {
158         &DEBUG("wUF: nothing to write.");
159         return;
160     }
161
162     if ( !open OUT, ">$bot_state_dir/infobot.users" ) {
163         &ERROR("Cannot write userfile ($bot_state_dir/infobot.users): $!");
164         return;
165     }
166
167     my $time = scalar(gmtime);
168
169     print OUT "#v1: infobot -- $ident -- written $time\n\n";
170
171     ### USER LIST.
172     my $cusers = 0;
173     foreach ( sort keys %users ) {
174         my $user = $_;
175         $cusers++;
176         my $count = scalar keys %{ $users{$user} };
177         if ( !$count ) {
178             &WARN("user $user has no other attributes; skipping.");
179             next;
180         }
181
182         print OUT "$user\n";
183
184         foreach ( sort keys %{ $users{$user} } ) {
185             my $what = $_;
186             my $val  = $users{$user}{$_};
187
188             if ( ref($val) eq 'HASH' ) {
189                 foreach ( sort keys %{ $users{$user}{$_} } ) {
190                     print OUT "--$what\t\t$_\n";
191                 }
192
193             }
194             elsif ( $_ eq 'FLAGS' ) {
195                 print OUT "--$_\t\t"
196                   . join( '', sort split( '', $val ) ) . "\n";
197             }
198             else {
199                 print OUT "--$_\t\t$val\n";
200             }
201         }
202         print OUT "\n";
203     }
204
205     ### BAN LIST.
206     my $cbans = 0;
207     foreach ( keys %bans ) {
208         my $chan = $_;
209         $cbans++;
210
211         my $count = scalar keys %{ $bans{$chan} };
212         if ( !$count ) {
213             &WARN("bans: chan $chan has no other attributes; skipping.");
214             next;
215         }
216
217         print OUT "::$chan bans\n";
218         foreach ( keys %{ $bans{$chan} } ) {
219
220             # format: bans: mask expire time-added count who-added reason
221             my @array = @{ $bans{$chan}{$_} };
222             if ( scalar @array != 5 ) {
223                 &WARN("bans: $chan/$_ is corrupted.");
224                 next;
225             }
226
227             printf OUT "- %s:+%d:+%d:%d:%s:%s\n", $_, @array;
228         }
229     }
230     print OUT "\n" if ($cbans);
231
232     ### IGNORE LIST.
233     my $cignore = 0;
234     foreach ( keys %ignore ) {
235         my $chan = $_;
236         $cignore++;
237
238         my $count = scalar keys %{ $ignore{$chan} };
239         if ( !$count ) {
240             &WARN("ignore: chan $chan has no other attributes; skipping.");
241             next;
242         }
243
244         ### TODO: use hash instead of array for flexibility?
245         print OUT "::$chan ignore\n";
246         foreach ( keys %{ $ignore{$chan} } ) {
247
248             # format: ignore: mask expire time-added who-added reason
249             my @array = @{ $ignore{$chan}{$_} };
250             if ( scalar @array != 4 ) {
251                 &WARN("ignore: $chan/$_ is corrupted.");
252                 next;
253             }
254
255             printf OUT "- %s:+%d:+%d:%s:%s\n", $_, @array;
256         }
257     }
258
259     close OUT;
260
261     $wtime_userfile = time();
262     &status(
263 "--- Saved USERFILE ($cusers users; $cbans bans; $cignore ignore) at $time"
264     );
265     if ( defined $msgType and $msgType =~ /^chat$/ ) {
266         &performStrictReply("--- Writing user file...");
267     }
268 }
269
270 #####
271 ##### CHANNEL CONFIGURATION READER/WRITER
272 #####
273
274 sub readChanFile {
275     my $f = "$bot_state_dir/infobot.chan";
276     if ( -f $f and -f "$f~" ) {
277         my $s1 = -s $f;
278         my $s2 = -s "$f~";
279
280         if ( $s2 > $s1 * 3 ) {
281             &FIXME("rCF: backup file bigger than current file.");
282         }
283     }
284
285     if ( !open IN, $f ) {
286         &ERROR("Cannot read chanfile ($f): $!");
287         return;
288     }
289
290     undef %chanconf;    # reset.
291
292     $_ = <IN>;          # version string.
293
294     my $chan;
295     while (<IN>) {
296         chop;
297
298         next if /^\s*$/;
299         next if /^\// or /^\;/;    # / or ; are comment lines.
300
301         if (/^(\S+)\s*$/) {
302             $chan = $1;
303             next;
304         }
305         next unless ( defined $chan );
306
307         if (/^[\s\t]+\+(\S+)$/) {    # bool, true.
308             $chanconf{$chan}{$1} = 1;
309
310         }
311         elsif (/^[\s\t]+\-(\S+)$/) {    # bool, false.
312                 # although this is supported in run-time configuration.
313             $chanconf{$chan}{$1} = 0;
314
315         }
316         elsif (/^[\s\t]+(\S+)[\s\t]+(.*)$/) {    # what = val.
317             $chanconf{$chan}{$1} = $2;
318
319         }
320         else {
321             &WARN("unknown line: $_") unless (/^#/);
322         }
323     }
324     close IN;
325
326     # verify configuration
327     ### TODO: check against valid params.
328     foreach $chan ( keys %chanconf ) {
329         foreach ( keys %{ $chanconf{$chan} } ) {
330             next unless /^[+-]/;
331
332             &WARN("invalid param: chanconf{$chan}{$_}; removing.");
333             delete $chanconf{$chan}{$_};
334             undef $chanconf{$chan}{$_};
335         }
336     }
337
338     &status(
339         "CHANFILE: Loaded: " . ( scalar( keys %chanconf ) - 1 ) . " chans" );
340 }
341
342 sub writeChanFile {
343     if ( !scalar keys %chanconf ) {
344         &DEBUG("wCF: nothing to write.");
345         return;
346     }
347
348     if ( !open OUT, ">$bot_state_dir/infobot.chan" ) {
349         &ERROR("Cannot write chanfile ($bot_state_dir/infobot.chan): $!");
350         return;
351     }
352
353     my $time = scalar(gmtime);
354     print OUT "#v1: infobot -- $ident -- written $time\n\n";
355
356     if ($flag_quit) {
357
358         ### Process 1: if defined in _default, remove same definition
359         ###             from non-default channels.
360         foreach ( keys %{ $chanconf{_default} } ) {
361             my $opt = $_;
362             my $val = $chanconf{_default}{$opt};
363             my @chans;
364
365             foreach ( keys %chanconf ) {
366                 $chan = $_;
367
368                 next if ( $chan eq "_default" );
369                 next unless ( exists $chanconf{$chan}{$opt} );
370                 next unless ( $val eq $chanconf{$chan}{$opt} );
371
372                 push( @chans, $chan );
373                 delete $chanconf{$chan}{$opt};
374             }
375
376             if ( scalar @chans ) {
377                 &DEBUG(
378 "Removed config $opt to @chans since it's defiend in '_default'"
379                 );
380             }
381         }
382
383         ### Process 2: if defined in all chans but _default, set in
384         ###             _default and remove all others.
385         my ( %optsval, %opts );
386         foreach ( keys %chanconf ) {
387             $chan = $_;
388             next if ( $chan eq "_default" );
389             my $opt;
390
391             foreach ( keys %{ $chanconf{$chan} } ) {
392                 $opt = $_;
393                 if ( exists $optsval{$opt}
394                     and $optsval{$opt} eq $chanconf{$chan}{$opt} )
395                 {
396                     $opts{$opt}++;
397                     next;
398                 }
399                 $optsval{$opt} = $chanconf{$chan}{$opt};
400                 $opts{$opt}    = 1;
401             }
402         }
403
404         foreach ( keys %opts ) {
405             next unless ( $opts{$_} > 2 );
406             &DEBUG("  opts{$_} => $opts{$_}");
407         }
408
409         ### other optimizations are in UserDCC.pl
410     }
411
412     ### lets do it...
413     foreach ( sort keys %chanconf ) {
414         $chan = $_;
415
416         print OUT "$chan\n";
417
418         foreach ( sort keys %{ $chanconf{$chan} } ) {
419             my $val = $chanconf{$chan}{$_};
420
421             if ( $val =~ /^0$/ ) {    # bool, false.
422                 print OUT "    -$_\n";
423
424             }
425             elsif ( $val =~ /^1$/ ) {    # bool, true.
426                 print OUT "    +$_\n";
427
428             }
429             else {                       # what = val.
430                 print OUT "    $_ $val\n";
431
432             }
433
434         }
435         print OUT "\n";
436     }
437
438     close OUT;
439
440     $wtime_chanfile = time();
441     &status("--- Saved CHANFILE ("
442           . scalar( keys %chanconf )
443           . " chans) at $time" );
444
445     if ( defined $msgType and $msgType =~ /^chat$/ ) {
446         &performStrictReply("--- Writing chan file...");
447     }
448 }
449
450 #####
451 ##### USER COMMANDS.
452 #####
453
454 # TODO: support multiple flags.
455 # TODO: return all flags for opers
456 sub IsFlag {
457     my $flags = shift;
458     my ( $ret, $f, $o ) = '';
459
460     &verifyUser( $who, $nuh );
461
462     foreach $f ( split //, $users{$userHandle}{FLAGS} ) {
463         foreach $o ( split //, $flags ) {
464             next unless ( $f eq $o );
465
466             $ret = $f;
467             last;
468         }
469     }
470
471     $ret;
472 }
473
474 sub verifyUser {
475     my ( $nick, $lnuh ) = @_;
476     my ( $user, $m );
477
478     if ( $userHandle = $dcc{'CHATvrfy'}{$who} ) {
479         &VERB( "vUser: cached auth for $who.", 2 );
480         return $userHandle;
481     }
482
483     $userHandle = '';
484
485     foreach $user ( keys %users ) {
486         next if ( $user eq "_default" );
487
488         foreach $m ( keys %{ $users{$user}{HOSTS} } ) {
489             $m =~ s/\?/./g;
490             $m =~ s/\*/.*?/g;
491             $m =~ s/([\@\(\)\[\]])/\\$1/g;
492
493             next unless ( $lnuh =~ /^$m$/i );
494
495             if ( $user !~ /^\Q$nick\E$/i and !exists $cache{VUSERWARN}{$user} )
496             {
497                 &status("vU: host matched but diff nick ($nick != $user).");
498                 $cache{VUSERWARN}{$user} = 1;
499             }
500
501             $userHandle = $user;
502             last;
503         }
504
505         last if ( $userHandle ne '' );
506
507         if ( $user =~ /^\Q$nick\E$/i and !exists $cache{VUSERWARN}{$user} ) {
508             &status("vU: nick matched but host is not in list ($lnuh).");
509             $cache{VUSERWARN}{$user} = 1;
510         }
511     }
512
513     $userHandle ||= "_default";
514
515     # what's talkchannel for?
516     $talkWho{$talkchannel} = $who if ( defined $talkchannel );
517     $talkWho = $who;
518
519     return $userHandle;
520 }
521
522 sub ckpasswd {
523
524     # returns true if arg1 encrypts to arg2
525     my ( $plain, $encrypted ) = @_;
526     if ( $encrypted eq '' ) {
527         ( $plain, $encrypted ) = split( /\s+/, $plain, 2 );
528     }
529     return 0 unless ( $plain ne '' and $encrypted ne '' );
530
531     # MD5 // DES. Bobby Billingsley++.
532     my $salt;
533     if ( $encrypted =~ /^(\S{2})/ and length $encrypted == 13 ) {
534         $salt = $1;
535     }
536     elsif ( $encrypted =~ /^\$\d\$(\w\w)\$/ ) {
537         $salt = $1;
538     }
539     else {
540         &DEBUG("unknown salt from $encrypted.");
541         return 0;
542     }
543
544     return ( $encrypted eq crypt( $plain, $salt ) );
545 }
546
547 # mainly for dcc chat... hrm.
548 sub hasFlag {
549     my ($flag) = @_;
550
551     if ( &IsFlag($flag) eq $flag ) {
552         return 1;
553     }
554     else {
555         &status("DCC CHAT: <$who> $message -- not enough flags.");
556         &performStrictReply(
557             "error: you do not have enough flags for that. ($flag required)");
558         return 0;
559     }
560 }
561
562 # expire is time in minutes
563 sub ignoreAdd {
564     my ( $mask, $chan, $expire, $comment ) = @_;
565
566     $chan     ||= '*';    # global if undefined.
567     $comment  ||= '';     # optional.
568     $expire   ||= 0;      # permament.
569     my $count ||= 0;
570
571     if ( $expire > 0 ) {
572         $expire = ( $expire * 60 ) + time();
573     }
574     else {
575         $expire = 0;
576     }
577
578     my $exist = 0;
579     $exist++ if ( exists $ignore{$chan}{$mask} );
580
581     $ignore{$chan}{$mask} = [ $expire, time(), $who, $comment ];
582
583     # TODO: improve this.
584     if ( $expire == 0 ) {
585         &status(
586 "ignore: Added $mask for $chan to NEVER expire, by $who, for $comment"
587         );
588     }
589     else {
590         &status(
591 "ignore: Added $mask for $chan to expire $expire mins, by $who, for $comment"
592         );
593     }
594
595     if ($exist) {
596         $utime_userfile = time();
597         $ucount_userfile++;
598
599         return 2;
600     }
601     else {
602         return 1;
603     }
604 }
605
606 sub ignoreDel {
607     my ($mask) = @_;
608     my @match;
609
610     ### TODO: support wildcards.
611     foreach ( keys %ignore ) {
612         my $chan = $_;
613
614         foreach ( grep /^\Q$mask\E$/i, keys %{ $ignore{$chan} } ) {
615             delete $ignore{$chan}{$mask};
616             push( @match, $chan );
617         }
618
619         &DEBUG( "iD: scalar => " . scalar( keys %{ $ignore{$chan} } ) );
620     }
621
622     if ( scalar @match ) {
623         $utime_userfile = time();
624         $ucount_userfile++;
625     }
626
627     return @match;
628 }
629
630 sub userAdd {
631     my ( $nick, $mask ) = @_;
632
633     if ( exists $users{$nick} ) {
634         return 0;
635     }
636
637     $utime_userfile = time();
638     $ucount_userfile++;
639
640     if ( defined $mask and $mask !~ /^\s*$/ ) {
641         &DEBUG("userAdd: mask => $mask");
642         $users{$nick}{HOSTS}{$mask} = 1;
643     }
644
645     $users{$nick}{FLAGS} ||= $users{_default}{FLAGS};
646
647     return 1;
648 }
649
650 sub userDel {
651     my ($nick) = @_;
652
653     if ( !exists $users{$nick} ) {
654         return 0;
655     }
656
657     $utime_userfile = time();
658     $ucount_userfile++;
659
660     delete $users{$nick};
661
662     return 1;
663 }
664
665 sub banAdd {
666     my ( $mask, $chan, $expire, $reason ) = @_;
667
668     $chan   ||= '*';
669     $expire ||= 0;
670
671     if ( $expire > 0 ) {
672         $expire = $expire * 60 + time();
673     }
674
675     my $exist = 1;
676     $exist++ if ( exists $bans{$chan}{$mask}
677         or exists $bans{'*'}{$mask} );
678     $bans{$chan}{$mask} = [ $expire, time(), 0, $who, $reason ];
679
680     my @chans = ( $chan eq '*' ) ? keys %channels : $chan;
681     my $m = $mask;
682     $m =~ s/\?/\\./g;
683     $m =~ s/\*/\\S*/g;
684     foreach (@chans) {
685         my $chan = $_;
686         foreach ( keys %{ $channels{$chan}{''} } ) {
687             next unless ( exists $nuh{ lc $_ } );
688             next unless ( $nuh{ lc $_ } =~ /^$m$/i );
689             &FIXME("nuh{$_} =~ /$m/");
690         }
691     }
692
693     if ( $exist == 1 ) {
694         $utime_userfile = time();
695         $ucount_userfile++;
696     }
697
698     return $exist;
699 }
700
701 sub banDel {
702     my ($mask) = @_;
703     my @match;
704
705     foreach ( keys %bans ) {
706         my $chan = $_;
707
708         foreach ( grep /^\Q$mask\E$/i, keys %{ $bans{$chan} } ) {
709             delete $bans{$chan}{$_};
710             push( @match, $chan );
711         }
712
713         &DEBUG( "bans: scalar => " . scalar( keys %{ $bans{$chan} } ) );
714     }
715
716     if ( scalar @match ) {
717         $utime_userfile = time();
718         $ucount_userfile++;
719     }
720
721     return @match;
722 }
723
724 sub IsUser {
725     my ($user) = @_;
726
727     if ( &getUser($user) ) {
728         return 1;
729     }
730     else {
731         return 0;
732     }
733 }
734
735 sub getUser {
736     my ($user) = @_;
737
738     if ( !defined $user ) {
739         &WARN("getUser: user == NULL.");
740         return;
741     }
742
743     if ( my @retval = grep /^\Q$user\E$/i, keys %users ) {
744         if ( $retval[0] ne $user ) {
745             &WARN("getUser: retval[0] ne user ($retval[0] ne $user)");
746         }
747         my $count = scalar keys %{ $users{ $retval[0] } };
748         &DEBUG("count => $count.");
749
750         return $retval[0];
751     }
752     else {
753         return;
754     }
755 }
756
757 sub chanSet {
758     my ( $cmd, $chan, $what, $val ) = @_;
759
760     if ( $cmd eq "+chan" ) {
761         if ( exists $chanconf{$chan} ) {
762             &performStrictReply("chan $chan already exists.");
763             return;
764         }
765         $chanconf{$chan}{_time_added} = time();
766         $chanconf{$chan}{autojoin}    = $conn->nick();
767
768         &performStrictReply("Joining $chan...");
769         &joinchan($chan);
770
771         return;
772     }
773
774     if ( !exists $chanconf{$chan} ) {
775         &performStrictReply("no such channel $chan");
776         return;
777     }
778
779     my $update = 0;
780
781     if ( defined $what and $what =~ s/^([+-])(\S+)/$2/ ) {
782         ### ".chanset +blah"
783         ### ".chanset +blah 10"         -- error.
784
785         my $set = ( $1 eq "+" ) ? 1 : 0;
786         my $was = $chanconf{$chan}{$what};
787
788         if ($set) {    # add/set.
789             if ( defined $was and $was eq '1' ) {
790                 &performStrictReply("setting $what for $chan already 1.");
791                 return;
792             }
793
794             $val = 1;
795
796         }
797         else {         # delete/unset.
798             if ( !defined $was ) {
799                 &performStrictReply("setting $what for $chan is not set.");
800                 return;
801             }
802
803             $val = 0;
804         }
805
806         # alter for cosmetic (print out) reasons only.
807         $was = ( defined $was ) ? "; was '$was'" : '';
808
809         if ( $val eq '0' ) {
810             &performStrictReply("Unsetting $what for $chan$was.");
811             delete $chanconf{$chan}{$what};
812             delete $cache{ircTextCounters} if $what eq 'ircTextCounters';
813         }
814         else {
815             &performStrictReply("Setting $what for $chan to '$val'$was.");
816             $chanconf{$chan}{$what} = $val;
817             delete $cache{ircTextCounters} if $what eq 'ircTextCounters';
818         }
819
820         $update++;
821
822     }
823     elsif ( defined $val ) {
824         ### ".chanset blah testing"
825
826         my $was = $chanconf{$chan}{$what};
827         if ( defined $was and $was eq $val ) {
828             &performStrictReply("setting $what for $chan already '$val'.");
829             return;
830         }
831         $was = ($was) ? "; was '$was'" : '';
832         &performStrictReply("Setting $what for $chan to '$val'$was.");
833
834         $chanconf{$chan}{$what} = $val;
835         delete $cache{ircTextCounters} if $what eq 'ircTextCounters';
836
837         $update++;
838
839     }
840     else {    # read only.
841         ### ".chanset"
842         ### ".chanset blah"
843
844         if ( !defined $what ) {
845             &WARN("chanset/DC: what == undefine.");
846             return;
847         }
848
849         if ( exists $chanconf{$chan}{$what} ) {
850             &performStrictReply("$what for $chan is '$chanconf{$chan}{$what}'");
851         }
852         else {
853             &performStrictReply("$what for $chan is not set.");
854         }
855     }
856
857     if ($update) {
858         $utime_chanfile = time();
859         $ucount_chanfile++;
860     }
861
862     return;
863 }
864
865 sub rehashConfVars {
866
867     # this is an attempt to fix where an option is enabled but the module
868     # has been not loaded. it also can be used for other things.
869
870     foreach ( keys %{ $cache{confvars} } ) {
871         my $i = $cache{confvars}{$_};
872         &DEBUG("rehashConfVars: _ => $_");
873
874         if ( /^news$/ and $i ) {
875             &loadMyModule('News');
876             delete $cache{confvars}{$_};
877         }
878
879         if ( /^uptime$/ and $i ) {
880             &loadMyModule('Uptime');
881             delete $cache{confvars}{$_};
882         }
883
884         if ( /^rootwarn$/i and $i ) {
885             &loadMyModule('RootWarn');
886             delete $cache{confvars}{$_};
887         }
888
889         if ( /^onjoin$/i and $i ) {
890             &loadMyModule('OnJoin');
891             delete $cache{confvars}{$_};
892         }
893     }
894
895     &DEBUG("end of rehashConfVars");
896
897     delete $cache{confvars};
898 }
899
900 1;
901
902 # vim:ts=4:sw=4:expandtab:tw=80