1#!--PERL--
2# -*- indent-tabs-mode: nil; -*-
3# vim:ft=perl:et:sw=4
4# $Id$
5
6# Sympa - SYsteme de Multi-Postage Automatique
7#
8# Copyright (c) 1997, 1998, 1999 Institut Pasteur & Christophe Wolfhugel
9# Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
10# 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites
11# Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017 GIP RENATER
12# Copyright 2018 The Sympa Community. See the AUTHORS.md file at the
13# top-level directory of this distribution and at
14# <https://github.com/sympa-community/sympa.git>.
15#
16# This program is free software; you can redistribute it and/or modify
17# it under the terms of the GNU General Public License as published by
18# the Free Software Foundation; either version 2 of the License, or
19# (at your option) any later version.
20#
21# This program is distributed in the hope that it will be useful,
22# but WITHOUT ANY WARRANTY; without even the implied warranty of
23# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24# GNU General Public License for more details.
25#
26# You should have received a copy of the GNU General Public License
27# along with this program.  If not, see <http://www.gnu.org/licenses/>.
28
29use lib '--modulesdir--';
30use strict;
31use warnings;
32use Encode qw();
33use English qw(-no_match_vars);
34use Getopt::Long;
35use Pod::Usage;
36use Sys::Hostname qw();
37
38use Sympa::ConfDef;
39use Sympa::Constants;
40
41my $with_CPAN;    # check if module "CPAN" installed.
42my $modfail;      # any of required modules are not installed.
43
44BEGIN {
45    $with_CPAN = eval { require CPAN; };
46    $modfail = !eval {
47        require Conf;
48        require Sympa::Language;
49        require Sympa::Tools::Text;
50    };
51}
52
53# Detect console encoding.
54if (-t) {
55    no warnings;
56
57    eval { require Encode::Locale; };
58    unless ($EVAL_ERROR
59        or Encode::resolve_alias($Encode::Locale::ENCODING_CONSOLE_IN) eq
60        'ascii'
61        or Encode::resolve_alias($Encode::Locale::ENCODING_CONSOLE_OUT) eq
62        'ascii') {
63        binmode(STDIN,  ':encoding(console_in):bytes');
64        binmode(STDOUT, ':encoding(console_out):bytes');
65        binmode(STDERR, ':encoding(console_out):bytes');
66    }
67}
68
69# Set language context if possible.
70if ($modfail) {
71    no warnings;
72
73    *gettext = sub { $_[1] ? sprintf('%*s', $_[1], $_[0]) : $_[0] };
74
75    eval { require Text::Wrap; };
76    if ($EVAL_ERROR) {
77        *Sympa::Tools::Text::wrap_text = sub {"$_[1]$_[0]\n"};
78    } else {
79        $Text::Wrap::columns = 78;
80        *Sympa::Tools::Text::wrap_text =
81            sub { Text::Wrap::wrap($_[1], $_[2], $_[0]) . "\n"; };
82    }
83} else {
84    no warnings;
85
86    my $language = Sympa::Language->instance;
87    *gettext = sub {
88        $_[1]
89            ? Sympa::Tools::Text::pad($language->gettext($_[0]), $_[1])
90            : $language->gettext($_[0]);
91    };
92
93    my $lang = $ENV{'LANGUAGE'} || $ENV{'LC_ALL'} || $ENV{'LANG'};
94    $lang =~ s/\..*// if $lang;
95    $language->set_lang($lang, 'en-US', 'en');
96}
97
98## sympa configuration file
99my $sympa_conf = Sympa::Constants::CONFIG;
100
101my %options;
102GetOptions(
103    \%options,
104    'target=s',
105    'create:s',    # parameter is optional and only "sympa.conf" is allowed.
106    'batch',
107    'display',
108    'check',
109    'help|h',
110    'version|v',
111);
112
113if ($options{help}) {
114    pod2usage();
115} elsif ($options{'version'}) {
116    printf "Sympa %s\n", Sympa::Constants::VERSION;
117    exit 0;
118} elsif (defined $options{create}) {
119    create_configuration();
120} elsif ($options{display}) {
121    display_configuration();
122} elsif ($options{check}) {
123    check_cpan();
124} else {
125    my %user_param;
126    foreach my $arg (@ARGV) {
127        # check for key/values settings
128        if ($arg =~ /\A(\w+)=(.+)/) {
129            $user_param{$1} = $2;
130        } else {
131            die "$0: Invalid commandline argument: $arg\n";
132        }
133    }
134    edit_configuration(%user_param);
135}
136
137exit 0;
138
139sub create_configuration {
140    my $conf;
141    if ($options{create} eq '' or $options{create} eq 'sympa.conf') {
142        $conf = $options{target} ? $options{target} : $sympa_conf;
143    } else {
144        pod2usage("$options{create} is not a valid argument");
145        exit 1;
146    }
147
148    if (-f $conf) {
149        print STDERR "$conf file already exists, exiting\n";
150        exit 1;
151    }
152
153    my $umask = umask 037;
154    unless (open NEWF, '>', $conf) {
155        umask $umask;
156        die "$0: "
157            . sprintf(gettext("Unable to open %s : %s"), $conf, $ERRNO)
158            . "\n";
159    }
160    umask $umask;
161
162    if ($options{create} eq 'sympa.conf') {
163#        print NEWF <<EOF
164## Configuration file for Sympa
165## many parameters are optional
166## refer to the documentation for a detailed list of parameters
167
168#EOF
169    }
170
171    my $title;
172    foreach my $param (@Sympa::ConfDef::params) {
173        next if $param->{obsolete};
174
175        unless ($param->{'name'}) {
176            $title = gettext($param->{'gettext_id'})
177                if $param->{'gettext_id'};
178            next;
179        }
180
181        next unless $param->{'file'};
182        ##next unless defined $param->{'default'} or defined $param->{'sample'};
183
184        if ($title) {
185            printf NEWF "###\\\\\\\\ %s ////###\n\n", $title;
186            undef $title;
187        }
188
189        printf NEWF "## %s\n", $param->{'name'};
190
191        if ($param->{'gettext_id'}) {
192            print NEWF Sympa::Tools::Text::wrap_text(
193                gettext($param->{'gettext_id'}),
194                '## ', '## ');
195        }
196
197        print NEWF Sympa::Tools::Text::wrap_text(
198            gettext($param->{'gettext_comment'}),
199            '## ', '## ')
200            if $param->{'gettext_comment'};
201
202        if (defined $param->{'sample'}) {
203            printf NEWF '## ' . gettext('Example: ') . "%s\t%s\n",
204                $param->{'name'}, $param->{'sample'};
205        }
206
207        if (defined $param->{'default'}) {
208            printf NEWF "#%s\t%s\n", $param->{'name'}, $param->{'default'};
209        } elsif ($param->{'optional'}) {
210            printf NEWF "#%s\t\n", $param->{'name'};
211        } else {
212            printf NEWF "#%s\t%s\n", $param->{'name'},
213                gettext("(You must define this parameter)");
214        }
215        print NEWF "\n";
216    }
217
218    close NEWF;
219    print STDERR "$conf file has been created\n";
220}
221
222sub display_configuration {
223    die "$0: You must run as superuser.\n"
224        if $UID;
225    die "$0: Installation of Sympa has not been completed.\n"
226        . "Run sympa_wizard.pl --check\n"
227        if $modfail;
228
229    # Load sympa config (but not using database)
230    unless (defined Conf::load($sympa_conf, 1)) {
231        printf STDERR
232            "$0: Unable to load sympa configuration, file %s or one of the virtual host robot.conf files contain errors. Exiting.\n",
233            $sympa_conf;
234        exit 1;
235    }
236
237    my ($var, $disp);
238
239    print "[SYMPA]\n";
240    foreach my $key (sort keys %Conf::Conf) {
241        next
242            if grep { $key eq $_ }
243            qw(auth_services blocklist cas_number crawlers_detection
244            generic_sso_number ldap ldap_number listmasters
245            locale2charset nrcpt_by_domain robot_by_http_host request
246            robot_name robots source_file sympa trusted_applications
247            use_passwd);
248
249        $var = $Conf::Conf{$key};
250
251        if ($key eq 'automatic_list_families') {
252            $disp = join ';', map {
253                my $name = $_;
254                join ':', map { sprintf '%s=%s', $_, $var->{$name}{$_} }
255                    grep { !/\Aescaped_/ }
256                    sort keys %{$var->{$name} || {}};
257            } sort keys %{$var || {}};
258        } elsif (ref $var eq 'ARRAY') {
259            $disp = join(',', map { defined $_ ? $_ : '' } @$var);
260        } else {
261            $disp = defined $var ? $var : '';
262        }
263
264        printf "%s=\"%s\"\n", $key, $disp;
265    }
266}
267
268sub edit_configuration {
269    my %user_param = @_;
270
271    die "$0: You must run as superuser.\n"
272        if $UID;
273    die "$0: Installation of Sympa has not been completed.\n"
274        . "Run sympa_wizard.pl --check\n"
275        if $modfail;
276
277    # complement required fields.
278    foreach my $param (@Sympa::ConfDef::params) {
279        next if $param->{obsolete};
280        next unless $param->{'name'};
281        if ($param->{'name'} eq 'domain') {
282            $param->{'default'} = Sys::Hostname::hostname();
283        } elsif ($param->{'name'} eq 'wwsympa_url') {
284            $param->{'default'} = sprintf 'http://%s/sympa',
285                Sys::Hostname::hostname();
286        } elsif ($param->{'name'} eq 'listmaster') {
287            $param->{'default'} = sprintf 'your_email_address@%s',
288                Sys::Hostname::hostname();
289        }
290    }
291
292    ## Load sympa config (but not using database)
293    unless (defined Conf::load($sympa_conf, 1)) {
294        printf STDERR
295            "$0: Unable to load sympa configuration, file %s or one of the virtual host robot.conf files contain errors. Exiting.\n",
296            $sympa_conf;
297        exit 1;
298    }
299
300    my $somechange = 0;
301
302    my @new_sympa_conf;
303    my $title = undef;
304
305    # dynamic defaults
306    my $domain    = Sys::Hostname::hostname();
307    my $http_host = "http://$domain";
308
309    ## Edition mode
310    foreach my $param (@Sympa::ConfDef::params) {
311        next if $param->{obsolete};
312
313        unless ($param->{'name'}) {
314            $title = gettext($param->{'gettext_id'})
315                if $param->{'gettext_id'};
316            next;
317        }
318
319        my $file  = $param->{'file'};
320        my $name  = $param->{'name'};
321        my $query = $param->{'gettext_id'} || '';
322        $query = gettext($query) if $query;
323        my $advice = $param->{'gettext_comment'};
324        $advice = gettext($advice) if $advice;
325        my $sample = $param->{'sample'};
326        my $current_value;
327
328        next unless $file;
329        if ($file eq 'sympa.conf' or $file eq 'wwsympa.conf') {
330            $current_value = $Conf::Conf{$name};
331            $current_value = '' unless defined $current_value;
332        } else {
333            next;
334        }
335
336        if ($title) {
337            ## write to conf file
338            push @new_sympa_conf,
339                sprintf "###\\\\\\\\ %s ////###\n\n", $title;
340        }
341
342        my $new_value = '';
343        if ($options{batch}) {
344            if (exists $user_param{$name}) {
345                $new_value = $user_param{$name};
346            }
347        } elsif ($param->{'edit'} and $param->{'edit'} eq '1') {
348            print "\n\n** $title **\n" if $title;
349
350            print "\n";
351            print Sympa::Tools::Text::wrap_text($query || '', '* ', '  ');
352            print Sympa::Tools::Text::wrap_text($advice, '  ... ', '  ')
353                if $advice;
354            printf(gettext('%s [%s] : '), $name, $current_value);
355            $new_value = <STDIN>;
356            chomp $new_value;
357        }
358        if ($new_value eq '') {
359            $new_value = $current_value;
360        }
361
362        undef $title;
363
364        ## Skip empty parameters
365        next if $new_value eq '' and !$sample;
366
367        ## param is an ARRAY
368        if (ref($new_value) eq 'ARRAY') {
369            $new_value = join ',', @{$new_value};
370        }
371
372        unless ($file eq 'sympa.conf' or $file eq 'wwsympa.conf') {
373            printf STDERR gettext("Incorrect parameter definition: %s\n"),
374                $file;
375        }
376
377        if ($new_value eq '') {
378            next unless $sample;
379
380            push @new_sympa_conf,
381                Sympa::Tools::Text::wrap_text($query, '## ', '## ');
382
383            if (defined $advice and length $advice) {
384                push @new_sympa_conf,
385                    Sympa::Tools::Text::wrap_text($advice, '## ', '## ');
386            }
387
388            push @new_sympa_conf, "# $name\t$sample\n\n";
389        } else {
390            push @new_sympa_conf,
391                Sympa::Tools::Text::wrap_text($query, '## ', '## ');
392            if (defined $advice and length $advice) {
393                push @new_sympa_conf,
394                    Sympa::Tools::Text::wrap_text($advice, '## ', '## ');
395            }
396
397            if ($current_value ne $new_value) {
398                push @new_sympa_conf, "# was $name $current_value\n";
399                $somechange = 1;
400            }
401
402            push @new_sympa_conf, "$name\t$new_value\n\n";
403        }
404    }
405
406    if ($somechange) {
407        my @time = localtime time;
408        my $date = sprintf '%d%02d%02d%02d%02d%02d',
409            $time[5] + 1900, $time[4] + 1, @time[3, 2, 1, 0];
410
411        ## Keep old config file
412        unless (rename $sympa_conf, $sympa_conf . '.' . $date) {
413            warn sprintf(gettext("Unable to rename %s : %s"),
414                $sympa_conf, $ERRNO);
415        }
416
417        ## Write new config file
418        my $umask = umask 037;
419        unless (open(SYMPA, "> $sympa_conf")) {
420            umask $umask;
421            die "$0: "
422                . sprintf(gettext("Unable to open %s : %s"),
423                $sympa_conf, $ERRNO)
424                . "\n";
425        }
426        umask $umask;
427        chown [getpwnam(Sympa::Constants::USER)]->[2],
428            [getgrnam(Sympa::Constants::GROUP)]->[2], $sympa_conf;
429
430        print SYMPA @new_sympa_conf;
431        close SYMPA;
432
433        printf gettext(
434            "%s have been updated.\nPrevious versions have been saved as %s.\n"
435        ), $sympa_conf, "$sympa_conf.$date";
436    }
437}
438
439sub check_cpan {
440    my %cpan_modules = CPANFile::load() or die;
441
442    print gettext(
443        "##############################################################################
444# This process will help you install all Perl (CPAN) modules required by Sympa
445# software.
446# Sympa requires from 50 to 65 additional Perl modules to run properly.
447# The whole installation process should take around 15 minutes.
448# You'll first have to configure the CPAN shell itself and select your
449# favourite CPAN server.
450# Note that you might prefer to install the required Perl modules using your
451# favourite DEB/RPM mechanism.
452# Feel free to interrupt the process if needed ; you can restart it safely
453# afterward.
454##############################################################################
455Press the Enter key to continue..."
456    ) . "\n";
457    my $rep = <STDIN>;
458
459    print "\n";
460
461    # Choose default DBD module if it has not been defined.
462    my $db_type;
463    if (open my $fh, '<', $sympa_conf) {
464        foreach my $line (<$fh>) {
465            if ($line =~ /\Adb_type\s+(\S*)/) {
466                $db_type = $1;
467            }
468        }
469        close $fh;
470    }
471    if ($db_type
472        and exists $cpan_modules{'DBD::' . $db_type}) {
473        $cpan_modules{'DBD::' . $db_type}->{mandatory} = 1;
474    } else {
475        my @dbd = (
476            'MySQL/MariaDB' => 'DBD::mysql',
477            'PostgreSQL'    => 'DBD::Pg',
478            'SQLite'        => 'DBD::SQLite',
479            'Oracle'        => 'DBD::Oracle',
480        );
481        my $selected;
482        while (1) {
483            print "\n"
484                . gettext('Which RDBMS will you use for core database:')
485                . "\n";
486            for (my $i = 0; $i < scalar @dbd; $i += 2) {
487                printf "%d: %s\n", $i / 2 + 1, $dbd[$i];
488            }
489            printf gettext('-> Select RDBMS [1-%d] '), scalar @dbd / 2;
490            $selected = <STDIN>;
491            chomp $selected;
492            last
493                if $selected =~ /\A\d+\z/
494                and 0 < $selected
495                and $selected * 2 <= scalar @dbd;
496        }
497        $cpan_modules{$dbd[$selected * 2 - 1]}->{mandatory} = 1;
498    }
499
500    ### REQ perl version
501    print "\n" . gettext('Checking for PERL version:') . "\n\n";
502    # Compat. for perl < 5.10: $^V is not an object but a vector of integers.
503    my $rpv = eval 'v' . $cpan_modules{"perl"}{'required_version'} or die $@;
504    if ($^V ge $rpv) {
505        printf gettext('Your version of perl is OK (%s  >= %s)') . "\n", $],
506            $cpan_modules{"perl"}{'required_version'};
507    } else {
508        printf gettext(
509            "Your version of perl is TOO OLD (%s  < %s)\nPlease INSTALL a new one !"
510        ) . "\n", $], $cpan_modules{"perl"}{'required_version'};
511    }
512
513    print "\n" . gettext('Checking for REQUIRED modules:') . "\n\n";
514    check_modules('y', \%cpan_modules, 'mandatory');
515    print "\n" . gettext('Checking for OPTIONAL modules:') . "\n\n";
516    check_modules('n', \%cpan_modules, 'optional');
517
518    print gettext(
519        "******* NOTE *******
520You can retrieve all theses modules from any CPAN server
521(for example ftp://ftp.pasteur.fr/pub/computing/CPAN/CPAN.html)"
522    ) . "\n";
523###--------------------------
524# reports modules status
525# $cpan_modules is the cpan_modules structure
526# $type is the type of modules (mandatory | optional) that should be installed
527###--------------------------
528}
529
530sub check_modules {
531#    my($default, $todo, $versions, $opt_features) = @_;
532    my ($default, $cpan_modules, $type) = @_;
533
534    printf "%s%s\n", gettext('perl module', -32), gettext('STATUS');
535    printf "%-32s%s\n", gettext('-----------'), gettext('------');
536
537    foreach my $mod (sort keys %$cpan_modules) {
538
539        ## Only check modules of the expected type
540        if ($type eq 'mandatory') {
541            next unless ($cpan_modules->{$mod}{mandatory});
542        } elsif ($type eq 'optional') {
543            next if ($cpan_modules->{$mod}{mandatory});
544        }
545
546        ## Skip perl itself to prevent a huge upgrade
547        next if ($mod eq 'perl');
548
549        printf "%-32s", $mod;
550
551        eval "require $mod";
552        if ($EVAL_ERROR) {
553            ### not installed
554            print gettext('was not found on this system.') . "\n";
555            install_module($mod, {'default' => $default}, $cpan_modules);
556        } else {
557            my ($vs, $v);
558            $vs = "$mod" . "::VERSION";
559            {
560                no strict 'refs';
561                $v = $$vs;
562            }
563
564            my $rv = $cpan_modules->{$mod}{required_version} || "1.0";
565            ### OK: check version
566            if ($v ge $rv) {
567                printf gettext('OK (%-6s >= %s)') . "\n", $v, $rv;
568                next;
569            } else {
570                printf gettext('version is too old (%s < %s)') . "\n", $v,
571                    $rv;
572                printf gettext(
573                    '>>>>>>> You must update "%s" to version "%s" <<<<<<.')
574                    . "\n", $mod,
575                    $cpan_modules->{$mod}{required_version};
576                install_module($mod, {'default' => $default}, $cpan_modules);
577            }
578        }
579    }
580}
581
582##----------------------
583# Install a CPAN module
584##----------------------
585sub install_module {
586    return unless $with_CPAN;
587
588    my ($module, $options, $cpan_modules) = @_;
589
590    my $default = $options->{'default'};
591
592    unless ($ENV{'FTP_PASSIVE'} and $ENV{'FTP_PASSIVE'} eq 1) {
593        $ENV{'FTP_PASSIVE'} = 1;
594        print "Setting FTP Passive mode\n";
595    }
596
597    # This is required on RedHat 9 for DBD::mysql installation
598    my $lang;
599    if ($ENV{'LANG'} and $ENV{'LANG'} =~ /UTF-8/) {
600        $lang = $ENV{'LANG'};
601        $ENV{'LANG'} = 'C';
602    }
603
604    unless ($EUID == 0) {
605        printf gettext('## You need root privileges to install %s module. ##')
606            . "\n", $module;
607        print gettext(
608            '## Press the Enter key to continue checking modules. ##')
609            . "\n";
610        my $t = <STDIN>;
611        return undef;
612    }
613
614    unless ($options->{'force'}) {
615        print Sympa::Tools::Text::wrap_text(
616            sprintf(
617                gettext('-> Usage of this module: %s') . "\n",
618                gettext($cpan_modules->{$module}{'gettext_id'})
619            ),
620            '', '   '
621        ) if ($cpan_modules->{$module}{'gettext_id'});
622        print Sympa::Tools::Text::wrap_text(
623            sprintf(
624                gettext('-> Prerequisites: %s') . "\n",
625                gettext($cpan_modules->{$module}{'gettext_comment'})
626            ),
627            '', '   '
628        ) if ($cpan_modules->{$module}{'gettext_comment'});
629        printf gettext('-> Install module %s ? [%s] '), $module, $default;
630        my $answer = <STDIN>;
631        chomp $answer;
632        $answer ||= $default;
633        return unless ($answer =~ /^y$/i);
634    }
635
636    $CPAN::Config->{'inactivity_timeout'} =
637        0;   ## disable timeout to prevent timeout during modules installation
638    $CPAN::Config->{'colorize_output'} = 1;
639    $CPAN::Config->{'build_requires_install_policy'} =
640        'yes';    ## automatically installed prerequisites without asking
641    $CPAN::Config->{'prerequisites_policy'} =
642        'follow';    ## build prerequisites automatically
643    $CPAN::Config->{'load_module_verbosity'} =
644        'none';      ## minimum verbosity during module loading
645    $CPAN::Config->{'tar_verbosity'} =
646        'none';      ## minimum verbosity with tar command
647
648    # CPAN::Shell->clean($module) if ($options->{'force'});
649
650    # CPAN::Shell->make($module);
651    # if ($options->{'force'}) {
652    #     CPAN::Shell->force('test', $module);
653    # } else {
654    #     CPAN::Shell->test($module);
655    # }
656    # # Could use CPAN::Shell->force('install') if make test failed
657    CPAN::Shell->install($module);
658
659    ## Check if module has been successfuly installed
660    unless (eval "require $module") {
661
662        ## Prevent recusive calls if already in force mode
663        if ($options->{'force'}) {
664            printf gettext(
665                "Installation of %s still FAILED. You should download the tar.gz from http://search.cpan.org and install it manually."
666            ), $module;
667            my $answer = <STDIN>;
668        } else {
669            printf gettext(
670                'Installation of %s FAILED. Do you want to force the installation of this module? (y/N) '
671            ), $module;
672            my $answer = <STDIN>;
673            chomp $answer;
674            if ($answer =~ /^y/i) {
675                install_module($module, {'force' => 1}, $cpan_modules);
676            }
677        }
678    }
679
680    # Restore lang
681    $ENV{'LANG'} = $lang if $lang;
682}
683
684package CPANFile;
685
686use lib '--modulesdir--';
687use strict;
688use warnings;
689
690our $description;
691our $is_optional;
692my %cpan_modules;
693
694sub feature {
695    shift;
696    local $description = shift;
697    local $is_optional = 1;
698    shift->();
699}
700
701sub on {
702    return unless shift eq 'runtime';
703    shift->();
704}
705
706sub recommends {
707    local $is_optional = 1;
708    _depends(@_);
709}
710
711sub requires {
712    _depends(@_);
713}
714
715sub load {
716    do 'cpanfile';
717    %cpan_modules;
718}
719
720sub _depends {
721    my $module = shift;
722    my $verreq = shift || '0';
723    $verreq = [grep { !/[!<]/ } split /\s*,\s*/, $verreq]->[0];
724    $verreq =~ s/\A[\s=>]+//;
725    $cpan_modules{$module} = {
726        required_version => $verreq,
727        ($is_optional ? () : (mandatory => 1)),
728        ($description ? (gettext_id => $description) : ()),
729    };
730}
731
7321;
733__END__
734
735=encoding utf-8
736
737=head1 NAME
738
739sympa_wizard, sympa_wizard.pl - Help Performing Sympa Initial Setup
740
741=head1 SYNOPSIS
742
743C<sympa_wizard.pl>
744S<[ C<--batch> [ I<key>=I<value> ... ] ]>
745S<[ C<--check> ]>
746S<[ C<--create> [ C<--target=>I<file> ] ]>
747S<[ C<--display> ]>
748S<[ C<-h, --help> ]>
749S<[ C<-v, --version> ]>
750
751=head1 OPTIONS
752
753=over 4
754
755=item C<sympa_wizard.pl>
756
757Edit current Sympa configuration.
758
759=item C<sympa_wizard.pl> C<--batch> I<key>=I<value> ...
760
761Edit in batch mode.
762Arguments would include pairs of parameter name and value.
763
764=item C<sympa_wizard.pl> C<--check>
765
766Check CPAN modules needed for running Sympa.
767
768=item C<sympa_wizard.pl> C<--create> [ C<--target> I<file> ]
769
770Creates a new F<sympa.conf> configuration file.
771
772=item C<sympa_wizard.pl> C<--display>
773
774Outputs all configuration parameters.
775
776=item C<sympa_wizard.pl> C<--help>
777
778Display usage instructions.
779
780=item C<sympa_wizard.pl> C<--version>
781
782Print version number.
783
784=back
785
786=head1 HISTORY
787
788This program was originally written by:
789
790=over 4
791
792=item Serge Aumont <sa@cru.fr>
793
794=item Olivier SalaE<252>n <os@cru.fr>
795
796=back
797
798C<--batch> and C<--display> options are added on Sympa 6.1.25 and 6.2.15.
799
800=cut
801