Admin.pm 56.1 KB
Newer Older
1
2
3
4
# -*- indent-tabs-mode: nil; -*-
# vim:ft=perl:et:sw=4
# $Id$

5
# Sympa - SYsteme de Multi-Postage Automatique
6
7
8
9
#
# Copyright (c) 1997, 1998, 1999 Institut Pasteur & Christophe Wolfhugel
# Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
# 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites
10
# Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017 GIP RENATER
11
# Copyright 2017 The Sympa Community. See the AUTHORS.md file at the top-level
12
13
# directory of this distribution and at
# <https://github.com/sympa-community/sympa.git>.
14
15
16
17
18
19
20
21
22
23
24
25
#
# 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
26
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
27

28
=encoding utf-8
29

30
31
32
#=head1 NAME 
#
#I<admin.pm> - This module includes administrative function for the lists.
33
34
35
36
37
38
39

=head1 DESCRIPTION 

Central module for creating and editing lists.

=cut 

40
package Sympa::Admin;
41
42

use strict;
43
use warnings;
sikeda's avatar
sikeda committed
44
use Encode qw();
45
use English qw(-no_match_vars);
46
use File::Copy qw();
47

48
use Sympa;
49
use Conf;
50
use Sympa::Constants;
51
use Sympa::DatabaseManager;
52
use Sympa::Language;
53
use Sympa::List;
sikeda's avatar
sikeda committed
54
use Sympa::LockedFile;
55
use Sympa::Log;
56
use Sympa::Regexps;
57
58
use Sympa::Robot;
use Sympa::Scenario;
59
use Sympa::Template;
60
use Sympa::Tools::File;
sikeda's avatar
sikeda committed
61
use Sympa::User;
62

63
my $language = Sympa::Language->instance;
64
my $log      = Sympa::Log->instance;
65

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
=head1 SUBFUNCTIONS 

This is the description of the subfunctions contained by admin.pm 

=cut 

=pod 

=head2 sub create_list_old(HASHRef,STRING,STRING)

Creates a list. Used by the create_list() sub in sympa.pl and the do_create_list() sub in wwsympa.fcgi.

=head3 Arguments 

=over 

=item * I<$param>, a ref on a hash containing parameters of the config list. The following keys are mandatory:

=over 4

=item - I<$param-E<gt>{'listname'}>,

=item - I<$param-E<gt>{'subject'}>,

=item - I<$param-E<gt>{'owner'}>, (or owner_include): array of hashes, with key email mandatory

=item - I<$param-E<gt>{'owner_include'}>, array of hashes, with key source mandatory

=back

96
=item * I<$list_tpl>, a string containing the list creation template
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121

=item * I<$robot>, a string containing the name of the robot the list will be hosted by.

=back 

=head3 Return 

=over 

=item * I<undef>, if something prevents the list creation

=item * I<a reference to a hash>, if the list is normally created. This hash contains two keys:

=over 4

=item - I<list>, the list object corresponding to the list just created

=item - I<aliases>, undef if not applicable; 1 (if ok) or $aliases : concatenated string of aliases if they are not installed or 1 (in status open)

=back

=back 

=cut 

122
########################################################
123
124
125
# create_list_old
########################################################
# Create a list : used by sympa.pl--create_list and
126
127
#                 wwsympa.fcgi--do_create_list
# without family concept
128
#
129
130
131
132
# IN  : - $param : ref on parameters of the config list
#         with obligatory :
#         $param->{'listname'}
#         $param->{'subject'}
133
#         $param->{'owner'} (or owner_include):
134
135
136
#          array of hash,with key email obligatory
#         $param->{'owner_include'} array of hash :
#              with key source obligatory
137
#       - $list_tpl : the create list template
138
139
#       - $robot : the list's robot
#       - $origin : the source of the command : web, soap or command_line
140
#              no longer used
141
142
# OUT : - hash with keys :
#          -list :$list
143
#          -aliases : undef if not applicable; 1 (if ok) or
144
#           $aliases : concated string of alias if they
145
146
#           are not installed or 1(in status open)
#######################################################
147
sub create_list_old {
148
    my ($param, $list_tpl, $robot, $origin, $user_mail) = @_;
149
    $log->syslog('debug', '(%s, %s)', $param->{'listname'}, $robot, $origin);
150
151
152
153

    ## obligatory list parameters
    foreach my $arg ('listname', 'subject') {
        unless ($param->{$arg}) {
154
            $log->syslog('err', 'Missing list param %s', $arg);
155
156
            return undef;
        }
157
    }
158
    # owner.email || owner_include.source
159
160
    unless (check_owner_defined($param->{'owner'}, $param->{'owner_include'}))
    {
161
        $log->syslog('err',
162
            'Problem in owner definition in this list creation');
163
        return undef;
164
    }
165
166

    # template
167
    unless ($list_tpl) {
168
        $log->syslog('err', 'Missing param "template"', $list_tpl);
169
        return undef;
170
    }
171
172
    # robot
    unless ($robot) {
173
        $log->syslog('err', 'Missing param "robot"', $robot);
174
        return undef;
175
    }
176

177
    ## check listname
178
    $param->{'listname'} = lc($param->{'listname'});
179
    my $listname_regexp = Sympa::Regexps::listname();
180

181
182
    unless ($param->{'listname'} =~ /^$listname_regexp$/i
        and length $param->{'listname'} <= Sympa::Constants::LIST_LEN()) {
183
        $log->syslog('err', 'Incorrect listname %s', $param->{'listname'});
184
        return undef;
185
186
    }

187
188
189
    my $regx = Conf::get_robot_conf($robot, 'list_check_regexp');
    if ($regx) {
        if ($param->{'listname'} =~ /^(\S+)-($regx)$/) {
190
            $log->syslog('err',
191
192
                'Incorrect listname %s matches one of service aliases',
                $param->{'listname'});
193
194
195
            return undef;
        }
    }
196

197
198
199
    if (   $param->{'listname'} eq Conf::get_robot_conf($robot, 'email')
        or $param->{'listname'} eq
        Conf::get_robot_conf($robot, 'listmaster_email')) {
200
        $log->syslog('err',
201
202
            'Incorrect listname %s matches one of service aliases',
            $param->{'listname'});
203
        return undef;
204
205
    }

206
    ## Check listname on SMTP server
sikeda's avatar
sikeda committed
207
    my $res = list_check_smtp($param->{'listname'}, $robot);
208
    unless (defined $res) {
209
        $log->syslog('err', 'Can\'t check list %.128s on %s',
210
211
            $param->{'listname'}, $robot);
        return undef;
212
    }
213

214
    ## Check this listname doesn't exist already.
sikeda's avatar
sikeda committed
215
216
217
    if ($res
        || Sympa::List->new($param->{'listname'}, $robot, {'just_try' => 1}))
    {
218
        $log->syslog('err',
219
220
            'Could not create already existing list %s on %s for',
            $param->{'listname'}, $robot);
221
        foreach my $o (@{$param->{'owner'}}) {
222
            $log->syslog('err', $o->{'email'});
223
224
        }
        return undef;
225
226
    }

227
    ## Check the template supposed to be used exist.
228
    my $template_file = Sympa::search_fullpath($robot, 'config.tt2',
229
        subdir => 'create_list_templates/' . $list_tpl);
230
    unless (defined $template_file) {
231
        $log->syslog('err', 'No template %s found', $list_tpl);
232
233
234
235
236
237
238
239
240
        return undef;
    }

    ## Create the list directory
    my $list_dir;

    # a virtual robot
    if (-d "$Conf::Conf{'home'}/$robot") {
        unless (-d $Conf::Conf{'home'} . '/' . $robot) {
241
            unless (mkdir $Conf::Conf{'home'} . '/' . $robot, 0777) {
242
                $log->syslog('err', 'Unable to create %s/%s: %s',
243
                    $Conf::Conf{'home'}, $robot, $ERRNO);
244
245
246
247
248
249
250
251
                return undef;
            }
        }
        $list_dir =
            $Conf::Conf{'home'} . '/' . $robot . '/' . $param->{'listname'};
    } else {
        $list_dir = $Conf::Conf{'home'} . '/' . $param->{'listname'};
    }
252

253
    ## Check the privileges on the list directory
254
    unless (mkdir $list_dir, 0777) {
255
        $log->syslog('err', 'Unable to create %s: %s', $list_dir, $ERRNO);
256
257
258
        return undef;
    }

259
    ## Check topics
260
261
    if ($param->{'topics'}) {
        unless (check_topics($param->{'topics'}, $robot)) {
262
            $log->syslog('err', 'Topics param %s not defined in topics.conf',
263
                $param->{'topics'});
264
        }
265
    }
266

267
    # Creation of the config file.
268
    $param->{'creation'}{'date_epoch'} = time;
269
270
    $param->{'creation_email'} ||= Sympa::get_address($robot, 'listmaster');
    $param->{'status'} ||= 'open';
271

272
    ## Lock config before openning the config file
273
274
    my $lock_fh = Sympa::LockedFile->new($list_dir . '/config', 5, '>');
    unless ($lock_fh) {
275
        $log->syslog('err', 'Impossible to create %s/config: %m', $list_dir);
276
        return undef;
277
    }
278

279
    my $config = '';
280
281
282
283
    my $template =
        Sympa::Template->new($robot,
        subdir => 'create_list_templates/' . $list_tpl);
    unless ($template->parse($param, 'config.tt2', \$config)) {
284
        $log->syslog(
285
286
            'err',     'Can\'t parse %s/config.tt2: %s',
            $list_tpl, $template->{last_error}
287
288
289
290
        );
        return undef;
    }

291
    print $lock_fh $config;
292

293
    ## Unlock config file
294
    $lock_fh->close;
295

296
297
298
    ## Creation of the info file
    # remove DOS linefeeds (^M) that cause problems with Outlook 98, AOL, and
    # EIMS:
299
    $param->{'description'} =~ s/\r\n|\r/\n/g;
300

301
302
    ## info file creation.
    unless (open INFO, '>', "$list_dir/info") {
303
        $log->syslog('err', 'Impossible to create %s/info: %m', $list_dir);
304
    }
305
    if (defined $param->{'description'}) {
306
307
308
        Encode::from_to($param->{'description'},
            'utf8', $Conf::Conf{'filesystem_encoding'});
        print INFO $param->{'description'};
309
    }
310
    close INFO;
311

312
313
    ## Create list object
    my $list;
314
    unless ($list = Sympa::List->new($param->{'listname'}, $robot)) {
315
        $log->syslog('err', 'Unable to create list %s', $param->{'listname'});
316
        return undef;
317
318
    }

319
320
321
322
    ## Create shared if required.
    #if (defined $list->{'admin'}{'shared_doc'}) {
    #    $list->create_shared();
    #}
323

324
325
    #log in stat_table to make statistics

326
    if ($origin eq "web") {
327
328
329
330
331
332
        $log->add_stat(
            'robot'     => $robot,
            'list'      => $param->{'listname'},
            'operation' => 'create_list',
            'parameter' => '',
            'mail'      => $user_mail
333
        );
334
335
    }

336
337
338
    my $return = {};
    $return->{'list'} = $list;

339
    if ($list->{'admin'}{'status'} eq 'open') {
340
        $return->{'aliases'} = install_aliases($list);
341
342
    } else {
        $return->{'aliases'} = 1;
343
    }
344

345
    ## Synchronize list members if required
346
    if ($list->has_include_data_sources()) {
347
        $log->syslog('notice', "Synchronizing list members...");
348
        $list->sync_include();
349
    }
350

351
    $list->save_config($param->{'creation_email'});
352
    return $return;
353
354
355
}

########################################################
356
357
358
# create_list
########################################################
# Create a list : used by sympa.pl--instantiate_family
359
# with family concept
360
#
361
362
363
364
# IN  : - $param : ref on parameters of the config list
#         with obligatory :
#         $param->{'listname'}
#         $param->{'subject'}
365
#         $param->{'owner'} (or owner_include):
366
367
368
#          array of hash,with key email obligatory
#         $param->{'owner_include'} array of hash :
#              with key source obligatory
369
#       - $family : the family object
370
#       - $robot : the list's robot  ** No longer used.
371
#       - $abort_on_error : won't create the list directory on
372
#          tt2 process error (useful for dynamic lists that
373
#          throw exceptions)
374
375
# OUT : - hash with keys :
#          -list :$list
376
#          -aliases : undef if not applicable; 1 (if ok) or
377
#           $aliases : concated string of alias if they
378
379
#           are not installed or 1(in status open)
#######################################################
380
sub create_list {
sikeda's avatar
sikeda committed
381
    my ($param, $family, $dummy, $abort_on_error) = @_;
382
    $log->syslog('info', '(%s, %s, %s)', $param->{'listname'},
383
        $family->{'name'}, $param->{'subject'});
384

385
    ## mandatory list parameters
386
    foreach my $arg ('listname') {
387
        unless ($param->{$arg}) {
388
            $log->syslog('err', 'Missing list param %s', $arg);
389
390
            return undef;
        }
391
    }
392
393

    unless ($family) {
394
        $log->syslog('err', 'Missing param "family"');
395
        return undef;
396
    }
397
398

    #robot
399
    my $robot = $family->{'robot'};
400
    unless ($robot) {
401
        $log->syslog('err', 'Missing param "robot"');
402
        return undef;
403
    }
404

405
    ## check listname
406
    $param->{'listname'} = lc($param->{'listname'});
407
    my $listname_regexp = Sympa::Regexps::listname();
408

409
410
    unless ($param->{'listname'} =~ /^$listname_regexp$/i
        and length $param->{'listname'} <= Sympa::Constants::LIST_LEN()) {
411
        $log->syslog('err', 'Incorrect listname %s', $param->{'listname'});
412
413
414
415
416
417
        return undef;
    }

    my $regx = Conf::get_robot_conf($robot, 'list_check_regexp');
    if ($regx) {
        if ($param->{'listname'} =~ /^(\S+)-($regx)$/) {
418
            $log->syslog('err',
419
420
                'Incorrect listname %s matches one of service aliases',
                $param->{'listname'});
421
422
423
            return undef;
        }
    }
424
425
426
    if (   $param->{'listname'} eq Conf::get_robot_conf($robot, 'email')
        or $param->{'listname'} eq
        Conf::get_robot_conf($robot, 'listmaster_email')) {
427
        $log->syslog('err',
428
429
            'Incorrect listname %s matches one of service aliases',
            $param->{'listname'});
430
        return undef;
431
    }
432
433

    ## Check listname on SMTP server
sikeda's avatar
sikeda committed
434
    my $res = list_check_smtp($param->{'listname'}, $robot);
435
    unless (defined $res) {
436
        $log->syslog('err', 'Can\'t check list %.128s on %s',
437
438
            $param->{'listname'}, $robot);
        return undef;
439
440
441
    }

    if ($res) {
442
        $log->syslog('err',
443
444
            'Could not create already existing list %s on %s for',
            $param->{'listname'}, $robot);
445
        foreach my $o (@{$param->{'owner'}}) {
446
            $log->syslog('err', $o->{'email'});
447
448
        }
        return undef;
449
450
451
    }

    ## template file
452
    my $template_file = Sympa::search_fullpath($family, 'config.tt2');
453
    unless (defined $template_file) {
454
        $log->syslog('err', 'No config template from family %s@%s',
455
456
            $family->{'name'}, $robot);
        return undef;
457
458
    }

459
460
    my $family_config =
        Conf::get_robot_conf($robot, 'automatic_list_families');
461
    $param->{'family_config'} = $family_config->{$family->{'name'}};
462
    my $conf;
463
464
465
466
    my $template =
        Sympa::Template->new(undef, include_path => [$family->{'dir'}]);
    my $tt_result = $template->parse($param, 'config.tt2', \$conf);
    if (not $tt_result and $abort_on_error) {
467
        $log->syslog(
468
            'err',
469
            'Abort on template error. List %s from family %s@%s, file config.tt2 : %s',
470
471
472
            $param->{'listname'},
            $family->{'name'},
            $robot,
473
            $template->{last_error}
474
        );
475
        return undef;
476
    }
477

478
479
    ## Create the list directory
    my $list_dir;
480

481
    if (-d "$Conf::Conf{'home'}/$robot") {
482
        unless (-d $Conf::Conf{'home'} . '/' . $robot) {
483
            unless (mkdir $Conf::Conf{'home'} . '/' . $robot, 0777) {
484
                $log->syslog('err', 'Unable to create %s/%s: %s',
485
                    $Conf::Conf{'home'}, $robot, $ERRNO);
486
487
488
489
490
491
492
493
494
                return undef;
            }
        }
        $list_dir =
            $Conf::Conf{'home'} . '/' . $robot . '/' . $param->{'listname'};
    } else {
        $list_dir = $Conf::Conf{'home'} . '/' . $param->{'listname'};
    }

495
    unless (-r $list_dir or mkdir($list_dir, 0777)) {
496
        $log->syslog('err', 'Unable to create %s: %s', $list_dir, $ERRNO);
497
498
499
        return undef;
    }

500
    ## Check topics
501
502
    if (defined $param->{'topics'}) {
        unless (check_topics($param->{'topics'}, $robot)) {
503
            $log->syslog('err', 'Topics param %s not defined in topics.conf',
504
                $param->{'topics'});
505
        }
506
    }
507

508
    ## Lock config before openning the config file
509
510
    my $lock_fh = Sympa::LockedFile->new($list_dir . '/config', 5, '>');
    unless ($lock_fh) {
511
        $log->syslog('err', 'Impossible to create %s/config: %m', $list_dir);
512
        return undef;
513
    }
514
515
    print $lock_fh $conf;

516
    ## Unlock config file
517
    $lock_fh->close;
518

519
520
521
    ## Creation of the info file
    # remove DOS linefeeds (^M) that cause problems with Outlook 98, AOL, and
    # EIMS:
522
    if (defined $param->{'description'}) {
523
524
        $param->{'description'} =~ s/\r\n|\r/\n/g;
    }
525
526

    unless (open INFO, '>', "$list_dir/info") {
527
        $log->syslog('err', 'Impossible to create %s/info: %m', $list_dir);
528
529
    }
    if (defined $param->{'description'}) {
530
        print INFO $param->{'description'};
531
    }
532
    close INFO;
533
534

    ## Create associated files if a template was given.
535
    my @files_to_parse;
536
537
538
539
    foreach my $file (split ',',
        Conf::get_robot_conf($robot, 'parsed_family_files')) {
        $file =~ s{\s}{}g;
        push @files_to_parse, $file;
540
541
    }
    for my $file (@files_to_parse) {
542
        my $template_file = Sympa::search_fullpath($family, $file . ".tt2");
543
544
        if (defined $template_file) {
            my $file_content;
545
546
547
548
549
            my $template =
                Sympa::Template->new(undef,
                include_path => [$family->{'dir'}]);
            my $tt_result =
                $template->parse($param, $file . ".tt2", \$file_content);
550
            unless (defined $tt_result) {
551
                $log->syslog(
552
                    'err',
553
                    'Template error. List %s from family %s@%s, file %s : %s',
554
555
556
557
                    $param->{'listname'},
                    $family->{'name'},
                    $robot,
                    $file,
558
                    $template->{last_error}
559
                );
560
561
            }
            unless (open FILE, '>', "$list_dir/$file") {
562
                $log->syslog('err', 'Impossible to create %s/%s: %m',
563
                    $list_dir, $file);
564
565
566
567
            }
            print FILE $file_content;
            close FILE;
        }
568
569
    }

570
571
    ## Create list object
    my $list;
572
    unless ($list = Sympa::List->new($param->{'listname'}, $robot)) {
573
        $log->syslog('err', 'Unable to create list %s', $param->{'listname'});
574
        return undef;
575
576
    }

577
578
579
580
    ## Create shared if required.
    #if (defined $list->{'admin'}{'shared_doc'}) {
    #    $list->create_shared();
    #}
581

582
    $list->{'admin'}{'creation'}{'date_epoch'} = time;
sikeda's avatar
sikeda committed
583
    $list->{'admin'}{'creation'}{'email'}      = $param->{'creation_email'}
584
585
        || Sympa::get_address($robot, 'listmaster');
    $list->{'admin'}{'status'} = $param->{'status'} || 'open';
586
587
588
589
590
591
    $list->{'admin'}{'family_name'} = $family->{'name'};

    my $return = {};
    $return->{'list'} = $list;

    if ($list->{'admin'}{'status'} eq 'open') {
592
        $return->{'aliases'} = install_aliases($list);
593
594
    } else {
        $return->{'aliases'} = 1;
595
    }
596
597
598

    ## Synchronize list members if required
    if ($list->has_include_data_sources()) {
599
        $log->syslog('notice', "Synchronizing list members...");
600
        $list->sync_include();
601
602
    }

603
604
605
606
    return $return;
}

########################################################
607
608
609
# update_list
########################################################
# update a list : used by sympa.pl--instantiate_family
610
# with family concept when the list already exists
611
#
612
# IN  : - $list : the list to update
613
#       - $param : ref on parameters of the new
614
615
616
#          config list with obligatory :
#         $param->{'listname'}
#         $param->{'subject'}
617
#         $param->{'owner'} (or owner_include):
618
619
620
#          array of hash,with key email obligatory
#         $param->{'owner_include'} array of hash :
#              with key source obligatory
621
622
#       - $family : the family object
#       - $robot : the list's robot
623
624
625
#
# OUT : - $list : the updated list or undef
#######################################################
626
627
sub update_list {
    my ($list, $param, $family, $robot) = @_;
628
    $log->syslog('info', '(%s, %s, %s)', $param->{'listname'},
629
        $family->{'name'}, $param->{'subject'});
630

631
632
    ## mandatory list parameters
    foreach my $arg ('listname') {
633
        unless ($param->{$arg}) {
634
            $log->syslog('err', 'Missing list param %s', $arg);
635
636
            return undef;
        }
637
    }
638

639
    ## template file
640
    my $template_file = Sympa::search_fullpath($family, 'config.tt2');
641
    unless (defined $template_file) {
642
        $log->syslog('err', 'No config template from family %s@%s',
643
644
            $family->{'name'}, $robot);
        return undef;
645
646
647
    }

    ## Check topics
648
649
    if (defined $param->{'topics'}) {
        unless (check_topics($param->{'topics'}, $robot)) {
650
            $log->syslog('err', 'Topics param %s not defined in topics.conf',
651
                $param->{'topics'});
652
        }
653
654
    }

655
    ## Lock config before openning the config file
656
657
    my $lock_fh = Sympa::LockedFile->new($list->{'dir'} . '/config', 5, '>');
    unless ($lock_fh) {
658
        $log->syslog('err', 'Impossible to create %s/config: %s',
659
660
661
662
663
664
665
            $list->{'dir'}, $ERRNO);
        return undef;
    }

    my $template =
        Sympa::Template->new(undef, include_path => [$family->{'dir'}]);
    unless ($template->parse($param, 'config.tt2', $lock_fh)) {
666
        $log->syslog('err', 'Can\'t parse %s/config.tt2: %s',
667
            $family->{'dir'}, $template->{last_error});
668
        return undef;
669
    }
670
    ## Unlock config file
671
    $lock_fh->close;
672

673
    ## Create list object
674
    unless ($list = Sympa::List->new($param->{'listname'}, $robot)) {
675
        $log->syslog('err', 'Unable to create list %s', $param->{'listname'});
676
        return undef;
677
    }
678

679
    $list->{'admin'}{'creation'}{'date_epoch'} = time;
sikeda's avatar
sikeda committed
680
    $list->{'admin'}{'creation'}{'email'}      = $param->{'creation_email'}
681
682
        || Sympa::get_address($robot, 'listmaster');
    $list->{'admin'}{'status'} = $param->{'status'} || 'open';
683
684
    $list->{'admin'}{'family_name'} = $family->{'name'};

685
    ## Create associated files if a template was given.
686
    my @files_to_parse;
687
688
689
690
    foreach my $file (split ',',
        Conf::get_robot_conf($robot, 'parsed_family_files')) {
        $file =~ s{\s}{}g;
        push @files_to_parse, $file;
691
692
    }
    for my $file (@files_to_parse) {
693
        my $template_file = Sympa::search_fullpath($family, $file . ".tt2");
694
695
        if (defined $template_file) {
            my $file_content;
696
697
698
699
700
701
702

            my $template =
                Sympa::Template->new(undef,
                include_path => [$family->{'dir'}]);
            my $tt_result =
                $template->parse($param, $file . ".tt2", \$file_content);
            unless ($tt_result) {
703
                $log->syslog(
704
705
706
707
708
709
                    'err',
                    'Template error. List %s from family %s@%s, file %s: %s',
                    $param->{'listname'},
                    $family->{'name'},
                    $robot,
                    $file,
710
                    $template->{last_error}
711
712
                );
                next;    #FIXME: Abort processing and rollback.
713
714
            }
            unless (open FILE, '>', "$list->{'dir'}/$file") {
715
                $log->syslog('err', 'Impossible to create %s/%s: %s',
716
717
718
719
720
                    $list->{'dir'}, $file, $!);
            }
            print FILE $file_content;
            close FILE;
        }
721
722
    }

723
724
    ## Synchronize list members if required
    if ($list->has_include_data_sources()) {
725
        $log->syslog('notice', "Synchronizing list members...");
726
        $list->sync_include();
727
728
    }

729
730
731
    return $list;
}

732
########################################################
733
734
# rename_list
########################################################
735
# Rename a list or move a list to another virtual host
736
#
737
738
739
# IN  : - list
#       - new_listname
#       - new_robot
740
#       - mode  : 'copy'
741
742
743
744
745
#       - auth_method
#       - user_email
#       - remote_host
#       - remote_addr
#       - options : 'skip_authz' to skip authorization scenarios eval
746
#
747
748
749
750
751
752
753
754
755
# OUT via reference :
#       - aliases
#       - status : 'pending'
#
# OUT : - scalar
#           undef  : error
#           1      : success
#           string : error code
#######################################################
756
sub rename_list {
757
    my (%param) = @_;
758
    $log->syslog('info', '',);
759

760
761
    my $list         = $param{'list'};
    my $robot        = $list->{'domain'};
762
763
764
    my $old_listname = $list->{'name'};

    # check new listname syntax
765
    my $new_listname    = lc($param{'new_listname'});
766
    my $listname_regexp = Sympa::Regexps::listname();
767

768
769
    unless ($new_listname =~ /^$listname_regexp$/i
        and length $new_listname <= Sympa::Constants::LIST_LEN()) {
770
        $log->syslog('err', 'Incorrect listname %s', $new_listname);
771
        return 'incorrect_listname';
772
    }
773

sikeda's avatar
sikeda committed
774
775
776
777
    # If list is included by another list, then it cannot be renamed.
    unless ($param{'mode'} and $param{'mode'} eq 'copy') {
        if ($list->is_included) {
            $log->syslog('err',
sikeda's avatar
sikeda committed
778
                'List %s is included by other list: cannot rename it', $list);
sikeda's avatar
sikeda committed
779
780
781
782
            return 'intern';
        }
    }

783
    ## Evaluate authorization scenario unless run as listmaster (sympa.pl)
784
    my ($result, $r_action, $reason);
785
    unless ($param{'options'}{'skip_authz'}) {
786
        $result = Sympa::Scenario::request_action(
787
            $param{'new_robot'},
788
789
790
791
792
793
794
795
796
797
798
799
800
801
            'create_list',
            $param{'auth_method'},
            {   'sender'      => $param{'user_email'},
                'remote_host' => $param{'remote_host'},
                'remote_addr' => $param{'remote_addr'}
            }
        );

        if (ref($result) eq 'HASH') {
            $r_action = $result->{'action'};
            $reason   = $result->{'reason'};
        }

        unless ($r_action =~ /do_it|listmaster/) {
802
            $log->syslog('err', 'Authorization error');
803
804
            return 'authorization';
        }
805
806
807
808
    }

    ## Check listname on SMTP server
    my $res = list_check_smtp($param{'new_listname'}, $param{'new_robot'});
809
    unless (defined($res)) {
810
        $log->syslog('err', 'Can\'t check list %.128s on %.128s',
811
812
813
814
815
816
817
            $param{'new_listname'}, $param{'new_robot'});
        return 'internal';
    }

    if ($res
        || ($list->{'name'} ne $param{'new_listname'})
        &&    ## Do not test if listname did not change
818
        (   Sympa::List->new(
819
820
821
822
823
                $param{'new_listname'}, $param{'new_robot'},
                {'just_try' => 1}
            )
        )
        ) {
824
        $log->syslog(
825
826
827
828
829
830
831
832
833
834
835
836
837
            'err',
            'Could not rename list %s on %s: new list %s on %s already existing list',
            $list->{'name'},
            $robot,
            $param{'new_listname'},
            $param{'new_robot'}
        );
        return 'list_already_exists';
    }

    my $regx = Conf::get_robot_conf($param{'new_robot'}, 'list_check_regexp');
    if ($regx) {
        if ($param{'new_listname'} =~ /^(\S+)-($regx)$/) {
838
            $log->syslog('err',