]> git.donarmstrong.com Git - infobot.git/blob - src/modules.pl
791bd9f5f946998f5ef35efebfeb330d76a64c6d
[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 if (&IsParam("useStrict")) { 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         "factoids"      => "Factoids.pl",
30         "freshmeat"     => "Freshmeat.pl",
31         "kernel"        => "Kernel.pl",
32         "ircdcc"        => "UserDCC.pl",
33         "perlMath"      => "Math.pl",
34         "news"          => "News.pl",
35         "quote"         => "Quote.pl",
36         "rootwarn"      => "RootWarn.pl",
37         "search"        => "Search.pl",
38         "slashdot"      => "Slashdot3.pl",
39         "topic"         => "Topic.pl",
40         "units"         => "Units.pl",
41         "uptime"        => "Uptime.pl",
42         "userinfo"      => "UserInfo.pl",
43         "wwwsearch"     => "W3Search.pl",
44         "whatis"        => "WhatIs.pl",
45         "wingate"       => "Wingate.pl",
46         "insult"        => "insult.pl",
47         "nickometer"    => "nickometer.pl",
48         "babelfish"     => "babel.pl",
49 );
50 ### THIS IS NOT LOADED ON RELOAD :(
51 BEGIN {
52     @myModulesLoadNow   = ('topic', 'uptime', 'news');
53     @myModulesReloadNot = ('IRC/Irc.pl','IRC/Schedulers.pl');
54 }
55
56 sub loadCoreModules {
57     if (!opendir(DIR, $bot_src_dir)) {
58         &ERROR("can't open source directory $bot_src_dir: $!");
59         exit 1;
60     }
61
62     my @mods;
63     while (defined(my $file = readdir DIR)) {
64         next unless $file =~ /\.pl$/;
65         next unless $file =~ /^[A-Z]/;
66         push(@mods, $file);
67     }
68     closedir DIR;
69     &status("Loading ".scalar(@mods)." CORE modules...");
70
71     foreach (sort @mods) {
72         my $mod = "$bot_src_dir/$_";
73
74         eval "require \"$mod\"";
75         if ($@) {
76             &ERROR("lCM => $@");
77             &shutdown();
78             exit 1;
79         }
80
81         $moduleAge{$mod} = (stat $mod)[9];
82         &showProc(" ($_)") if (&IsParam("DEBUG"));
83     }
84 }
85
86 sub loadDBModules {
87     &status("Loading DB modules...");
88
89     if ($param{'DBType'} =~ /^mysql$/i) {
90         eval "use DBI";
91         if ($@) {
92             &ERROR("libdbd-mysql-perl is not installed!");
93             exit 1;
94         }
95         &showProc(" (DBI // mysql)");
96
97         &status("  using MySQL support.");
98         require "$bot_src_dir/db_mysql.pl";
99
100     } elsif ($param{'DBType'} =~ /^pgsql$/i) {
101         eval "use Pg";
102         if ($@) {
103             &ERROR("libpgperl is not installed!");
104             exit 1;
105         }
106         &showProc(" (Pg // postgreSQLl)");
107
108         &status("  using PostgreSQL support.");
109         require "$bot_src_dir/db_pgsql.pl";
110     } elsif ($param{'DBType'} =~ /^dbm$/i) {
111
112         &status("  using Berkeley DBM 1.85/2.0 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     &status("Loading Factoids modules...");
123
124     if (!&IsParam("factoids")) {
125         &status("Factoid support DISABLED.");
126         return;
127     }
128
129     if (!opendir(DIR, "$bot_src_dir/Factoids")) {
130         &ERROR("can't open source directory Factoids: $!");
131         exit 1;
132     }
133
134     while (defined(my $file = readdir DIR)) {
135         next unless $file =~ /\.pl$/;
136         next unless $file =~ /^[A-Z]/;
137         my $mod = "$bot_src_dir/Factoids/$file";
138         ### TODO: use eval and exit gracefully?
139         eval "require \"$mod\"";
140         if ($@) {
141             &WARN("lFM: $@");
142             exit 1;
143         }
144
145         $moduleAge{$mod} = (stat $mod)[9];
146         &showProc(" ($file)") if (&IsParam("DEBUG"));
147     }
148     closedir DIR;
149 }
150
151 sub loadIRCModules {
152     &status("Loading IRC modules...");
153     if (&whatInterface() =~ /IRC/) {
154         eval "use Net::IRC";
155         if ($@) {
156             &ERROR("libnet-irc-perl is not installed!");
157             exit 1;
158         }
159         &showProc(" (Net::IRC)");
160
161     } else {
162         &status("IRC support DISABLED.");
163         return;
164     }
165
166     if (!opendir(DIR, "$bot_src_dir/IRC")) {
167         &ERROR("can't open source directory Factoids: $!");
168         exit 1;
169     }
170
171     while (defined(my $file = readdir DIR)) {
172         next unless $file =~ /\.pl$/;
173         next unless $file =~ /^[A-Z]/;
174         my $mod = "$bot_src_dir/IRC/$file";
175         ### TODO: use eval and exit gracefully?
176         require $mod;
177         $moduleAge{$mod} = (stat $mod)[9];
178         &showProc(" ($file)") if (&IsParam("DEBUG"));
179     }
180     closedir DIR;
181 }
182
183 sub loadMyModulesNow {
184     my $loaded = 0;
185     my $total  = 0;
186
187     &status("Loading MyModules...");
188     foreach (@myModulesLoadNow) {
189         $total++;
190         if (!defined $_) {
191             &WARN("mMLN: null element.");
192             next;
193         }
194
195         if (!&IsParam($_) and !&IsChanConf($_) and !&getChanConfList($_)) {
196             if (exists $myModules{$_}) {
197                 &status("myModule: $myModules{$_} or $_ (1) not loaded.");
198             } else {
199                 &DEBUG("myModule: $_ (2) not loaded.");
200             }
201
202             next;
203         }
204
205         &loadMyModule($myModules{$_});
206         $loaded++;
207     }
208
209     &status("Module: Runtime: Loaded/Total [$loaded/$total]");
210 }
211
212 ### rename to moduleReloadAll?
213 sub reloadAllModules {
214 ###    &status("Module: reloading all.");
215     foreach (map { substr($_,2) } keys %moduleAge) {
216         &reloadModule($_);
217     }
218 ###    &status("Module: reloading done.");
219 }
220
221 ### rename to modulesReload?
222 sub reloadModule {
223     my ($mod)   = @_;
224     my $file    = (grep /\/$mod/, keys %INC)[0];
225
226     # don't reload if it's not our module.
227     if ($mod =~ /::/ or $mod !~ /pl$/) {
228         &VERB("Not reloading $mod.",3);
229         return;
230     }
231
232     if (!defined $file) {
233         &WARN("rM: Cannot reload $mod since it was not loaded anyway.");
234         return;
235     }
236
237     if (! -f $file) {
238         &ERROR("rM: file '$file' does not exist?");
239         return;
240     }
241
242     my $age = (stat $file)[9];
243     return if ($age == $moduleAge{$file});
244
245     if ($age < $moduleAge{$file}) {
246         &WARN("rM: we're not gonna downgrade the file. use 'touch'.");
247         return;
248     }
249
250     if (grep /$mod/, @myModulesReloadNot) {
251         &DEBUG("rM: SHOULD NOT RELOAD $mod!!!");
252         return;
253     }
254
255     my $dc  = &Time2String($age   - $moduleAge{$file});
256     my $ago = &Time2String(time() - $moduleAge{$file});
257
258     &status("Module: Loading $mod...");
259     &VERB("Module:  delta change: $dc",2);
260     &VERB("Module:           ago: $ago",2);
261
262     delete $INC{$file};
263     eval "require \"$file\"";   # require or use?
264     if (@$) {
265         &DEBUG("rM: failure: @$");
266     } else {
267         my $basename = $file;
268         $basename =~ s/^.*\///;
269         &status("Module: reloaded $basename");
270         $moduleAge{$file} = $age;
271     }
272 }
273
274 ###
275 ### OPTIONAL MODULES.
276 ###
277
278 local %perlModulesLoaded  = ();
279 local %perlModulesMissing = ();
280
281 sub loadPerlModule {
282     return 0 if (exists $perlModulesMissing{$_[0]});
283     &reloadModule($_[0]);
284     return 1 if (exists $perlModulesLoaded{$_[0]});
285
286     eval "use $_[0]";
287     if ($@) {
288         &WARN("Module: $_[0] is not installed!");
289         $perlModulesMissing{$_[0]} = 1;
290         return 0;
291     } else {
292         $perlModulesLoaded{$_[0]} = 1;
293         &status("Module: Loaded $_[0] ...");
294         &showProc(" ($_[0])");
295         return 1;
296     }
297 }
298
299 sub loadMyModule {
300     my ($tmp) = @_;
301     if (!defined $tmp) {
302         &WARN("loadMyModule: module is NULL.");
303         return 0; 
304     }
305
306     my ($modulebase, $modulefile);
307     if (exists $myModules{$tmp}) {
308         ($modulename, $modulebase) = ($tmp, $myModules{$tmp});
309     } else {
310         $modulebase = $tmp;
311         if ($tmp = grep /^$modulebase$/, keys %myModules) {
312             &DEBUG("lMM: lame hack, file => name => $tmp.");
313             $modulename = $tmp;
314         }
315     }
316     my $modulefile = "$bot_src_dir/Modules/$modulebase";
317
318     # call reloadModule() which checks age of file and reload.
319     if (grep /\/$modulebase$/, keys %INC) {
320         &reloadModule($modulebase);
321         return 1;       # depend on reloadModule?
322     }
323
324     if (! -f $modulefile) {
325         &ERROR("lMM: module ($modulebase) does not exist.");
326         if ($$ == $bot_pid) {   # parent.
327             &shutdown() if (defined $shm and defined $dbh);
328         } else {                        # child.
329             &DEBUG("b4 delfork 1");
330             &delForked($modulebase);
331         }
332
333         exit 1;
334     }
335
336     eval "require \"$modulefile\"";
337     if ($@) {
338         &ERROR("cannot load my module: $modulebase");
339         if ($bot_pid != $$) {   # child.
340             &DEBUG("b4 delfork 2");
341             &delForked($modulebase);
342             exit 1;
343         }
344
345         return 0;
346     } else {
347         $moduleAge{$modulefile} = (stat $modulefile)[9];
348
349         &status("myModule: Loaded $modulebase ...");
350         &showProc(" ($modulebase)");
351         return 1;
352     }
353 }
354
355 $no_timehires = 0;
356 eval "use Time::HiRes qw(gettimeofday tv_interval)";
357 if ($@) {
358     &WARN("No Time::HiRes?");
359     $no_timehires = 1;
360 }
361 &showProc(" (Time::HiRes)");
362
363 sub AUTOLOAD {
364     return if ($AUTOLOAD =~ /__/);      # internal.
365
366     &ERROR("UNKNOWN FUNCTION CALLED: $AUTOLOAD");
367     foreach (@_) {
368         next unless (defined $_);
369         &status("  => $_");
370     }
371 }
372
373 1;