]> git.donarmstrong.com Git - infobot.git/blob - src/DynaConfig.pl
pre-config 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 if (&IsParam("useStrict")) { use strict; }
10
11 #####
12 ##### USERFILE CONFIGURATION READER/WRITER
13 #####
14
15 sub readUserFile {
16     if (!open IN,"$bot_misc_dir/blootbot.users") {
17         &ERROR("cannot read userfile.");
18         &closeLog();
19         exit 1;
20     }
21
22     my $ver = <IN>;
23     if ($ver !~ /^#v1/) {
24         &ERROR("old or invalid user file found.");
25         &closeLog();
26         exit 1; # correct?
27     }
28
29     my $nick;
30     while (<IN>) {
31         chop;
32
33         next if /^$/;
34         next if /^#/;
35
36         if (/^--(\S+)[\s\t]+(.*)$/) {           # user: middle entry.
37             my ($what,$val) = ($1,$2);
38
39             # nice little hack.
40             if ($what eq "HOSTS") {
41                 $users{$nick}{$1}{$2} = 1;
42             } else {
43                 $users{$nick}{$1} = $2;
44             }
45
46         } elsif (/^(\S+)$/) {                   # user: start entry.
47             $nick       = $1;
48
49         } elsif (/^::(\S+) ignore$/) {          # ignore: start entry.
50             $chan       = $1;
51
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;
57
58         } elsif (/^::(\S+) bans$/) {            # bans: start entry.
59             $chan       = $1;
60
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;
66
67         } else {                                # unknown.
68             &WARN("unknown line: $_");
69         }
70     }
71     close IN;
72
73     &status( sprintf("USERFILE: Loaded: %d users, %d bans, %d ignore",
74                 scalar(keys %users)-1,
75                 scalar(keys %bans),
76                 scalar(keys %ignore),
77         )
78     );
79 }
80
81 sub writeUserFile {
82     if (!open OUT,">$bot_misc_dir/blootbot.users") {
83         &ERROR("cannot write to userfile.");
84         return;
85     }
86
87     my $time            = scalar(localtime);
88
89     print OUT "#v1: blootbot -- $ident -- written $time\n\n";
90
91     ### USER LIST.
92     my $cusers  = 0;
93     foreach (sort keys %users) {
94         my $user = $_;
95         $cusers++;
96         my $count = scalar keys %{ $users{$user} };
97         if (!$count) {
98             &WARN("user $user has no other attributes; skipping.");
99             next;
100         }
101
102         print OUT "$user\n";
103
104         foreach (sort keys %{ $users{$user} }) {
105             my $what    = $_;
106             my $val     = $users{$user}{$_};
107
108             if (ref($val) eq "HASH") {
109                 foreach (sort keys %{ $users{$user}{$_} }) {
110                     print OUT "--$what\t\t$_\n";
111                 }
112
113             } else {
114                 print OUT "--$_\t\t$val\n";
115             }
116         }
117         print OUT "\n";
118     }
119
120     ### BAN LIST.
121     my $cbans   = 0;
122     foreach (keys %bans) {
123         my $chan = $_;
124         $cbans++;
125
126         my $count = scalar keys %{ $bans{$chan} };
127         if (!$count) {
128             &WARN("bans: chan $chan has no other attributes;
129 skipping.");
130             next;
131         }
132
133         print OUT "::$chan bans\n";
134         &DEBUG("::$chan bans");
135         foreach (keys %{ $bans{$chan} }) {
136             printf OUT "- %s:+%d:+%d:%d:%s:%s\n",
137             $_, @{ $bans{$chan}{$_} };
138             &DEBUG( sprintf("- %s:+%d:+%d:%d:%s:%s\n",
139             $_, @{ $bans{$chan}{$_} } ));
140         }
141     }
142     print OUT "\n" if ($cbans);
143
144     ### IGNORE LIST.
145     my $cignore = 0;
146     foreach (keys %ignore) {
147         my $chan = $_;
148         $cignore++;
149
150         my $count = scalar keys %{ $ignore{$chan} };
151         if (!$count) {
152             &WARN("ignore: chan $chan has no other attributes; skipping.");
153             next;
154         }
155
156         print OUT "::$chan ignore\n";
157         &DEBUG("::$chan ignore");
158         foreach (keys %{ $ignore{$chan} }) {
159             printf OUT "- %s:+%d:%s:%d:%s\n",
160             $_, @{ $bans{$chan}{$_} };
161             &DEBUG( sprintf("- %s:+%d:%s:%d:%s\n",
162                     $_, @{ $bans{$chan}{$_} } ));
163         }
164     }
165
166     close OUT;
167
168     $wtime_userfile = time();
169     &status("--- Saved USERFILE ($cusers users; $cbans bans; $cignore ignore) at $time");
170     if (defined $msgType and $msgType =~ /^chat$/) {
171         &performStrictReply("--- Writing user file...");
172     }
173 }
174
175 #####
176 ##### CHANNEL CONFIGURATION READER/WRITER
177 #####
178
179 sub readChanFile {
180     if (!open IN,"$bot_misc_dir/blootbot.chan") {
181         &ERROR("cannot erad chanfile.");
182         return;
183     }
184
185     $_ = <IN>;  # version string.
186
187     my $chan;
188     while (<IN>) {
189         chop;
190
191         next if /^$/;
192
193         if (/^(\S+)\s*$/) {
194             $chan       = $1;
195             next;
196         }
197         next unless (defined $chan);
198
199         if (/^[\s\t]+\+(\S+)$/) {               # bool, true.
200             $chanconf{$chan}{$1} = 1;
201
202         } elsif (/^[\s\t]+\-(\S+)$/) {          # bool, false.
203             $chanconf{$chan}{$1} = 0;
204
205         } elsif (/^[\s\t]+(\S+)[\ss\t]+(.*)$/) {# what = val.
206             $chanconf{$chan}{$1} = $2;
207
208         } else {
209             &WARN("unknown line: $_") unless (/^#/);
210         }
211     }
212     close IN;
213
214     &status("CHANFILE: Loaded: ".(scalar(keys %chanconf)-1)." chans");
215 }
216
217 sub writeChanFile {
218     if (!open OUT,">$bot_misc_dir/blootbot.chan") {
219         &ERROR("cannot write chanfile.");
220         return;
221     }
222
223     my $time            = scalar(localtime);
224     print OUT "#v1: blootbot -- $ident -- written $time\n\n";
225
226     foreach (sort keys %chanconf) {
227         $chan   = $_;
228
229         print OUT "$chan\n";
230
231         foreach (sort keys %{ $chanconf{$chan} }) {
232             my $val = $chanconf{$chan}{$_};
233
234             if ($val =~ /^0$/) {                # bool, false.
235                 print OUT "    -$_\n";
236
237             } elsif ($val =~ /^1$/) {           # bool, true.
238                 print OUT "    +$_\n";
239
240             } else {                            # what = val.
241                 print OUT "    $_ $val\n";
242
243             }
244
245         }
246         print OUT "\n";
247     }
248
249     close OUT;
250
251     $wtime_chanfile = time();
252     &status("--- Saved CHANFILE (".scalar(keys %chanconf).
253                 " chans) at $time");
254
255     if (defined $msgType and $msgType =~ /^chat$/) {
256         &performStrictReply("--- Writing chan file...");
257     }
258 }
259
260 #####
261 ##### USER COMMANDS.
262 #####
263
264 sub IsFlag {
265     my $flags = shift;
266     my ($ret, $f, $o) = "";
267
268     foreach $f (split //, $users{$userHandle}{FLAGS}) {
269         foreach $o ( split //, $flags ) {
270             next unless ($f eq $o);
271
272             $ret = $f;
273             last;
274         }
275     }
276
277     $ret;
278 }
279
280 sub verifyUser {
281     my ($nick, $lnuh) = @_;
282     my ($user,$m);
283
284     $userHandle = "";
285
286     foreach $user (keys %users) {
287         next if ($user eq "_default");
288
289         foreach $m (keys %{$users{$user}{HOSTS}}) {
290             $m =~ s/\?/./g;
291             $m =~ s/\*/.*?/g;
292             $m =~ s/([\@\(\)\[\]])/\\$1/g;
293
294             next unless ($lnuh =~ /^$m$/i);
295
296             if ($user !~ /^\Q$nick\E$/i) {
297                 &status("vU: host matched but diff nick ($nick != $user).");
298             }
299
300             $userHandle = $user;
301             last;
302         }
303
304         last if ($userHandle ne "");
305
306         if ($user =~ /^\Q$nick\E$/i) {
307             &status("vU: nick matched but host is not in list ($lnuh).");
308         }
309     }
310
311     $userHandle ||= "_default";
312     $talkWho{$talkchannel} = $who if (defined $talkchannel);
313     $talkWho = $who;
314
315     return $userHandle;
316 }
317
318 sub ckpasswd {
319     # returns true if arg1 encrypts to arg2
320     my ($plain, $encrypted) = @_;
321     if ($encrypted eq "") {
322         ($plain, $encrypted) = split(/\s+/, $plain, 2);
323     }
324     return 0 unless ($plain ne "" and $encrypted ne "");
325
326     # MD5 // DES. Bobby Billingsley++.
327     my $salt = substr($encrypted, 0, 2);
328     if ($encrypted =~ /^\$\d\$(\w\w)\$/) {
329         $salt = $1;
330     }
331
332     return ($encrypted eq crypt($plain, $salt));
333 }
334
335 # mainly for dcc chat... hrm.
336 sub hasFlag {
337     my ($flag) = @_;
338
339     if (&IsFlag($flag) eq $flag) {
340         return 1;
341     } else {
342         &status("DCC CHAT: <$who> $message -- not enough flags.");
343         &performStrictReply("error: you do not have enough flags for that. ($flag required)");
344         return 0;
345     }
346 }
347
348 sub ignoreAdd {
349     my($mask,$chan,$expire,$comment) = @_;
350
351     $chan       ||= "*";        # global if undefined.
352     $comment    ||= "";         # optional.
353     $expire     ||= 0;          # permament.
354     my $count   ||= 0;
355
356     if ($expire > 0) {
357         $expire         = $expire*60 + time();
358     } else {
359         $expire         = 0;
360     }
361
362     $ignore{$chan}{$mask} = [$expire, $count, $who, time(), $comment];
363
364     if (exists $ignore{$chan}{$mask}) {
365         return 0;
366     } else {
367         $utime_userfile = time();
368         $ucount_userfile++;
369
370         return 1;
371     }
372 }
373
374 sub ignoreDel {
375     my($mask)   = @_;
376     my @match;
377
378     ### TODO: support wildcards.
379     foreach (keys %ignore) {
380         my $chan = $_;
381
382         foreach (grep /^\Q$mask\E$/i, keys %{ $ignore{$chan} }) {
383             delete $ignore{$chan}{$mask};
384             push(@match,$chan);
385         }
386
387         &DEBUG("iD: scalar => ".scalar(keys %{ $ignore{$chan} }) );
388     }
389
390     if (scalar @match) {
391         $utime_userfile = time();
392         $ucount_userfile++;
393     }
394
395     return @match;
396 }
397
398 sub userAdd {
399     my($nick,$mask)     = @_;
400
401     if (exists $users{$nick}) {
402         return 0;
403     }
404
405     $utime_userfile = time();
406     $ucount_userfile++;
407
408     $users{$nick}{HOSTS}{$mask} = 1;
409     $users{$nick}{FLAGS}        = $users{_default}{FLAGS};
410
411     return 1;
412 }
413
414 sub userDel {
415     my($nick)   = @_;
416
417     if (!exists $users{$nick}) {
418         return 0;
419     }
420
421     $utime_userfile = time();
422     $ucount_userfile++;
423
424     delete $users{$nick};
425
426     return 1;
427 }
428
429 sub banAdd {
430     my($mask,$chan,$expire,$reason) = @_;
431
432     $chan       ||= "*";
433     $expire     ||= 0;
434
435     if ($expire > 0) {
436         $expire         = $expire*60 + time();
437     }
438
439     my $exist   = 1;
440     $exist++ if (exists $bans{$chan}{$mask} or
441                 exists $bans{_default}{$mask});
442     $bans{$chan}{$mask} = [$expire, 0, $who, time(), $reason];
443
444     if ($exist == 1) {
445         $utime_userfile = time();
446         $ucount_userfile++;
447     }
448
449     return $exist;
450 }
451
452 sub banDel {
453     my($mask)   = @_;
454     my @match;
455
456     foreach (keys %bans) {
457         my $chan        = $_;
458
459         foreach (grep /^\Q$mask\E$/i, keys %{ $bans{$chan} }) {
460             delete $bans{$chan}{$_};
461             push(@match, $chan);
462         }
463
464         &DEBUG("bans: scalar => ".scalar(keys %{ $bans{$chan} }) );
465     }
466
467     if (scalar @match) {
468         $utime_userfile = time();
469         $ucount_userfile++;
470     }
471
472     return @match;
473 }
474
475 sub IsUser {
476     my($user) = @_;
477
478     if ( &getUser($user) ) {
479         return 1;
480     } else {
481         return 0;
482     }
483 }
484
485 sub getUser {
486     my($user) = @_;
487
488     if (!defined $user) {
489         &WARN("getUser: user == NULL.");
490         return;
491     }
492
493     if (my @retval = grep /^\Q$user\E$/i, keys %users) {
494         if ($retval[0] ne $user) {
495             &WARN("getUser: retval[0] ne user ($retval[0] ne $user)");
496         }
497         my $count = scalar keys %{ $users{$retval[0]} };
498         &DEBUG("count => $count.");
499
500         return $retval[0];
501     } else {
502         return;
503     }
504 }
505
506 my @regFlagsChan = (
507         "autojoin",
508         "freshmeat",
509         "limitcheckInterval",
510         "limitcheckPlus",
511         "allowConv",
512         "allowDNS",
513 ### TODO: finish off this list.
514 );
515
516 my @regFlagsUser = ("mno");     # todo...
517
518 1;