]> git.donarmstrong.com Git - infobot.git/blob - src/modules.pl
- berkeley dbm support now works! thanks to tim riker.
[infobot.git] / src / modules.pl
1 #
2 #  modules.pl: pseudo-Module handler
3 #      Author: dms
4 #     Version: v0.2 (20000629)
5 #     Created: 20000624
6 #
7
8 #use strict;
9 use vars qw($AUTOLOAD);
10
11 ###
12 ### REQUIRED MODULES.
13 ###
14
15 eval "use IO::Socket";
16 if ($@) {
17     &ERROR("no IO::Socket?");
18     exit 1;
19 }
20 &showProc(" (IO::Socket)");
21
22 ### MODULES.
23 %myModules = (
24         "countdown"     => "Countdown.pl",
25         "debian"        => "Debian.pl",
26         "debianExtra"   => "DebianExtra.pl",
27         "dict"          => "Dict.pl",
28         "dumpvars"      => "DumpVars.pl",
29         "symdump"       => "DumpVars2.pl",
30         "factoids"      => "Factoids.pl",
31         "freshmeat"     => "Freshmeat.pl",
32         "kernel"        => "Kernel.pl",
33         "ircdcc"        => "UserDCC.pl",
34         "perlMath"      => "Math.pl",
35         "news"          => "News.pl",
36         "quote"         => "Quote.pl",
37         "rootwarn"      => "RootWarn.pl",
38         "search"        => "Search.pl",
39         "slashdot"      => "Slashdot3.pl",
40         "topic"         => "Topic.pl",
41         "units"         => "Units.pl",
42         "uptime"        => "Uptime.pl",
43         "userinfo"      => "UserInfo.pl",
44         "wwwsearch"     => "W3Search.pl",
45         "whatis"        => "WhatIs.pl",
46         "wingate"       => "Wingate.pl",
47         "insult"        => "insult.pl",
48         "nickometer"    => "nickometer.pl",
49         "babelfish"     => "babel.pl",
50 );
51 ### THIS IS NOT LOADED ON RELOAD :(
52 my @myModulesLoadNow;
53 my @myModulesReloadNot;
54 BEGIN {
55     @myModulesLoadNow   = ('topic', 'uptime', 'news', 'rootWarn', 'symdump');
56     @myModulesReloadNot = ('IRC/Irc.pl','IRC/Schedulers.pl');
57 }
58
59 sub loadCoreModules {
60     my @mods = &getPerlFiles($bot_src_dir);
61
62     &status("Loading ".scalar(@mods)." CORE modules...");
63
64     foreach (sort @mods) {
65         my $mod = "$bot_src_dir/$_";
66
67         eval "require \"$mod\"";
68         if ($@) {
69             &ERROR("lCM => $@");
70             &shutdown();
71             exit 1;
72         }
73
74         $moduleAge{$mod} = (stat $mod)[9];
75         &showProc(" ($_)") if (&IsParam("DEBUG"));
76     }
77 }
78
79 sub loadDBModules {
80     &status("Loading DB modules...");
81
82     my $f = "$bot_src_dir/modules.pl";
83     $moduleAge{$f} = (stat $f)[9];
84
85     if ($param{'DBType'} =~ /^mysql$/i) {
86         eval "use DBI";
87         if ($@) {
88             &ERROR("libdbd-mysql-perl is not installed!");
89             exit 1;
90         }
91         &showProc(" (DBI // mysql)");
92
93         &status("  using MySQL support.");
94         $f = "$bot_src_dir/db_mysql.pl";
95         require $f;
96         $moduleAge{$f} = (stat $f)[9];
97
98     } elsif ($param{'DBType'} =~ /^pgsql$/i) {
99 #       eval "use Pg";
100         eval "use DBI";
101         if ($@) {
102             &ERROR("libpgperl is not installed!");
103             exit 1;
104         }
105         &showProc(" (pgsql)");
106
107         &status("  using pgsql support.");
108         require "$bot_src_dir/db_pgsql.pl";
109
110     } elsif ($param{'DBType'} =~ /^dbm$/i) {
111
112         &status("  using Berkeley DBM support.");
113         require "$bot_src_dir/db_dbm.pl";
114     } else {
115
116         &status("DB support DISABLED.");
117         return;
118     }
119 }
120
121 sub loadFactoidsModules {
122     if (!&IsParam("factoids")) {
123         &status("Factoid support DISABLED.");
124         return;
125     }
126
127     &status("Loading Factoids modules...");
128
129     foreach ( &getPerlFiles("$bot_src_dir/Factoids") ) {
130         my $mod = "$bot_src_dir/Factoids/$_";
131
132         eval "require \"$mod\"";
133         if ($@) {
134             &ERROR("lFM: $@");
135             exit 1;
136         }
137
138         $moduleAge{$mod} = (stat $mod)[9];
139         &showProc(" ($_)") if (&IsParam("DEBUG"));
140     }
141 }
142
143 sub loadIRCModules {
144     my ($interface) = &whatInterface();
145     if ($interface =~ /IRC/) {
146         &status("Loading IRC modules...");
147
148         eval "use Net::IRC";
149         if ($@) {
150             &ERROR("libnet-irc-perl is not installed!");
151             exit 1;
152         }
153         &showProc(" (Net::IRC)");
154     } else {
155         &status("IRC support DISABLED.");
156         # disabling forking.
157         $param{forking} = 0;
158         $param{noSHM}   = 1;
159     }
160
161     foreach ( &getPerlFiles("$bot_src_dir/$interface") ) {
162         my $mod = "$bot_src_dir/$interface/$_";
163
164         &status("Loading Modules \"$mod\"");
165         eval "require \"$mod\"";
166         if ($@) {
167             &ERROR("require \"$mod\" => $@");
168             &shutdown();
169             exit 1;
170         }
171
172         $moduleAge{$mod} = (stat $mod)[9];
173         &showProc(" ($_)") if (&IsParam("DEBUG"));
174     }
175 }
176
177 sub loadMyModulesNow {
178     my $loaded = 0;
179     my $total  = 0;
180
181     &status("Loading MyModules...");
182     foreach (@myModulesLoadNow) {
183         $total++;
184         if (!defined $_) {
185             &WARN("mMLN: null element.");
186             next;
187         }
188
189         if (!&IsParam($_) and !&IsChanConf($_) and !&getChanConfList($_)) {
190             if (exists $myModules{$_}) {
191                 &status("myModule: $myModules{$_} or $_ (1) not loaded.");
192             } else {
193                 &DEBUG("myModule: $_ (2) not loaded.");
194             }
195
196             next;
197         }
198
199         # weird hack to get rootwarn to work.
200         # it may break on other cases though, any ideas?
201         &loadMyModule( $myModules{$_} || $myModules{lc $_} );
202         $loaded++;
203     }
204
205     &status("Module: Runtime: Loaded/Total [$loaded/$total]");
206 }
207
208 ### rename to moduleReloadAll?
209 sub reloadAllModules {
210     &VERB("Module: reloading all.",2);
211
212     # obscure usage of map and regex :)
213     foreach (map { s/.*?\/?src/src/; $_ } keys %moduleAge) {
214         &reloadModule($_);
215     }
216
217     &VERB("Module: reloading done.",2);
218 }
219
220 ### rename to modulesReload?
221 sub reloadModule {
222     my ($mod)   = @_;
223     my $file    = (grep /\/$mod/, keys %INC)[0];
224
225     # don't reload if it's not our module.
226     if ($mod =~ /::/ or $mod !~ /pl$/) {
227         &VERB("Not reloading $mod.",3);
228         return;
229     }
230
231     if (!defined $file) {
232         &WARN("rM: Cannot reload $mod since it was not loaded anyway.");
233         return;
234     }
235
236     if (! -f $file) {
237         &ERROR("rM: file '$file' does not exist?");
238         return;
239     }
240
241     if (grep /$mod/, @myModulesReloadNot) {
242         &DEBUG("rM: should not reload $mod");
243         return;
244     }
245
246     my $age = (stat $file)[9];
247
248     if (!exists $moduleAge{$file}) {
249         &DEBUG("Looks like $file was not loaded; fixing.");
250     } else {
251         return if ($age == $moduleAge{$file});
252
253         if ($age < $moduleAge{$file}) {
254             &WARN("rM: we're not gonna downgrade '$file'; use touch.");
255             &DEBUG("age => $age");
256             &DEBUG("mA{$file} => $moduleAge{$file}");
257             return;
258         }
259
260         my $dc  = &Time2String($age   - $moduleAge{$file});
261         my $ago = &Time2String(time() - $moduleAge{$file});
262
263         &VERB("Module:  delta change: $dc",2);
264         &VERB("Module:           ago: $ago",2);
265     }
266
267     &status("Module: Loading $mod...");
268
269     delete $INC{$file};
270     eval "require \"$file\"";   # require or use?
271     if (@$) {
272         &DEBUG("rM: failure: @$");
273     } else {
274         my $basename = $file;
275         $basename =~ s/^.*\///;
276         &status("Module: reloaded $basename");
277         $moduleAge{$file} = $age;
278     }
279 }
280
281 ###
282 ### OPTIONAL MODULES.
283 ###
284
285 my %perlModulesLoaded  = ();
286 my %perlModulesMissing = ();
287
288 sub loadPerlModule {
289     return 0 if (exists $perlModulesMissing{$_[0]});
290     &reloadModule($_[0]);
291     return 1 if (exists $perlModulesLoaded{$_[0]});
292
293     eval "use $_[0]";
294     if ($@) {
295         &WARN("Module: $_[0] is not installed!");
296         $perlModulesMissing{$_[0]} = 1;
297         return 0;
298     } else {
299         $perlModulesLoaded{$_[0]} = 1;
300         &status("Module: Loaded $_[0] ...");
301         &showProc(" ($_[0])");
302         return 1;
303     }
304 }
305
306 sub loadMyModule {
307     my ($tmp) = @_;
308     if (!defined $tmp) {
309         &WARN("loadMyModule: module is NULL.");
310         return 0; 
311     }
312
313     my ($modulename, $modulebase);
314     if (exists $myModules{$tmp}) {
315         ($modulename, $modulebase) = ($tmp, $myModules{$tmp});
316     } else {
317         $modulebase = $tmp;
318         if ($tmp = grep /^$modulebase$/, keys %myModules) {
319             &DEBUG("lMM: lame hack, file => name => $tmp.");
320             $modulename = $tmp;
321         }
322     }
323     my $modulefile = "$bot_src_dir/Modules/$modulebase";
324
325     # call reloadModule() which checks age of file and reload.
326     if (grep /\/$modulebase$/, keys %INC) {
327         &reloadModule($modulebase);
328         return 1;       # depend on reloadModule?
329     }
330
331     if (! -f $modulefile) {
332         &ERROR("lMM: module ($modulebase) does not exist.");
333         if ($$ == $bot_pid) {   # parent.
334             &shutdown() if (defined $shm and defined $dbh);
335         } else {                        # child.
336             &DEBUG("b4 delfork 1");
337             &delForked($modulebase);
338         }
339
340         exit 1;
341     }
342
343     eval "require \"$modulefile\"";
344     if ($@) {
345         &ERROR("cannot load my module: $modulebase");
346         if ($bot_pid != $$) {   # child.
347             &DEBUG("b4 delfork 2");
348             &delForked($modulebase);
349             exit 1;
350         }
351
352         return 0;
353     } else {
354         $moduleAge{$modulefile} = (stat $modulefile)[9];
355
356         &status("myModule: Loaded $modulebase ...");
357         &showProc(" ($modulebase)");
358         return 1;
359     }
360 }
361
362 $no_timehires = 0;
363 eval "use Time::HiRes qw(gettimeofday tv_interval)";
364 if ($@) {
365     &WARN("No Time::HiRes?");
366     $no_timehires = 1;
367 }
368 &showProc(" (Time::HiRes)");
369
370 sub AUTOLOAD {
371     if (!defined $AUTOLOAD and defined $::AUTOLOAD) {
372         &DEBUG("AUTOLOAD: hrm.. ::AUTOLOAD defined!");
373     }
374     return unless (defined $AUTOLOAD);
375     return if ($AUTOLOAD =~ /__/);      # internal.
376
377     my $str = join(', ', @_);
378     &ERROR("UNKNOWN FUNCTION CALLED: $AUTOLOAD ($str)");
379
380     $AUTOLOAD =~ s/^(\S+):://g;
381
382     if (exists $myModules{lc $AUTOLOAD}) {
383         # hopefully this will work.
384         &DEBUG("Trying to load module $AUTOLOAD...");
385         &loadMyModule(lc $AUTOLOAD);
386     }
387 }
388
389 sub getPerlFiles {
390     my($dir) = @_;
391
392     if (!opendir(DIR, $dir)) {
393         &ERROR("Cannot open source directory ($dir): $!");
394         exit 1;
395     }
396
397     my @mods;
398     while (defined(my $file = readdir DIR)) {
399         next unless $file =~ /\.pl$/;
400         next unless $file =~ /^[A-Z]/;
401         push(@mods, $file);
402     }
403     closedir DIR;
404
405     return reverse sort @mods;
406 }
407
408 1;