#!--PERL-- # Sympa - SYsteme de Multi-Postage Automatique # Copyright (c) 1997, 1998, 1999, 2000, 2001 Comite Reseau des Universites # # 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. =head1 NAME sympa_wizard.pl - help perform sympa initial setup =head1 SYNOPSIS =over =item sympa_wizard.pl Edit current sympa configuration =item sympa_wizard.pl [--target file] --create Creates a new sympa or wwsympa configuration file =item sympa_wizard.pl --check check CPAN modules needed for running sympa =item sympa_wizard.pl --help Display usage instructions =back =head1 AUTHORS =over =item Serge Aumont =item Olivier Salaün =back =cut use lib '--modulesdir--'; use strict; use POSIX qw(strftime); use English qw(-no_match_vars); use Getopt::Long; use Pod::Usage; use Sympa::Constants; ## sympa configuration files my $wwsympa_conf = Sympa::Constants::WWSCONFIG; my $sympa_conf = Sympa::Constants::CONFIG; my %options; GetOptions( \%options, 'target=s', 'create=s', 'check', 'help' ); if ($options{help}) { pod2usage(); } elsif ($options{create}) { create_configuration(); } elsif ($options{check}) { check_cpan(); } else { edit_configuration(); } exit 0; sub create_configuration { use confdef; my $conf; if ($options{create} eq 'sympa.conf') { $conf = $options{target} ? $options{target} : $sympa_conf; } elsif ($options{create} eq 'wwsympa.conf') { $conf = $options{target} ? $options{target} : $wwsympa_conf; } else { pod2usage("$options{create} is not a valid argument"); exit 1; } if (-f $conf) { print STDERR "$conf file already exists, exiting\n"; exit 1; } unless (open (NEWF,"> $conf")){ die "Unable to open $conf : $!"; }; if ($options{create} eq 'sympa.conf') { # print NEWF <{'title'}) { printf NEWF "###\\\\\\\\ %s ////###\n\n", $param->{'title'}; next; } next unless ($param->{'file'} eq $options{create}); next unless (defined $param->{'default'} || defined $param->{'sample'}); printf NEWF "## %s\n", $param->{'query'} if (defined $param->{'query'}); printf NEWF "## %s\n", $param->{'advice'} if (defined $param->{'advice'}); printf NEWF "%s\t%s\n\n", $param->{'name'}, $param->{'default'} if (defined $param->{'default'}); printf NEWF "#%s\t%s\n\n", $param->{'name'}, $param->{'sample'} if (defined $param->{'sample'}); } close NEWF; print STDERR "$conf file has been created\n"; } sub edit_configuration { require Conf; my $new_wwsympa_conf = '/tmp/wwsympa.conf'; my $new_sympa_conf = '/tmp/sympa.conf'; my $wwsconf = {}; my $somechange = 0; ## Load config unless ($wwsconf = wwslib::load_config($wwsympa_conf)) { die("Unable to load config file $wwsympa_conf"); } ## Load sympa config (but not using database) unless (Conf::load( $sympa_conf,'nodb')) { die("Unable to load sympa config file $sympa_conf"); } my (@new_wwsympa_conf, @new_sympa_conf); ## Edition mode foreach my $param (@confdef::params) { my $desc; if ($param->{'title'}) { my $title = $param->{'title'}; printf "\n\n** $title **\n"; ## write to conf file push @new_wwsympa_conf, sprintf "###\\\\\\\\ %s ////###\n\n", $param->{'title'}; push @new_sympa_conf, sprintf "###\\\\\\\\ %s ////###\n\n", $param->{'title'}; next; } my $file = $param->{'file'} ; my $name = $param->{'name'} ; my $query = $param->{'query'} ; my $advice = $param->{'advice'} ; my $sample = $param->{'sample'} ; my $current_value ; if ($file eq 'wwsympa.conf') { $current_value = $wwsconf->{$name} ; } elsif ($file eq 'sympa.conf') { $current_value = $Conf::Conf{$name}; } else { next; } my $new_value; if ($param->{'edit'} eq '1') { printf "... $advice\n" unless ($advice eq '') ; printf "$name: $query \[$current_value\] : "; $new_value = ; chomp $new_value; } if ($new_value eq '') { $new_value = $current_value; } ## SKip empty parameters next if (($new_value eq '') && ! $sample); ## param is an ARRAY if (ref($new_value) eq 'ARRAY') { $new_value = join ',',@{$new_value}; } if ($file eq 'wwsympa.conf') { $desc = \@new_wwsympa_conf; }elsif ($file eq 'sympa.conf') { $desc = \@new_sympa_conf; }else{ printf STDERR "incorrect parameter $name definition \n"; } if ($new_value eq '') { next unless $sample; push @{$desc}, sprintf "## $query\n"; unless ($advice eq '') { push @{$desc}, sprintf "## $advice\n"; } push @{$desc}, sprintf "# $name\t$sample\n\n"; }else { push @{$desc}, sprintf "## $query\n"; unless ($advice eq '') { push @{$desc}, sprintf "## $advice\n"; } if ($current_value ne $new_value) { push @{$desc}, sprintf "# was $name $current_value\n"; $somechange = 1; } push @{$desc}, sprintf "$name\t$new_value\n\n"; } } if ($somechange) { my $date = strftime("%d.%b.%Y-%H.%M.%S", localtime(time)); ## Keep old config files unless (rename $wwsympa_conf, $wwsympa_conf.'.'.$date) { warn "Unable to rename $wwsympa_conf : $!"; } unless (rename $sympa_conf, $sympa_conf.'.'.$date) { warn "Unable to rename $sympa_conf : $!"; } ## Write new config files unless (open (WWSYMPA,"> $wwsympa_conf")){ die "unable to open $wwsympa_conf : $!"; }; my $umask = umask 037; unless (open (SYMPA,"> $sympa_conf")){ umask $umask; die "unable to open $sympa_conf : $!"; }; umask $umask; chown [getpwnam(Sympa::Constants::USER)]->[2], [getgrnam(Sympa::Constants::GROUP)]->[2], $sympa_conf; print SYMPA @new_sympa_conf; print WWSYMPA @new_wwsympa_conf; close SYMPA; close WWSYMPA; printf "$sympa_conf and $wwsympa_conf have been updated.\nPrevious versions have been saved as $sympa_conf.$date and $wwsympa_conf.$date\n"; } } sub check_cpan { require CPAN; ## assume required_version = 1.0 if not specified. my %cpan_modules = ( 'Archive::Zip' => { required_version => '1.05', package_name => 'Archive-Zip', mandatory => 1, usage => 'this module provides zip/unzip for archive and shared document download/upload', }, 'AuthCAS' => { required_version =>'1.4', package_name => 'AuthCAS', usage => 'CAS Single Sign-On client libraries. Required if you configure Sympa to delegate web authentication to a CAS server.', }, 'CGI' => { required_version =>'3.35', package_name => 'CGI', mandatory => 1, usage => 'required to run Sympa web interface', }, 'Crypt::CipherSaber' => { required_version =>'0.50', package_name => 'CipherSaber', usage => 'this module provides reversible encryption of user passwords in the database.usefull only when updating from old version with password reversible encryption.', }, 'DB_File' => { required_version =>'1.75', package_name => 'DB_FILE', mandatory => 1, usage => ' used for maintaining snapshots of list members', }, 'DBD::Oracle' => { required_version =>'0.90', package_name => 'DBD-Oracle', usage => 'Oracle database driver, required if you connect to a Oracle database.', }, 'DBD::Pg' => { required_version =>'0.90', prerequisites => 'postgresql-devel and postgresql-server. postgresql should be running for make test to succeed', package_name => 'DBD-Pg', usage => 'PostgreSQL database driver, required if you connect to a PostgreSQL database.', }, 'DBD::SQLite' => { required_version =>'0.90', prerequisites => 'sqlite-devel. No need to install a server, the SQLite server code being provided with the client code.', package_name => 'DBD-SQLite', usage => 'SQLite database driver, required if you connect to a SQLite database.', }, 'DBD::Sybase' => { required_version =>'0.90', package_name => 'DBD-Sybase', usage => 'Sybase database driver, required if you connect to a Sybase database.', }, 'DBD::mysql' => { required_version =>'4.008', prerequisites => 'mysql-devel and myslq-server. mysql should be running for make test to succeed', package_name => 'Msql-Mysql-modules', mandatory => 1, usage => 'Mysql database driver, required if you connect to a Mysql database.\nYou first need to install the Mysql server and have it started before installing the Perl DBD module.', }, 'DBI' => { required_version =>'1.48', package_name => 'DBI', mandatory => 1, usage => 'a generic Database Driver, required by Sympa to access Subscriber information and User preferences. An additional Database Driver is required for each database type you wish to connect to.', }, 'Digest::MD5' => { required_version =>'2.00', package_name => 'Digest-MD5', mandatory => 1, usage => 'used to compute MD5 digests for passwords, etc', }, 'Encode' => { package_name => 'Encode', mandatory => 1, usage => 'module for character encoding processing', }, 'FCGI' => { required_version =>'0.67', package_name => 'FCGI', mandatory => 1, usage => 'WWSympa, Sympa\'s web interface can run as a FastCGI (ie: a persistent CGI). If you install this module, you will also need to install the associated mod_fastcgi for Apache.', }, 'File::Copy::Recursive' => { required_version =>'0.36', package_name => 'File-Copy-Recursive', mandatory => 1, usage => 'used to copy file hierarchies', }, 'File::NFSLock' => { package_name => 'File-NFSLock', usage => 'required to perform NFS lock ; see also lock_method sympa.conf parameter' }, 'HTML::FormatText' => { package_name => 'HTML-Format', mandatory => 1, usage => 'used to compute plaindigest messages from HTML', }, 'HTML::StripScripts::Parser' => { required_version =>'1.03', package_name => 'HTML-StripScripts-Parser', mandatory => 1, usage => 'required for XSS protection on the web interface', }, 'HTML::TreeBuilder' => { package_name => 'HTML-Tree', mandatory => 1, usage => 'used to compute plaindigest messages from HTML', }, 'IO::Scalar' => { package_name => 'IO-stringy', mandatory => 1, usage => 'internal use for string processing', }, 'IO::Socket::SSL' => { required_version =>'0.90', package_name => 'IO-Socket-SSL', usage => 'required when including members of a remote list', }, 'Locale::TextDomain' => { package_name => 'libintl-perl', mandatory => 1, usage => 'internationalization functions', }, 'LWP' => { package_name => 'libwww-per', mandatory => 1, usage => 'required when including members of a remote list', }, 'MHonArc::UTF8' => { required_version =>'2.6.0', package_name => 'MHonArc', mandatory => 1, usage => 'mhonarc is used to build Sympa web archives', }, 'MIME::Base64' => { required_version =>'3.03', package_name => 'MIME-Base64', mandatory => 1, usage => 'required to compute digest for password and emails', }, 'MIME::Charset' => { required_version =>'1.006.2', package_name => 'MIME-Charset', mandatory => 1, usage => 'used to encode mail body using a different charset', }, 'MIME::EncWords' => { required_version =>'1.010', package_name => 'MIME-EncWords', mandatory => 1, usage => 'required to decode/encode SMTP header fields without breaking character encoding', }, 'MIME::Lite::HTML' => { required_version =>'1.23', package_name => 'MIME-Lite-HTML', mandatory => 1, usage => 'used to compose HTML mail from the web interface', }, 'MIME::Tools' => { required_version =>'5.423', package_name => 'MIME-tools', mandatory => 1, usage => 'provides libraries for manipulating MIME messages', }, 'Net::LDAP' => { required_version =>'0.27', prerequisites => 'openldap-devel is needed to build the Perl code', package_name => 'perl-ldap', usage => 'required to query LDAP directories. Sympa can do LDAP-based authentication ; it can also build mailing lists with LDAP-extracted members.', }, 'Net::Netmask' => { required_version =>'1.9015', package_name => 'Net-Netmask', mandatory => 1, usage => 'used to check netmask within Sympa autorization scenario rules', }, 'Net::SMTP' => { package_name => 'libnet', usage => 'this is required if you set \'list_check_smtp\' sympa.conf parameter, used to check existing aliases before mailing list creation.', }, 'perl' => { required_version =>'5.008', }, 'SOAP::Lite' => { required_version =>'0.60', package_name => 'SOAP-Lite', usage => 'required if you want to run the Sympa SOAP server that provides ML services via a "web service"', }, 'Template' => { package_name => 'Template-Toolkit', mandatory => 1, usage => 'Sympa template format, used for web pages and other mail, config file templates. See http://template-toolkit.org/.', }, 'Term::ProgressBar' => { required_version =>'2.09', package_name => 'Term-ProgressBar', mandatory => 1, usage => 'used while checking the RDBMS buffer size', }, 'Text::LineFold' => { required_version =>'2011.05', package_name => 'Unicode-LineBreak', mandatory => 1, usage => 'used to fold lines in HTML mail composer and system messages, prior to Text::Wrap', }, 'Time::HiRes' => { required_version =>'1.29', package_name => 'Time-HiRes', mandatory => 1, usage => 'used by sympa.pl --test_database_message_buffer to test database performances', }, 'URI::Escape' => { required_version =>'1.35', package_name => 'URI-Escape', mandatory => 1, usage => 'Used to create URI containing non URI-canonical characters.', }, 'XML::LibXML' => { prerequisites => 'libxml2-devel is needed to build the Perl code', package_name => 'XML-LibXML', mandatory => 1, usage => 'used to parse list configuration templates and instanciate list families', }, 'Mail::DKIM' => { required_version =>'0.36', package_name => 'Mail-DKIM', usage => 'required in order to use DKIM features (both for signature verification and signature insertion)', } ); print "########################################################################################## # This process will help you install all Perl (CPAN) modules required by Sympa software. # Sympa requires from 50 to 65 additional Perl modules to run properly. # The whole installation process should take around 15 minutes. # You'll first have to configure the CPAN shell itself and select your favourite CPAN server. # Note that you might prefer to install the required Perl modules using your favourite DEB/RPM mechanism. # Feel free to interrupt the process if needed ; you can restart it safely afterward. ############################################################################################## Strike return key to continue... "; my $rep = ; my %opt_CPAN = ( 'AuthCAS' => 'AuthCAS', 'DBD::Pg' => 'DBD-Pg', 'DBD::Oracle' => 'DBD-Oracle', 'DBD::Sybase' => 'DBD-Sybase', 'DBD::SQLite' => 'DBD-SQLite', 'Net::LDAP' => 'perl-ldap', 'CGI::Fast' => 'CGI', 'Net::SMTP' => 'libnet', 'IO::Socket::SSL' => 'IO-Socket-SSL', 'Net::SSLeay' => 'NET-SSLeay', 'Bundle::LWP' => 'LWP', 'SOAP::Lite' => 'SOAP-Lite', 'File::NFSLock' => 'File-NFSLock', 'File::Copy::Recursive' => 'File-Copy-Recursive', 'Crypt::CipherSaber' => 'CipherSaber', 'mail::DKIM' =>'Mail-DKIM', ); my %opt_features = ( 'AuthCAS' => 'CAS Single Sign-On client libraries. Required if you configure Sympa to delegate web authentication to a CAS server.', 'DBI' => 'a generic Database Driver, required by Sympa to access Subscriber information and User preferences. An additional Database Driver is required for each database type you wish to connect to.', 'DBD::mysql' => 'Mysql database driver, required if you connect to a Mysql database.\nYou first need to install the Mysql server and have it started before installing the Perl DBD module.', 'DBD::Pg' => 'PostgreSQL database driver, required if you connect to a PostgreSQL database.', 'DBD::Oracle' => 'Oracle database driver, required if you connect to a Oracle database.', 'DBD::Sybase' => 'Sybase database driver, required if you connect to a Sybase database.', 'DBD::SQLite' => 'SQLite database driver, required if you connect to a SQLite database.', 'Net::LDAP' => 'required to query LDAP directories. Sympa can do LDAP-based authentication ; it can also build mailing lists with LDAP-extracted members.', 'CGI::Fast' => 'WWSympa, Sympa\'s web interface can run as a FastCGI (ie: a persistent CGI). If you install this module, you will also need to install the associated mod_fastcgi for Apache.', 'Crypt::CipherSaber' => 'this module provides reversible encryption of user passwords in the database.usefull only when updating from old version with password reversible encryption.', 'Archive::Zip ' => 'this module provides zip/unzip for archive and shared document download/upload', 'FCGI' => 'WSympa, Sympa\'s web interface can run as a FastCGI (ie: a persistent CGI). If you install this module, you will also need to install the associated mod_fastcgi for Apache.', 'Net::SMTP' => 'this is required if you set \'list_check_smtp\' sympa.conf parameter, used to check existing aliases before mailing list creation.', 'IO::Socket::SSL' => 'required by CAS (single sign-on) and the \'include_remote_sympa_list\' feature that includes members of a list on a remote server, using X509 authentication', 'Net::SSLeay' => 'required by the \'include_remote_sympa_list\' feature that includes members of a list on a remote server, using X509 authentication', 'Bundle::LWP' => 'required by the \'include_remote_sympa_list\' feature that includes members of a list on a remote server, using X509 authentication', 'SOAP::Lite' => 'required if you want to run the Sympa SOAP server that provides ML services via a "web service"', 'File::NFSLock' => 'required to perform NFS lock ; see also lock_method sympa.conf parameter', 'mail::DKIM' => 'requiered in order to use Sympa DKIM features, both for signature verification and signature insertion. it should be used event if you do not want your server to add signature !', ); ### main: print "******* Check perl for SYMPA ********\n"; ### REQ perl version print "\nChecking for PERL version:\n-----------------------------\n"; my $rpv = $cpan_modules{"perl"}{'required_version'}; if ($] >= $cpan_modules{"perl"}{'required_version'}){ print "your version of perl is OK ($] >= $rpv)\n"; }else { print "Your version of perl is TOO OLD ($] < $rpv)\nPlease INSTALL a new one !\n"; } print "\nChecking for REQUIRED modules:\n------------------------------------------\n"; check_modules('y', \%cpan_modules, 'mandatory'); print "\nChecking for OPTIONAL modules:\n------------------------------------------\n"; check_modules('n', \%cpan_modules, 'optional'); print <{$mod}{mandatory}); }elsif ($type eq 'optional') { next if ($cpan_modules->{$mod}{mandatory}); } ## Skip perl itself to prevent a huge upgrade next if ($mod eq 'perl'); printf ("%-20s %-15s", $mod, $cpan_modules->{$mod}{package_name}); eval "require $mod"; if ($@) { ### not installed print "was not found on this system.\n"; install_module($mod, {'default' => $default}, $cpan_modules); } else { my ($vs, $v); ## MHonArc module does not provide its version the standard way if ($mod =~ /^MHonArc/i) { require "mhamain.pl"; $v = $mhonarc::VERSION; }else { $vs = "$mod" . "::VERSION"; $v; { no strict 'refs'; $v = $$vs; } } my $rv = $cpan_modules->{$mod}{required_version} || "1.0" ; ### OK: check version if ($v ge $rv) { printf ("OK (%-6s >= %s)\n", $v, $rv); next; } else { print "version is too old ($v < $rv).\n"; print ">>>>>>> You must update \"$cpan_modules->{$mod}{package_name}\" to version \"$cpan_modules->{$mod}{required_version}}\" <<<<<<.\n"; install_module($mod, {'default' => $default}, $cpan_modules); } } } } ##---------------------- # Install a CPAN module ##---------------------- sub install_module { # my ($module, $options, $opt_features) = @_; my ($module, $options, $cpan_modules) = @_; my $default = $options->{'default'}; unless ($ENV{'FTP_PASSIVE'} eq 1) { $ENV{'FTP_PASSIVE'} = 1; print "Setting FTP Passive mode\n"; } ## This is required on RedHat 9 for DBD::mysql installation my $lang = $ENV{'LANG'}; $ENV{'LANG'} = 'C' if ($ENV{'LANG'} =~ /UTF\-8/); unless ($EUID == 0) { print "\#\# You need root privileges to install $module module. \#\#\n"; print "\#\# Press the Enter key to continue checking modules. \#\#\n"; my $t = ; return undef; } unless ($options->{'force'}) { printf "-> Usage of this module: %s\n", $cpan_modules->{$module}{usage} if ($cpan_modules->{$module}{usage}); printf "-> Prerequisites: %s\n", $cpan_modules->{$module}{prerequisites} if ($cpan_modules->{$module}{prerequisites}); printf "-> Install module $module ? [$default]"; my $answer = ; chomp $answer; $answer ||= $default; return unless ($answer =~ /^y$/i); } $CPAN::Config->{'inactivity_timeout'} = 0; ## disable timeout to prevent timeout during modules installation $CPAN::Config->{'colorize_output'} = 1; $CPAN::Config->{'build_requires_install_policy'} = 'yes'; ## automatically installed prerequisites without asking $CPAN::Config->{'prerequisites_policy'} = 'follow'; ## build prerequisites automatically $CPAN::Config->{'load_module_verbosity'} = 'none'; ## minimum verbosity during module loading $CPAN::Config->{'tar_verbosity'} = 'none'; ## minimum verbosity with tar command #CPAN::Shell->clean($module) if ($options->{'force'}); CPAN::Shell->make($module); if ($options->{'force'}) { CPAN::Shell->force('test', $module); }else { CPAN::Shell->test($module); } CPAN::Shell->install($module); ## Could use CPAN::Shell->force('install') if make test failed ## Check if module has been successfuly installed unless (eval "require $module") { ## Prevent recusive calls if already in force mode if ($options->{'force'}) { print "Installation of $module still FAILED. You should download the tar.gz from http://search.cpan.org and install it manually."; my $answer = ; }else { print "Installation of $module FAILED. Do you want to force the installation of this module? (y/N) "; my $answer = ; chomp $answer; if ($answer =~ /^y/i) { install_module($module, {'force' => 1}, $cpan_modules); } } } ## Restore lang $ENV{'LANG'} = $lang if (defined $lang); }