]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - configure
76f1543c67001eac96f7dfa4ae95241431914619
[user/henk/code/inspircd.git] / configure
1 #!/usr/bin/perl
2 ###################################################
3 # InspIRCd Configuration Script
4 #
5 # Copyright 2002-2009 The InspIRCd Development Team
6 #  http://wiki.inspircd.org/Credits
7 #
8 # Licensed under GPL, please see the COPYING file
9 # for more information
10 #
11 # $Id$
12 #
13 ###################################################
14
15 BEGIN {
16         require 5.8.0;
17 }
18
19 use strict;
20 use warnings FATAL => qw(all);
21
22 use Data::Dumper;
23 BEGIN {
24         $Data::Dumper::Sortkeys = 1;
25         $Data::Dumper::Useqq = 1;
26 };
27
28 use File::Copy ();
29 use Socket;
30 use Cwd;
31 use Getopt::Long;
32
33 # Utility functions for our buildsystem
34 use make::utilities;
35 use make::configure;
36 use make::gnutlscert;
37 use make::opensslcert;
38
39 ###############################################################################################
40 #
41 #                                 NON-EDITABLE VARIABLES
42 #
43 ###############################################################################################
44
45 our ($opt_use_gnutls, $opt_rebuild, $opt_use_openssl, $opt_nointeractive, $opt_ports,
46     $opt_epoll, $opt_kqueue, $opt_noports, $opt_noepoll, $opt_nokqueue,
47     $opt_ipv6, $opt_ipv6links, $opt_noipv6links, $opt_maxbuf, $opt_disable_debug, $opt_freebsd_port);
48
49 our ($opt_cc, $opt_base_dir, $opt_config_dir, $opt_module_dir, $opt_binary_dir,
50     $opt_library_dir);
51
52 sub list_extras ();
53
54 sub enable_extras (@);
55
56 sub disable_extras (@);
57
58 my @opt_enableextras;
59 my @opt_disableextras;
60
61 GetOptions (
62         'enable-gnutls' => \$opt_use_gnutls,
63         'rebuild' => \$opt_rebuild,
64         'enable-openssl' => \$opt_use_openssl,
65         'disable-interactive' => \$opt_nointeractive,
66         'enable-ports' => \$opt_ports,
67         'enable-epoll' => \$opt_epoll,
68         'enable-kqueue' => \$opt_kqueue,
69         'disable-ports' => \$opt_noports,
70         'disable-epoll' => \$opt_noepoll,
71         'disable-kqueue' => \$opt_nokqueue,
72         'enable-ipv6' => \$opt_ipv6,
73         'enable-remote-ipv6' => \$opt_ipv6links,
74         'disable-remote-ipv6' => \$opt_noipv6links,
75         'with-cc=s' => \$opt_cc,
76         'with-maxbuf=i' => \$opt_maxbuf,
77         'enable-freebsd-ports-openssl' => \$opt_freebsd_port,
78         'prefix=s' => \$opt_base_dir,
79         'config-dir=s' => \$opt_config_dir,
80         'module-dir=s' => \$opt_module_dir,
81         'binary-dir=s' => \$opt_binary_dir,
82         'library-dir=s' => \$opt_library_dir,
83         'disable-debuginfo' => sub { $opt_disable_debug = 1 },
84         'help'  => sub { showhelp(); },
85         'update' => sub { update(); },
86         'svnupdate' => sub { svnupdate(); },
87         'clean' => sub { clean(); },
88         'list-extras' => sub { list_extras; exit 0; }, # This, --enable-extras, and --disable-extras are for non-interactive managing.
89         'enable-extras=s@' => \@opt_enableextras, # ^
90         'disable-extras=s@' => \@opt_disableextras, # ^
91         'generate-openssl-cert' => sub { make_openssl_cert(); exit(0); },
92         'generate-gnutls-cert' => sub { make_gnutls_cert(); exit(0); }
93 );
94
95 if (scalar(@opt_enableextras) + scalar(@opt_disableextras) > 0) {
96         @opt_enableextras = split /,/, join(',', @opt_enableextras);
97         @opt_disableextras = split /,/, join(',', @opt_disableextras);
98         enable_extras(@opt_enableextras);
99         disable_extras(@opt_disableextras);
100         list_extras;
101         print "Remember: YOU are responsible for making sure any libraries needed have been installed!\n";
102         exit 0;
103 }
104
105 our $non_interactive = (
106         (defined $opt_library_dir) ||
107         (defined $opt_base_dir) ||
108         (defined $opt_config_dir) ||
109         (defined $opt_module_dir) ||
110         (defined $opt_base_dir) ||
111         (defined $opt_binary_dir) ||
112         (defined $opt_nointeractive) ||
113         (defined $opt_cc) ||
114         (defined $opt_ipv6) ||
115         (defined $opt_ipv6links) ||
116         (defined $opt_noipv6links) ||
117         (defined $opt_kqueue) ||
118         (defined $opt_epoll) ||
119         (defined $opt_ports) ||
120         (defined $opt_use_openssl) ||
121         (defined $opt_nokqueue) ||
122         (defined $opt_noepoll) ||
123         (defined $opt_noports) ||
124         (defined $opt_maxbuf) ||
125         (defined $opt_use_gnutls) ||
126         (defined $opt_freebsd_port)
127 );
128 our $interactive = !$non_interactive;
129
130 chomp(our $topdir = getcwd());
131 our $this = resolve_directory($topdir);                                         # PWD, Regardless.
132 our @modlist = ();                                                                      # Declare for Module List..
133 our %config = ();                                                                       # Initiate Configuration Hash..
134 $config{ME}              = resolve_directory($topdir);                          # Present Working Directory
135
136 $config{BASE_DIR}          = $config{ME};
137
138 if (defined $opt_base_dir)
139 {
140         $config{BASE_DIR} = $opt_base_dir;
141 }
142
143 $config{CONFIG_DIR}      = resolve_directory($config{BASE_DIR}."/conf");        # Configuration Directory
144 $config{MODULE_DIR}      = resolve_directory($config{BASE_DIR}."/modules");     # Modules Directory
145 $config{BINARY_DIR}      = resolve_directory($config{BASE_DIR}."/bin");         # Binary Directory
146 $config{LIBRARY_DIR}    = resolve_directory($config{BASE_DIR}."/lib");          # Library Directory
147
148 if (defined $opt_config_dir)
149 {
150         $config{CONFIG_DIR} = $opt_config_dir;
151 }
152 if (defined $opt_module_dir)
153 {
154         $config{MODULE_DIR} = $opt_module_dir;
155 }
156 if (defined $opt_binary_dir)
157 {
158         $config{BINARY_DIR} = $opt_binary_dir;
159 }
160 if (defined $opt_library_dir)
161 {
162         $config{LIBRARY_DIR} = $opt_library_dir;
163 }
164 chomp($config{HAS_GNUTLS}   = `pkg-config --modversion gnutls 2>/dev/null | cut -c 1,2,3`); # GNUTLS Version.
165
166 if (defined $opt_freebsd_port)
167 {
168         chomp($config{HAS_OPENSSL} = `pkg-config --modversion openssl 2>/dev/null`);
169         chomp($config{HAS_OPENSSL_PORT}  = `pkg-config --modversion openssl 2>/dev/null`);
170         $config{USE_FREEBSD_BASE_SSL} = "n";
171 }
172 else
173 {
174         if ($^O eq "freebsd")
175         {
176                 # default: use base ssl
177                 chomp($config{HAS_OPENSSL} = `openssl version | cut -d ' ' -f 2`);                      # OpenSSL version, freebsd specific
178                 chomp($config{HAS_OPENSSL_PORT}  = `pkg-config --modversion openssl 2>/dev/null`);      # Port version, may be different
179         }
180         else
181         {
182                 chomp($config{HAS_OPENSSL}  = `pkg-config --modversion openssl 2>/dev/null`);           # Openssl version, others
183                 $config{HAS_OPENSSL_PORT} = "";
184         }
185 }
186
187 chomp(our $gnutls_ver = $config{HAS_GNUTLS});
188 chomp(our $openssl_ver = $config{HAS_OPENSSL});
189 $config{USE_GNUTLS}         = "n";
190 if (defined $opt_use_gnutls)
191 {
192         $config{USE_GNUTLS} = "y";                                      # Use gnutls.
193 }
194 $config{USE_OPENSSL}    = "n";                                          # Use openssl.
195 if (defined $opt_use_openssl)
196 {
197         $config{USE_OPENSSL} = "y";
198 }
199
200 # no, let's not change these.
201 $config{OPTIMITEMP}      = "0";                                         # Default Optimisation Value
202 if (!defined $opt_disable_debug)
203 {
204         $config{OPTIMISATI}      = "-g1";                               # Optimisation Flag
205 }
206 else
207 {
208         $config{OPTIMISATI}      = "-O2";                               # DEBUGGING OFF!
209 }
210
211 $config{HAS_STRLCPY}    = "false";                                      # strlcpy Check.
212 $config{HAS_STDINT}      = "false";                                     # stdint.h check
213 $config{USE_KQUEUE}      = "y";                                         # kqueue enabled
214 if (defined $opt_kqueue)
215 {
216         $config{USE_KQUEUE} = "y";
217 }
218 if (defined $opt_nokqueue)
219 {
220         $config{USE_KQUEUE} = "n";
221 }
222 $config{USE_POLL}     = "y";                                    # poll enabled
223 $config{USE_EPOLL}        = "y";                                        # epoll enabled
224 if (defined $opt_epoll)
225 {
226         $config{USE_EPOLL} = "y";
227 }
228 if (defined $opt_noepoll)
229 {
230         $config{USE_EPOLL} = "n";
231 }
232 $config{USE_PORTS}        = "y";                                        # epoll enabled
233 if (defined $opt_ports)
234 {
235         $config{USE_PORTS} = "y";
236 }
237 if (defined $opt_noports)
238 {
239         $config{USE_PORTS} = "n";
240 }
241 $config{IPV6}          = "n";                                           # IPv6 support (experimental)
242 if (defined $opt_ipv6)
243 {
244         $config{IPV6} = "y";
245 }
246 $config{SUPPORT_IP6LINKS}   = "y";                                      # IPv4 supporting IPv6 links (experimental)
247 if (defined $opt_ipv6links)
248 {
249         $config{SUPPORT_IP6LINKS} = "y";
250 }
251 if (defined $opt_noipv6links)
252 {
253         $config{SUPPORT_IP6LINKS} = "n";
254 }
255 chomp($config{GCCVER}       = `g++ -dumpversion | cut -c 1`);           # Major GCC Version
256 chomp($config{GCCMINOR}     = `g++ -dumpversion | cut -c 3`);
257 $config{_SOMAXCONN} = SOMAXCONN;                                        # Max connections in accept queue
258 $config{OSNAME}             = $^O;                                      # Operating System Name
259 $config{IS_DARWIN}        = "NO";                                       # Is OSX?
260 $config{STARTSCRIPT}      = "inspircd";                 # start script?
261 $config{DESTINATION}      = "BASE";                             # Is target path.
262 $config{EXTRA_DIR}        = "";                                         # Is empty.
263 if ($config{OSNAME} =~ /darwin/i)
264 {
265         $config{IS_DARWIN} = "YES";
266         $config{STARTSCRIPT}      = "org.inspircd.plist";               # start script for OSX.
267         $config{DESTINATION}      = "LAUNCHDPATH";                              # Is OSX target.
268         $config{EXTRA_DIR}          = " launchd_dir";                           # Is OSX specific path.
269 }
270 $config{CC}                 = "g++";                                            # C++ compiler
271 if (defined $opt_cc)
272 {
273         $config{CC} = $opt_cc;
274 }
275 our $exec = $config{CC} . " -dumpversion | cut -c 1";
276 chomp($config{GCCVER}           = `$exec`);                             # Major GCC Version
277 $exec = $config{CC} . " -dumpversion | cut -c 3";
278 chomp($config{GCCMINOR}         = `$exec`);
279 $config{MAXBUF}                 = "512";                                # Max buffer size
280
281 if ($config{HAS_OPENSSL} =~ /^([-[:digit:].]+)([a-z])?(\-[a-z][0-9])?$/) {
282         $config{HAS_OPENSSL} = $1;
283 } else {
284         $config{HAS_OPENSSL} = "";
285 }
286
287 if (($config{GCCVER} eq "") || ($config{GCCMINOR} eq "")) {
288         print $config{CC} . " was not found! You require g++ (the GNU C++ compiler, part of GCC) to build InspIRCd!\n";
289         exit;
290 }
291
292 # Get and Set some important vars..
293 getmodules();
294
295 sub clean
296 {
297         unlink(".config.cache");
298 }
299
300 our ($has_epoll, $has_ports, $has_kqueue) = (0, 0, 0);
301
302 sub update
303 {
304         eval {
305                 chomp($topdir = getcwd());
306                 $this = resolve_directory($topdir);                                          # PWD, Regardless.
307                 getmodules();
308                 # Does the cache file exist?
309                 if (!getcache()) {
310                         # No, No it doesn't.. *BASH*
311                         print "You have not run ./configure before. Please do this before trying to run the update script.\n";
312                         exit 0;
313                 } else {
314                         # We've Loaded the cache file and all our variables..
315                         print "Updating files...\n";
316                         if (defined($opt_disable_debug) && $opt_disable_debug == 1)
317                         {
318                                 print "Disabling debug information (-g).\n";
319                                 $config{OPTIMISATI} = "";
320                         }
321                         $has_epoll = $config{HAS_EPOLL};
322                         $has_ports = $config{HAS_PORTS};
323                         $has_kqueue = $config{HAS_KQUEUE};
324                         writefiles(1);
325                         makecache();
326                         print "Complete.\n";
327                         exit;
328                 }
329         };
330         if ($@)
331         {
332                 print "Configure update failed: $@\n";
333         }
334         exit;
335 }
336
337 sub svnupdate
338 {
339         my $fail = 0;
340         open(FH,"<.svn/entries") or $fail = 1;
341         if ($fail) {
342                 print "This is not an SVN copy of InspIRCd.\n";
343                 exit 1;
344         }
345         else
346         {
347                 close(FH);
348         }
349         open my $fd, "-|", "svn update";
350         my $configurechanged = 0; # Needs ./configure -update
351         my $rootincchanged = 0;
352         my @conflicted = ();
353         while (defined(my $line = <$fd>))
354         {
355                 my ($action, $file);
356                 print $line;
357                 $line =~ m/^([ADUCG])\s+(.*)$/ or next;
358                 ($action, $file) = ($1, $2);
359                 if ($action eq "C")
360                 {
361                         push @conflicted, $file;
362                         if ($file eq "configure")
363                         {
364                                 $configurechanged = 1;
365                         }
366                         elsif ($file =~ m/^\..*\.inc$/)
367                         {
368                                 $rootincchanged = 1;
369                         }
370                 }
371                 elsif ($action eq "U" || $action eq "G")
372                 {
373                         if ($file eq "configure")
374                         {
375                                 $configurechanged = 1;
376                         }
377                         elsif ($file =~ m/^\..*\.inc$/)
378                         {
379                                 $rootincchanged = 1;
380                         }
381                 }
382         }
383         unless (close $fd) # close() waits for exit and returns false if the command failed
384         {
385                 if ($! == 0)
386                 {
387                         print STDERR "Problem updating from SVN, please check above for errors\n";
388                 }
389                 else
390                 {
391                         print STDERR "Failed to run SVN: $!\n";
392                 }
393                 exit 1;
394         }
395         if (scalar(@conflicted) > 0)
396         {
397                 print STDERR "\e[0;33;1mERROR:\e[0m You have local modifications which conflicted with the updates from SVN\n";
398                 print STDERR "Configure is not able to complete the update. Please resolve these conflicts, then run ./configure -update\n";
399                 print "Conflicted files: " . join ", ", @conflicted . "\n";
400                 exit 1;
401         }
402         if ($configurechanged)
403         {
404                 system("perl configure -update");
405         }
406         else
407         {
408                 print "No need to update Makefiles.\n";
409         }
410         if (defined $opt_rebuild) {
411                 system("make install");
412         }
413         exit;
414 }
415
416 sub test_compile {
417         my $feature = shift;
418         my $fail = 0;
419         $fail ||= system "$config{CC} -o test_$feature make/check_$feature.cpp >/dev/null 2>&1";
420         $fail ||= system "./test_$feature";
421         unlink "test_$feature";
422         return !$fail;
423 }
424
425 print "Running non-interactive configure...\n" unless $interactive;
426 print "Checking for cache from previous configure... ";
427 print ((!getcache()) ? "not found\n" : "found\n");
428 $config{SYSTEM} = lc $^O;
429 print "Checking operating system version... $config{SYSTEM}\n";
430
431 printf "Checking if stdint.h exists... ";
432 $config{HAS_STDINT} = "true";
433 our $fail = 0;
434 open(STDINT, "</usr/include/stdint.h") or $config{HAS_STDINT} = "false";
435 if ($config{HAS_STDINT} eq "true") {
436         close(STDINT);
437 }
438 print "yes\n" if $config{HAS_STDINT} eq "true";
439 print "no\n" if $config{HAS_STDINT} eq "false";
440
441 printf "Checking if strlcpy exists... ";
442 # Perform the strlcpy() test..
443 $config{HAS_STRLCPY} = "false";
444 $fail = 0;
445 open(STRLCPY, "</usr/include/string.h") or $fail = 1;
446 if (!$fail) {
447         while (defined(my $line = <STRLCPY>)) {
448                 chomp($line);
449                 # try and find the delcaration of:
450                 # size_t strlcpy(...)
451                 if ($line =~ /size_t(\0x9|\s)+strlcpy/) {
452                         $config{HAS_STRLCPY} = "true";
453                 }
454         }
455         close(STRLCPY);
456 }
457 print "yes\n" if $config{HAS_STRLCPY} eq "true";
458 print "no\n" if $config{HAS_STRLCPY} eq "false";
459
460 printf "Checking if kqueue exists... ";
461 $has_kqueue = 0;
462 $fail = 0;
463 open(KQUEUE, "</usr/include/sys/event.h") or $fail = 1;
464 if (!$fail) {
465         while (defined(my $line = <KQUEUE>)) {
466                 chomp($line);
467                 # try and find the delcaration of:
468                 # int kqueue(void);
469                 if ($line =~ /int(\0x9|\s)+kqueue/) {
470                         $has_kqueue = 1;
471                 }
472         }
473         close(KQUEUE);
474 }
475 print "yes\n" if $has_kqueue == 1;
476 print "no\n" if $has_kqueue == 0;
477
478 printf "Checking for epoll support... ";
479 $has_epoll = test_compile('epoll');
480 print $has_epoll ? "yes\n" : "no\n";
481
482 printf "Checking for eventfd support... ";
483 $config{HAS_EVENTFD} = test_compile('eventfd') ? 'true' : 'false';
484 print $config{HAS_EVENTFD} eq 'true' ? "yes\n" : "no\n";
485
486 printf "Checking if Solaris I/O completion ports are available... ";
487 $has_ports = 0;
488 our $system = `uname -s`;
489 chomp ($system);
490 $has_ports = 1 if ($system eq "SunOS");
491
492 if ($has_ports) {
493         my $kernel = `uname -r`;
494         chomp($kernel);
495         if (($kernel !~ /^5\.1./)) {
496                 $has_ports = 0;
497         }
498 }
499 print "yes\n" if $has_ports == 1;
500 print "no\n" if $has_ports == 0;
501
502 $config{HAS_EPOLL} = $has_epoll;
503 $config{HAS_KQUEUE} = $has_kqueue;
504
505 printf "Checking for libgnutls... ";
506 if (defined($config{HAS_GNUTLS}) && (($config{HAS_GNUTLS}) || ($config{HAS_GNUTLS} eq "y"))) {
507         if (defined($gnutls_ver) && ($gnutls_ver ne "")) {
508                 print "yes\n";
509                 $config{HAS_GNUTLS} = "y";
510         } else {
511                 print "no\n";
512                 $config{HAS_GNUTLS} = "n";
513         }
514 } else {
515         print "no\n";
516         $config{HAS_GNUTLS} = "n";
517 }
518
519 printf "Checking for openssl... ";
520 if (defined($config{HAS_OPENSSL}) && (($config{HAS_OPENSSL}) || ($config{HAS_OPENSSL} eq "y"))) {
521         if (defined($openssl_ver) && ($openssl_ver ne "")) {
522                 print "yes\n";
523                 $config{HAS_OPENSSL} = "y";
524         } else {
525                 print "no\n";
526                 $config{HAS_OPENSSL} = "n";
527         }
528 } else {
529         print "no\n";
530         $config{HAS_OPENSSL} = "n";
531 }
532
533 printf "Checking if you are running an ancient, unsupported OS... ";
534 if ($config{OSNAME} =~ /FreeBSD/i)
535 {
536         my $version = `uname -r`;
537         if ($version =~ /^4\./)
538         {
539                 print "yes\n";
540                 exit 1;
541         }
542         else
543         {
544                 print "no ($version)\n";
545         }
546 }
547 else
548 {
549         print "no ($config{OSNAME})\n";
550 }
551
552 print "Checking for upgrades to extra and third party modules... ";
553 system "./modulemanager upgrade";
554
555 ################################################################################
556 #                         BEGIN INTERACTIVE PART                              #
557 ################################################################################
558
559 # Clear the Screen..
560 if ($interactive)
561 {
562         print "\e[2J\e[0G\e[0d"; # J = Erase in Display, 2 = Entire Screen, (G, d) = Move cursor to (..,..)
563         my $wholeos = $^O;
564
565         my $rev = getrevision();
566         # Display Introduction Message..
567         print <<"STOP" ;
568 Welcome to the \e[1mInspIRCd\e[0m Configuration program! (\e[1minteractive mode\e[0m)
569 \e[1mPackage maintainers: Type ./configure --help for non-interactive help\e[0m
570
571 *** If you are unsure of any of these values, leave it blank for    ***
572 *** standard settings that will work, and your server will run      ***
573 *** using them. Please consult your IRC network admin if in doubt.  ***
574
575 Press \e[1m<RETURN>\e[0m to accept the default for any option, or enter
576 a new value. Please note: You will \e[1mHAVE\e[0m to read the docs
577 dir, otherwise you won't have a config file!
578
579 Your operating system is: \e[1;32m$config{OSNAME}\e[0m ($wholeos)
580 Your InspIRCd revision ID is \e[1;32mr$rev\e[0m
581 STOP
582         if ($rev eq "r0") {
583                 print " (Non-SVN build)";
584         }
585         print ".\n\n";
586
587         $config{CHANGE_COMPILER} = "n";
588         print "I have detected the following compiler: \e[1;32m$config{CC}\e[0m (version \e[1;32m$config{GCCVER}.$config{GCCMINOR}\e[0m)\n";
589
590         while (($config{GCCVER} < 3) || ($config{GCCVER} eq "")) {
591                 print "\e[1;32mIMPORTANT!\e[0m A GCC 2.x compiler has been detected, and
592 should NOT be used. You should probably specify a newer compiler.\n\n";
593                 yesno('CHANGE_COMPILER',"Do you want to change the compiler?");
594                 if ($config{CHANGE_COMPILER} =~ /y/i) {
595                         print "What command do you want to use to invoke your compiler?\n";
596                         print "[\e[1;32m$config{CC}\e[0m] -> ";
597                         chomp($config{CC} = <STDIN>);
598                         if ($config{CC} eq "") {
599                                 $config{CC} = "g++";
600                         }
601                         chomp(my $foo = `$config{CC} -dumpversion | cut -c 1`);
602                         if ($foo ne "") {
603                                 chomp($config{GCCVER}       = `$config{CC} -dumpversion | cut -c 1`); # we must redo these if we change compilers
604                                 chomp($config{GCCMINOR}     = `$config{CC} -dumpversion | cut -c 3`);
605                                 print "Queried compiler: \e[1;32m$config{CC}\e[0m (version \e[1;32m$config{GCCVER}.$config{GCCMINOR}\e[0m)\n";
606                                 if ($config{GCCVER} < 3) {
607                                         print "\e[1;32mGCC 2.x WILL NOT WORK!\e[0m. Let's try that again, shall we?\n";
608                                 }
609                         }
610                         else {
611                                 print "\e[1;32mWARNING!\e[0m Could not execute the compiler you specified. You may want to try again.\n";
612                         }
613                 }
614         }
615
616         print "\n";
617
618         # Directory Settings..
619         my $tmpbase = $config{BASE_DIR};
620         dir_check("do you wish to install the InspIRCd base", "BASE_DIR");
621         if ($tmpbase ne $config{BASE_DIR}) {
622                 $config{CONFIG_DIR}      = resolve_directory($config{BASE_DIR}."/conf");           # Configuration Dir
623                 $config{MODULE_DIR}      = resolve_directory($config{BASE_DIR}."/modules");     # Modules Directory
624                 $config{BINARY_DIR}      = resolve_directory($config{BASE_DIR}."/bin");     # Binary Directory
625                 $config{LIBRARY_DIR}    = resolve_directory($config{BASE_DIR}."/lib");      # Library Directory
626         }
627
628         dir_check("are the configuration files", "CONFIG_DIR");
629         dir_check("are the modules to be compiled to", "MODULE_DIR");
630         dir_check("is the IRCd binary to be placed", "BINARY_DIR");
631         dir_check("are the IRCd libraries to be placed", "LIBRARY_DIR");
632
633         my $chose_hiperf = 0;
634         if ($has_kqueue) {
635                 yesno('USE_KQUEUE',"You are running a BSD operating system, and kqueue\nwas detected. Would you like to enable kqueue support?\nThis is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable kqueue?");
636                 print "\n";
637                 if ($config{USE_KQUEUE} eq "y") {
638                         $chose_hiperf = 1;
639                 }
640         }
641         if ($has_epoll) {
642                 yesno('USE_EPOLL',"You are running a Linux 2.6+ operating system, and epoll\nwas detected. Would you like to enable epoll support?\nThis is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable epoll?");
643                 print "\n";
644                 if ($config{USE_EPOLL} eq "y") {
645                         $chose_hiperf = 1;
646                 }
647         }
648         if ($has_ports) {
649                 yesno('USE_PORTS',"You are running Solaris 10.\nWould you like to enable I/O completion ports support?\nThis is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable support for I/O completion ports?");
650                 print "\n";
651                 if ($config{USE_PORTS} eq "y") {
652                         $chose_hiperf = 1;
653                 }
654         }
655
656         if (!$chose_hiperf) {
657                 yesno('USE_POLL', "Would you like to use poll?\n This is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable poll?\n");
658                 if ($config{USE_POLL} ne "y")
659                 {
660                         print "No high-performance socket engines are available, or you chose\n";
661                         print "not to enable one. Defaulting to select() engine.\n\n";
662                 }
663         }
664
665         yesno('IPV6',"Would you like to build InspIRCd with IPv6 support?");
666         print "\n";
667
668         if ($config{IPV6} eq "y") {
669                 print "You have chosen to build an \e[1;32mIPV6-enabled\e[0m server.\nTo accept IPV4 users, you can still use IPV4 addresses\nin your port bindings..\n\n";
670                 $config{SUPPORT_IP6LINKS} = "y";
671         } else {
672                 yesno('SUPPORT_IP6LINKS',"You have chosen to build an \e[1;32mIPV4-only\e[0m server.\nWould you like to enable support for linking to IPV6-enabled\nInspIRCd servers? If you are using a recent operating system and are\nunsure, answer yes. If you answer 'no' here, your InspIRCd server will\nbe unable to parse IPV6 addresses (e.g. for CIDR bans)\n\nEnable linking to servers which have IPV6 enabled?");
673                 print "\n";
674         }
675
676         $config{USE_FREEBSD_BASE_SSL} = "n";
677         $config{USE_FREEBSD_PORTS_SSL} = "n";
678         if ($config{HAS_OPENSSL_PORT} ne "")
679         {
680                 $config{USE_FREEBSD_PORTS_SSL} = "y";
681                 print "I have detected the OpenSSL FreeBSD port installed on your system,\n";
682                 print "version \e[1;32m".$config{HAS_OPENSSL_PORT}."\e[0m. Your base system OpenSSL is version \e[1;32m".$openssl_ver."\e[0m.\n\n";
683                 yesno('USE_FREEBSD_PORTS_SSL', "Do you want to use the FreeBSD ports version?");
684                 print "\n";
685                 $config{USE_FREEBSD_BASE_SSL} = "y" if ($config{USE_FREEBSD_PORTS_SSL} eq "n");
686
687                 if ($config{USE_FREEBSD_BASE_SSL} eq "n")
688                 {
689                         # update to port version
690                         $openssl_ver = $config{HAS_OPENSSL_PORT};
691                 }
692         }
693         else
694         {
695                 $config{USE_FREEBSD_BASE_SSL} = "y" if ($^O eq "freebsd");
696         }
697
698         $config{USE_SSL} = "n";
699
700         if ($config{HAS_GNUTLS} eq "y" || $config{HAS_OPENSSL} eq "y")
701         {
702                 print "Detected GnuTLS version: \e[1;32m" . $gnutls_ver . "\e[0m\n";
703                 print "Detected OpenSSL version: \e[1;32m" . $openssl_ver . "\e[0m\n\n";
704
705                 yesno('USE_SSL', "One or more SSL libraries detected. Would you like to enable SSL support?");
706                 if ($config{USE_SSL} eq "y")
707                 {
708                         if ($config{HAS_GNUTLS} eq "y")
709                         {
710                                 yesno('USE_GNUTLS',"Would you like to enable SSL with m_ssl_gnutls? (recommended)");
711                                 if ($config{USE_GNUTLS} eq "y")
712                                 {
713                                         print "\nUsing GnuTLS SSL module.\n";
714                                 }
715                         }
716
717                         if ($config{HAS_OPENSSL} eq "y")
718                         {
719                                 yesno('USE_OPENSSL', "Would you like to enable SSL with m_ssl_openssl?");
720                                 if ($config{USE_OPENSSL} eq "y")
721                                 {
722                                         print "\nUsing OpenSSL SSL module.\nYou will get better performance if you move to GnuTLS in the future.\n";
723                                 }
724                         }
725                 }
726         }
727         else
728         {
729                 print "\nCould not detect OpenSSL or GnuTLS. Make sure pkg-config is installed if\n";
730                 print "you intend to use OpenSSL, or that GnuTLS is in your path if you intend\nto use GnuTLS.\n\n";
731         }
732 }
733
734 dumphash();
735
736 if (($config{USE_GNUTLS} eq "y") && ($config{HAS_GNUTLS} ne "y"))
737 {
738         print "Sorry, but i couldn't detect gnutls. Make sure gnutls-config is in your path.\n";
739         exit(0);
740 }
741 if (($config{USE_OPENSSL} eq "y") && ($config{HAS_OPENSSL} ne "y"))
742 {
743         print "Sorry, but i couldn't detect openssl. Make sure openssl is in your path.\n";
744         exit(0);
745 }
746 our $failed = 0;
747
748 $config{CERTGEN} ||= 'y';
749 yesno('CERTGEN',"Would you like generate SSL certificates now?") if ($interactive && ($config{USE_GNUTLS} eq "y" || $config{USE_OPENSSL} eq "y"));
750
751 if ($config{USE_GNUTLS} eq "y") {
752         unless (-r "src/modules/m_ssl_gnutls.cpp") {
753                 print "Symlinking src/modules/m_ssl_gnutls.cpp from extra/\n";
754                 symlink "extra/m_ssl_gnutls.cpp", "src/modules/m_ssl_gnutls.cpp" or print STDERR "Symlink failed: $!";
755         }
756         if ($interactive && $config{CERTGEN} eq 'y')
757         {
758                 unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") {
759                         print "SSL Certificates Not found, Generating.. \n\n
760 *************************************************************
761 * Generating the Private Key may take some time, go grab a  *
762 * Coffee. Even better, to generate some more entropy if it  *
763 * is taking a while, open another console and type du / a   *
764 * few times and get that HD going :) Then answer the        *
765 * Questions which follow. If you are unsure, just hit enter *
766 *************************************************************\n\n";
767                         $failed = make_gnutls_cert();
768                         if ($failed) {
769                                 print "\n\e[1;32mCertificate generation failed!\e[0m\n\n";
770                         } else {
771                                 print "\nCertificate generation complete, copying to config directory... ";
772                                 File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
773                                 File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
774                                 print "Done.\n\n";
775                         }
776                 }
777                 else {
778                         print "SSL Certificates found, skipping.\n\n";
779                 }
780         }
781         else
782         {
783                 print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
784         }
785 }
786
787 if ($config{USE_OPENSSL} eq "y") {
788         unless (-r "src/modules/m_ssl_openssl.cpp") {
789                 print "Symlinking src/modules/m_ssl_openssl.cpp from extra/\n";
790                 symlink "extra/m_ssl_openssl.cpp", "src/modules/m_ssl_openssl.cpp" or print STDERR "Symlink failed: $!";
791         }
792         $failed = 0;
793         if ($interactive && $config{CERTGEN} eq 'y')
794         {
795                 unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") {
796                         print "SSL Certificates Not found, Generating.. \n\n
797 *************************************************************
798 * Generating the certificates may take some time, go grab a *
799 * coffee, or something.                                     *
800 *************************************************************\n\n";
801                         make_openssl_cert();
802                         print "\nCertificate generation complete, copying to config directory... ";
803                         File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
804                         File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
805                         File::Copy::move("dhparams.pem", "$config{CONFIG_DIR}/dhparams.pem") or print STDERR "Could not copy dhparams.pem!\n";
806                         print "Done.\n\n";
807                 } else {
808                         print "SSL Certificates found, skipping.\n\n"
809                 }
810         }
811         else
812         {
813                 print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
814         }
815 }
816 if (($config{USE_GNUTLS} eq "n") && ($config{USE_OPENSSL} eq "n")) {
817         print "Skipping SSL Certificate generation, SSL support is not available.\n\n";
818 }
819
820 writefiles(1);
821 makecache();
822
823 print "\n\n";
824 print "To build your server with these settings, please run '\e[1;32mmake\e[0m' now.\n";
825 if (($config{USE_GNUTLS} eq "y") || ($config{USE_OPENSSL} eq "y")) {
826         print "Please note: for \e[1;32mSSL support\e[0m you will need to load required\n";
827         print "modules in your config. This configure script has added those modules to the\n";
828         print "build process. For more info please refer to:\n";
829         print "\e[1;32mhttp://wiki.inspircd.org/Installation_From_Tarball\e[0m\n";
830 }
831 print "*** \e[1;32mRemember to edit your configuration files!!!\e[0m ***\n\n\n";
832 if (($config{OSNAME} eq "OpenBSD") && ($config{CC} ne "eg++")) {
833         print "\e[1;32mWARNING!\e[0m You are running OpenBSD but you are using the base gcc package\nrather than eg++. This compile will most likely fail, but i'm letting you\ngo ahead with it anyway, just in case i'm wrong :-)\n";
834 }
835
836 if ($config{GCCVER} < "3") {
837         print <<FOO2;
838 \e[1;32mWARNING!\e[0m You are attempting to compile InspIRCd on GCC 2.x!
839 GCC 2.x series compilers only had partial (read as broken) C++ support, and
840 your compile will most likely fail horribly! If you have any problems, do NOT
841 report them to the bugtracker or forums without first upgrading your compiler
842 to a newer 3.x or 4.x (or whatever is available currently) version.
843 FOO2
844 }
845
846 ################################################################################
847 #                             HELPER FUNCTIONS                          #
848 ################################################################################
849 sub getcache {
850         # Retrieves the .config.cache file, and loads values into the main config hash.
851         open(CACHE, ".config.cache") or return 0;
852         while (<CACHE>) {
853                 chomp;
854                 # Ignore Blank lines, and comments..
855                 next if /^\s*$/;
856                 next if /^\s*#/;
857                 my ($key, $value) = split("=", $_, 2);
858                 $value =~ /^\"(.*)\"$/;
859                 # Do something with data here!
860                 $config{$key} = $1;
861         }
862         close(CACHE);
863         return 1;
864 }
865
866 sub makecache {
867         # Dump the contents of %config
868         print "Writing \e[1;32mcache file\e[0m for future ./configures ...\n";
869         open(FILEHANDLE, ">.config.cache");
870         foreach my $key (keys %config) {
871                 print FILEHANDLE "$key=\"$config{$key}\"\n";
872         }
873         close(FILEHANDLE);
874 }
875
876 sub dir_check {
877         my ($desc, $hash_key) = @_;
878         my $complete = 0;
879         while (!$complete) {
880                 print "In what directory $desc?\n";
881                 print "[\e[1;32m$config{$hash_key}\e[0m] -> ";
882                 chomp(my $var = <STDIN>);
883                 if ($var eq "") {
884                         $var = $config{$hash_key};
885                 }
886                 if ($var =~ /^\~\/(.+)$/) {
887                         # Convert it to a full path..
888                         $var = resolve_directory($ENV{HOME} . "/" . $1);
889                 }
890                 elsif ((($config{OSNAME} =~ /MINGW32/i) and ($var !~ /^[A-Z]{1}:\\.*/)) and (substr($var,0,1) ne "/"))
891                 {
892                         # Assume relative Path was given.. fill in the rest.
893                         $var = $this . "/$var";
894                 }
895
896                 $var = resolve_directory($var);
897                 if (! -e $var) {
898                         print "$var does not exist. Create it?\n[\e[1;32my\e[0m] ";
899                         chomp(my $tmp = <STDIN>);
900                         if (($tmp eq "") || ($tmp =~ /^y/i)) {
901                                 # Attempt to Create the Dir..
902                                 my $chk = eval {
903                                         use File::Path ();
904                                         File::Path::mkpath($var, 0, 0777);
905                                         1;
906                                 };
907                                 unless (defined($chk) && -d $var) {
908                                         print "Unable to create directory. ($var)\n\n";
909                                         # Restart Loop..
910                                         next;
911                                 }
912                         } else {
913                                 # They said they don't want to create, and we can't install there.
914                                 print "\n\n";
915                                 next;
916                         }
917                 } else {
918                         if (!is_dir($var)) {
919                                 # Target exists, but is not a directory.
920                                 print "File $var exists, but is not a directory.\n\n";
921                                 next;
922                         }
923                 }
924                 # Either Dir Exists, or was created fine.
925                 $config{$hash_key} = $var;
926                 $complete = 1;
927                 print "\n";
928         }
929 }
930
931 our $SHARED = "";
932
933 my ($mliflags, $mfrules, $mobjs, $mfcount) = ("", "", "", 0);
934
935 sub writefiles {
936         my($writeheader) = @_;
937         # First File.. inspircd_config.h
938         chomp(my $incos = `uname -n -s -r`);
939         chomp(my $version = `sh src/version.sh`);
940         chomp(my $revision2 = getrevision());
941         if ($writeheader == 1)
942         {
943                 print "Writing \e[1;32minspircd_config.h\e[0m\n";
944                 open(FILEHANDLE, ">include/inspircd_config.h.tmp");
945                 print FILEHANDLE <<EOF;
946 /* Auto generated by configure, do not modify! */
947 #ifndef __CONFIGURATION_AUTO__
948 #define __CONFIGURATION_AUTO__
949
950 /* this is for windows support. */
951 #define CoreExport /**/
952 #define DllExport /**/
953
954 #define CONFIG_FILE "$config{CONFIG_DIR}/inspircd.conf"
955 #define MOD_PATH "$config{MODULE_DIR}"
956 #define SOMAXCONN_S "$config{_SOMAXCONN}"
957 #define OPTIMISATION $config{OPTIMITEMP}
958 #define LIBRARYDIR "$config{LIBRARY_DIR}"
959 #define ENTRYPOINT int main(int argc, char** argv)
960
961 EOF
962 print FILEHANDLE "#define MAXBUF " . ($config{MAXBUF}+2) . "\n";
963
964                 if ($config{OSNAME} =~ /SunOS/i) {
965                         print FILEHANDLE "#define IS_SOLARIS\n";
966                 }
967                 if ($config{OSNAME} =~ /MINGW32/i) {
968                         print FILEHANDLE "#define IS_MINGW\n";
969                 }
970                 if ($config{GCCVER} >= 3) {
971                         print FILEHANDLE "#define GCC3\n";
972                 }
973                 if (
974                         (($config{GCCVER} == 4) && ($config{GCCMINOR} >= 3))
975                                 ||
976                         ($config{GCCVER} > 4)
977                 ) {
978                         print FILEHANDLE "#define HASHMAP_DEPRECATED\n";
979                 }
980                 if ($config{HAS_STRLCPY} eq "true") {
981                         print FILEHANDLE "#define HAS_STRLCPY\n";
982                 }
983                 if ($config{HAS_STDINT} eq "true") {
984                         print FILEHANDLE "#define HAS_STDINT\n";
985                 }
986                 if ($config{IPV6} =~ /y/i) {
987                         print FILEHANDLE "#define IPV6\n";
988                 }
989                 if ($config{SUPPORT_IP6LINKS} =~ /y/i) {
990                         print FILEHANDLE "#define SUPPORT_IP6LINKS\n";
991                 }
992                 if ($config{HAS_EVENTFD} eq 'true') {
993                         print FILEHANDLE "#define HAS_EVENTFD\n";
994                 }
995                 my $use_hiperf = 0;
996                 if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) {
997                         print FILEHANDLE "#define USE_KQUEUE\n";
998                         $config{SOCKETENGINE} = "socketengine_kqueue";
999                         $use_hiperf = 1;
1000                 }
1001                 if (($has_epoll) && ($config{USE_EPOLL} eq "y")) {
1002                         print FILEHANDLE "#define USE_EPOLL\n";
1003                         $config{SOCKETENGINE} = "socketengine_epoll";
1004                         $use_hiperf = 1;
1005                 }
1006                 if (($has_ports) && ($config{USE_PORTS} eq "y")) {
1007                         print FILEHANDLE "#define USE_PORTS\n";
1008                         $config{SOCKETENGINE} = "socketengine_ports";
1009                         $use_hiperf = 1;
1010                 }
1011                 # user didn't choose either epoll or select for their OS.
1012                 # default them to USE_SELECT (ewwy puke puke)
1013                 if (!$use_hiperf) {
1014                         print "no hi-perf, " . $config{USE_POLL};
1015                         if ($config{USE_POLL} eq "y")
1016                         {
1017                                 print FILEHANDLE "#define USE_POLL\n";
1018                                 $config{SOCKETENGINE} = "socketengine_poll";
1019                         }
1020                         else
1021                         {
1022                                 print FILEHANDLE "#define USE_SELECT\n";
1023                                 $config{SOCKETENGINE} = "socketengine_select";
1024                         }
1025                 }
1026                 print FILEHANDLE "\n#include \"threadengines/threadengine_pthread.h\"\n\n#endif\n";
1027                 close(FILEHANDLE);
1028
1029                 open(FILEHANDLE, ">include/inspircd_se_config.h.tmp");
1030                 print FILEHANDLE <<EOF;
1031 /* Auto generated by configure, do not modify or commit to svn! */
1032 #ifndef __CONFIGURATION_SOCKETENGINE__
1033 #define __CONFIGURATION_SOCKETENGINE__
1034
1035 #include "socketengines/$config{SOCKETENGINE}.h"
1036
1037 #endif
1038 EOF
1039                 close(FILEHANDLE);
1040
1041                 open(FILEHANDLE, ">include/inspircd_version.h.tmp");
1042                 print FILEHANDLE <<EOF;
1043 #define VERSION "$version"
1044 #define REVISION "$revision2"
1045 #define SYSTEM "$incos"
1046 EOF
1047                 close FILEHANDLE;
1048
1049                 for my $file (qw(include/inspircd_config.h include/inspircd_se_config.h include/inspircd_version.h)) {
1050                         my $diff = 0;
1051                         open my $fh1, $file or $diff = 1;
1052                         open my $fh2, $file.'.tmp' or die "Can't read $file.tmp that we just wrote: $!";
1053                         while (!$diff) {
1054                                 my $line1 = <$fh1>;
1055                                 my $line2 = <$fh2>;
1056                                 if (defined($line1) != defined($line2)) {
1057                                         $diff = 1;
1058                                 } elsif (!defined $line1) {
1059                                         last;
1060                                 } else {
1061                                         $diff = ($line1 ne $line2);
1062                                 }
1063                         }
1064                         if ($diff) {
1065                                 unlink $file;
1066                                 rename "$file.tmp", $file;
1067                         } else {
1068                                 unlink "$file.tmp";
1069                         }
1070                 }
1071         }
1072
1073         # Write all .in files.
1074         my $tmp = "";
1075         my $file = "";
1076         my $exe = "inspircd";
1077
1078         # Do this once here, and cache it in the .*.inc files,
1079         # rather than attempting to read src/version.sh from
1080         # compiled code -- we might not have the source to hand.
1081         # Fix for bug#177 by Brain.
1082
1083         chomp($version = `sh ./src/version.sh`);
1084         chomp(my $revision = getrevision());
1085         $version = "$version(r$revision)";
1086
1087         # We can actually parse any file starting with . and ending with .inc,
1088         # but right now we only parse .inspircd.inc to form './inspircd'
1089         prepare_dynamic_makefile();
1090
1091     print "Writing \e[1;32mMakefiles\e[0m\n";
1092
1093         opendir(DIRHANDLE, $this);
1094
1095         foreach my $name (sort readdir(DIRHANDLE)) {
1096                 if ($name =~ /^\.(.+)\.inc$/) {
1097                         $file = $1;
1098
1099                         # Bug #353, omit this on non-darwin
1100                         next if (($config{OSNAME} !~ /darwin/) && ($file eq "org.inspircd.plist"));
1101
1102                         # All .name.inc files need parsing!
1103                         open(FILEHANDLE, ".$file.inc") or die ("Can't open .$file.inc");
1104                         $_ = join '', <FILEHANDLE>;
1105                         close(FILEHANDLE);
1106
1107                         print "Writing \e[1;32m$file\e[0m ...\n";
1108                         for my $var (qw(
1109                                 CC SYSTEM BASE_DIR CONFIG_DIR MODULE_DIR BINARY_DIR LIBRARY_DIR
1110                                 STARTSCRIPT DESTINATION EXTRA_DIR SOCKETENGINE CORE_FLAGS
1111                         )) {
1112                                 s/\@$var\@/$config{$var}/g;
1113                         }
1114                         s/\@EXECUTABLE\@/$exe/ if defined $exe;
1115                         s/\@VERSION\@/$version/ if defined $version;
1116
1117                         if ($file eq 'Makefile') {
1118                                 my $mk_tmp = $_;
1119                                 s/\@IFDEF (\S+)/ifdef $1/g;
1120                                 s/\@IFNDEF (\S+)/ifndef $1/g;
1121                                 s/\@IFEQ (\S+) (\S+)/ifeq ($1,$2)/g;
1122                                 s/\@ELSIFEQ (\S+) (\S+)/else ifeq ($1,$2)/g;
1123                                 s/\@ELSE/else/g;
1124                                 s/\@ENDIF/endif/g;
1125                                 s/ *\@BSD_ONLY .*\n//g;
1126                                 s/\@GNU_ONLY //g;
1127                                 s/\@DO_EXPORT (.*)/export $1/g;
1128                                 open MKF, '>GNUmakefile' or die "Can't write to GNUmakefile: $!";
1129                                 print MKF $_;
1130                                 close MKF;
1131                                 $_ = $mk_tmp;
1132                                 s/\@IFDEF (\S+)/.if defined($1)/g;
1133                                 s/\@IFNDEF (\S+)/.if !defined($1)/g;
1134                                 s/\@IFEQ (\S+) (\S+)/.if $1 == $2/g;
1135                                 s/\@ELSIFEQ (\S+) (\S+)/.elif $1 == $2/g;
1136                                 s/\@ELSE/.else/g;
1137                                 s/\@ENDIF/.endif/g;
1138                                 s/\@BSD_ONLY //g;
1139                                 s/ *\@GNU_ONLY .*\n//g;
1140                                 $mk_tmp = $_;
1141                                 $mk_tmp =~ s#\@DO_EXPORT (.*)#"MAKEENV += ".join ' ', map "$_='\${$_}'", split /\s/, $1#eg;
1142                                 open MKF, '>BSDmakefile' or die "Can't write to BSDmakefile: $!";
1143                                 print MKF $mk_tmp;
1144                                 close MKF;
1145                         } else {
1146                                 open(FILEHANDLE, ">$file") or die("Can't write to $file: $!\n");
1147                                 print FILEHANDLE $_;
1148                                 close(FILEHANDLE);
1149                         }
1150                 }
1151         }
1152         closedir(DIRHANDLE);
1153
1154         # Make inspircd executable!
1155         chmod 0744, 'inspircd';
1156 }
1157
1158 sub prepare_dynamic_makefile
1159 {
1160         my $i = 0;
1161
1162         if (!$has_epoll)
1163         {
1164                 $config{USE_EPOLL} = 0;
1165         }
1166         if (!$has_kqueue)
1167         {
1168                 $config{USE_KQUEUE} = 0;
1169         }
1170         if (!$has_ports)
1171         {
1172                 $config{USE_PORTS} = 0;
1173         }
1174 }
1175
1176 # Routine to list out the extra/ modules that have been enabled.
1177 # Note: when getting any filenames out and comparing, it's important to lc it if the
1178 # file system is not case-sensitive (== Epoc, MacOS, OS/2 (incl DOS/DJGPP), VMS, Win32
1179 # (incl NetWare, Symbian)). Cygwin may or may not be case-sensitive, depending on
1180 # configuration, however, File::Spec does not currently tell us (it assumes Unix behavior).
1181 sub list_extras () {
1182         use File::Spec;
1183         # @_ not used
1184         my $srcdir = File::Spec->catdir("src", "modules");
1185         my $abs_srcdir = File::Spec->rel2abs($srcdir);
1186         local $_;
1187         my $dd;
1188         opendir $dd, File::Spec->catdir($abs_srcdir, "extra") or die (File::Spec->catdir($abs_srcdir, "extra") . ": $!\n");
1189         my @extras = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
1190         closedir $dd;
1191         undef $dd;
1192         opendir $dd, $abs_srcdir or die "$abs_srcdir: $!\n";
1193         my @sources = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
1194         closedir $dd;
1195         undef $dd;
1196         my $maxlen = (sort { $b <=> $a } (map {length($_)} (@extras)))[0];
1197         my %extras = ();
1198 EXTRA:  for my $extra (@extras) {
1199                 next if (File::Spec->curdir() eq $extra || File::Spec->updir() eq $extra);
1200                 next if ($extra eq '.svn');
1201                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
1202                 my $abs_source = File::Spec->catfile($abs_srcdir, $extra);
1203                 next unless ($extra =~ m/\.(cpp|h)$/ || (-d $abs_extra)); # C++ Source/Header, or directory
1204                 if (-l $abs_source) {
1205                         # Symlink, is it in the right place?
1206                         my $targ = readlink($abs_source);
1207                         my $abs_targ = File::Spec->rel2abs($targ, $abs_srcdir);
1208                         if ($abs_targ eq $abs_extra) {
1209                                 $extras{$extra} = "\e[32;1menabled\e[0m";
1210                         } else {
1211                                 $extras{$extra} = sprintf("\e[31;1mwrong symlink target (%s)\e[0m", $abs_targ);
1212                         }
1213                 } elsif (-e $abs_source) {
1214                         my ($devext, $inoext) = stat($abs_extra);
1215                         my ($devsrc, $inosrc, undef, $lnksrc) = stat($abs_source);
1216                         if ($lnksrc > 1) {
1217                                 if ($devsrc == $devext && $inosrc == $inoext) {
1218                                         $extras{$extra} = "\e[32;1menabled\e[0m";
1219                                 } else {
1220                                         $extras{$extra} = sprintf("\e[31;1mwrong hardlink target (%d:%d)\e[0m", $devsrc, $inosrc);
1221                                 }
1222                         } else {
1223                                 open my $extfd, "<", $abs_extra;
1224                                 open my $srcfd, "<", $abs_source;
1225                                 local $/ = undef;
1226                                 if (scalar(<$extfd>) eq scalar(<$srcfd>)) {
1227                                         $extras{$extra} = "\e[32;1menabled\e[0m";
1228                                 } else {
1229                                         $extras{$extra} = sprintf("\e[31;1mout of synch (re-copy)\e[0m");
1230                                 }
1231                         }
1232                 } else {
1233                         $extras{$extra} = "\e[33;1mdisabled\e[0m";
1234                 }
1235         }
1236         # Now let's add dependency info
1237         for my $extra (keys(%extras)) {
1238                 next unless $extras{$extra} =~ m/enabled/; # only process enabled extras.
1239                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
1240                 my @deps = split / +/, getdependencies($abs_extra);
1241                 for my $dep (@deps) {
1242                         if (exists($extras{$dep})) {
1243                                 my $ref = \$extras{$dep}; # Take reference.
1244                                 if ($$ref !~ m/needed by/) {
1245                                         # First dependency found.
1246                                         if ($$ref =~ m/enabled/) {
1247                                                 $$ref .= " (needed by \e[32;1m$extra\e[0m";
1248                                         } else {
1249                                                 $$ref =~ s/\e\[.*?m//g; # Strip out previous coloring. Will be set in bold+red+blink later.
1250                                                 $$ref .= " (needed by \e[0;32;1;5m$extra\e[0;31;1;5m";
1251                                         }
1252                                 } else {
1253                                         if ($$ref =~ m/enabled/) {
1254                                                 $$ref .= ", \e[32;1m$extra\e[0m";
1255                                         } else {
1256                                                 $$ref .= ", \e[0;32;1;5m$extra\e[0;31;1;5m";
1257                                         }
1258                                 }
1259                         }
1260                 }
1261         }
1262         for my $extra (sort {$a cmp $b} keys(%extras)) {
1263                 my $text = $extras{$extra};
1264                 if ($text =~ m/needed by/ && $text !~ m/enabled/) {
1265                         printf "\e[31;1;5m%-*s = %s%s\e[0m\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? ")" : "");
1266                 } else {
1267                         printf "%-*s = %s%s\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? "\e[0m)" : "");
1268                 }
1269         }
1270         return keys(%extras) if wantarray; # Can be used by manage_extras.
1271 }
1272
1273 sub enable_extras (@) {
1274         my (@extras) = @_;
1275         for my $extra (@extras) {
1276                 my $extrapath = "src/modules/extra/$extra";
1277                 if (!-e $extrapath) {
1278                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : No such file or directory in src/modules/extra\n";
1279                         next;
1280                 }
1281                 my $source = "src/modules/$extra";
1282                 if (-e $source) {
1283                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : destination in src/modules exists (might already be enabled?)\n";
1284                         next;
1285                 }
1286                 # Get dependencies, and add them to be processed.
1287                 my @deps = split / +/, getdependencies($extrapath);
1288                 for my $dep (@deps) {
1289                         next if scalar(grep { $_ eq $dep } (@extras)) > 0; # Skip if we're going to be enabling it anyway.
1290                         if (!-e "src/modules/$dep") {
1291                                 if (-e "src/modules/extra/$dep") {
1292                                         print STDERR "Will also enable extra \e[32;1m$dep\e[0m (needed by \e[32;1m$extra\e[0m)\n";
1293                                         push @extras, $dep;
1294                                 } else {
1295                                         print STDERR "\e[33;1mWARNING:\e[0m module \e[32;1m$extra\e[0m might be missing dependency \e[32;1m$dep\e[0m - YOU are responsible for satisfying it!\n";
1296                                 }
1297                         }
1298                 }
1299                 print "Enabling $extra ... \n";
1300                 symlink "extra/$extra", $source or print STDERR "$source: Cannot link to 'extra/$extra': $!\n";
1301         }
1302 }
1303
1304 sub disable_extras (@)
1305 {
1306         opendir my $dd, "src/modules/extra/";
1307         my @files = readdir($dd);
1308         closedir $dd;
1309         my (@extras) = @_;
1310 EXTRA:  for my $extra (@extras) {
1311                 my $extrapath = "src/modules/extra/$extra";
1312                 my $source = "src/modules/$extra";
1313                 if (!-e $extrapath) {
1314                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : Is not an extra\n";
1315                         next;
1316                 }
1317                 if ((! -l $source) || readlink($source) ne "extra/$extra") {
1318                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : Source is not a link or doesn't refer to the right file. Remove manually if this is in error.\n";
1319                         next;
1320                 }
1321                 # Check if anything needs this.
1322                 for my $file (@files) {
1323                         my @deps = split / +/, getdependencies("src/modules/extra/$file");
1324                         # File depends on this extra...
1325                         if (scalar(grep { $_ eq $extra } @deps) > 0) {
1326                                 # And is both enabled and not about to be disabled.
1327                                 if (-e "src/modules/$file" && scalar(grep { $_ eq $file } @extras) < 1) {
1328                                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : is needed by \e[32;1m$file\e[0m\n";
1329                                         next EXTRA;
1330                                 }
1331                         }
1332                 }
1333                 # Now remove.
1334                 print "Disabling $extra ... \n";
1335                 unlink "src/modules/$extra" or print STDERR "Cannot disable \e[32;1m$extra\e[0m : $!\n";
1336         }
1337 }