#!/usr/bin/perl -w -I/opt/eprints/perl_lib

######################################################################
#
#  This file is part of GNU EPrints 2.
#  
#  Copyright (c) 2000-2004 University of Southampton, UK. SO17 1BJ.
#  
#  EPrints 2 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.
#  
#  EPrints 2 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 EPrints 2; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
######################################################################

=pod

=head1 NAME

B<generate_apacheconf> - Create the apache config files needed for EPrints

=head1 SYNOPSIS

B<generate_apacheconf> [B<options>] 

=head1 DESCRIPTION

This script generates the apache config files which will be used by EPrints. In the simple case all you need to do is run this script then add a line to your main apache configuration file - often, but not always, B</usr/local/apache/conf/httpd.conf>

 Include /opt/eprints2/cfg/apache.conf

Or elsewhere if you installed EPrints somewhere other than /opt/eprints2. This file then uses the "Include" directive to include all relevant apache config files from this EPrints installation.

By default the virtualhost directives are

 VirtualHost *

But the * can be changed to something different by editing the C<virtualhost> option in SystemSettings.pm

=head1 ARGUMENTS

=over 8

=back

=head1 OPTIONS

=over 8

=item B<--help>

Print a brief help message and exit.

=item B<--man>

Print the full manual page and then exit.

=item B<--quiet>

Be vewwy vewwy quiet. This option will supress all output unless an error occurs.

=item B<--verbose>

Explain in detail what is going on.
May be repeated for greater effect.

=item B<--version>

Output version information and exit.

=back   

=head1 FILES

=over 4

=item B<EPRINTS/cfg/apache.conf>

This file is not updated if it already exists, so you can add system-wide
apache configuration directives here. By default it just includes the two other system wide files: auto-apache-includes.conf and auto-apache.conf

=item B<EPRINTS/cfg/auto-apache-includes.conf>

This file is updated with Include lines to each of the repository specific apache config files. This file should not be edited by hand,

=item B<EPRINTS/cfg/auto-apache.conf>

This file contains the system wide apache directives required by EPrints. This file should not be edited by hand.

=item B<EPRINTS/archives/ARCHIVEDIR/cfg/apache.conf>

This file is not updated if it already exists, so you can add repository-specific
apache configuration directives here. By default it just includes the automatically generated repository specific file: auto-apache.conf

=item B<EPRINTS/archives/ARCHIVEDIR/var/auto-apache.conf>

This file contains all the configuration directives needed for an repository. This is where the bulk of the configuration appears, the clever stuff, if you will. This file should not be edited by hand.

=item B<EPRINTS/archives/ARCHIVEDIR/var/auto-secure.conf>

Only created if the repository has a securehost configured. This file contains all the configuration options that need to be included into the secure server virtualhost.

=item B<EPRINTS/archives/ARCHIVEDIR/cfg/apachevhost.conf>

This file is not updated if it already exists, it is included into the virutalhost in auto-apache.conf so that you can a couple of additional directives if you need to. For example, redirects or additional log directives.

=back

=head1 AUTHOR

This is part of this EPrints 2 system. EPrints 2 is developed by Christopher Gutteridge.

=head1 VERSION

EPrints Version: eprints-2-cvs-2006-06-27

=head1 CONTACT

For more information goto B<http://www.eprints.org/> which give information on mailing lists and the like.

Chris Gutteridge may be contacted at B<support@eprints.org>

Should you need a real world address for some reason, EPrints can be contacted in the real world at

 EPrints c/o Christopher Gutteridge
 Department of Electronics and Computer Science
 University of Southampton
 SO17 1BJ
 United Kingdom

=head1 COPYRIGHT

This file is part of GNU EPrints 2.

Copyright (c) 2000-2004 University of Southampton, UK. SO17 1BJ.

EPrints 2 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.

EPrints 2 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 EPrints 2; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


=cut


use EPrints;

use strict;
use Getopt::Long;
use Pod::Usage;

my $version = 0;
my $verbose = 0;
my $quiet = 0;
my $help = 0;
my $man = 0;

GetOptions( 
	'help|?' => \$help,
	'man' => \$man,
	'version' => \$version,
	'verbose+' => \$verbose,
	'silent' => \$quiet,
	'quiet' => \$quiet
) || pod2usage( 2 );
EPrints::Utils::cmd_version( "generate_apacheconf" ) if $version;
pod2usage( 1 ) if $help;
pod2usage( -exitstatus => 0, -verbose => 2 ) if $man;
pod2usage( 2 ) if( scalar @ARGV != 0 ); 

our $noise = 1;
$noise = 0 if( $quiet );
$noise = 1+$verbose if( $verbose );

#cjg Write a more simple conf if only one language involved?

# Set STDOUT to auto flush (without needing a \n)
$|=1;

my $av =  $EPrints::SystemSettings::conf->{apache};
$av = "1" unless defined $av;

my $site_sysfile = EPrints::Config::get( "var_path" )."/auto-apache.conf";
my $site_incfile = EPrints::Config::get( "var_path" )."/auto-apache-includes.conf";
my $site_userfile = EPrints::Config::get( "cfg_path" )."/apache.conf";

print "Creating system wide apache conf files.\n" if( $noise >= 1 );

# Clean up old auto files. Especially old secure ones
opendir( my $dir, EPrints::Config::get( "var_path" ) );
while( my $file = readdir( $dir ) )
{
	if( $file =~ m/^auto-.*\.conf$/ )
	{
		my $fn = EPrints::Config::get( "var_path" ).'/'.$file;
		unlink( $fn );
	}
}

unless( -e $site_userfile )
{
	print "Creating $site_userfile\n" if( $noise >= 2 );
	open( CONF, ">$site_userfile" ) || die "Can't write to $site_userfile";
	print CONF <<END;
#
# apache.conf include file for EPrints
#
# If this file exists then it will not be over written by
#
# Put your own extra directives for this site here
#
# Comment out the "Include" lines if you don't want to use the
# autogenerated config for this repository.
#

# Include list of 'Include's for each repository
Include $site_incfile

# Include autogenerate apache.conf elements
Include $site_sysfile




END
	close CONF;
}
else
{
	print "$site_userfile already exists.\n" if( $noise >= 2 );
}

my $virtualhost = EPrints::Config::get( "virtualhost" );
if( !EPrints::Utils::is_set( $virtualhost ) )
{
	$virtualhost = '*';
}

print "Creating $site_sysfile\n" if( $noise >= 2 );
my $startupfile = EPrints::Config::get( "bin_path" )."/startup.pl";
open( CONF, ">$site_sysfile" ) || die "Can't write to $site_sysfile";
print CONF <<END;
#
# auto-apache.conf include file for EPrints
#
# DO NOT EDIT, this file is created by bin/generate_apacheconf
# and may be overwritten. To modify, change the repository configuration
# and re-run: bin/generate_apacheconf
#

# Load the perl modules & repository configurations
PerlSetEnv EPRINTS_APACHE $av
PerlRequire $startupfile

END
my %portlist = ();
foreach my $repository_id ( EPrints::Config::get_repository_ids() )
{
	my $repository = EPrints::Repository->new( $repository_id, 1 );
	exit( 1 ) unless( defined $repository );
	$portlist{$repository->get_conf( 'port' )} = 1;
}
foreach my $port ( keys %portlist )
{
	print CONF "NameVirtualHost $virtualhost:$port\n";
}
print CONF "\n";

if( $av eq "2" )
{
	# apache 2
	print CONF <<END;
# Makes the request object accessable for other objects
# (apache 2.0 only)
PerlOptions +GlobalRequest

END
}
close CONF;

########################################

print "Creating $site_incfile\n" if( $noise >= 2 );
open( CONF, ">$site_incfile" ) || die "Can't write to $site_incfile";
print CONF <<END;
#
# auto-apache-includes.conf include file for EPrints
#
# DO NOT EDIT, this file is created by bin/generate_apacheconf
# and may be overwritten. To modify, change the repository configuration
# and re-run: bin/generate_apacheconf
#
# List of files to include for repository specific config...

END
foreach my $repository_id ( EPrints::Config::get_repository_ids() )
{
	my $repository_config = EPrints::Config::get_repository_config( $repository_id );
	my $repository_inc = $repository_config->{archiveroot}."/cfg/apache.conf";
	print CONF <<END;
# $repository_id
Include $repository_inc

END
}
close CONF;








########################################F#N#O#R#D########
# 
#   Write apache conf files for each repository
#
########################################F#N#O#R#D########

my $secureconfigs = {};
foreach my $repository_id ( EPrints::Config::get_repository_ids() )
{
my $repository = EPrints::Repository->new( $repository_id, 1 );
exit( 1 ) unless( defined $repository );

my $sysfile = $repository->get_conf( "variables_path" )."/auto-apache.conf";
my $userfile = $repository->get_conf( "config_path" )."/apache.conf";
my $vhostfile = $repository->get_conf( "config_path" )."/apachevhost.conf";
my $securefile = $repository->get_conf( "variables_path" )."/auto-secure.conf";

my $id = $repository->get_id();

print "Creating apache conf files for repository $repository_id\n" if( $noise >= 1 );
unless( -e $userfile )
{
	print "Creating $userfile\n" if( $noise >= 2 );
	open( CONF, ">$userfile" ) || die "Can't write to $userfile";
	print CONF <<END;
#
# apache.conf include file for $id
#
# If this file exists then it will not be over written by
# the generate_apacheconf command.
#
# Put your own extra directives for this site here
#
# Comment out the "Include" line if you don't want to use the
# autogenerated config for this repository.
#

Include $sysfile
END
}
else
{
	print "$userfile already exists.\n" if( $noise >= 2 );
}


unless( -e $vhostfile )
{
	print "Creating $vhostfile\n" if( $noise >= 2 );
	open( CONF, ">$vhostfile" ) || die "Can't write to $vhostfile";
	print CONF <<END;
#
# apachevhost.conf include file for $id
#
# If this file exists then it will not be over written by
# the generate_apacheconf command.
#
# Directives in this file are interpreted inside the virtualhost 
# configuration for this repository.
#


END
}
else
{
	print "$vhostfile already exists.\n" if( $noise >= 2 );
}


my $cgidir = EPrints::Config::get( "cgi_path" );
my $adminemail = $repository->get_conf( "adminemail" );
my $htdocs_path = $repository->get_conf( "htdocs_path" );
my $htdocs_secure_path = $repository->get_conf( "htdocs_secure_path" );
my $host = $repository->get_conf( "host" );
my $port = $repository->get_conf( "port" );
my $urlpath = $repository->get_conf( "urlpath" );
my $userhome = $repository->get_conf( "userhome" );
my $securehost = $repository->get_conf( "securehost" );
my $securepath = '';
if( EPrints::Utils::is_set( $securehost ) )
{
	$securepath = $repository->get_conf( "securepath" );
}


print "Creating $sysfile\n" if( $noise >= 2 );
open( CONF, ">$sysfile" ) || die "Can't write to $sysfile";
print CONF <<END;
#
# auto-apache.conf include file for $id
#
# DO NOT EDIT, this file is created by bin/generate_apacheconf
# and may be overwritten. To modify, change the repository configuration
# and re-run: bin/generate_apacheconf $id
#

END
my $aliasinfo;
my $aliases = "";
foreach $aliasinfo ( @{$repository->get_conf( "aliases" )} )
{
	if( $aliasinfo->{redirect} )
	{
		my $vname = $aliasinfo->{name};
		print CONF <<END;

# Redirect to the correct hostname
<VirtualHost $virtualhost:$port>
  ServerName $vname
  Redirect / http://$host/
</VirtualHost>
END
	}
	else
	{
		$aliases.="  ServerAlias ".$aliasinfo->{name}."\n";
	}
}
print CONF <<END;

# The main virtual host for this repository
<VirtualHost $virtualhost:$port>
  ServerName $host
$aliases
  ServerAdmin $adminemail

  # Include this here, so that it's rules come first.
  Include $vhostfile

END

# If we want to use the non-perl CGI script mimetex.cgi we need to 
# insert the script alias here.
if( $repository->get_conf( "use_mimetex" ) ) 
{
	if( !defined $EPrints::SystemSettings::conf->{executables}->{mimetex} )
	{
		EPrints::Config::abort( "use_mimetex is set to true but\n\$EPrints::SystemSettings::conf->{executables}->{mimetex}\nis not set." );
	}
	if( !-e $EPrints::SystemSettings::conf->{executables}->{mimetex} )
	{
		EPrints::Config::abort( "use_mimetex is set to true but\n\$EPrints::SystemSettings::conf->{executables}->{mimetex}\nis set to a non existant file." );
	}
	     
	print CONF '  ScriptAlias '.$urlpath.'/cgi/mimetex.cgi '.$EPrints::SystemSettings::conf->{executables}->{mimetex}."\n\n";
}

print CONF <<END;
  Alias $urlpath/perl $cgidir
  Alias $urlpath/ $htdocs_path/

  <Location "$urlpath">
    ErrorDocument 401 $urlpath/error401.html
    ErrorDocument 404 $urlpath/perl/handle_404
    PerlSetVar EPrints_ArchiveID $repository_id
END
# EPrints log handler (this gets called for all requests, not just
# mod_perl)
if(
	$av == 2 &&
	$repository->get_conf( "loghandler" ) &&
	$repository->get_conf( "loghandler" )->{ "enable" }
  )
{
	# apache 2
	print CONF <<END;
    PerlLogHandler EPrints::Apache::LogHandler
END
}

print CONF <<END;
  </Location>

  # Note that PerlTransHandler can't go inside
  # a "Location" block as it occurs before the
  # Location is known.
  PerlTransHandler EPrints::Apache::Rewrite

END

my @langs = @{$repository->get_conf( "languages" )};

#my $defaultlang = $repository->get_conf( "defaultlanguage" );
# cjg remove this stuff later.
#
#foreach my $langid ( @langs )
#{
	#next if( $langid eq $defaultlang );
		#print CONF <<END;
  #RewriteCond %{HTTP_COOKIE}   lang=$langid
  #RewriteRule ^/(.*)\$         /$langid/\$1   [L]
#
#END
#}
#
#print CONF <<END;
  ## Default Language
  #RewriteRule ^/(.*)\$         /$defaultlang/\$1   [L]
#
#END


if( $repository->get_conf( "vlit" )->{enable} )
{
	foreach my $langid ( @langs )
	{
		print CONF <<END;
  <Directory "$htdocs_path/$langid/archive">
    SetHandler perl-script
    PerlHandler EPrints::Apache::VLit::handler
  </Directory>

END
	}
}

if( $repository->get_conf( "dynamic_template","enable" ) )
{
	foreach my $langid ( @langs )
	{
		print CONF <<END;
  <Directory "$htdocs_path">
    SetHandler perl-script
    PerlResponseHandler EPrints::Apache::Template::handler
  </Directory>

END
	}
}

my $registry_module;
if( $av eq "1" ) 
{
	$registry_module = "Apache::Registry";
}
else # apache 2
{
	$registry_module = "ModPerl::Registry";
}

print CONF <<END;
  <Directory "$htdocs_path">
    Order deny,allow
    Allow from all
    AddType 'text/html; charset=UTF-8' .html
  </Directory>

  <Directory "$cgidir">
    SetHandler perl-script
    PerlHandler $registry_module
    PerlSendHeader Off
    Options ExecCGI FollowSymLinks
  </Directory>

END

my $secureconfig = <<END;
  <Directory "$cgidir/users">
    AuthName "User Area"
    AuthType "Basic"
    PerlAuthenHandler EPrints::Apache::Auth::authen
    PerlAuthzHandler EPrints::Apache::Auth::authz
    PerlSetVar EPrints_Security_Area User
    require valid-user

    SetHandler perl-script
    PerlHandler $registry_module
    PerlSendHeader Off
    Options ExecCGI FollowSymLinks
  </Directory>
  <Directory "$cgidir/users/awstats">
    PerlSendHeader On
  </Directory>

  <Directory "$htdocs_secure_path">
    AuthName "Secure Document Area"
    AuthType "Basic"
    PerlAuthenHandler EPrints::Apache::Auth::authen
    PerlAuthzHandler EPrints::Apache::Auth::authz
    PerlSetVar EPrints_Security_Area Documents
    require valid-user
  </Directory>

  # This sets up the change_user URL, which does
  # not have a REAL file associated with it, it
  # forces the browser to fail to register the
  # current user as a valid user, and thus ask
  # for re-validation.
  <Location "$securepath/change_user">
    AuthName "User Area"
    AuthType "Basic"
    PerlAuthenHandler EPrints::Apache::Auth::authen
    PerlAuthzHandler EPrints::Apache::Auth::authz
    PerlSetVar EPrints_Security_Area ChangeUser
    PerlSetVar EPrints_ArchiveID $repository_id
    require valid-user
    Redirect $securepath/change_user $userhome
  </Location>

END

unless( EPrints::Utils::is_set( $securehost ) )
{
	print CONF <<END;
$secureconfig

</VirtualHost>

END
	close CONF;
	next;
}

# This site has an HTTPS component. Redirect sceure stuff there...

my $securebase = "https://".$securehost.$securepath;

print CONF <<END;

  Redirect /secure/ $securebase/secure/
  Redirect /perl/users/ $securebase/perl/users/
  Redirect /change_user $securebase/change_user
  Redirect /perl/confirm $securebase/perl/accounts/confirm
  Redirect /perl/register $securebase/perl/accounts/register
  Redirect /perl/reset_password $securebase/perl/accounts/reset_password
  Redirect /perl/set_password $securebase/perl/accounts/set_password

</VirtualHost>

END
close CONF;

# Create secure include file


# error documents can't change server
# need to make secure 401 and 404 pages, I guess.
    #ErrorDocument 401 $baseurl/error401.html
    #ErrorDocument 404 $baseurl/perl/handle_404
open( CONF, ">$securefile" ) || die "Can't write to $securefile";
print CONF <<END;
#
# auto-secure.conf include file for $id
#
# DO NOT EDIT, this file is created by bin/generate_apacheconf
# and may be overwritten. To modify, change the repository configuration
# and re-run: bin/generate_apacheconf $id

# This file is intended to be included inside your HTTPS virtualhost
# You have to do that yourself.

$secureconfig

  <Location "$securepath">
    PerlSetVar EPrints_ArchiveID $repository_id
    PerlSetVar EPrints_Secure yes
END
# EPrints log handler (this gets called for all requests, not just
# mod_perl)
if(
	$av == 2 &&
	$repository->get_conf( "loghandler" ) &&
	$repository->get_conf( "loghandler" )->{ "enable" }
  )
{
	# apache 2
	print CONF <<END;
	PerlLogHandler EPrints::Apache::LogHandler
END
}
print CONF <<END;
  </Location>
  <Directory "$cgidir">
    SetHandler perl-script
    PerlHandler $registry_module
    PerlSendHeader Off
    Options ExecCGI FollowSymLinks
  </Directory>

  PerlTransHandler EPrints::Apache::Rewrite

  Alias $securepath/perl/accounts/confirm $cgidir/confirm
  Alias $securepath/perl/accounts/register $cgidir/register
  Alias $securepath/perl/accounts/reset_password $cgidir/reset_password
  Alias $securepath/perl/accounts/set_password $cgidir/set_password
  Alias $securepath/perl/users/ $cgidir/users/
  Alias $securepath/secure/ $htdocs_secure_path/
  Alias $securepath/ $htdocs_path/

##### END OF CONFIG FOR $id
END
close CONF;

}





print "\nDo not forget to stop and restart apache to cause changes to take effect!\n" if( $noise >= 1 );

print "Exiting normally.\n" if( $noise >= 2 );
exit;



