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