#!/usr/bin/env perl
 ---------------------------------------------------------------------------
# Copyright (C) 2008 TJ Saunders <tj@castaglia.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
#
#  $Id: prxs.in,v 1.2 2008/08/26 02:47:21 castaglia Exp $
# ---------------------------------------------------------------------------

use strict;

use File::Basename qw(basename);
use Getopt::Long;

Getopt::Long::Configure("no_ignorecase");

my $prog = basename($0);

my $compiler = q(gcc);
my $cflags = q( -DLINUX -O2 -Wall -DPR_SHARED_MODULE);
my $cppflags = q();
my $ltdl_ldflags = q();
my $sbindir = q(/usr/local/sbin);
my $includedir = q(/usr/local/include);
my $installer = q(/usr/bin/install -c);
my $install_strip = q(-s);
my $libexecdir = q(/usr/local/libexec);
my $libtool = 'libtool';

if (!defined($ENV{LIBTOOL})) {
  if ($^O eq 'darwin') {
    $libtool = 'glibtool';
  }

} else {
  $libtool = $ENV{LIBTOOL};
}

my $shell = q(/bin/sh);

my $opts = {};
GetOptions($opts, 'c|compile', 'i|install', 'd|clean', 'name=s', 'D=s@',
  'I=s@', 'L=s@', 'l=s@', 'W=s@');

# Make sure we can query proftpd to find out its list of installed modules.
# Unless we see mod_dso listed, there's no point in compiling a shared
# module for proftpd to use.

my $proftpd = "$sbindir/proftpd";
unless (-x $proftpd) {
  print STDERR "$proftpd not found or not executable\n";
  exit 1;
}

unless (grep /mod_dso/, `$proftpd -l`) {
  print STDERR "\nYour installed proftpd does not support shared modules/DSOs.\n";
  print STDERR "Make sure the --enable-dso configure option is used when\n";
  print STDERR "compiling proftpd.\n\n";
  exit 1;
}

# Now, depending on the requested mode (compile/install/clean), build up
# and execute the commands.

my $mod_name = get_module_name();

if (defined($opts->{c})) {
  my $srcs = [];
  my $objs = [];

  foreach my $file (@ARGV) {
    if ($file =~ /\.c$/) {
      push(@$srcs, $file);

      my $obj = $file;
      $obj =~ s/\.c$/\.lo/;
      push(@$objs, $obj);

    } else {
      print STDERR "Cannot compile non-.c file $file, aborting\n";
      exit 1;
    }
  }

  foreach my $def (@{ $opts->{D} }) {
    if ($def =~ /^(\S+)=(\S+)$/) {
      $cflags .= " -D'$1=$2'";

    } else {
      $cflags .= " -D$def";
    }
  }

  $cflags .= " -I. -I$includedir/proftpd";

  foreach my $incdir (@{ $opts->{I} }) {
    $cflags .= " -I$incdir";
  }

  my $cmds = [];
  foreach my $src (@$srcs) {
    push(@$cmds, "$shell $libtool --mode=compile $compiler $cflags -c $src");
  }

  run_cmds($cmds);

  my $objlist = '';
  foreach my $obj (@$objs) {
    $objlist .= " $obj";
  }

  my $ldflags .= " $ltdl_ldflags";

  foreach my $libdir (@{ $opts->{L} }) {
    $ldflags .= " -L$libdir";
  }

  my $libs = "";
  foreach my $lib (@{ $opts->{l} }) {
    $libs .= " -l$lib";
  }

  $cmds = [];
  push(@$cmds, "$shell $libtool --mode=link $compiler -o $mod_name.la -rpath $libexecdir $ldflags $objlist $libs");

  run_cmds($cmds);
}

if (defined($opts->{i})) {
  my $cmds = [];
  push(@$cmds, "$shell $libtool --mode=install $installer $install_strip $mod_name.la $libexecdir");

  run_cmds($cmds);

  # Don't forget to remind the user to manually edit their proftpd.conf
  # and add the LoadModule to load the just-installed module.

  print STDOUT "\nTo load your newly installed module into proftpd, be sure\n";
  print STDOUT "to edit your proftpd.conf and add the following:\n\n";
  print STDOUT "  <IfModule mod_dso.c>\n";
  print STDOUT "    LoadModule $mod_name.c\n";
  print STDOUT "  </IfModule>\n\n";
  print STDOUT "and then restart your proftpd server, so that the config change\n";
  print STDOUT "becomes live.\n\n";
}

if (defined($opts->{d})) {
  my $cmds = [];
  push(@$cmds, "$shell $libtool --mode=clean rm -f $mod_name.la *.lo");

  run_cmds($cmds);
}

if (!defined($opts->{c}) &&
    !defined($opts->{i}) &&
    !defined($opts->{d})) {
  print STDERR "No compile, install, or clean mode requested, exiting\n";
  exit 1;
}

exit 0;

sub get_module_name {
  # Determine the name of the module (e.g. "mod_foo") being operated upon.
  if (defined($opts->{n})) {
    return $opts->{n};
  }

  foreach my $file (@ARGV) {
    if ($file =~ /^mod_(\S+)\.(c|la)$/) {
      return "mod_$1";
    }
  }

  return "mod_unknown";
}

sub run_cmds {
  my $cmds = shift;

  foreach my $cmd (@$cmds) {
    print STDOUT "$cmd\n";

    my $res = system($cmd);
    if ($res) {
      print STDERR "$prog: error executing command (", $res >> 8, ")\n";
      exit 1;
    }
  }
}
