]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - configure
zap the evil externs, and comment the lot
[user/henk/code/inspircd.git] / configure
index aa26430968b4b8c472b771ac62b1b95876d50ee1..616ebfea790f42ddd5db34bae4b7a6865959ee4b 100755 (executable)
--- a/configure
+++ b/configure
 #!/usr/bin/perl
-
+###################################################
 # InspIRCd Configuration Script
 #
-# Copyright 2003 The ChatSpike Development Team
-# <brain@chatspike.net>
-# <Craig@chatspike.net>
+# Copyright 2002-2008 The InspIRCd Development Team
+#  http://www.inspircd.org/wiki/index.php/Credits
 #
-# [14:21] Brain: <matrix impression> i know perl-fu!
+# Licensed under GPL, please see the COPYING file
+# for more information
 #
 # $Id$
 #
-########################################
+###################################################
+
+BEGIN {
+       require 5.8.0;
+}
+
+use strict;
+use warnings FATAL => qw(all);
 
+use Data::Dumper;
+BEGIN {
+       $Data::Dumper::Sortkeys = 1;
+       $Data::Dumper::Useqq = 1;
+};
+
+use File::Copy ();
+
+use Socket;
 use Cwd;
+use Getopt::Long;
 
-chomp($topdir = getcwd());
-$this = resolve_directory($topdir);                                            # PWD, Regardless.
-@modlist = ();                                                                 # Declare for Module List..
-%config = ();                                                                  # Initiate Configuration Hash..
-$config{ME}                 = resolve_directory($topdir);                      # Present Working Directory
-$config{BASE_DIR}           = $config{ME};                                      # Use CWD as 'Base' Directory.
-$config{CONFIG_DIR}         = resolve_directory($config{ME}."/conf");          # Configuration Directory
-$config{MODULE_DIR}         = resolve_directory($config{ME}."/modules");       # Modules Directory
-$config{BINARY_DIR}         = resolve_directory($config{ME}."/bin");           # Binary Directory
-$config{LIBRARY_DIR}        = resolve_directory($config{ME}."/lib");           # Library Directory
-chomp($config{HAS_GNUTLS}   = `libgnutls-config --version 2>/dev/null | cut -c 1,2,3`); # GNUTLS Version.
-chomp($config{HAS_OPENSSL}  = `openssl version 2>/dev/null`);                  # Openssl version
-$config{USE_GNUTLS}         = "n";                                             # Use gnutls.
-$config{USE_OPENSSL}        = "n";                                             # Use openssl.
-$config{OPTIMITEMP}         = "0";                                             # Default Optimisation Value
-$config{OPTIMISATI}         = "-g";                                            # Optimisation Flag
-$config{NICK_LENGT}         = "31";                                            # Default Nick Length
-$config{CHAN_LENGT}         = "64";                                            # Default Channel Name Length
-$config{MAX_CHANNE}         = "20";                                            # Default Max. Channels per user
-$config{MAX_OPERCH}         = "60";                                            # Default Max. Channels per oper
-$config{MAXI_MODES}         = "20";                                            # Default Max. Number of Modes set at once.
-$config{HAS_STRLCPY}        = "false";                                         # strlcpy Check.
-$config{HAS_STDINT}         = "false";                                         # stdint.h check
-$config{HAS_EXECINFO}       = "0";                                             # execinfo.h Check.
-$config{USE_KQUEUE}         = "y";                                             # kqueue enabled
-$config{USE_EPOLL}          = "y";                                             # epoll enabled
-$config{THREADED_DNS}       = "n";                                             # threaded dns
-$config{IPV6}               = "n";                                             # IPv6 support (experimental)
-$config{SUPPORT_IP6LINKS}   = "y";                                             # IPv4 supporting IPv6 links (experimental)
-$config{STATIC_LINK}       = "no";                                             # are doing static modules?
-chomp($config{MAX_CLIENT_T} = `sh -c \"ulimit -n\"`);                          # FD Limit
-chomp($config{MAX_DESCRIPTORS} = `sh -c \"ulimit -n\"`);                       # Hard FD Limit
-chomp($config{GCCVER}       = `g++ -dumpversion | cut -c 1`);                  # Major GCC Version
-chomp($config{OSNAME}       = `uname`);                                # Operating System Name
-$config{CC}                = "g++";                                            # C++ compiler
-$config{MAKEORDER}         = "ircd mods";                                      # build order
-$config{STATICLIBS}         = "";                                              # library archive path
-$config{MAX_IDENT}          = "12";                                            # max ident size
-$config{MAX_QUIT}           = "255";                                           # max quit message size
-$config{MAX_TOPIC}          = "307";                                           # max topic size
-$config{MAX_KICK}           = "255";                                           # max kick message size
-$config{MAX_GECOS}          = "128";                                           # max GECOS size
-$config{MAX_AWAY}           = "200";                                           # max AWAY size
-
-$no_svn = 0;
-
-$config{HAS_OPENSSL} =~ /OpenSSL (\S+) \d+ \S+ \d{4}/;
-$config{HAS_OPENSSL} = $1;
-
-if ($config{GCCVER} eq "") {
-       print "g++ was not found! You require g++ (the GNU C++ compiler, part of GCC) to build InspIRCd!\n";
-       exit;
+# Utility functions for our buildsystem
+use make::utilities;
+use make::configure;
+use make::gnutlscert;
+use make::opensslcert;
+
+###############################################################################################
+#
+#                                   EDITABLE VARIABLES
+#
+###############################################################################################
+
+# If you wish to ignore a dependency throughout the entire core, add it here.
+
+our @ignoredeps = (
+       "inspircd_win32wrapper.h",      # windows has its own configure program
+);
+
+# If you wish for all files in the entire core to have a given dependency, insert it here.
+# You should keep this to an absolute minimum to avoid rebuilds that are not neccessary.
+
+our @immutabledeps = (
+       "inspircd_config.h",            # auto re-generated by configure
+       "inspircd.h",
+);
+
+###############################################################################################
+#
+#                                 NON-EDITABLE VARIABLES
+#
+###############################################################################################
+
+# List of commands that make up 'make install' and 'make deinstall'
+
+our $install_list = "";
+our $uninstall_list = "";
+
+# This is a list of all files in the core. Each cpp file is mapped to a shared object file,
+# whos file extension is omitted (these can vary from system to system). Auto detected by
+# scanning the src/*.cpp files for files containing /* $Core */ identifiers.
+
+our %filelist = ();
+
+# If you wish for a file to have special dependencies in the makefile, add an entry here.
+# Auto populated by /* $ExtraDeps: */ instruction
+
+our %specialdeps = ();
+
+# If you wish for a file to have extra make lines (in between the compile and link steps)
+# then insert them here.
+# Auto populated by /* $ExtraBuild: */ instruction
+        
+our %extrabuildlines = ();
+
+# If you wish for a file to be linked against extra objects or arctives, insert them here.
+# Auto populated by /* $ExtraObjects: */ instruction
+
+our %extraobjects = ();
+
+# If you wish to compile extra cpp sources into an object, define them here.
+# NOTE: Certain cpp files such as the socket engines have a value auto calculated
+# for this table so that their derived class is built.
+# Auto populated by /* $ExtraSources: */ instruction
+
+our %extrasources = ();
+
+our ($opt_use_gnutls, $opt_rebuild, $opt_use_openssl, $opt_nointeractive, $opt_ports,
+    $opt_epoll, $opt_kqueue, $opt_noports, $opt_noepoll, $opt_nokqueue,
+    $opt_ipv6, $opt_ipv6links, $opt_noipv6links, $opt_maxbuf, $opt_disable_debug,
+    $opt_freebsd_port);
+
+our ($opt_cc, $opt_base_dir, $opt_config_dir, $opt_module_dir, $opt_binary_dir,
+    $opt_library_dir);
+
+sub list_extras ();
+
+sub enable_extras (@);
+
+sub disable_extras (@);
+
+my @opt_enableextras;
+my @opt_disableextras;
+
+GetOptions (
+       'enable-gnutls' => \$opt_use_gnutls,
+       'rebuild' => \$opt_rebuild,
+       'enable-openssl' => \$opt_use_openssl,
+       'disable-interactive' => \$opt_nointeractive,
+       'enable-ports' => \$opt_ports,
+       'enable-epoll' => \$opt_epoll,
+       'enable-kqueue' => \$opt_kqueue,
+       'disable-ports' => \$opt_noports,
+       'disable-epoll' => \$opt_noepoll,
+       'disable-kqueue' => \$opt_nokqueue,
+       'enable-ipv6' => \$opt_ipv6,
+       'enable-remote-ipv6' => \$opt_ipv6links,
+       'disable-remote-ipv6' => \$opt_noipv6links,
+       'with-cc=s' => \$opt_cc,
+       'with-maxbuf=i' => \$opt_maxbuf,
+       'enable-freebsd-ports-openssl' => \$opt_freebsd_port,
+       'prefix=s' => \$opt_base_dir,
+       'config-dir=s' => \$opt_config_dir,
+       'module-dir=s' => \$opt_module_dir,
+       'binary-dir=s' => \$opt_binary_dir,
+       'library-dir=s' => \$opt_library_dir,
+       'disable-debuginfo' => sub { $opt_disable_debug = 1 },
+       'help'  => sub { showhelp(); },
+       'modupdate' => sub { modupdate(); },
+       'update' => sub { update(); },
+       'svnupdate' => sub { svnupdate(); },
+       'clean' => sub { clean(); },
+       'list-extras' => sub { list_extras; exit 0; }, # This, --enable-extras, and --disable-extras are for non-interactive managing.
+       'enable-extras=s@' => \@opt_enableextras, # ^
+       'disable-extras=s@' => \@opt_disableextras, # ^
+);
+
+if (scalar(@opt_enableextras) + scalar(@opt_disableextras) > 0) {
+       @opt_enableextras = split /,/, join(',', @opt_enableextras);
+       @opt_disableextras = split /,/, join(',', @opt_disableextras);
+       enable_extras(@opt_enableextras);
+       disable_extras(@opt_disableextras);
+       list_extras;
+       print "Remember: YOU are responsible for making sure any libraries needed have been installed!\n";
+       print "Run $0 -modupdate after you've done this to update the makefiles.\n";
+       exit 0;
+}
+
+our $non_interactive = (
+       (defined $opt_library_dir) ||
+       (defined $opt_base_dir) ||
+       (defined $opt_config_dir) ||
+       (defined $opt_module_dir) ||
+       (defined $opt_base_dir) ||
+       (defined $opt_binary_dir) ||
+       (defined $opt_nointeractive) ||
+       (defined $opt_cc) ||
+       (defined $opt_ipv6) ||
+       (defined $opt_ipv6links) ||
+       (defined $opt_noipv6links) ||
+       (defined $opt_kqueue) ||
+       (defined $opt_epoll) ||
+       (defined $opt_ports) ||
+       (defined $opt_use_openssl) ||
+       (defined $opt_nokqueue) ||
+       (defined $opt_noepoll) ||
+       (defined $opt_noports) ||
+       (defined $opt_maxbuf) ||
+       (defined $opt_use_gnutls) ||
+       (defined $opt_freebsd_port)
+);
+our $interactive = !$non_interactive;
+
+chomp(our $topdir = getcwd());
+our $this = resolve_directory($topdir);                                                # PWD, Regardless.
+our @modlist = ();                                                                     # Declare for Module List..
+our %config = ();                                                                      # Initiate Configuration Hash..
+$config{ME}             = resolve_directory($topdir);                          # Present Working Directory
+
+$config{BASE_DIR}         = $config{ME};
+
+if (defined $opt_base_dir)
+{
+       $config{BASE_DIR} = $opt_base_dir;
 }
 
-# Minihack! Convert Cygwin to 'Cyg-Static' so i can
-# Keep my dynamic module experiments here for later
-# concideration!
+$config{CONFIG_DIR}     = resolve_directory($config{BASE_DIR}."/conf");        # Configuration Directory
+$config{MODULE_DIR}     = resolve_directory($config{BASE_DIR}."/modules");     # Modules Directory
+$config{BINARY_DIR}     = resolve_directory($config{BASE_DIR}."/bin");         # Binary Directory
+$config{LIBRARY_DIR}   = resolve_directory($config{BASE_DIR}."/lib");          # Library Directory
 
-if ($config{OSNAME} =~ /CYGWIN/)
+if (defined $opt_config_dir)
 {
-       $config{OSNAME} = "CYG-STATIC";
+       $config{CONFIG_DIR} = $opt_config_dir;
 }
-elsif($config{OSNAME} =~ /^MINGW32/)
+if (defined $opt_module_dir)
 {
-       $config{OSNAME} = "MINGW32";
+       $config{MODULE_DIR} = $opt_module_dir;
 }
-elsif ((!$config{OSNAME}) || ($config{OSNAME} eq ""))
+if (defined $opt_binary_dir)
 {
-       chomp($config{OSNAME} = `/usr/bin/uname`);
-       
-       if((!$config{OSNAME}) || ($config{OSNAME} eq ""))
+       $config{BINARY_DIR} = $opt_binary_dir;
+}
+if (defined $opt_library_dir)
+{
+       $config{LIBRARY_DIR} = $opt_library_dir;
+}
+chomp($config{HAS_GNUTLS}   = `libgnutls-config --version 2>/dev/null | cut -c 1,2,3`); # GNUTLS Version.
+
+if (defined $opt_freebsd_port)
+{
+       chomp($config{HAS_OPENSSL} = `pkg-config --modversion openssl 2>/dev/null`);
+       chomp($config{HAS_OPENSSL_PORT}  = `pkg-config --modversion openssl 2>/dev/null`);
+       $config{USE_FREEBSD_BASE_SSL} = "n";
+}
+else
+{
+       if ($^O eq "freebsd")
+       {
+               # default: use base ssl
+               chomp($config{HAS_OPENSSL} = `openssl version | cut -d ' ' -f 2`);                      # OpenSSL version, freebsd specific
+               chomp($config{HAS_OPENSSL_PORT}  = `pkg-config --modversion openssl 2>/dev/null`);      # Port version, may be different
+       }
+       else
        {
-               $config{OSNAME} = "Unknown";
-       }       
+               chomp($config{HAS_OPENSSL}  = `pkg-config --modversion openssl 2>/dev/null`);           # Openssl version, others
+               $config{HAS_OPENSSL_PORT} = "";
+       }
+}
+
+chomp(our $gnutls_ver = $config{HAS_GNUTLS});
+chomp(our $openssl_ver = $config{HAS_OPENSSL});
+$config{USE_GNUTLS}        = "n";
+if (defined $opt_use_gnutls)
+{
+       $config{USE_GNUTLS} = "y";                                      # Use gnutls.
+}
+$config{USE_OPENSSL}   = "n";                                          # Use openssl.
+if (defined $opt_use_openssl)
+{
+       $config{USE_OPENSSL} = "y";
+}
+
+# no, let's not change these.
+$config{OPTIMITEMP}     = "0";                                         # Default Optimisation Value
+if (!defined $opt_disable_debug)
+{
+       $config{OPTIMISATI}      = "-g1";                               # Optimisation Flag
+}
+else
+{
+       $config{OPTIMISATI}      = "-O2";                               # DEBUGGING OFF!
+}
+
+$config{HAS_STRLCPY}   = "false";                                      # strlcpy Check.
+$config{HAS_STDINT}     = "false";                                     # stdint.h check
+$config{USE_KQUEUE}     = "y";                                         # kqueue enabled
+if (defined $opt_kqueue)
+{
+       $config{USE_KQUEUE} = "y";
+}
+if (defined $opt_nokqueue)
+{
+       $config{USE_KQUEUE} = "n";
+}
+$config{USE_EPOLL}       = "y";                                        # epoll enabled
+if (defined $opt_epoll)
+{
+       $config{USE_EPOLL} = "y";
+}
+if (defined $opt_noepoll)
+{
+       $config{USE_EPOLL} = "n";
+}
+$config{USE_PORTS}       = "y";                                        # epoll enabled
+if (defined $opt_ports)
+{
+       $config{USE_PORTS} = "y";
+}
+if (defined $opt_noports)
+{
+       $config{USE_PORTS} = "n";
+}
+$config{IPV6}         = "n";                                           # IPv6 support (experimental)
+if (defined $opt_ipv6)
+{
+       $config{IPV6} = "y";
+}
+$config{SUPPORT_IP6LINKS}   = "y";                                     # IPv4 supporting IPv6 links (experimental)
+if (defined $opt_ipv6links)
+{
+       $config{SUPPORT_IP6LINKS} = "y";
+}
+if (defined $opt_noipv6links)
+{
+       $config{SUPPORT_IP6LINKS} = "n";
+}
+chomp($config{GCCVER}       = `g++ -dumpversion | cut -c 1`);          # Major GCC Version
+chomp($config{GCCMINOR}     = `g++ -dumpversion | cut -c 3`);
+$config{_SOMAXCONN} = SOMAXCONN;                                       # Max connections in accept queue
+$config{OSNAME}            = $^O;                                      # Operating System Name
+$config{IS_DARWIN}       = "NO";                                       # Is OSX?
+$config{STARTSCRIPT}     = "inspircd";                 # start script?
+$config{DESTINATION}     = "BASE";                             # Is target path.
+$config{EXTRA_DIR}       = "";                                         # Is empty.
+if ($config{OSNAME} =~ /darwin/i)
+{
+       $config{IS_DARWIN} = "YES";
+       $config{STARTSCRIPT}      = "org.inspircd.plist";               # start script for OSX.
+       $config{DESTINATION}      = "LAUNCHDPATH";                              # Is OSX target.
+       $config{EXTRA_DIR}          = " launchd_dir";                           # Is OSX specific path.
+}
+$config{CC}                = "g++";                                            # C++ compiler
+if (defined $opt_cc)
+{
+       $config{CC} = $opt_cc;
+}
+our $exec = $config{CC} . " -dumpversion | cut -c 1";
+chomp($config{GCCVER}          = `$exec`);                             # Major GCC Version
+$exec = $config{CC} . " -dumpversion | cut -c 3";
+chomp($config{GCCMINOR}                = `$exec`);
+$config{MAKEORDER}             = "ircd mods";                          # build order
+$config{MAXBUF}                        = "512";                                # Max buffer size
+
+if ($config{HAS_OPENSSL} =~ /^([-[:digit:].]+)([a-z])?(\-[a-z][0-9])?$/) {
+       $config{HAS_OPENSSL} = $1;
+} else {
+       $config{HAS_OPENSSL} = "";
 }
 
-if (!$config{MAX_CLIENT_T}) { 
-       $config{MAX_CLIENT_T} = 1024;                                 # Set a reasonable 'Default'
-       $fd_scan_fail = "true";                                       # Used Later
+if (($config{GCCVER} eq "") || ($config{GCCMINOR} eq "")) {
+       print $config{CC} . " was not found! You require g++ (the GNU C++ compiler, part of GCC) to build InspIRCd!\n";
+       exit;
 }
 
 # Get and Set some important vars..
 getmodules();
 
-my $arg = $ARGV[0];                                            # Do Some Argument Checks..
-if ($arg eq "-clean") {
-       system("rm -rf .config.cache");
-}               # Remove the config.cache file.
-
-if ($arg eq "-update") {
-       # Does the cache file exist?
-       if (!getcache()) {
-               # No, No it doesn't.. *BASH*
-               print "You have not run ./configure before. Please do this before trying to run the update script.\n";
-               exit 0;
-       } else {
-               # We've Loaded the cache file and all our variables..
-               print "Updating Files..\n";
-               getosflags();
-               $has_epoll = $config{HAS_EPOLL};
-               $has_kqueue = $config{HAS_KQUEUE};
-               writefiles(1);
-               print "Complete.\n";
-               exit;
+sub clean
+{
+       unlink(".config.cache");
+}
+
+our ($has_epoll, $has_ports, $has_kqueue) = (0, 0, 0);
+
+sub update
+{
+       eval {
+               chomp($topdir = getcwd());
+               $this = resolve_directory($topdir);                                          # PWD, Regardless.
+               getmodules();
+               # Does the cache file exist?
+               if (!getcache()) {
+                       # No, No it doesn't.. *BASH*
+                       print "You have not run ./configure before. Please do this before trying to run the update script.\n";
+                       exit 0;
+               } else {
+                       # We've Loaded the cache file and all our variables..
+                       print "Updating files...\n";
+                       getosflags();
+                       if (defined($opt_disable_debug) && $opt_disable_debug == 1)
+                       {
+                               print "Disabling debug information (-g).\n";
+                               $config{OPTIMISATI} = "";
+                               getosflags();
+                       }
+                       $has_epoll = $config{HAS_EPOLL};
+                       $has_ports = $config{HAS_PORTS};
+                       $has_kqueue = $config{HAS_KQUEUE};
+                       writefiles(1);
+                       makecache();
+                       print "Complete.\n";
+                       exit;
+               }
+       };
+       if ($@)
+       {
+               print "Configure update failed: $@\n";
        }
+       exit;
 }
 
-if ($arg eq "-modupdate") {
-        # Does the cache file exist?
-        if (!getcache()) {
-                # No, No it doesn't.. *BASH*
-                print "You have not run ./configure before. Please do this before trying to run the update script.\n";
-                exit 0;
-        } else {
-                # We've Loaded the cache file and all our variables..
-                print "Updating Files..\n";
-                getosflags();
-                $has_epoll = $config{HAS_EPOLL};
-                $has_kqueue = $config{HAS_KQUEUE};
-                writefiles(0);
-                print "Complete.\n";
-                exit;
-        }
+sub modupdate
+{
+       eval {
+               chomp($topdir = getcwd());
+               $this = resolve_directory($topdir);                                          # PWD, Regardless.
+               getmodules();
+               # Does the cache file exist?
+               if (!getcache()) {
+                       # No, No it doesn't.. *BASH*
+                       print "You have not run ./configure before. Please do this before trying to run the update script.\n";
+                       exit 0;
+               } else {
+                       # We've Loaded the cache file and all our variables..
+                       print "Updating files...\n";
+                       getosflags();
+                       $has_epoll = $config{HAS_EPOLL};
+                       $has_ports = $config{HAS_PORTS};
+                       $has_kqueue = $config{HAS_KQUEUE};
+                       writefiles(0);
+                       makecache();
+                       print "Complete.\n";
+                       exit;
+               }
+       };
+       if ($@)
+       {
+               print "Module update failed: $@\n";
+       }
+       exit;
 }
 
 
 
-if ($arg eq "-svnupdate") {
+sub svnupdate
+{
        my $fail = 0;
        open(FH,"<.svn/entries") or $fail = 1;
        if ($fail) {
                print "This is not an SVN copy of InspIRCd.\n";
-               exit;
+               exit 1;
+       }
+       else
+       {
+               close(FH);
+       }
+       open my $fd, "-|", "svn update";
+       my $configurechanged = 0; # Needs ./configure -update
+       my $coredirchanged = 0; # Needs ./configure -update
+       my $moduledirchanged = 0; # Needs ./configure -modupdate
+       my $rootincchanged = 0;
+       my @conflicted = ();
+       while (defined(my $line = <$fd>))
+       {
+               my ($action, $file);
+               print $line;
+               $line =~ m/^([ADUCG])\s+(.*)$/ or next;
+               ($action, $file) = ($1, $2);
+               if ($action eq "C")
+               {
+                       push @conflicted, $file;
+                       if ($file eq "configure")
+                       {
+                               $configurechanged = 1;
+                       }
+                       elsif ($file =~ m#^src/modules#)
+                       {
+                               $moduledirchanged = 1;
+                       }
+                       elsif ($file =~ m#^src/#)
+                       {
+                               $coredirchanged = 1;
+                       }
+                       elsif ($file =~ m/^\..*\.inc$/)
+                       {
+                               $rootincchanged = 1;
+                       }
+               }
+               elsif ($action eq "U" || $action eq "G")
+               {
+                       if ($file eq "configure")
+                       {
+                               $configurechanged = 1;
+                       }
+                       elsif ($file =~ m/^\..*\.inc$/)
+                       {
+                               $rootincchanged = 1;
+                       }
+               }
+               elsif ($action eq "A" || $action eq "D")
+               {
+                       if ($file =~ m#^src/modules#)
+                       {
+                               $moduledirchanged = 1;
+                       }
+                       elsif ($file =~ m#^src/#)
+                       {
+                               $coredirchanged = 1;
+                       }
+               }
+       }
+       unless (close $fd) # close() waits for exit and returns false if the command failed
+       {
+               if ($! == 0)
+               {
+                       print STDERR "Problem updating from SVN, please check above for errors\n";
+               }
+               else
+               {
+                       print STDERR "Failed to run SVN: $!\n";
+               }
+               exit 1;
+       }
+       if (scalar(@conflicted) > 0)
+       {
+               print STDERR "\e[0;33;1mERROR:\e[0m You have local modifications which conflicted with the updates from SVN\n";
+               printf STDERR "Configure is not able to complete the update. Please resolve these conflicts, then run ./configure -%supdate\n", (($coredirchanged || $configurechanged) ? "" : "mod");
+               print "Conflicted files: " . join ", ", @conflicted . "\n";
+               exit 1;
+       }
+       if ($configurechanged || $coredirchanged)
+       {
+               system("perl configure -update");
+       }
+       elsif ($moduledirchanged || $rootincchanged)
+       {
+               system("perl configure -modupdate");
+       }
+       else
+       {
+               print "No need to update Makefiles.\n";
        }
-       system("svn update");
-       system("perl configure -update");
-       if ($ARGV[1] eq "rebuild") {
+       if (defined $opt_rebuild) {
                system("make install");
        }
        exit;
 }
 
-print "Checking for cache from previous configure...\n";
-getcache();
-print "Checking operating system version...\n";
-getosflags();
-
-if (!$config{MAX_CLIENT}) { 
-       # If the cache hasn't set the max clients, copy the variable of MAX_CLIENT_T, this
-       # allows us to keep _T for testing purposes. (ie. "Are you sure you want to go
-       # higher than the found value" :))
-       $config{MAX_CLIENT} = $config{MAX_CLIENT_T};
-}
+print "Running non-interactive configure...\n" unless $interactive;
+print "Checking for cache from previous configure... ";
+print ((!getcache()) ? "not found\n" : "found\n");
+print "Checking operating system version... ";
+print getosflags() . "\n";
 
 printf "Checking if stdint.h exists... ";
 $config{HAS_STDINT} = "true";
-my $fail = 0;
+our $fail = 0;
 open(STDINT, "</usr/include/stdint.h") or $config{HAS_STDINT} = "false";
 if ($config{HAS_STDINT} eq "true") {
        close(STDINT);
@@ -178,14 +545,14 @@ if ($config{HAS_STDINT} eq "true") {
 print "yes\n" if $config{HAS_STDINT} eq "true";
 print "no\n" if $config{HAS_STDINT} eq "false";
 
-
 printf "Checking if strlcpy exists... ";
 # Perform the strlcpy() test..
 $config{HAS_STRLCPY} = "false";
-my $fail = 0;
+$fail = 0;
 open(STRLCPY, "</usr/include/string.h") or $fail = 1;
 if (!$fail) {
-       while (chomp($line = <STRLCPY>)) {
+       while (defined(my $line = <STRLCPY>)) {
+               chomp($line);
                # try and find the delcaration of:
                # size_t strlcpy(...)
                if ($line =~ /size_t(\0x9|\s)+strlcpy/) {
@@ -197,35 +564,14 @@ if (!$fail) {
 print "yes\n" if $config{HAS_STRLCPY} eq "true";
 print "no\n" if $config{HAS_STRLCPY} eq "false";
 
-printf "Checking if execinfo.h exists... ";
-$config{HAS_EXECINFO} = "0";
-my $fail = 0;
-open(EXECINFO, "</usr/include/execinfo.h") or $fail = 1;
-if ($fail) {
-       $fail = 0;
-       open(EXECINFO, "</usr/local/include/execinfo.h") or $fail = 1;
-       if (!$fail) {
-               printf "/usr/local/include/execinfo.h\n";
-               $config{HAS_EXECINFO} = "1";
-               close(EXECINFO);
-       }
-       else {
-               printf "Not found!\n";
-       }
-}
-else {
-       printf "/usr/include/execinfo.h\n";
-       $config{HAS_EXECINFO} = "1";
-       close(EXECINFO);
-}
-
 printf "Checking if kqueue exists... ";
 $has_kqueue = 0;
 $fail = 0;
 open(KQUEUE, "</usr/include/sys/event.h") or $fail = 1;
 if (!$fail) {
-        while (chomp($line = <KQUEUE>)) {
-                # try and find the delcaration of:
+       while (defined(my $line = <KQUEUE>)) {
+               chomp($line);
+               # try and find the delcaration of:
                # int kqueue(void);
                if ($line =~ /int(\0x9|\s)+kqueue/) {
                        $has_kqueue = 1;
@@ -247,22 +593,80 @@ if (!$fail) {
 if ($has_epoll) {
        my $kernel = `uname -r`;
        chomp($kernel);
-       if (($kernel =~ /2\.0/) || ($kernel =~ /2\.2/) || ($kernel =~ /2\.4/)) {
+       if (($kernel =~ /^2\.0\./) || ($kernel =~ /^2\.2\./) || ($kernel =~ /^2\.4\./)) {
                $has_epoll = 0;
        }
+       else
+       {
+               # Suggestion from nenolod, weed out odd systems which have glibc built
+               # against 2.4 kernels (ick)
+               my $kernel_arch = `uname -p`;
+               chomp($kernel_arch);
+               my $libcv = 0.0;
+               my $kernelv = 0.0;
+               if ($kernel_arch =~ /x86_64/) {
+                       open (FH,"/lib64/libc.so.6|") or $has_epoll = 0;
+               }
+               else {
+                       open (FH,"/lib/libc.so.6|") or $has_epoll = 0;
+               }
+               if ($has_epoll)
+               {
+                       while (defined(my $line = <FH>))
+                       {
+                               chomp($line);
+                               if ($line =~ /GNU C Library .* version (.*?) /)
+                               {
+                                       $libcv = $1;
+                                       $libcv =~  /(\d+\.\d+)/;
+                                       $libcv = $1;
+                               }
+                               elsif ($line =~ /Compiled on a Linux (.*?\..*?)\.* system/)
+                               {
+                                       $kernelv = $1;
+                                       # Fix for some retarded libc builds, strip off >> and << etc.
+                                       $kernelv =~ /(\d+\.\d+)/;
+                                       $kernelv = $1;
+                               }
+                       }
+                       close FH;
+                       if ($libcv < 2.3)
+                       {
+                               $has_epoll = 0;
+                               printf "libc too old: $libcv... ";
+                       }
+                       if ($kernelv < 2.6)
+                       {
+                               $has_epoll = 0;
+                               printf "libc built against older kernel $kernelv... ";
+                       }
+               }
+       }
 }
 print "yes\n" if $has_epoll == 1;
 print "no\n" if $has_epoll == 0;
 
-if (($config{OSNAME} =~ /CYGWIN/) || ($config{OSNAME} eq "CYG-STATIC")) {
-       $config{HAS_STRLCPY} = "true";
+printf "Checking if Solaris I/O completion ports are available... ";
+$has_ports = 0;
+our $system = `uname -s`;
+chomp ($system);
+$has_ports = 1 if ($system eq "SunOS");
+
+if ($has_ports) {
+       my $kernel = `uname -r`;
+       chomp($kernel);
+       if (($kernel !~ /^5\.1./)) {
+               $has_ports = 0;
+       }
 }
+print "yes\n" if $has_ports == 1;
+print "no\n" if $has_ports == 0;
 
 $config{HAS_EPOLL} = $has_epoll;
 $config{HAS_KQUEUE} = $has_kqueue; 
 
 printf "Checking for libgnutls... ";
-if (($config{HAS_GNUTLS}) && (($config{HAS_GNUTLS} >= 1.2) || ($config{HAS_GNUTLS} eq "y"))) {
+if (defined($config{HAS_GNUTLS}) && (($config{HAS_GNUTLS}) || ($config{HAS_GNUTLS} eq "y"))) {
        print "yes\n";
        $config{HAS_GNUTLS} = "y";
 } else {
@@ -271,7 +675,7 @@ if (($config{HAS_GNUTLS}) && (($config{HAS_GNUTLS} >= 1.2) || ($config{HAS_GNUTL
 }
 
 printf "Checking for openssl... ";
-if (($config{HAS_OPENSSL}) && (($config{HAS_OPENSSL} >= 0.8) || ($config{HAS_OPENSSL} eq "y"))) {
+if (defined($config{HAS_OPENSSL}) && (($config{HAS_OPENSSL}) || ($config{HAS_OPENSSL} eq "y"))) {
        print "yes\n";
        $config{HAS_OPENSSL} = "y";
 } else {
@@ -279,441 +683,214 @@ if (($config{HAS_OPENSSL}) && (($config{HAS_OPENSSL} >= 0.8) || ($config{HAS_OPE
        $config{HAS_OPENSSL} = "n";
 }
 
+printf "Checking if you are running an ancient, unsupported OS... ";
+if ($config{OSNAME} =~ /FreeBSD/i)
+{
+       my $version = `uname -r`;
+       if ($version =~ /^4\./)
+       {
+               my $foundit = `ls -l /usr/local/lib/libgnugetopt* | wc -l`;
+               if ($foundit > 0)
+               {
+                       # ICKY ICKY ICK, FREEBSD 4.x! GET AN UPGRADE!
+                       $config{CRAQ} = "-L/usr/local/lib -lgnugetopt -DHAVE_DECL_GETOPT=1";
+                       print "yes\n";
+               }
+               else
+               {
+                       print "\n\nERROR: You require libgnugetopt (from ports or packages) to build InspIRCd on FreeBSD 4.11.\n";
+               }
+       }
+       else
+       {
+               $config{CRAQ} = " ";
+               print "no ($version)\n";
+       }
+}
+else
+{
+       $config{CRAQ} = " ";
+       print "no ($config{OSNAME})\n";
+}
+
 ################################################################################
-#                          BEGIN INTERACTIVE PART                              #
+#                        BEGIN INTERACTIVE PART                              #
 ################################################################################
 
 # Clear the Screen..
-system("clear");
-# Display Splash Logo..
-show_splash();
-chomp($wholeos = `uname -mnr`);
+if ($interactive)
+{
+       print "\e[2J\e[0G\e[0d"; # J = Erase in Display, 2 = Entire Screen, (G, d) = Move cursor to (..,..)
+       my $wholeos = $^O;
 
-my $rev = getrevision();
-# Display Introduction Message..
-print "
-Welcome to the InspIRCd Configuration program!
+       my $rev = getrevision();
+       # Display Introduction Message..
+       print <<"STOP" ;
+Welcome to the \e[1mInspIRCd\e[0m Configuration program! (\e[1minteractive mode\e[0m)
+\e[1mPackage maintainers: Type ./configure --help for non-interactive help\e[0m
 
 *** If you are unsure of any of these values, leave it blank for    ***
 *** standard settings that will work, and your server will run      ***
-*** using them. If you are running this server as part of a         ***
-*** larger network, you must consult with your network admins       ***
-*** for the proper values to use, or server links will be unstable! ***
+*** using them. Please consult your IRC network admin if in doubt.  ***
 
-Press \033[1m<RETURN>\033[0m to accept the default for any option, or enter
-a new value. Please note: You will \033[1mHAVE\033[0m to read the docs
+Press \e[1m<RETURN>\e[0m to accept the default for any option, or enter
+a new value. Please note: You will \e[1mHAVE\e[0m to read the docs
 dir, otherwise you won't have a config file!
 
-Your operating system is: \033[1;32m$config{OSNAME}\033[0m ($wholeos), fdmax: $config{MAX_CLIENT_T}
-Your InspIRCd revision ID is \033[1;32mr$rev\033[0m";
-if ($rev eq "r0") {
-       print " (Non-SVN build)";
-}
-print ".\n\n";
+Your operating system is: \e[1;32m$config{OSNAME}\e[0m ($wholeos)
+Your InspIRCd revision ID is \e[1;32mr$rev\e[0m
+STOP
+       if ($rev eq "r0") {
+               print " (Non-SVN build)";
+       }
+       print ".\n\n";
 
-$config{CHANGE_COMPILER} = "n";
-print "I have detected the following compiler: \033[1;32m$config{CC}\033[0m (version \033[1;32m$config{GCCVER}.x\033[0m)\n";
+       $config{CHANGE_COMPILER} = "n";
+       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";
 
-while (($config{GCCVER} < 3) || ($config{GCCVER} eq "")) {
-       print "\033[1;32mIMPORTANT!\033[0m A GCC 2.x compiler has been detected, and
+       while (($config{GCCVER} < 3) || ($config{GCCVER} eq "")) {
+               print "\e[1;32mIMPORTANT!\e[0m A GCC 2.x compiler has been detected, and
 should NOT be used. You should probably specify a newer compiler.\n\n";
-       yesno(CHANGE_COMPILER,"Do you want to change the compiler?");
-       if ($config{CHANGE_COMPILER} =~ /y/i) {
-               print "What command do you want to use to invoke your compiler?\n";
-               print "[\033[1;32m$config{CC}\033[0m] -> ";
-               chomp($config{CC} = <STDIN>);
-               if ($config{CC} eq "") {
-                       $config{CC} = "g++";
-               }
-               chomp($foo = `$config{CC} -dumpversion | cut -c 1`);
-               if ($foo ne "") {
-                       chomp($config{GCCVER}       = `$config{CC} -dumpversion | cut -c 1`); # we must redo these if we change compilers
-                       print "Queried compiler: \033[1;32m$config{CC}\033[0m (version \033[1;32m$config{GCCVER}.x\033[0m)\n";
-                       if ($config{GCCVER} < 3) {
-                               print "\033[1;32mGCC 2.x WILL NOT WORK!\033[0m. Let's try that again, shall we?\n";
+               yesno('CHANGE_COMPILER',"Do you want to change the compiler?");
+               if ($config{CHANGE_COMPILER} =~ /y/i) {
+                       print "What command do you want to use to invoke your compiler?\n";
+                       print "[\e[1;32m$config{CC}\e[0m] -> ";
+                       chomp($config{CC} = <STDIN>);
+                       if ($config{CC} eq "") {
+                               $config{CC} = "g++";
+                       }
+                       chomp(my $foo = `$config{CC} -dumpversion | cut -c 1`);
+                       if ($foo ne "") {
+                               chomp($config{GCCVER}       = `$config{CC} -dumpversion | cut -c 1`); # we must redo these if we change compilers
+                               chomp($config{GCCMINOR}     = `$config{CC} -dumpversion | cut -c 3`);
+                               print "Queried compiler: \e[1;32m$config{CC}\e[0m (version \e[1;32m$config{GCCVER}.$config{GCCMINOR}\e[0m)\n";
+                               if ($config{GCCVER} < 3) {
+                                       print "\e[1;32mGCC 2.x WILL NOT WORK!\e[0m. Let's try that again, shall we?\n";
+                               }
+                       }
+                       else {
+                               print "\e[1;32mWARNING!\e[0m Could not execute the compiler you specified. You may want to try again.\n";
                        }
-               }
-               else {
-                       print "\033[1;32mWARNING!\033[0m Could not execute the compiler you specified. You may want to try again.\n";
                }
        }
-}
-
-print "\n";
-
-# Directory Settings..
-my $tmpbase = $config{BASE_DIR};
-dir_check("do you wish to install the InspIRCd base", "BASE_DIR");
-if ($tmpbase ne $config{BASE_DIR}) {
-       $config{CONFIG_DIR}         = resolve_directory($config{BASE_DIR}."/conf");           # Configuration Directory
-       $config{MODULE_DIR}         = resolve_directory($config{BASE_DIR}."/modules");        # Modules Directory
-       $config{BINARY_DIR}         = resolve_directory($config{BASE_DIR}."/bin");            # Binary Directory
-       $config{LIBRARY_DIR}        = resolve_directory($config{BASE_DIR}."/lib");            # Library Directory
-}
-
-dir_check("are the configuration files", "CONFIG_DIR");
-dir_check("are the modules to be compiled to", "MODULE_DIR");
-dir_check("is the IRCd binary to be placed", "BINARY_DIR");
-dir_check("are the IRCd libraries to be placed", "LIBRARY_DIR");
-
-if ($has_kqueue) {
-       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?");
-       print "\n";
-}
-if ($has_epoll) {
-       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?");
-       print "\n";
-}
-$chose_hiperf = (($config{USE_EPOLL} eq "y") || ($config{USE_KQUEUE} eq "y"));
-if (!$chose_hiperf) {
-       print "No high-performance socket engines are available, or you chose\n";
-       print "not to enable one. Defaulting to select() engine.\n\n";
-}
 
-yesno(IPV6,"Would you like to build InspIRCd with IPv6 support?");
-print "\n";
-
-if ($config{IPV6} eq "y") {
-       print "You have chosen to build an \033[1;32mIPV6-only\033[0m server.\nTo accept IPV4 users, you must use the '::ffff:' notation of addresses.\n\n";
-       $config{SUPPORT_IP6LINKS} = "y";
-} else {
-       yesno(SUPPORT_IP6LINKS,"You have chosen to build an \033[1;32mIPV4-only\033[0m server.\nWould you like to enable support for linking to IPV6-enabled\nInspIRCd servers which are using '::ffff:' notation?\nIf you are using a recent operating\nsystem and are unsure, answer yes.");
        print "\n";
-}
-
-if (($config{HAS_GNUTLS} eq "y") && ($config{HAS_OPENSSL} eq "y")) {
-       print "I have detected both GnuTLS and OpenSSL on your system.\n";
-       print "I will default to GnuTLS. If you wish to use OpenSSL\n";
-       print "instead, you should enable the OpenSSL module yourself\n";
-       print "by copying it from src/modules/extra to src/modules.\n\n";
-}
 
-if ($config{HAS_GNUTLS} eq "y") {
-       yesno(USE_GNUTLS, "Would you like to enable SSL Support?");
-       if ($config{USE_GNUTLS} eq "y") {
-               print "\nUsing GnuTLS SSL module.\n";
+       # Directory Settings..
+       my $tmpbase = $config{BASE_DIR};
+       dir_check("do you wish to install the InspIRCd base", "BASE_DIR");
+       if ($tmpbase ne $config{BASE_DIR}) {
+               $config{CONFIG_DIR}      = resolve_directory($config{BASE_DIR}."/conf");           # Configuration Dir
+               $config{MODULE_DIR}      = resolve_directory($config{BASE_DIR}."/modules");     # Modules Directory
+               $config{BINARY_DIR}      = resolve_directory($config{BASE_DIR}."/bin");     # Binary Directory
+               $config{LIBRARY_DIR}    = resolve_directory($config{BASE_DIR}."/lib");      # Library Directory
        }
-} elsif ($config{HAS_OPENSSL} eq "y") {
-       yesno(USE_OPENSSL, "Would you like to enable SSL Support?");
-       if ($config{USE_OPENSSL} eq "y") {
-               print "\nUsing OpenSSL SSL module.\nYou will get better performance if you move to GnuTLS in the future.\n";
-       }
-}
 
-print "\nThe following questions will ask you for various figures relating\n";
-print "To your IRCd install. Please note that these should usually be left\n";
-print "as defaults unless you have a real reason to change them. If they\n";
-print "changed, then the values must be identical on all servers on your\n";
-print "network, or malfunctions and/or crashes may occur, with the exception\n";
-print "of the 'maximum number of clients' setting which may be different on\n";
-print "different servers on the network.\n\n";
-
-# File Descriptor Settings..
-my $continue = 0;
-while (!$continue) {
-       print "Maximum number of clients at any one time ($config{MAX_CLIENT_T})\n";
-       print "[\033[1;32m$config{MAX_CLIENT}\033[0m] -> ";
-       chomp($var = <STDIN>);
-       if ($var eq "") {
-               $var = $config{MAX_CLIENT};
-       }
-       if ($var =~ /^\d+$/) {
-               if (($var > $config{MAX_CLIENT_T}) && ($fd_scan_failed ne true)) {
-                       # Client has entered a larger number than the 'discovered' value
-                       # Confirm.
-                       print "WARNING: Our scans have indicated that you are attempting
-to use more sockets than there are avaliable. Are you sure
-you wish to do this? It may cause the IRCd to malfunction [y/n]
-[\033[1;32mn\033[0m] -> $c";
-                       chomp($tmp = <STDIN>);
-                       if ($tmp ne "y") {
-                               print "Please enter the correct value.\n\n";
-                               next;
-                       }
-               }
-       } else {
-               print "You must enter a number in this field. Please try again.\n\n";
-               next;
-       }
-       # If we get here, we should be good to go.
-       $config{MAX_CLIENT} = $var;
-       $continue = 1;
-       print "\n";
-}
+       dir_check("are the configuration files", "CONFIG_DIR");
+       dir_check("are the modules to be compiled to", "MODULE_DIR");
+       dir_check("is the IRCd binary to be placed", "BINARY_DIR");
+       dir_check("are the IRCd libraries to be placed", "LIBRARY_DIR");
 
-my $continue = 0;
-while (!$continue) {
-       print "What is the maximum length of nicknames?\n";
-       print "[\033[1;32m$config{NICK_LENGT}\033[0m] -> ";
-       chomp($var = <STDIN>);
-       if ($var eq "") {
-               $var = $config{NICK_LENGT};
-       }
-       if ($var =~ /^\d+$/) {
-               # We don't care what the number is, set it and be on our way.
-               $config{NICK_LENGT} = $var;
-               $continue = 1;
+       if ($has_kqueue) {
+               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?");
                print "\n";
-       } else {
-               print "You must enter a number in this field. Please try again.\n\n";
        }
-}
-
-$continue = 0;
-while (!$continue) {
-       print "What is the maximum length of channel names?\n";
-       print "[\033[1;32m$config{CHAN_LENGT}\033[0m] -> ";
-       chomp($var = <STDIN>);
-       if ($var eq "") {
-               $var = $config{CHAN_LENGT};
-       }
-       if ($var =~ /^\d+$/) {
-               # We don't care what the number is, set it and be on our way.
-               $config{CHAN_LENGT} = $var;
-               $continue = 1;
+       if ($has_epoll) {
+               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?");
                print "\n";
-       } else {
-               print "You must enter a number in this field. Please try again.\n\n";
        }
-}
-
-$continue = 0;
-while (!$continue) {
-       print "What is the maximum number of channels a normal user may join at any one time?\n";
-       print "[\033[1;32m$config{MAX_CHANNE}\033[0m] -> ";
-       chomp($var = <STDIN>);
-       if ($var eq "") {
-               $var = $config{MAX_CHANNE};
-       }
-       if ($var =~ /^\d+$/) {
-               # We don't care what the number is, set it and be on our way.
-               $config{MAX_CHANNE} = $var;
-               $continue = 1;
+       if ($has_ports) {
+               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?");
                print "\n";
-       } else {
-               print "You must enter a number in this field. Please try again.\n\n";
        }
-}
-
-$continue = 0;
-while (!$continue) {
-       print "What is the maximum number of channels an oper may join at any one time?\n";
-       print "[\033[1;32m$config{MAX_OPERCH}\033[0m] -> ";
-       chomp($var = <STDIN>);
-       if ($var eq "") {
-               $var = $config{MAX_OPERCH};
-       }
-       if ($var =~ /^\d+$/) {
-               # We don't care what the number is, set it and be on our way.
-               $config{MAX_OPERCH} = $var;
-               $continue = 1;
-               print "\n";
+       my $chose_hiperf = (($config{USE_EPOLL} eq "y") || ($config{USE_KQUEUE} eq "y") || ($config{USE_PORTS} eq "y"));
+       if (!$chose_hiperf) {
+               print "No high-performance socket engines are available, or you chose\n";
+               print "not to enable one. Defaulting to select() engine.\n\n";
        }
-}
 
-$continue = 0;
-while (!$continue) {
-       print "What is the maximum number of mode changes in one line?\n";
-       print "[\033[1;32m$config{MAXI_MODES}\033[0m] -> ";
-       chomp($var = <STDIN>);
-       if ($var eq "") {
-               $var = $config{MAXI_MODES};
-       }
-       if ($var =~ /^\d+$/) {
-               # We don't care what the number is, set it and be on our way.
-               $config{MAXI_MODES} = $var;
-               $continue = 1;
-               print "\n";
-       } else {
-               print "You must enter a number in this field. Please try again.\n\n";
-       }
-}
+       yesno('IPV6',"Would you like to build InspIRCd with IPv6 support?");
+       print "\n";
 
-$continue = 0;
-while (!$continue) {
-       print "What is the maximum length of an ident (username)?\n";
-       print "[\033[1;32m$config{MAX_IDENT}\033[0m] -> ";
-       chomp($var = <STDIN>);
-       if ($var eq "") {
-               $var = $config{MAX_IDENT};
-       }
-       if ($var =~ /^\d+$/) {
-               # We don't care what the number is, set it and be on our way.
-               $config{MAX_IDENT} = $var;
-               $continue = 1;
-               print "\n";
+       if ($config{IPV6} eq "y") {
+               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";
+               $config{SUPPORT_IP6LINKS} = "y";
        } else {
-               print "You must enter a number in this field. Please try again.\n\n";
-       }
-}
-
-$continue = 0;
-while (!$continue) {
-       print "What is the maximum length of a quit message?\n";
-       print "[\033[1;32m$config{MAX_QUIT}\033[0m] -> ";
-       chomp($var = <STDIN>);
-       if ($var eq "") {
-               $var = $config{MAX_QUIT};
-       }
-       if ($var =~ /^\d+$/) {
-               # We don't care what the number is, set it and be on our way.
-               $config{MAX_QUIT} = $var;
-               $continue = 1;
+               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?");
                print "\n";
-       } else {
-               print "You must enter a number in this field. Please try again.\n\n";
        }
-}
 
-$continue = 0;
-while (!$continue) {
-       print "What is the maximum length of a channel topic?\n";
-       print "[\033[1;32m$config{MAX_TOPIC}\033[0m] -> ";
-       chomp($var = <STDIN>);
-       if ($var eq "") {
-               $var = $config{MAX_TOPIC};
-       }
-       if ($var =~ /^\d+$/) {
-               # We don't care what the number is, set it and be on our way.
-               $config{MAX_TOPIC} = $var;
-               $continue = 1;
+       $config{USE_FREEBSD_BASE_SSL} = "n";
+       $config{USE_FREEBSD_PORTS_SSL} = "n";
+       if ($config{HAS_OPENSSL_PORT} ne "")
+       {
+               $config{USE_FREEBSD_PORTS_SSL} = "y";
+               print "I have detected the OpenSSL FreeBSD port installed on your system,\n";
+               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";
+               yesno('USE_FREEBSD_PORTS_SSL', "Do you want to use the FreeBSD ports version?");
                print "\n";
-       } else {
-               print "You must enter a number in this field. Please try again.\n\n";
-       }
-}
+               $config{USE_FREEBSD_BASE_SSL} = "y" if ($config{USE_FREEBSD_PORTS_SSL} eq "n");
 
-$continue = 0;
-while (!$continue) {
-       print "What is the maximum length of a kick message?\n";
-       print "[\033[1;32m$config{MAX_KICK}\033[0m] -> ";
-       chomp($var = <STDIN>);
-       if ($var eq "") {
-               $var = $config{MAX_KICK};
-       }
-       if ($var =~ /^\d+$/) {
-               # We don't care what the number is, set it and be on our way.
-               $config{MAX_KICK} = $var;
-               $continue = 1;
-               print "\n";
-       } else {
-               print "You must enter a number in this field. Please try again.\n\n";
+               if ($config{USE_FREEBSD_BASE_SSL} eq "n")
+               {
+                       # update to port version
+                       $openssl_ver = $config{HAS_OPENSSL_PORT};
+               }
+       }
+       else
+       {
+               $config{USE_FREEBSD_BASE_SSL} = "y" if ($^O eq "freebsd");
        }
-}
 
-$continue = 0;
-while (!$continue) {
-       print "What is the maximum length of a GECOS (real name) field?\n";
-       print "[\033[1;32m$config{MAX_GECOS}\033[0m] -> ";
-       chomp($var = <STDIN>);
-       if ($var eq "") {
-               $var = $config{MAX_GECOS};
-       }
-       if ($var =~ /^\d+$/) {
-               # We don't care what the number is, set it and be on our way.
-               $config{MAX_GECOS} = $var;
-               $continue = 1;
-               print "\n";
-       } else {
-               print "You must enter a number in this field. Please try again.\n\n";
+       if (($config{HAS_GNUTLS} eq "y") && ($config{HAS_OPENSSL} eq "y")) {
+               print "I have detected both \e[1;32mGnuTLS\e[0m and \e[1;32mOpenSSL\e[0m on your system.\n";
+               print "I will default to GnuTLS. If you wish to use OpenSSL\n";
+               print "instead, you should enable the OpenSSL module yourself\n";
+               print "by copying it from src/modules/extra to src/modules.\n\n";
+               print "Detected GnuTLS version: \e[1;32m" . $gnutls_ver . "\e[0m\n";
+               print "Detected OpenSSL version: \e[1;32m" . $openssl_ver . "\e[0m\n\n";
        }
-}
 
-$continue = 0;
-while (!$continue) {
-       print "What is the maximum length of an away message?\n";
-       print "[\033[1;32m$config{MAX_AWAY}\033[0m] -> ";
-       chomp($var = <STDIN>);
-       if ($var eq "") {
-               $var = $config{MAX_AWAY};
-       }
-       if ($var =~ /^\d+$/) {
-               # We don't care what the number is, set it and be on our way.
-               $config{MAX_AWAY} = $var;
-               $continue = 1;
-               print "\n";
-       } else {
-               print "You must enter a number in this field. Please try again.\n\n";
+       if ($config{HAS_GNUTLS} eq "y") {
+               yesno('USE_GNUTLS', "Would you like to enable SSL Support?");
+               if ($config{USE_GNUTLS} eq "y") {
+                       print "\nUsing GnuTLS SSL module.\n";
+               }
+       } elsif ($config{HAS_OPENSSL} eq "y") {
+                       yesno('USE_OPENSSL', "Would you like to enable SSL Support?");
+       if ($config{USE_OPENSSL} eq "y") {
+                       print "\nUsing OpenSSL SSL module.\nYou will get better performance if you move to GnuTLS in the future.\n";
+               }
+       }
+       else {
+               print "\nCould not detect OpenSSL or GnuTLS. Make sure pkg-config is installed if\nyou intend to use OpenSSL, or that GnuTLS is in your path if you intend\nto use GnuTLS.\n\n";
        }
 }
 
-# Code Optimisation
-print "Enter the Level Of Binary optimisation. This is a number between 0 and 3.
-The InspIRCd Team will NOT support any bug reports above 0. Also note,
-the IRCd behaviour will be different depending on this value. Please
-read the documentation for more information.
-
-The higher the number, the more optimised your binary will be. This
-value will default to 0 if you either don't enter a number, or enter
-a value outside the range.
-
-As always, if you are unsure, just press enter and accept the default.\n\n";
-print "[\033[1;32m$config{OPTIMITEMP}\033[0m] -> ";
-chomp($var = <STDIN>);
-if ($var eq "") {
-       $var = $config{OPTIMITEMP};
-}
+dumphash();
 
-if ($var eq "1") {
-       $config{OPTIMITEMP} = 1;
-       $config{OPTIMISATI} = "-O";
-} elsif ($var eq "2") {
-       $config{OPTIMITEMP} = 2;
-       $config{OPTIMISATI} = "-O2";
-} elsif ($var eq "3") {
-       $config{OPTIMITEMP} = 3;
-       $config{OPTIMISATI} = "-O3";
-} else {
-       $config{OPTIMITEMP} = 0;
-       $config{OPTIMISATI} = "-g";
+if (($config{USE_GNUTLS} eq "y") && ($config{HAS_GNUTLS} ne "y"))
+{
+       print "Sorry, but i couldn't detect gnutls. Make sure gnutls-config is in your path.\n";
+       exit(0);
 }
-
-print "\n\033[1;32mPre-build configuration is complete!\033[0m\n\n";
-print "\033[0mBase install path:\033[1;32m\t\t$config{BASE_DIR}\033[0m\n";
-print "\033[0mConfig path:\033[1;32m\t\t\t$config{CONFIG_DIR}\033[0m\n";
-print "\033[0mModule path:\033[1;32m\t\t\t$config{MODULE_DIR}\033[0m\n";
-print "\033[0mLibrary path:\033[1;32m\t\t\t$config{LIBRARY_DIR}\033[0m\n";
-print "\033[0mMax connections:\033[1;32m\t\t$config{MAX_CLIENT}\033[0m\n";
-print "\033[0mMax User Channels:\033[1;32m\t\t$config{MAX_CHANNE}\033[0m\n";
-print "\033[0mMax Oper Channels:\033[1;32m\t\t$config{MAX_OPERCH}\033[0m\n";
-print "\033[0mMax nickname length:\033[1;32m\t\t$config{NICK_LENGT}\033[0m\n";
-print "\033[0mMax channel length:\033[1;32m\t\t$config{CHAN_LENGT}\033[0m\n";
-print "\033[0mMax mode length:\033[1;32m\t\t$config{MAXI_MODES}\033[0m\n";
-print "\033[0mMax ident length:\033[1;32m\t\t$config{MAX_IDENT}\033[0m\n";
-print "\033[0mMax quit length:\033[1;32m\t\t$config{MAX_QUIT}\033[0m\n";
-print "\033[0mMax topic length:\033[1;32m\t\t$config{MAX_TOPIC}\033[0m\n";
-print "\033[0mMax kick length:\033[1;32m\t\t$config{MAX_KICK}\033[0m\n";
-print "\033[0mMax name length:\033[1;32m\t\t$config{MAX_GECOS}\033[0m\n";
-print "\033[0mMax away length:\033[1;32m\t\t$config{MAX_AWAY}\033[0m\n";
-print "\033[0mGCC Version Found:\033[1;32m\t\t$config{GCCVER}.x\033[0m\n";
-print "\033[0mOptimization Flag:\033[1;32m\t\t$config{OPTIMISATI}\033[0m\n";
-print "\033[0mCompiler program:\033[1;32m\t\t$config{CC}\033[0m\n";
-print "\033[0mStatic modules:\033[1;32m\t\t\t$config{STATIC_LINK}\033[0m\n";
-print "\033[0mMultithread DNS:\033[1;32m\t\t$config{THREADED_DNS}\033[0m\n";
-print "\033[0mIPv6 Support:\033[1;32m\t\t\t$config{IPV6}\033[0m\n";
-print "\033[0mIPv6 to IPv4 Links:\033[1;32m\t\t$config{SUPPORT_IP6LINKS}\033[0m\n";
-print "\033[0mGnuTLS Support:\033[1;32m\t\t\t$config{USE_GNUTLS}\033[0m\n";
-print "\033[0mOpenSSL Support:\033[1;32m\t\t$config{USE_OPENSSL}\033[0m\n\n";
+if (($config{USE_OPENSSL} eq "y") && ($config{HAS_OPENSSL} ne "y"))
+{
+       print "Sorry, but i couldn't detect openssl. Make sure openssl is in your path.\n";
+       exit(0);
+}
+our $failed = 0;
 
 if ($config{USE_GNUTLS} eq "y") {
-       $failed = 0;
-       open(TMP, "<src/modules/m_ssl_gnutls.cpp") or $failed = 1;
-       close(TMP);
-       if ($failed) {
+       unless (-r "src/modules/m_ssl_gnutls.cpp") {
                print "Symlinking src/modules/m_ssl_gnutls.cpp from extra/\n";
-               chdir("src/modules");
-               system("ln -s extra/m_ssl_gnutls.cpp");
-               system("ln -s extra/ssl_cert.h");
-               chdir("../..");
+               symlink "extra/m_ssl_gnutls.cpp", "src/modules/m_ssl_gnutls.cpp" or print STDERR "Symlink failed: $!";
        }
        getmodules();
-       $failed = 0;
-       open(TMP, "<$config{CONFIG_DIR}/key.pem") or $failed = 1;
-       close(TMP);
-       open(TMP, "<$config{CONFIG_DIR}/cert.pem") or $failed = 1;
-       close(TMP);
-       if ($failed) {
-               print "SSL Certificates Not found, Generating.. \n\n
+       if ($interactive)
+       {
+               unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") {
+                       print "SSL Certificates Not found, Generating.. \n\n
 *************************************************************
 * Generating the Private Key may take some time, go grab a  *
 * Coffee. Even better, to generate some more entropy if it  *
@@ -721,47 +898,52 @@ if ($config{USE_GNUTLS} eq "y") {
 * few times and get that HD going :) Then answer the        *
 * Questions which follow. If you are unsure, just hit enter *
 *************************************************************\n\n";
-               system("certtool --generate-privkey --outfile key.pem");
-               system("certtool --generate-self-signed --load-privkey key.pem --outfile cert.pem");
-               print "\nCertificate generation complete, copying to config directory... ";
-               system("mv key.pem $config{CONFIG_DIR}/key.pem");
-               system("mv cert.pem $config{CONFIG_DIR}/cert.pem");
-               print "Done.\n\n";
-       } else {
-               print "SSL Certificates found, skipping.\n\n"
-       }       
-} elsif ($config{USE_OPENSSL} eq "y") {
-       $failed = 0;
-       open(TMP, "<src/modules/m_ssl_openssl.cpp") or $failed = 1;
-       close(TMP);
-       if ($failed) {
-               print "Symlinking src/modules/m_ssl_openssl.cpp from extra/\n";
-               chdir("src/modules");
-               system("ln -s extra/m_ssl_openssl.cpp");
-               system("ln -s extra/ssl_cert.h");
-               chdir("../..");
-       }
-       getmodules();
+                       $failed = make_gnutls_cert();
+                       if ($failed) {
+                               print "\n\e[1;32mCertificate generation failed!\e[0m\n\n";
+                       } else {
+                               print "\nCertificate generation complete, copying to config directory... ";
+                               File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
+                               File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
+                               print "Done.\n\n";
+                       }
+               }
+               else {
+                       print "SSL Certificates found, skipping.\n\n";
+               }
+       }
+       else
+       {
+               print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
+       }
+} elsif ($config{USE_OPENSSL} eq "y") {
+       unless (-r "src/modules/m_ssl_openssl.cpp") {
+               print "Symlinking src/modules/m_ssl_openssl.cpp from extra/\n";
+               symlink "extra/m_ssl_openssl.cpp", "src/modules/m_ssl_openssl.cpp" or print STDERR "Symlink failed: $!";
+       }
+       getmodules();
        $failed = 0;
-       open(TMP, "<$config{CONFIG_DIR}/key.pem") or $failed = 1;
-       close(TMP);
-       open(TMP, "<$config{CONFIG_DIR}/cert.pem") or $failed = 1;
-       close(TMP);
-       if ($failed) {
-               print "SSL Certificates Not found, Generating.. \n\n
+       if ($interactive)
+       {
+               unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") {
+                       print "SSL Certificates Not found, Generating.. \n\n
 *************************************************************
 * Generating the certificates may take some time, go grab a *
-* coffee, or something.                                     *
+* coffee, or something.                                            *
 *************************************************************\n\n";
-               system("openssl req -x509 -nodes -newkey rsa:1024 -keyout key.pem -out cert.pem");
-               system("openssl dhparam -out dhparams.pem 1024");
-               print "\nCertificate generation complete, copying to config directory... ";
-               system("mv key.pem $config{CONFIG_DIR}/key.pem");
-               system("mv cert.pem $config{CONFIG_DIR}/cert.pem");
-               system("mv dhparams.pem $config{CONFIG_DIR}/dhparams.pem");
-               print "Done.\n\n";
-       } else {
-               print "SSL Certificates found, skipping.\n\n"
+                       make_openssl_cert();
+                       print "\nCertificate generation complete, copying to config directory... ";
+                       File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
+                       File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
+                       File::Copy::move("dhparams.pem", "$config{CONFIG_DIR}/dhparams.pem") or print STDERR "Could not copy dhparams.pem!\n";
+                       print "Done.\n\n";
+               } else {
+                       print "SSL Certificates found, skipping.\n\n"
+               }
+       }
+       else
+       {
+               print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
        }
 }
 if (($config{USE_GNUTLS} eq "n") && ($config{USE_OPENSSL} eq "n")) {
@@ -769,25 +951,25 @@ if (($config{USE_GNUTLS} eq "n") && ($config{USE_OPENSSL} eq "n")) {
 }
 
 getosflags();
-makecache();
 writefiles(1);
+makecache();
 
 print "\n\n";
-print "To build your server with these settings, please type '\033[1;32m$config{MAKEPROG}\033[0m' now.\n";
+print "To build your server with these settings, please type '\e[1;32m$config{MAKEPROG}\e[0m' now.\n";
 if (($config{USE_GNUTLS} eq "y") || ($config{USE_OPENSSL} eq "y")) {
-       print "Please remember that to enable \033[1;32mSSL support\033[0m you must\n";
-       print "load the required modules in your config. This configure process\n";
-       print "has just prepared these modules to be compiled for you, and has not\n";
-       print "configured them to be compiled into the core of the ircd.\n";
+       print "Please note: for \e[1;32mSSL support\e[0m you will need to load required\n";
+       print "modules in your config. This configure script has added those modules to the\n";
+       print "build process. For more info please refer to:\n";
+       print "\e[1;32mhttp://www.inspircd.org/wiki/Installation_From_Tarball\e[0m\n";
 }
-print "*** \033[1;32mRemember to edit your configuration files!!!\033[0m ***\n\n\n";
+print "*** \e[1;32mRemember to edit your configuration files!!!\e[0m ***\n\n\n";
 if (($config{OSNAME} eq "OpenBSD") && ($config{CC} ne "eg++")) {
-       print "\033[1;32mWARNING!\033[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";
+       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";
 }
 
 if ($config{GCCVER} < "3") {
        print <<FOO2;
-\033[1;32mWARNING!\033[0m You are attempting to compile InspIRCd on GCC 2.x!
+\e[1;32mWARNING!\e[0m You are attempting to compile InspIRCd on GCC 2.x!
 GCC 2.x series compilers only had partial (read as broken) C++ support, and
 your compile will most likely fail horribly! If you have any problems, do NOT
 report them to the bugtracker or forums without first upgrading your compiler
@@ -796,30 +978,30 @@ FOO2
 }
 
 ################################################################################
-#                              HELPER FUNCTIONS                                #
+#                            HELPER FUNCTIONS                          #
 ################################################################################
 sub getcache {
        # Retrieves the .config.cache file, and loads values into the main config hash.
-       open(CACHE, ".config.cache") or return undef;
+       open(CACHE, ".config.cache") or return 0;
        while (<CACHE>) {
                chomp;
                # Ignore Blank lines, and comments..
                next if /^\s*$/;
                next if /^\s*#/;
-               my ($key, $value) = split("=", $_);
+               my ($key, $value) = split("=", $_, 2);
                $value =~ /^\"(.*)\"$/;
                # Do something with data here!
                $config{$key} = $1;
        }
-       close(CONFIG);
-       return "true";
+       close(CACHE);
+       return 1;
 }
 
 sub makecache {
        # Dump the contents of %config
-       print "Writing \033[1;32mcache file\033[0m for future ./configures ...\n";
+       print "Writing \e[1;32mcache file\e[0m for future ./configures ...\n";
        open(FILEHANDLE, ">.config.cache");
-       foreach $key (keys %config) {
+       foreach my $key (keys %config) {
                print FILEHANDLE "$key=\"$config{$key}\"\n";
        }
        close(FILEHANDLE);
@@ -830,8 +1012,8 @@ sub dir_check {
        my $complete = 0;
        while (!$complete) {
                print "In what directory $desc?\n";
-               print "[\033[1;32m$config{$hash_key}\033[0m] -> ";
-               chomp($var = <STDIN>);
+               print "[\e[1;32m$config{$hash_key}\e[0m] -> ";
+               chomp(my $var = <STDIN>);
                if ($var eq "") {
                        $var = $config{$hash_key};
                }
@@ -839,7 +1021,7 @@ sub dir_check {
                        # Convert it to a full path..
                        $var = resolve_directory($ENV{HOME} . "/" . $1);
                }
-               elsif ((($config{OSNAME} == "MINGW32") and ($var !~ /^[A-Z]{1}:\\.*/)) and (substr($var,0,1) ne "/"))
+               elsif ((($config{OSNAME} =~ /MINGW32/i) and ($var !~ /^[A-Z]{1}:\\.*/)) and (substr($var,0,1) ne "/"))
                {
                        # Assume relative Path was given.. fill in the rest.
                        $var = $this . "/$var";
@@ -847,14 +1029,16 @@ sub dir_check {
                
                $var = resolve_directory($var); 
                if (! -e $var) {
-                       print "$var does not exist. Create it?\n[\033[1;32my\033[0m] ";
-                       chomp($tmp = <STDIN>);
+                       print "$var does not exist. Create it?\n[\e[1;32my\e[0m] ";
+                       chomp(my $tmp = <STDIN>);
                        if (($tmp eq "") || ($tmp =~ /^y/i)) {
                                # Attempt to Create the Dir..
-                               
-                               system("mkdir -p \"$var\" >> /dev/null 2>&1");
-                               $chk = system("mkdir -p \"$var\" >> /dev/null 2>&1") / 256;
-                               if ($chk != 0) {
+                               my $chk = eval {
+                                       use File::Path ();
+                                       File::Path::mkpath($var, 0, 0777);
+                                       1;
+                               };
+                               unless (defined($chk) && -d $var) {
                                        print "Unable to create directory. ($var)\n\n";
                                        # Restart Loop..
                                        next;
@@ -878,178 +1062,130 @@ sub dir_check {
        }
 }
 
+our $SHARED = "";
+
 sub getosflags {
-       if ($config{OSNAME} =~ /BSD$/) {
-               $config{LDLIBS} = "-lstdc++";
-               $config{FLAGS}  = "-fPIC -Wall -Woverloaded-virtual $config{OPTIMISATI}";
+
+       # Beware: Linux sets it's own cflags below for some retarded reason
+       $config{LDLIBS} = "-pthread -lstdc++";
+       $config{FLAGS}  = "-fPIC -Woverloaded-virtual -Wshadow -Wformat=2 -Wmissing-format-attribute -Wall $config{OPTIMISATI}";
+       $config{DEVELOPER} = "-fPIC -Woverloaded-virtual -Wshadow -Wall -Wformat=2 -Wmissing-format-attribute -g";
+       $SHARED = "-shared";
+       $config{MAKEPROG} = "make";
+
+       if ($config{OSNAME} =~ /darwin/i) {
+               $config{FLAGS}  = "-DDARWIN -frtti -fPIC -Wall $config{OPTIMISATI}";
+               $SHARED = "-bundle -twolevel_namespace -undefined dynamic_lookup";
+               $config{LDLIBS} = "-ldl -pthread -lstdc++";
+       }
+
+       if ($config{OSNAME} =~ /OpenBSD/i) {
                $config{MAKEPROG} = "gmake";
-               if ($config{OSNAME} eq "OpenBSD") {
-                       chomp($foo = `eg++ -dumpversion | cut -c 1`);
-                       # theyre running the package version of gcc (eg++)... detect it and set up its version numbers.
-                       # if theyre not running this, configure lets the build continue but they probably wont manage to
-                       # compile as this standard version is 2.95.3!
-                       if ($foo ne "") {
-                               $config{CC} = "eg++";
-                               chomp($config{GCCVER}       = `eg++ -dumpversion | cut -c 1`); # we must redo these if we change the compiler path
-                       }
+               $config{LDLIBS} = $config{LDLIBS} . " -lunwind";
+               chomp(my $foo = `eg++ -dumpversion | cut -c 1`);
+               # theyre running the package version of gcc (eg++)... detect it and set up its version numbers.
+               # if theyre not running this, configure lets the build continue but they probably wont manage to
+               # compile as this standard version is 2.95.3!
+               if ($foo ne "") {
+                       $config{CC} = "eg++";
+                       chomp($config{GCCVER}       = `eg++ -dumpversion | cut -c 1`); # we must redo these if we change the compiler path
+                       chomp($config{GCCMINOR}     = `eg++ -dumpversion | cut -c 3`);
                }
-       } else {
-               $config{LDLIBS} = "-ldl -lstdc++";
-               $config{FLAGS}  = "-fPIC -Wall -Woverloaded-virtual $config{OPTIMISATI}";
+               return "OpenBSD";
+       }
+
+       if ($config{OSNAME} =~ /Linux/i) {
+               $config{LDLIBS} = "-ldl -lstdc++ -pthread";
+#              $config{FLAGS}  = "-fPIC -Woverloaded-virtual -Wshadow -Wall $config{OPTIMISATI}";
+               $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});
+               $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});
                $config{MAKEPROG} = "make";
-               if ($config{OSNAME} =~ /CYGWIN/) {
-                       $config{FLAGS}  = "-Wall -Woverloaded-virtual $config{OPTIMISATI}";
-                       $config{LDLIBS} = "";
-                       $config{MAKEPROG} = "/usr/bin/make";
-                       $config{MAKEORDER} = "ircd mods";
-               } elsif ($config{OSNAME} eq "CYG-STATIC") {
-                       $config{FLAGS} = "-Wall -Woverloaded-virtual $config{OPTIMISATI}";
-                       $config{LDLIBS} = "";
-                       $config{MAKEPROG} = "/usr/bin/make";
-                       $config{MAKEORDER} = "mods ircd";
-                       $config{STATICLIBS} = "modules/mods.a";
-                       $config{STATIC_LINK} = "yes";
-               }
        }
-       
-       if ($config{OSNAME} =~ /SunOS/)
+
+       if ($config{OSNAME} =~ /FreeBSD/i) {
+               $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});
+               $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});
+       }
+
+       if ($config{OSNAME} =~ /SunOS/i or $config{OSNAME} =~ /solaris/i)
        {
                # solaris/sunos needs these
                # socket = bsd sockets api
                # nsl = dns stuff
                # rt = POSIX realtime extensions
                # resolv = inet_aton only (why isnt this in nsl?!)
-               $config{LDLIBS} = $config{LDLIBS} . " -lsocket -lnsl -lrt -lresolv";
+               $config{MAKEPROG} = "gmake";
+               $config{LDLIBS} .= " -lsocket -lnsl -lrt -lresolv -pthread";
+               return "Solaris";
        }
        
-       if($config{OSNAME} eq "MINGW32")
+       if($config{OSNAME} =~ /MINGW32/i)
        {
                # All code is position-independent on windows
                $config{FLAGS} =~ s/-fPIC //;
+               return "MinGW";
        }
-}
-
-sub is_dir {
-       my ($path) = @_;
-       if (chdir($path)) {
-               chdir($this);
-               return 1;
-       } else {
-               # Just in case..
-               chdir($this);
-               return 0;
-       }
-}
 
-sub getmodules {
-       my $i = 0;
-       print "Detecting modules ";
-       opendir(DIRHANDLE, "src/modules");
-       foreach $name (sort readdir(DIRHANDLE)) {
-               if ($name =~ /^m_(.+)\.cpp$/)
-               {
-                       $mod = $1;
-                       if ($mod !~ /_static$/) {
-                               $modlist[$i++] = $mod;
-                               print ".";
-                       }
-               }
-       }
-       closedir(DIRHANDLE);
-       print "\nOk, $i modules.\n";
+       return $config{OSNAME};
 }
 
-sub getrevision {
-       if ($no_svn) {
-               return "0";
-       }
-       my $data = `svn info`;
-       
-       if ($data eq "") {
-               $no_svn = 1;
-               $rev = "0";
-               return $rev;
-       }
-       $data =~ /Revision: (\d+)/;
-       my $rev = $1;
-       if (!defined($rev)) {
-               $rev = "0";
-       }
-       return $rev;
-}
+my ($mliflags, $mfrules, $mobjs, $mfcount) = ("", "", "", 0);
 
 sub writefiles {
        my($writeheader) = @_;
+       my $se = "";
        # First File.. inspircd_config.h
        chomp(my $incos = `uname -n -s -r`);
-       chomp(my $version = `sh ./src/version.sh`);
-        chomp(my $revision = getrevision());
-       $version = "$version(r$revision)";
+       chomp(my $version = `sh src/version.sh`);
        chomp(my $revision2 = getrevision());
        if ($writeheader == 1)
        {
-               print "Writing \033[1;32minspircd_config.h\033[0m\n";
+               print "Writing \e[1;32minspircd_config.h\e[0m\n";
                open(FILEHANDLE, ">include/inspircd_config.h");
-               my $NL = $config{NICK_LENGT}+1;
-               my $CL = $config{CHAN_LENGT}+1;
                print FILEHANDLE <<EOF;
 /* Auto generated by configure, do not modify! */
 #ifndef __CONFIGURATION_AUTO__
 #define __CONFIGURATION_AUTO__
 
+/* this is for windows support. */
+#define CoreExport /**/
+#define DllExport /**/
+
 #define CONFIG_FILE "$config{CONFIG_DIR}/inspircd.conf"
 #define MOD_PATH "$config{MODULE_DIR}"
 #define VERSION "$version"
 #define REVISION "$revision2"
-#define MAXCLIENTS $config{MAX_CLIENT}
-#define MAX_DESCRIPTORS $config{MAX_DESCRIPTORS}
-#define NICKMAX $NL
-#define CHANMAX $CL
-#define MAXCHANS $config{MAX_CHANNE}
-#define OPERMAXCHANS $config{MAX_OPERCH}
-#define MAXMODES $config{MAXI_MODES}
-#define IDENTMAX $config{MAX_IDENT}
-#define MAXQUIT $config{MAX_QUIT}
-#define MAXTOPIC $config{MAX_TOPIC}
-#define MAXKICK $config{MAX_KICK}
-#define MAXGECOS $config{MAX_GECOS}
-#define MAXAWAY $config{MAX_AWAY}
+#define SOMAXCONN_S "$config{_SOMAXCONN}"
 #define OPTIMISATION $config{OPTIMITEMP}
 #define LIBRARYDIR "$config{LIBRARY_DIR}"
 #define SYSTEM "$incos"
-#define MAXBUF 514
+#define ENTRYPOINT int main(int argc, char** argv)
+
 EOF
-               if ($config{OSNAME} =~ /SunOS/) {
+print FILEHANDLE "#define MAXBUF " . ($config{MAXBUF}+2) . "\n";
+
+               if ($config{OSNAME} =~ /SunOS/i) {
                        print FILEHANDLE "#define IS_SOLARIS\n";
                }
-               if ($config{OSNAME} =~ /CYGWIN/) {
-                       print FILEHANDLE "#define IS_CYGWIN\n";
-                       print FILEHANDLE "#ifndef FD_SETSIZE\n#define FD_SETSIZE        1024\n#endif\n";
-               }
-               if ($config{OSNAME} eq "MINGW32") {
+               if ($config{OSNAME} =~ /MINGW32/i) {
                        print FILEHANDLE "#define IS_MINGW\n";
                }
-               if ($config{OSNAME} eq "CYG-STATIC") {
-                       print FILEHANDLE "#ifndef FD_SETSIZE\n#define FD_SETSIZE    1024\n#endif\n";
-               }
-               if ($config{HAS_EXECINFO} eq "1") {
-                       print FILEHANDLE "#define HAS_EXECINFO\n";
-               }
-               if ($config{STATIC_LINK} eq "yes") {
-                       print FILEHANDLE "#define STATIC_LINK\n";
-               }
                if ($config{GCCVER} >= 3) {
                        print FILEHANDLE "#define GCC3\n";
                }
+               if (
+                       (($config{GCCVER} == 4) && ($config{GCCMINOR} >= 3))
+                               ||
+                       ($config{GCCVER} > 4)
+               ) {
+                       print FILEHANDLE "#define HASHMAP_DEPRECATED\n";
+               }
                if ($config{HAS_STRLCPY} eq "true") {
                        print FILEHANDLE "#define HAS_STRLCPY\n";
                }
                if ($config{HAS_STDINT} eq "true") {
                        print FILEHANDLE "#define HAS_STDINT\n";
                }
-               if ($config{THREADED_DNS} =~ /y/i) {
-                       print FILEHANDLE "#define THREADED_DNS\n";
-               }
                if ($config{IPV6} =~ /y/i) {
                        print FILEHANDLE "#define IPV6\n";
                }
@@ -1067,13 +1203,18 @@ EOF
                        $se = "socketengine_epoll";
                        $use_hiperf = 1;
                }
+               if (($has_ports) && ($config{USE_PORTS} eq "y")) {
+                       print FILEHANDLE "#define USE_PORTS\n";
+                       $se = "socketengine_ports";
+                       $use_hiperf = 1;
+               }
                # user didn't choose either epoll or select for their OS.
                # default them to USE_SELECT (ewwy puke puke)
                if (!$use_hiperf) {
                        print FILEHANDLE "#define USE_SELECT\n";
                        $se = "socketengine_select";
                }
-               print FILEHANDLE "\n#endif\n";
+               print FILEHANDLE "\n#include \"threadengines/threadengine_pthread.h\"\n\n#endif\n";
                close(FILEHANDLE);
        }
 
@@ -1085,7 +1226,7 @@ EOF
 #ifndef __CONFIGURATION_SOCKETENGINE__
 #define __CONFIGURATION_SOCKETENGINE__
 
-#include "$se.h"
+#include "socketengines/$se.h"
 
 #endif
 EOF
@@ -1095,57 +1236,84 @@ EOF
 
        # Create a Modules List..
        my $modules = "";
-       foreach $i (@modlist)
+       foreach my $i (@modlist)
        {
-               if ($config{STATIC_LINK} eq "yes") {
-                       $modules .= "m_".$i.".o ";
-               }
-               else {
-                       $modules .= "m_".$i.".so ";
-               }
+               $modules .= "m_".$i.".so ";
        }
        chomp($modules);   # Remove Redundant whitespace..
 
+       opendir(DIRHANDLE, "src/modules");
+       foreach my $name2 (sort readdir(DIRHANDLE)) {
+               if ($name2 =~ /^m_(.+?)$/) {
+                       if (defined(opendir(MDIRHANDLE, "src/modules/$name2"))) {
+                               closedir(MDIRHANDLE);
+                               $modules .= "$name2.so ";
+                               $uninstall_list = $uninstall_list . "   -rm \$(MODULES)/$name2.so\n";
+                       }
+               }
+       }
+       closedir(DIRHANDLE);
+
 
        # Write all .in files.
        my $tmp = "";
        my $file = "";
        my $exe = "inspircd";
 
-       if ($config{OSNAME} =~ /CYGWIN/) {
-               $exe = "inspircd.exe";
-       }
+       # Do this once here, and cache it in the .*.inc files,
+       # rather than attempting to read src/version.sh from
+       # compiled code -- we might not have the source to hand.
+       # Fix for bug#177 by Brain.
+
+       chomp($version = `sh ./src/version.sh`);
+       chomp(my $revision = getrevision());
+       $version = "$version(r$revision)";
+
+       # We can actually parse any file starting with . and ending with .inc,
+       # but right now we only parse .inspircd.inc to form './inspircd'
+
+        print "Writing \e[1;32mMakefiles\e[0m\n";
+       write_dynamic_modules_makefile();
+       write_dynamic_makefile();
 
        opendir(DIRHANDLE, $this);
-       if ($config{THREADED_DNS} =~ /y/i) {
-               $config{LDLIBS} = $config{LDLIBS} . " -pthread";
-       }
-       foreach $name (sort readdir(DIRHANDLE)) {
+
+       foreach my $name (sort readdir(DIRHANDLE)) {
                if ($name =~ /^\.(.+)\.inc$/) {
                        $file = $1;
+
+                       # Bug #353, omit this on non-darwin
+                       next if (($config{OSNAME} !~ /darwin/) && ($file eq "org.inspircd.plist"));
+
                        # All .name.inc files need parsing!
                        $tmp = "";
-                       open(FILEHANDLE, ".$file.inc");
+                       open(FILEHANDLE, ".$file.inc") or die ("Can't open .$file.inc");
                        while (<FILEHANDLE>) {
                                $tmp .= $_;
                        }
                        close(FILEHANDLE);
 
-                       $tmp =~ s/\@CC\@/$config{CC}/;
-                       $tmp =~ s/\@MAKEPROG\@/$config{MAKEPROG}/;
-                       $tmp =~ s/\@FLAGS\@/$config{FLAGS}/;
-                       $tmp =~ s/\@LDLIBS\@/$config{LDLIBS}/;
-                       $tmp =~ s/\@BASE_DIR\@/$config{BASE_DIR}/;
-                       $tmp =~ s/\@CONFIG_DIR\@/$config{CONFIG_DIR}/;
-                       $tmp =~ s/\@MODULE_DIR\@/$config{MODULE_DIR}/;
-                       $tmp =~ s/\@BINARY_DIR\@/$config{BINARY_DIR}/;
-                       $tmp =~ s/\@LIBRARY_DIR\@/$config{LIBRARY_DIR}/;
-                       $tmp =~ s/\@MODULES\@/$modules/;
-                       $tmp =~ s/\@EXECUTABLE\@/$exe/;
-                       $tmp =~ s/\@MAKEORDER\@/$config{MAKEORDER}/;
-                       $tmp =~ s/\@STATICLIBS\@/$config{STATICLIBS}/;
-
-                       print "Writing \033[1;32m$file\033[0m\n";
+                       print "Writing \e[1;32m$file\e[0m ...\n";
+                       $tmp =~ s/\@CC\@/$config{CC}/ if defined $config{CC};
+                       $tmp =~ s/\@MAKEPROG\@/$config{MAKEPROG}/ if defined $config{MAKEPROG};
+                       $tmp =~ s/\@FLAGS\@/$config{FLAGS}/ if defined $config{FLAGS};
+                       $tmp =~ s/\@DEVELOPER\@/$config{DEVELOPER}/ if defined $config{DEVELOPER};
+                       $tmp =~ s/\@LDLIBS\@/$config{LDLIBS}/ if defined $config{LDLIBS};
+                       $tmp =~ s/\@BASE_DIR\@/$config{BASE_DIR}/ if defined $config{BASE_DIR};
+                       $tmp =~ s/\@CONFIG_DIR\@/$config{CONFIG_DIR}/ if defined $config{CONFIG_DIR};
+                       $tmp =~ s/\@MODULE_DIR\@/$config{MODULE_DIR}/ if defined $config{MODULE_DIR};
+                       $tmp =~ s/\@BINARY_DIR\@/$config{BINARY_DIR}/ if defined $config{BINARY_DIR};
+                       $tmp =~ s/\@LIBRARY_DIR\@/$config{LIBRARY_DIR}/ if defined $config{LIBRARY_DIR};
+                       $tmp =~ s/\@MODULES\@/$modules/ if defined $modules;
+                       $tmp =~ s/\@STARTSCRIPT\@/$config{STARTSCRIPT}/ if defined $config{STARTSCRIPT};
+                       $tmp =~ s/\@DESTINATION\@/$config{DESTINATION}/ if defined $config{DESTINATION};
+                       $tmp =~ s/\@EXTRA_DIR\@/$config{EXTRA_DIR}/ if defined $config{EXTRA_DIR};
+                       $tmp =~ s/\@EXECUTABLE\@/$exe/ if defined $exe;
+                       $tmp =~ s/\@MAKEORDER\@/$config{MAKEORDER}/ if defined $config{MAKEORDER};
+                       $tmp =~ s/\@VERSION\@/$version/ if defined $version;
+                       $tmp =~ s/\@INSTALL_LIST\@/$install_list/ if defined $install_list;
+                       $tmp =~ s/\@UNINSTALL_LIST\@/$uninstall_list/ if defined $uninstall_list;
+
                        open(FILEHANDLE, ">$file");
                        print FILEHANDLE $tmp;
                }
@@ -1154,196 +1322,46 @@ EOF
 
        # Make inspircd executable!
        chmod 0744, 'inspircd';
-
-       if ($config{STATIC_LINK} eq "yes") {
-               print "Writing static-build \033[1;32msrc/Makefile\033[0m\n";
-               write_static_makefile();
-               write_static_modules_makefile();
-       } elsif ($config{OSNAME} =~ /CYGWIN/) {
-               print "Writing cygwin-build \033[1;32msrc/Makefile\033[0m\n";
-               write_static_makefile();
-               write_dynamic_modules_makefile();
-       } else {
-               print "Writing dynamic-build \033[1;32msrc/Makefile\033[0m\n";
-               write_dynamic_makefile();
-               write_dynamic_modules_makefile();
-       }
-}
-
-sub getcompilerflags {
-       my ($file) = @_;
-       open(FLAGS, $file);
-       while (<FLAGS>) {
-       if ($_ =~ /^\/\* \$CompileFlags: (.+) \*\/$/) {
-               close(FLAGS);
-                       return $1;
-               }
-       }
-       close(FLAGS);
-       return undef;
-}
-
-sub getlinkerflags {
-       my ($file) = @_;
-       open(FLAGS, $file);
-       while (<FLAGS>) {
-               if ($_ =~ /^\/\* \$LinkerFlags: (.+) \*\/$/) {
-                       close(FLAGS);
-                       return $1;
-               }
-       }
-       close(FLAGS);
-       return undef;
-}
-
-sub show_splash {
-  print "'\033[1;33m####\033[0m:'\033[1;33m##\033[0m::: \033[1;33m##\033[0m::'\033[1;33m######\033[0m::'\033[1;33m########\033[0m::'\033[1;33m####\033[0m:'\033[1;33m########\033[0m:::'\033[1;33m######\033[0m::'\033[1;33m########\033[0m::\n";
-  print ". \033[1;33m##\033[0m:: \033[1;33m###\033[0m:: \033[1;33m##\033[0m:'\033[1;33m##\033[0m... \033[1;33m##\033[0m: \033[1;33m##\033[0m.... \033[1;33m##\033[0m:. \033[1;33m##\033[0m:: \033[1;33m##\033[0m.... \033[1;33m##\033[0m:'\033[1;33m##\033[0m... \033[1;33m##\033[0m: \033[1;33m##\033[0m.... \033[1;33m##\033[0m:\n";
-  print ": \033[1;33m##\033[0m:: \033[1;33m####\033[0m: \033[1;33m##\033[0m: \033[1;33m##\033[0m:::..:: \033[1;33m##\033[0m:::: \033[1;33m##\033[0m:: \033[1;33m##\033[0m:: \033[1;33m##\033[0m:::: \033[1;33m##\033[0m: \033[1;33m##\033[0m:::..:: \033[1;33m##\033[0m:::: \033[1;33m##\033[0m:\n";
-  print ": \033[1;33m##\033[0m:: \033[1;33m##\033[0m \033[1;33m##\033[0m \033[1;33m##\033[0m:. \033[1;33m######\033[0m:: \033[1;33m########\033[0m::: \033[1;33m##\033[0m:: \033[1;33m########\033[0m:: \033[1;33m##\033[0m::::::: \033[1;33m##\033[0m:::: \033[1;33m##\033[0m:\n";
-  print ": \033[1;33m##\033[0m:: \033[1;33m##\033[0m. \033[1;33m####\033[0m::..... \033[1;33m##\033[0m: \033[1;33m##\033[0m.....:::: \033[1;33m##\033[0m:: \033[1;33m##\033[0m.. \033[1;33m##\033[0m::: \033[1;33m##\033[0m::::::: \033[1;33m##\033[0m:::: \033[1;33m##\033[0m:\n";
-  print ": \033[1;33m##\033[0m:: \033[1;33m##\033[0m:. \033[1;33m###\033[0m:'\033[1;33m##\033[0m::: \033[1;33m##\033[0m: \033[1;33m##\033[0m::::::::: \033[1;33m##\033[0m:: \033[1;33m##\033[0m::. \033[1;33m##\033[0m:: \033[1;33m##\033[0m::: \033[1;33m##\033[0m: \033[1;33m##\033[0m:::: \033[1;33m##\033[0m:\n";
-  print "'\033[1;33m####\033[0m: \033[1;33m##\033[0m::. \033[1;33m##\033[0m:. \033[1;33m######\033[0m:: \033[1;33m##\033[0m::::::::'\033[1;33m####\033[0m: \033[1;33m##\033[0m:::. \033[1;33m##\033[0m:. \033[1;33m######\033[0m:: \033[1;33m########\033[0m::\n";
-  print "\033[0m\033[0m....::..::::..:::......:::..:::::::::....::..:::::..:::......:::........:::\n\n";
-}
-
-sub resolve_directory {
-       use File::Spec;
-       return File::Spec->rel2abs($_[0]);
-}
-
-sub yesno {
-       my ($flag,$prompt) = @_;
-       print "$prompt [\033[1;32m$config{$flag}\033[0m] -> ";
-       chomp($tmp = <STDIN>);
-       if ($tmp eq "") { $tmp = $config{$flag} }
-
-       if (($tmp eq "") || ($tmp =~ /^y/i)) {
-               $config{$flag} = "y";
-       } else {
-               $config{$flag} = "n";
-        }
-       return;
 }
 
-sub write_static_modules_makefile {
+sub write_dynamic_modules_makefile {
        # Modules Makefile..
-       print "Writing \033[1;32msrc/modules/Makefile\033[0m\n";
+       print "Writing \e[1;32msrc/modules/Makefile\e[0m\n";
        open(FILEHANDLE, ">src/modules/Makefile");
 
-       ###
-       # Module Makefile Header
-       ###
+###
+# Module Makefile Header
+###
        print FILEHANDLE <<EOF;
-# (C) ChatSpike development team
-# Makefile by <Craig\@ChatSpike.net>
-# Many Thanks to Andrew Church <achurch\@achurch.org>
-#    for assisting with making this work right.
+###################################################
+# Copyright 2002-2007 The InspIRCd Development Team
+#  http://www.inspircd.org/wiki/index.php/Credits
+#
+# Thanks to Andrew Church <achurch\@achurch.org>
+#   for assisting with making this work right.
 #
-# Automatically Generated by ./configure to add a modules
-# please run ./configure --update
+# Automatically Generated by ./configure to add a
+#  modules please run ./configure -modupdate
+###################################################
 
 all: \$(MODULES)
 
 EOF
-       ###
-       # End Module Makefile Header
-       ###
 
-       # Create a Modules List..
-       my $modules = "";
-       my $cmflags = "";
-       my $liflags = "";
-
-       open(MODLIST,">include/modlist.h");
+if ($config{OSNAME} =~ /darwin/) {
+               print FILEHANDLE <<EOCHEESE;
 
-       ###
-       # Include File Header
-       ###
-       print MODLIST <<HEADER;
-// Generated automatically by configure. DO NOT EDIT!
-
-#ifndef __SYMBOLS__H_CONFIGURED__
-#define __SYMBOLS__H_CONFIGURED__
-
-HEADER
-       ###
-       # End Include File Header
-       ###
+PICLDFLAGS = -twolevel_namespace -undefined dynamic_lookup -bundle
 
-       # Place Module List into Include
-       foreach $i (@modlist) {
-               if ($i !~ /_static$/) {
-                       print MODLIST "extern \"C\" void * $i\_init (void);\n";
-               }
-       }
-       print MODLIST "\nstruct {const char *name; initfunc *value; } modsyms[] = {\n";
+EOCHEESE
+} else {
+               print FILEHANDLE <<EOCHEESE;
 
-       ###
-       # Build Module Crap
-       ###
-       foreach $i (@modlist)
-       {
-               if ($i !~ /_static$/) {
-                       $cmflags = getcompilerflags("src/modules/m_".$i.".cpp");
-                       $liflags = getlinkerflags("src/modules/m_".$i.".cpp");
-
-                       ###
-                       # Write Entry to the Makefile
-                       ###
-                       print FILEHANDLE <<EOCHEESE;
-m_$i.o: .m_$i\_static.cpp ../../include/modules.h ../../include/users.h ../../include/channels.h ../../include/base.h
-       \$(CC) -pipe -I../../include \$(FLAGS) $flags -export-dynamic -c .m_$i\_static.cpp
-       mv .m_$i\_static.o ../m_$i.o
+PICLDFLAGS = -fPIC -DPIC -shared
 
 EOCHEESE
-                       ###
-                       # End Write Entry to the MakeFile
-                       ###
-                       print "Configuring module [\033[1;32mm_$i.so\033[0m] for static linking... ";
-                       open(MODULE,"<src/modules/m_".$i.".cpp") or die("Could not open m_".$i.".cpp");
-                       open(MUNGED,">src/modules/.m_".$i."_static.cpp") or die("Could not create .m_".$i."_static.cpp");
-                       while (chomp($a = <MODULE>)) { 
-                               $a =~ s/init_module/$i\_init/g;
-                               print MUNGED "$a\n";
-                       }
-                       close(MODULE);
-                       close(MUNGED);
-                       print MODLIST <<EOENT;
-{"m_$i.so",\&$i\_init},
-EOENT
-                       print "done\n";
-               }
-       }
-       print MODLIST "{0}};\n\n#endif\n";
-       close(MODLIST);
 }
 
-sub write_dynamic_modules_makefile {
-       # Modules Makefile..
-       print "Writing \033[1;32msrc/modules/Makefile\033[0m\n";
-       open(FILEHANDLE, ">src/modules/Makefile");
-       my $extra = "";
-
-       if ($config{OSNAME} =~ /CYGWIN/) {
-               $extra = "../inspircd.dll.a";
-       }
-
-###
-# Module Makefile Header
-###
-       print FILEHANDLE <<EOF;
-# (C) ChatSpike development team
-# Makefile by <Craig\@ChatSpike.net>
-# Many Thanks to Andrew Church <achurch\@achurch.org>
-#    for assisting with making this work right.
-#
-# Automatically Generated by ./configure to add a modules
-# please run ./configure -update or ./configure -modupdate
-
-all: \$(MODULES)
-
-EOF
        ###
        # End Module Makefile Header
        ###
@@ -1352,334 +1370,531 @@ EOF
        my $modules = "";
        my $cmflags = "";
        my $liflags = "";
-       my $crud = "";
-
-       foreach $i (@modlist) {
-       ###
-       # Write Entry to the MakeFile
-       ###
-       $cmflags = getcompilerflags("src/modules/m_".$i.".cpp");
-       $liflags = getlinkerflags("src/modules/m_".$i.".cpp");
-       print FILEHANDLE <<EOCHEESE;
-m_$i.so: m_$i.cpp ../../include/modules.h ../../include/users.h ../../include/channels.h ../../include/base.h ../../include/inspircd_config.h ../../include/inspircd.h ../../include/configreader.h
-       \$(CC) -pipe -I../../include \$(FLAGS) $cmflags -export-dynamic -c m_$i.cpp
-       \$(CC) \$(FLAGS) -shared $liflags -o m_$i.so m_$i.o $extra
+       foreach my $i (@modlist) {
+               ###
+               # Write Entry to the MakeFile
+               ###
+               $cmflags = getcompilerflags("src/modules/m_".$i.".cpp");
+               $liflags = getlinkerflags("src/modules/m_".$i.".cpp");
+               my $deps = getdependencies("src/modules/m_".$i.".cpp");
+       
+               #print "file: $i: cmflags=$cmflags; liflags=$liflags; deps=$deps\n";
+       
 
-EOCHEESE
-       $crud = $crud . "       install -m 0700 m_$i.so \$(MODPATH)\n";
+               if (nopedantic("src/modules/m_".$i.".cpp"))
+               {
+                       print FILEHANDLE "
+m_$i.so: m_$i.cpp ../../include/modules.h ../../include/users.h ../../include/channels.h ../../include/base.h ../../include/inspircd_config.h ../../include/inspircd.h ../../include/configreader.h $deps
+       \@../../make/run-cc.pl \$(CC) -pipe -I../../include \$(NICEFLAGS) $cmflags \$(PICLDFLAGS) $liflags -export-dynamic -o m_$i.so m_$i.cpp
+"
+               }
+               else
+               {
+                       print FILEHANDLE "
+m_$i.so: m_$i.cpp ../../include/modules.h ../../include/users.h ../../include/channels.h ../../include/base.h ../../include/inspircd_config.h ../../include/inspircd.h ../../include/configreader.h $deps
+       \@../../make/run-cc.pl \$(CC) -pipe -I../../include \$(FLAGS) $cmflags \$(PICLDFLAGS) $liflags -export-dynamic -o m_$i.so m_$i.cpp
+";
+               }
+               $install_list = $install_list . "       install -m \$(INSTMODE) src/modules/m_$i.so \$(MODPATH)\n";
+               $uninstall_list = $uninstall_list . "   -rm \$(MODULES)/m_$i.so\n";
 ###
-       # End Write Entry to the MakeFile
-       ###
+               # End Write Entry to the MakeFile
+               ###
        }
-       print FILEHANDLE "modinst:\n    \@echo \"Installing modules...\"\n" . $crud;
-}
-
 
-sub write_static_makefile {
-       open(FH,">src/Makefile") or die("Could not write src/Makefile!");
-        my $i = 0;
-        my @cmdlist = ();
-        opendir(DIRHANDLE, "src");
-        foreach $name (sort readdir(DIRHANDLE)) {
-                if ($name =~ /^cmd_(.+)\.cpp$/) {
-                        $cmdlist[$i++] = $1;
-                }
-        }
-        closedir(DIRHANDLE);
-        my $cmdobjs = "";
-       my $srcobjs = "";
-        foreach my $cmd (@cmdlist) {
-                $cmdobjs = $cmdobjs . "cmd_$cmd.o ";
-                $srcobjs = $srcobjs . "cmd_$cmd.cpp ";
+       opendir(DIRHANDLE, "src/modules");
+       foreach my $name (sort readdir(DIRHANDLE)) {
+               if ($name =~ /^m_(.+?)$/) {
+                       $mfrules = "";
+                       $mobjs = "";
+                       $mliflags = "";
+                       $mfcount = 0;
+                       # A module made of multiple files, in a dir, e.g. src/modules/m_spanningtree/
+                       if (defined(opendir(MDIRHANDLE, "src/modules/$name"))) {
+                               read_module_directory("src/modules/$name", $name);
+                               print "Composing Makefile rules for directory \e[1;32m$name\e[0m... (\e[1;32m$mfcount files found\e[0m)\n";
+                               print FILEHANDLE "$name.so: ../../include/modules.h ../../include/users.h ../../include/channels.h ../../include/base.h ../../include/inspircd_config.h ../../include/inspircd.h ../../include/configreader.h $mobjs\n"; 
+                               if ($config{IS_DARWIN} eq "YES") {
+                                       print FILEHANDLE "      \@../../make/run-cc.pl \$(CC) -pipe -twolevel_namespace -undefined dynamic_lookup \$(FLAGS) $mliflags -bundle -o $name.so $mobjs\n"; 
+                               } else {
+                                       print FILEHANDLE "      \@../../make/run-cc.pl \$(CC) -pipe \$(FLAGS) -shared $mliflags -o $name.so $mobjs\n";
+                               }
+                               print FILEHANDLE "\n$mfrules\n";
+                               closedir(MDIRHANDLE);
+                               $install_list = $install_list . "       install -m \$(INSTMODE) src/modules/$name.so \$(MODPATH)\n";
+                       }
+               }
        }
-       print FH <<EOM;
-# Insp Makefile :p
-#
-# (C) ChatSpike development team
-# Makefile by <Craig\@ChatSpike.net>
-# Makefile version 2 (statically linked core) by <brain\@inspircd.org>
-#
-
-CC = im a cheezeball
-
-CXXFLAGS = -I../include \${FLAGS}
-CPPFILES = \$(shell /bin/ls -l modes/ | grep '\\.cpp' | sed 's/^.* //' | grep -v svn)
-RELCPPFILES = \$(shell /bin/ls -l modes/ | grep '\\.cpp' | sed 's/^.* /modes\\//' | grep -v svn)
-
-EOM
-
-$se = "socketengine_select";
-if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) {
-       $se = "socketengine_kqueue";
-}       
-elsif (($has_epoll) && ($config{USE_EPOLL} eq "y")) {
-       $se = "socketengine_epoll";
+       closedir(DIRHANDLE);
 }
 
-       ###
-       # This next section is for cygwin dynamic module builds.
-       # Basically, what we do, is build the inspircd core as a library
-       # then the main executable uses that. the library is capable of
-       # loading / unloading the modules dynamically :)
-       # Massive thanks to the guys on #cygwin @ irc.freenode.net for helping
-       # make this work :)
-       ###
-
-       if ($config{OSNAME} =~ /CYGWIN/) {
-               print FH <<EOM;
-all: timer.o aes.o command_parse.o cull_list.o userprocess.o socketengine.o socket.o hashcomp.o channels.o mode.o xline.o inspstring.o dns.o base.o configreader.o inspsocket.o $cmdobjs commands.o dynamic.o users.o modules.o wildcard.o helperfuncs.o snomasks.o inspircd.exe
-
-inspircd.exe: inspircd.dll.a
-       \$(CC) -o \$@ \$^
-
-inspircd.dll inspircd.dll.a: inspircd.o channels.o mode.o xline.o inspstring.o dns.o base.o configreader.o inspsocket.o $cmdobjs  commands.o dynamic.o users.o modules.o wildcard.o helperfuncs.o hashcomp.o socket.o socketengine.o userprocess.o cull_list.o command_parse.o aes.o timer.o snomasks.o
-       \$(CC) -shared -Wl,--out-implib=inspircd.dll.a -o inspircd.dll \$^
-EOM
-       } else {
-               print FH <<EOM;
-all: timer.o aes.o command_parse.o cull_list.o userprocess.o socketengine.o socket.o hashcomp.o channels.o mode.o xline.o inspstring.o dns.o base.o configreader.o inspsocket.o $cmdobjs commands.o dynamic.o users.o modules.o wildcard.o helperfuncs.o snomasks.o \$(MODULES) inspircd.exe
-
-inspircd.exe: inspircd.cpp ../include/base.h ../include/channels.h ../include/inspircd.h ../include/channels.h ../include/globals.h ../include/inspircd_config.h ../include/base.h
-       \$(CC) -I../include \$(FLAGS) inspircd.cpp -o inspircd.exe \$(LDLIBS) channels.o mode.o xline.o inspstring.o dns.o base.o inspsocket.o configreader.o $cmdobjs commands.o dynamic.o users.o modules.o wildcard.o helperfuncs.o hashcomp.o socket.o socketengine.o userprocess.o cull_list.o command_parse.o aes.o timer.o snomasks.o modes/modeclasses.a \$(MODULES)
-EOM
+sub read_module_directory {
+       my ($dpath, $reldpath) = @_;
+       
+       if (opendir(MDIRHANDLE, $dpath) == 0) {
+               return;
        }
+       
+       foreach my $fname (sort readdir(MDIRHANDLE)) {
+               if ($fname =~ /\.cpp$/) {
+                       my $cmflags = getcompilerflags("$dpath/$fname");
+                       $mliflags = $mliflags . " " . getlinkerflags("$dpath/$fname");
+                       my $deps = getdependencies("$dpath/$fname");
+                       my $oname = $fname;
+                       $oname =~ s/\.cpp$/.o/g;
+                       $mfrules = $mfrules .  "$reldpath/$oname: $reldpath/$fname ../../include/modules.h ../../include/users.h ../../include/channels.h ../../include/base.h ../../include/inspircd_config.h ../../include/inspircd.h ../../include/configreader.h $deps\n";
+                       $mfrules = $mfrules .  "        \@../../make/run-cc.pl \$(CC) -pipe -I../../include -I. \$(FLAGS) $cmflags -export-dynamic -o $reldpath/$oname -c $reldpath/$fname\n\n";
+                       $mobjs = $mobjs . " $reldpath/$oname";
+                       $mfcount++;
+               }
+               elsif ((-d "$dpath/$fname") && !($fname eq ".") && !($fname eq "..")) {
+                       read_module_directory($dpath."/".$fname, $reldpath."/".$fname);
+               }
+       }
+}
 
-       print FH <<EOM;
-
-cull_list.o: cull_list.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h ../include/users.h ../include/channels.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c cull_list.cpp
-
-snomasks.o: snomasks.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/channels.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c snomasks.cpp
-
-command_parse.o: command_parse.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c command_parse.cpp
-
-userprocess.o: userprocess.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c userprocess.cpp
-
-socketengine.o: $se.cpp socketengine.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h ../include/$se.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c socketengine.cpp $se.cpp
-
-hashcomp.o: hashcomp.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c hashcomp.cpp
-
-helperfuncs.o: helperfuncs.cpp ../include/base.h ../include/helperfuncs.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I/usr/local/include -L/usr/local/lib -I../include \$(FLAGS) -export-dynamic -c helperfuncs.cpp
-
-channels.o: channels.cpp ../include/base.h ../include/channels.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c channels.cpp
-
-mode.o: mode.cpp ../include/base.h ../include/mode.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h \$(RELCPPFILES) modes/modeclasses.a
-       \${MAKE} -C "modes" DIRNAME="src/modes" \$(MAKEARGS)
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c mode.cpp
-
-xline.o: xline.cpp ../include/base.h ../include/xline.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c xline.cpp
-
-inspstring.o: inspstring.cpp ../include/base.h ../include/inspstring.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c inspstring.cpp
-
-dns.o: dns.cpp ../include/base.h ../include/dns.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c dns.cpp
-
-base.o: base.cpp ../include/base.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c base.cpp
-
-configreader.o: configreader.cpp ../include/base.h ../include/configreader.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c configreader.cpp
-
-commands.o: commands.cpp ../include/base.h ../include/commands.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h $srcobjs
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c commands.cpp $cmdobjs
-
-dynamic.o: dynamic.cpp ../include/base.h ../include/dynamic.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c dynamic.cpp
-
-users.o: users.cpp ../include/base.h ../include/users.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c users.cpp
+sub calcdeps($)
+{
+       # Yes i know we could use gcc -M but it seems to ideneify a lot of 'deep'
+       # dependencies which are not relevent in C++.
 
-modules.o: modules.cpp ../include/base.h ../include/modules.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c modules.cpp
+       my $file = $_[0];
 
-wildcard.o: wildcard.cpp ../include/base.h ../include/wildcard.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c wildcard.cpp
+       open (CPP, "<$file") or die("Can't open $file for reading!");
 
-socket.o: socket.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c socket.cpp
-       
-inspsocket.o: inspsocket.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c inspsocket.cpp
+       my %dupe = ();
+       my $retlist = "";
 
-aes.o: aes.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c aes.cpp
+       foreach my $d (@ignoredeps)
+       {
+               $dupe{$d} = 1;
+       }
 
-timer.o: timer.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c timer.cpp
+       my $immutable = "";
+       foreach my $dep (@immutabledeps)
+       {
+               $immutable = $immutable . "../include/$dep ";
+       }
+       $immutable =~ s/ $//g;
 
-EOM
-       foreach my $cmd (@cmdlist) {
-               print FH <<ITEM;
-cmd_$cmd.o: cmd_$cmd.cpp ../include/base.h ../include/modules.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/commands/cmd_$cmd.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c cmd_$cmd.cpp
-ITEM
+       while (defined(my $line = <CPP>))
+       {
+               chomp($line);
+               if ($line =~ /#include "(.+\.h)"/)
+               {
+                       if (!exists($dupe{$1}))
+                       {
+                               $retlist = $retlist . "../include/$1 ";
+                               $dupe{$1} = 1;
+                       }
+               }
        }
-       close(FH);
+       close CPP;
+       return length($immutable) ? $immutable . " " . $retlist : $retlist;
 }
 
-sub write_dynamic_makefile {
-
+sub write_dynamic_makefile
+{
        my $i = 0;
        my @cmdlist = ();
-       opendir(DIRHANDLE, "src");
-       foreach $name (sort readdir(DIRHANDLE)) {
-               if ($name =~ /^cmd_(.+)\.cpp$/) {
-                       $cmdlist[$i++] = $1;
+       my %existing_install_list = ();
+       my %core_files_list = ();
+
+       opendir(DIRHANDLE, "src/commands");
+       foreach my $name (sort readdir(DIRHANDLE))
+       {
+               if ($name =~ /^cmd_(.+)\.cpp$/)
+               {
+                       $cmdlist[$i++] = $1;
+                       $install_list = $install_list . "       -install -m \$(INSTMODE) src/commands/cmd_" . $1 . ".so \$(LIBPATH)\n";
+                       $uninstall_list = $uninstall_list . "   -rm \$(LIBPATH)/cmd_$1.so\n";
                }
        }
        closedir(DIRHANDLE);
 
-       my $cmdobjs = "";
-       my $srcobjs = "";
-       foreach my $cmd (@cmdlist) {
-               $cmdobjs = $cmdobjs . "cmd_$cmd.so ";
-               $srcobjs = $srcobjs . "cmd_$cmd.cpp ";
+       if (!$has_epoll)
+       {
+               $config{USE_EPOLL} = 0;
+       }
+       if (!$has_kqueue)
+       {
+               $config{USE_KQUEUE} = 0;
+       }
+       if (!$has_ports)
+       {
+               $config{USE_PORTS} = 0;
        }
 
-if (($config{OSNAME} !~ /Linux/i) && ($config{HAS_EXECINFO} eq "1")) {
-       $extra = "-L/usr/local/lib -lexecinfo";
-} else {
-       $extra = "";
-}
+       # formerly generated below this foreach, now it's not! magic.
+       my $all_core = "";
 
-$se = "socketengine_select";
-if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) {
-       $se = "socketengine_kqueue";
-}
-elsif (($has_epoll) && ($config{USE_EPOLL} eq "y")) {
-       $se = "socketengine_epoll";
-}
+       foreach my $dir (("src","src/commands","src/modes","src/socketengines","src/modules"))
+       {
+               print "Scanning \e[1;32m$dir\e[0m for core files ";
+               opendir(DIRHANDLE, $dir);
+               foreach my $name (sort readdir(DIRHANDLE))
+               {
+                       if ($name =~ /\.cpp$/)
+                       {
+                               open (CPP, "<$dir/$name") or die("Can't open $dir/$name to scan it! oh bugger");
+                               print ".";
+                               while (defined(my $line = <CPP>))
+                               {
+                                       chomp($line);
+                                       if ($line =~ /\/\* \$Core \*\//i)
+                                       {
+                                               my $sname = $name;
+                                               $sname =~ s/\.cpp$/.o/;
+
+                                               # append it to list to be built
+                                               $all_core = $all_core . $sname . " ";
+                                               $filelist{$name} = $sname;
+
+                                               # mark it as a core file, so it won't get shared object cflags
+                                               if (!exists($core_files_list{$name}))
+                                               {
+                                                       $core_files_list{$name} = 1;
+                                               }
+                                       }
+                                       elsif ($line =~ /\/\* \$ExtraDeps: (.*?) \*\//i)
+                                       {
+                                               $specialdeps{$name} = $1;
+                                       }
+                                       elsif ($line =~ /\/\* \$ExtraObjects: (.*?) \*\//i)
+                                       {
+                                               $extraobjects{$name} = $1;
+                                       }
+                                       elsif ($line =~ /\/\* \$ExtraBuild: (.*?) \*\//i)
+                                       {
+                                               $extrabuildlines{$name} = $1;
+                                       }
+                                       elsif ($line =~ /\/\* \$ExtraSources: (.*?) \*\//i)
+                                       {
+                                               $extrasources{$name} = $1;
+                                               }
+                                       elsif ($line =~ /\/\* \$If: (\w+) \*\//i)
+                                       {
+                                               if (defined $config{$1})
+                                               {
+                                                       if (($config{$1} !~ /y/i) and ($config{$1} ne "1"))
+                                                       {
+                                                               # Skip to 'endif'
+                                                               while (defined($line = <CPP>))
+                                                               {
+                                                                       chomp($line);
+                                                                       die ("\$If buildsystem instruction within another \$If in file $dir/$name") if ($line =~ /\/\* \$If: (\w+) \*\//i);
+                                                                       last if ($line =~ /\/\* \$EndIf \*\//i);
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       elsif ($line =~ /\/\* \$Install: (.*?) \*\//i)
+                                       {
+                                               if (!exists($existing_install_list{$1}))
+                                               {
+                                                       $existing_install_list{$1} = 1;
+                                                       my $idir = (split(' ',$1))[1];
+                                                       my $ifile = (split(' ',$1))[0];
+                                                       $install_list = $install_list . "       -install -m \$(INSTMODE) $1\n";
+                                                       $ifile =~ s/.*\///g;
+                                                       $uninstall_list = $uninstall_list . "   -rm $idir/$ifile\n";
+                                               }
+                                       }
+                                       elsif ($line =~ /\/\* \$CopyInstall: (.*?) \*\//i)
+                                       {
+                                               if (!exists($existing_install_list{$1}))
+                                               {
+                                                       $existing_install_list{$1} = 1;
+                                                       my $idir = (split(' ',$1))[1];
+                                                       my $ifile = (split(' ',$1))[0];
+                                                       $install_list = $install_list . "       -cp $1\n";
+                                                       $ifile =~ s/.*\///g;
+                                                       $uninstall_list = $uninstall_list . "   -rm $idir/$ifile\n";
+                                               }
+                                       }
+                               }
+                               close CPP;
+                       }
+               }
+               closedir(DIRHANDLE);
+               print " done!\n";
+       }
+
+       # modes need to be compiled in too
+       $all_core = $all_core . "modes/modeclasses.a";
+
+       my $freebsd4libs = (defined $config{CRAQ} ? $config{CRAQ} : "");
+
+       my $libraryext = "";
+       my $binary_rule = "";
+
+       if ($config{IS_DARWIN} eq "YES")
+       {
+               $libraryext = "dylib";
+               $binary_rule = "        \@../make/run-cc.pl \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c inspircd.cpp\n       \@../make/run-cc.pl \$(CC) -pipe -dynamic -bind_at_load -L. -o inspircd \$(LDLIBS) inspircd.o "
+       }
+       else
+       {
+               $libraryext = "so";
+               $binary_rule = "        \@../make/run-cc.pl \$(CC) -pipe -I../include \$(FLAGS) $freebsd4libs -rdynamic -L. inspircd.cpp -o inspircd \$(LDLIBS) ";
+       }
 
        open(FH,">src/Makefile") or die("Could not write src/Makefile");
        print FH <<EOM;
-# Insp Makefile :p
-#
-# (C) ChatSpike development team
-# Makefile by <Craig\@ChatSpike.net>
-# Makefile version 2 (dynamically linked core) by <brain\@inspircd.org>
-#
 
 CC = im a cheezeball
-
 CXXFLAGS = -I../include \${FLAGS}
 CPPFILES = \$(shell /bin/ls -l modes/ | grep '\\.cpp' | sed 's/^.* //' | grep -v svn)
 RELCPPFILES = \$(shell /bin/ls -l modes/ | grep '\\.cpp' | sed 's/^.* /modes\\//' | grep -v svn)
 
-all: libIRCDtimer.so libIRCDaes.so libIRCDcull_list.so libIRCDuserprocess.so libIRCDsocketengine.so libIRCDsocket.so libIRCDhash.so libIRCDchannels.so libIRCDmode.so libIRCDxline.so libIRCDstring.so libIRCDasyncdns.so libIRCDbase.so libIRCDconfigreader.so libIRCDinspsocket.so $cmdobjs libIRCDcommands.so libIRCDdynamic.so libIRCDusers.so libIRCDmodules.so libIRCDwildcard.so libIRCDhelper.so libIRCDcommand_parse.so libIRCDsnomasks.so inspircd
-
-inspircd: inspircd.cpp ../include/base.h ../include/channels.h ../include/inspircd.h ../include/channels.h ../include/globals.h ../include/inspircd_config.h ../include/socket.h libIRCDtimer.so libIRCDaes.so libIRCDcull_list.so libIRCDuserprocess.so libIRCDsocketengine.so libIRCDsocket.so libIRCDhash.so libIRCDchannels.so libIRCDmode.so libIRCDxline.so libIRCDstring.so libIRCDasyncdns.so libIRCDbase.so libIRCDconfigreader.so libIRCDinspsocket.so $cmdobjs libIRCDsnomasks.so libIRCDcommands.so libIRCDdynamic.so libIRCDusers.so libIRCDmodules.so libIRCDwildcard.so libIRCDhelper.so libIRCDcommand_parse.so
-       \$(CC) -I../include $extra -Wl,--rpath -Wl,/usr/local/lib -Wl,--rpath -Wl,$config{LIBRARY_DIR} \$(FLAGS) -rdynamic -L. inspircd.cpp -o inspircd \$(LDLIBS) libIRCDchannels.so libIRCDmode.so libIRCDxline.so libIRCDstring.so libIRCDasyncdns.so libIRCDbase.so libIRCDconfigreader.so libIRCDinspsocket.so libIRCDcommands.so libIRCDdynamic.so libIRCDusers.so libIRCDmodules.so libIRCDwildcard.so libIRCDhelper.so libIRCDhash.so libIRCDsocket.so libIRCDsocketengine.so libIRCDuserprocess.so libIRCDcull_list.so libIRCDcommand_parse.so libIRCDaes.so libIRCDtimer.so libIRCDsnomasks.so
-
-libIRCDsocketengine.so: $se.cpp socketengine.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h ../include/$se.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c socketengine.cpp $se.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDsocketengine.so socketengine.o $se.o
-
-libIRCDsnomasks.so: snomasks.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/channels.h
-        \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c snomasks.cpp
-         \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDsnomasks.so snomasks.o
-
-libIRCDcommand_parse.so: command_parse.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c command_parse.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDcommand_parse.so command_parse.o
-
-libIRCDcull_list.so: cull_list.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h ../include/users.h ../include/channels.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c cull_list.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDcull_list.so cull_list.o
-
-libIRCDuserprocess.so: userprocess.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c userprocess.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDuserprocess.so userprocess.o
-
-libIRCDhash.so: hashcomp.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c hashcomp.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDhash.so hashcomp.o
-
-libIRCDhelper.so: helperfuncs.cpp ../include/base.h ../include/helperfuncs.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I/usr/local/include -L/usr/local/lib -I../include \$(FLAGS) -export-dynamic -c helperfuncs.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDhelper.so helperfuncs.o
-
-libIRCDchannels.so: channels.cpp ../include/base.h ../include/channels.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c channels.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDchannels.so channels.o
-
-libIRCDmode.so: mode.cpp ../include/base.h ../include/mode.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h \$(RELCPPFILES)
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c mode.cpp
-       \${MAKE} -C "modes" DIRNAME="src/modes" \$(MAKEARGS) CPPFILES="\$(CPPFILES)"
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDmode.so mode.o modes/modeclasses.a
+EOM
 
-libIRCDxline.so: xline.cpp ../include/base.h ../include/xline.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c xline.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDxline.so xline.o
+       my $buildstring = "";
+       my $deps = "";
 
-libIRCDstring.so: inspstring.cpp ../include/base.h ../include/inspstring.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c inspstring.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDstring.so inspstring.o
+       foreach my $cpp (sort keys %filelist)
+       {
+               my $objs = $cpp;
+               my $rawcpp = $cpp;
+               $objs =~ s/\.cpp$/.o/;
+               if (exists($extraobjects{$cpp}))
+               {
+                       $objs = $objs . " " . $extraobjects{$cpp};
+                       $all_core = $all_core . " " . $extraobjects{$cpp};
+               }
+               if (exists($extrasources{$cpp}))
+               {
+                       $rawcpp = $rawcpp . " " . $extrasources{$cpp};
+               }
 
-libIRCDasyncdns.so: dns.cpp ../include/base.h ../include/dns.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c dns.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDasyncdns.so dns.o
+               $deps = calcdeps("src/$cpp");
+               if (exists($extrasources{$cpp}))
+               {
+                       foreach my $seperate (sort split(' ',$extrasources{$cpp}))
+                       {
+                               my $d = calcdeps("src/$extrasources{$cpp}") . " ";
+                               if ($d ne "")
+                               {
+                                       $deps = $deps . $d . " ";
+                               }
+                       }
+               }
+               $buildstring = $buildstring . $objs . ": $cpp $deps ". (defined($specialdeps{$cpp}) ? $specialdeps{$cpp} : "") . "\n";
 
-libIRCDbase.so: base.cpp ../include/base.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c base.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDbase.so base.o
+               if (exists($core_files_list{$cpp}))
+               {
+                       # core files are statically linked into the binary and do not require -export-dynamic
+                       $buildstring = $buildstring . " \@../make/run-cc.pl \$(CC) -pipe -I../include \$(FLAGS) -c $rawcpp\n";
+               }
+               else
+               {
+                       $buildstring = $buildstring . " \@../make/run-cc.pl \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c $rawcpp\n";
+               }
 
-libIRCDconfigreader.so: configreader.cpp ../include/base.h ../include/configreader.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c configreader.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDconfigreader.so configreader.o
+               if (exists($extrabuildlines{$cpp}))
+               {
+                       $buildstring = $buildstring . " " . $extrabuildlines{$cpp} . "\n";
+               }
+       }
 
-libIRCDcommands.so: commands.cpp ../include/base.h ../include/commands.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c commands.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDcommands.so commands.o
+       print FH "all: inspircd moo\n\n\n";
 
-libIRCDdynamic.so: dynamic.cpp ../include/base.h ../include/dynamic.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c dynamic.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDdynamic.so dynamic.o
+       $deps = calcdeps("src/inspircd.cpp");
+       print FH "inspircd: inspircd.cpp $deps $all_core\n";
+       print FH "$binary_rule $all_core\n\n";
 
-libIRCDusers.so: users.cpp ../include/base.h ../include/users.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c users.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDusers.so users.o
+       print FH $buildstring;
+       print FH "moo:\n        \@\${MAKE} -C \"commands\" DIRNAME=\"src/commands\" CC=\"\$(CC)\" \$(MAKEARGS)\n\n";
 
-libIRCDmodules.so: modules.cpp ../include/base.h ../include/modules.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c modules.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDmodules.so modules.o
+       # close main makefile
+       close(FH);
 
-libIRCDwildcard.so: wildcard.cpp ../include/base.h ../include/wildcard.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c wildcard.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDwildcard.so wildcard.o
+       my $cmdobjs = "";
+       # generate a list of .so
+       foreach my $cmd (@cmdlist) {
+               $cmdobjs = $cmdobjs . "cmd_$cmd.so ";
+       }
 
-libIRCDsocket.so: socket.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c socket.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDsocket.so socket.o
+       # and now reopen the commands makefile
+       open(FH,">src/commands/Makefile") or die("Could not write src/commands/Makefile");
+       print FH <<ITEM;
+CC = i am cornholio
+CXXFLAGS = -I../../include \${FLAGS}
 
-libIRCDinspsocket.so: inspsocket.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c inspsocket.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDinspsocket.so inspsocket.o
+all: $cmdobjs
 
-libIRCDaes.so: aes.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c aes.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDaes.so aes.o
 
-libIRCDtimer.so: timer.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c timer.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDtimer.so timer.o
+ITEM
 
-EOM
+       # now print the command file details.
        foreach my $cmd (@cmdlist) {
                print FH <<ITEM;
-cmd_$cmd.so: cmd_$cmd.cpp ../include/base.h ../include/modules.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/commands/cmd_$cmd.h
-       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c cmd_$cmd.cpp
-       \$(CC) -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o cmd_$cmd.so cmd_$cmd.o
+cmd_$cmd.so: cmd_$cmd.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/commands/cmd_$cmd.h
+       \@../../make/run-cc.pl \$(CC) -pipe -I../../include \$(FLAGS) -export-dynamic $SHARED -o cmd_$cmd.so cmd_$cmd.cpp
 
 ITEM
        }
-       close(FH);
+}
+
+# Routine to list out the extra/ modules that have been enabled.
+# Note: when getting any filenames out and comparing, it's important to lc it if the
+# file system is not case-sensitive (== Epoc, MacOS, OS/2 (incl DOS/DJGPP), VMS, Win32
+# (incl NetWare, Symbian)). Cygwin may or may not be case-sensitive, depending on
+# configuration, however, File::Spec does not currently tell us (it assumes Unix behavior).
+sub list_extras () {
+       use File::Spec;
+       # @_ not used
+       my $srcdir = File::Spec->catdir("src", "modules");
+       my $abs_srcdir = File::Spec->rel2abs($srcdir);
+       local $_;
+       my $dd;
+       opendir $dd, File::Spec->catdir($abs_srcdir, "extra") or die (File::Spec->catdir($abs_srcdir, "extra") . ": $!\n");
+       my @extras = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
+       closedir $dd;
+       undef $dd;
+       opendir $dd, $abs_srcdir or die "$abs_srcdir: $!\n";
+       my @sources = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
+       closedir $dd;
+       undef $dd;
+       my $maxlen = (sort { $b <=> $a } (map {length($_)} (@extras)))[0];
+       my %extras = ();
+EXTRA: for my $extra (@extras) {
+               next if (File::Spec->curdir() eq $extra || File::Spec->updir() eq $extra);
+               next if ($extra eq '.svn');
+               my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
+               my $abs_source = File::Spec->catfile($abs_srcdir, $extra);
+               next unless ($extra =~ m/\.(cpp|h)$/ || (-d $abs_extra)); # C++ Source/Header, or directory
+               if (-l $abs_source) {
+                       # Symlink, is it in the right place?
+                       my $targ = readlink($abs_source);
+                       my $abs_targ = File::Spec->rel2abs($targ, $abs_srcdir);
+                       if ($abs_targ eq $abs_extra) {
+                               $extras{$extra} = "\e[32;1menabled\e[0m";
+                       } else {
+                               $extras{$extra} = sprintf("\e[31;1mwrong symlink target (%s)\e[0m", $abs_targ);
+                       }
+               } elsif (-e $abs_source) {
+                       my ($devext, $inoext) = stat($abs_extra);
+                       my ($devsrc, $inosrc, undef, $lnksrc) = stat($abs_source);
+                       if ($lnksrc > 1) {
+                               if ($devsrc == $devext && $inosrc == $inoext) {
+                                       $extras{$extra} = "\e[32;1menabled\e[0m";
+                               } else {
+                                       $extras{$extra} = sprintf("\e[31;1mwrong hardlink target (%d:%d)\e[0m", $devsrc, $inosrc);
+                               }
+                       } else {
+                               open my $extfd, "<", $abs_extra;
+                               open my $srcfd, "<", $abs_source;
+                               local $/ = undef;
+                               if (scalar(<$extfd>) eq scalar(<$srcfd>)) {
+                                       $extras{$extra} = "\e[32;1menabled\e[0m";
+                               } else {
+                                       $extras{$extra} = sprintf("\e[31;1mout of synch (re-copy)\e[0m");
+                               }
+                       }
+               } else {
+                       $extras{$extra} = "\e[33;1mdisabled\e[0m";
+               }
+       }
+       # Now let's add dependency info
+       for my $extra (keys(%extras)) {
+               next unless $extras{$extra} =~ m/enabled/; # only process enabled extras.
+               my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
+               my @deps = split / +/, getdependencies($abs_extra);
+               for my $dep (@deps) {
+                       if (exists($extras{$dep})) {
+                               my $ref = \$extras{$dep}; # Take reference.
+                               if ($$ref !~ m/needed by/) {
+                                       # First dependency found.
+                                       if ($$ref =~ m/enabled/) {
+                                               $$ref .= " (needed by \e[32;1m$extra\e[0m";
+                                       } else {
+                                               $$ref =~ s/\e\[.*?m//g; # Strip out previous coloring. Will be set in bold+red+blink later.
+                                               $$ref .= " (needed by \e[0;32;1;5m$extra\e[0;31;1;5m";
+                                       }
+                               } else {
+                                       if ($$ref =~ m/enabled/) {
+                                               $$ref .= ", \e[32;1m$extra\e[0m";
+                                       } else {
+                                               $$ref .= ", \e[0;32;1;5m$extra\e[0;31;1;5m";
+                                       }
+                               }
+                       }
+               }
+       }
+       for my $extra (sort {$a cmp $b} keys(%extras)) {
+               my $text = $extras{$extra};
+               if ($text =~ m/needed by/ && $text !~ m/enabled/) {
+                       printf "\e[31;1;5m%-*s = %s%s\e[0m\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? ")" : "");
+               } else {
+                       printf "%-*s = %s%s\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? "\e[0m)" : "");
+               }
+       }
+       return keys(%extras) if wantarray; # Can be used by manage_extras.
+}
+
+sub enable_extras (@) {
+       my (@extras) = @_;
+       for my $extra (@extras) {
+               my $extrapath = "src/modules/extra/$extra";
+               if (!-e $extrapath) {
+                       print STDERR "Cannot enable \e[32;1m$extra\e[0m : No such file or directory in src/modules/extra\n";
+                       next;
+               }
+               my $source = "src/modules/$extra";
+               if (-e $source) {
+                       print STDERR "Cannot enable \e[32;1m$extra\e[0m : destination in src/modules exists (might already be enabled?)\n";
+                       next;
+               }
+               # Get dependencies, and add them to be processed.
+               my @deps = split / +/, getdependencies($extrapath);
+               for my $dep (@deps) {
+                       next if scalar(grep { $_ eq $dep } (@extras)) > 0; # Skip if we're going to be enabling it anyway.
+                       if (!-e "src/modules/$dep") {
+                               if (-e "src/modules/extra/$dep") {
+                                       print STDERR "Will also enable extra \e[32;1m$dep\e[0m (needed by \e[32;1m$extra\e[0m)\n";
+                                       push @extras, $dep;
+                               } else {
+                                       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";
+                               }
+                       }
+               }
+               print "Enabling $extra ... \n";
+               symlink "extra/$extra", $source or print STDERR "$source: Cannot link to 'extra/$extra': $!\n";
+       }
+}
+
+sub disable_extras (@)
+{
+       opendir my $dd, "src/modules/extra/";
+       my @files = readdir($dd);
+       closedir $dd;
+       my (@extras) = @_;
+EXTRA: for my $extra (@extras) {
+               my $extrapath = "src/modules/extra/$extra";
+               my $source = "src/modules/$extra";
+               if (!-e $extrapath) {
+                       print STDERR "Cannot disable \e[32;1m$extra\e[0m : Is not an extra\n";
+                       next;
+               }
+               if ((! -l $source) || readlink($source) ne "extra/$extra") {
+                       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";
+                       next;
+               }
+               # Check if anything needs this.
+               for my $file (@files) {
+                       my @deps = split / +/, getdependencies("src/modules/extra/$file");
+                       # File depends on this extra...
+                       if (scalar(grep { $_ eq $extra } @deps) > 0) {
+                               # And is both enabled and not about to be disabled.
+                               if (-e "src/modules/$file" && scalar(grep { $_ eq $file } @extras) < 1) {
+                                       print STDERR "Cannot disable \e[32;1m$extra\e[0m : is needed by \e[32;1m$file\e[0m\n";
+                                       next EXTRA;
+                               }
+                       }
+               }
+               # Now remove.
+               print "Disabling $extra ... \n";
+               unlink "src/modules/$extra" or print STDERR "Cannot disable \e[32;1m$extra\e[0m : $!\n";
+       }
 }