#! --PERL-- # -*- indent-tabs-mode: nil; -*- # vim:ft=perl:et:sw=4 # $Id$ # Sympa - SYsteme de Multi-Postage Automatique # # 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 # Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017 GIP RENATER # # 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, see . use lib '--modulesdir--'; use strict; use warnings; use English qw(-no_match_vars); use Conf; use Sympa::Constants; use Sympa::DatabaseManager; use Sympa::Language; use Sympa::List; use Sympa::Log; use Sympa::Tools::File; my %options; $OUTPUT_AUTOFLUSH = 1; ## Check UID #unless (getlogin() eq Sympa::Constants::USER) { # print "You should run this script as user \"sympa\", ignore ? (y/CR)"; # my $s = ; # die unless ($s =~ /^y$/i); #} # FIXME: Is logging required? my $log = Sympa::Log->instance; ## Load sympa config unless (Conf::load()) { die 'config_error'; } # Check database connectivity and probe database #FIXME: Is it required? unless (Sympa::DatabaseManager::probe_db()) { die sprintf "Database %s defined in sympa.conf has not the right structure or is unreachable. verify db_xxx parameters in sympa.conf\n", $Conf::Conf{'db_name'}; } ## We have a parameter that should be a template to convert ## Output is sent to stdout if ($#ARGV >= 0) { my $f = $ARGV[0]; unless (-f $f) { die "unable to find file $f"; } convert($f); exit 0; } ## Default is to migrate every template to the new TT2 format my @directories; my @templates; ## Search in main robot if (-d $Conf::Conf{'etc'}) { push @directories, $Conf::Conf{'etc'}; } if (-d "$Conf::Conf{'etc'}/templates") { push @directories, "$Conf::Conf{'etc'}/templates"; } if (-d "$Conf::Conf{'etc'}/wws_templates") { push @directories, "$Conf::Conf{'etc'}/wws_templates"; } if (-f "$Conf::Conf{'etc'}/mhonarc-ressources") { push @templates, "$Conf::Conf{'etc'}/mhonarc-ressources"; } ## Create_list_templates if (-d $Conf::Conf{'etc'} . '/create_list_templates') { foreach my $dir (<$Conf::Conf{'etc'}/create_list_templates/*>) { next unless (-d $dir); push @directories, $dir; } } ## Go through Virtual Robots foreach my $vr (keys %{$Conf::Conf{'robots'}}) { ## Search in etc/ if (-d "$Conf::Conf{'etc'}/$vr") { push @directories, "$Conf::Conf{'etc'}/$vr"; } if (-d "$Conf::Conf{'etc'}/$vr/templates") { push @directories, "$Conf::Conf{'etc'}/$vr/templates"; } if (-d "$Conf::Conf{'etc'}/$vr/wws_templates") { push @directories, "$Conf::Conf{'etc'}/$vr/wws_templates"; } if (-f "$Conf::Conf{'etc'}/$vr/mhonarc-ressources") { push @templates, "$Conf::Conf{'etc'}/$vr/mhonarc-ressources"; } ## Create_list_templates if (-d $Conf::Conf{'etc'} . '/' . $vr . '/create_list_templates') { foreach my $dir (<$Conf::Conf{'etc'}/$vr/create_list_templates/*>) { next unless (-d $dir); push @directories, $dir; } } ## Search in V. Robot Lists my $listOfLists = Sympa::List::get_lists($vr); foreach my $list (@$listOfLists) { push @directories, $list->{'dir'}; if (-d "$list->{'dir'}/templates") { push @directories, "$list->{'dir'}/templates"; } if (-d "$list->{'dir'}/wws_templates") { push @directories, "$list->{'dir'}/wws_templates"; } } } ## List .tpl files foreach my $d (@directories) { unless (opendir DIR, $d) { printf STDERR "Error: Cannot read %s directory : %s\n", $d, $ERRNO; next; } foreach my $tpl (sort grep(/\.tpl$/, readdir DIR)) { push @templates, "$d/$tpl"; } closedir DIR; } my $total; foreach my $tpl (@templates) { ## We don't migrate mhonarc-ressources files if ($tpl =~ /mhonarc\-ressources$/) { rename $tpl, "$tpl.incompatible"; printf STDERR "File $tpl could not be translated to TT2 ; it has been renamed $tpl.incompatible. You should customize a standard mhonarc_rc.tt2 file\n"; next; } unless (-r $tpl) { printf STDERR "Error : Unable to read file %s\n", $tpl; next; } unless ($tpl =~ /^(.+)\/([^\/]+)$/) { printf STDERR "Error : Incorrect Path %s\n", $tpl; next; } my ($path, $file) = ($1, $2); my ($dest_path, $dest_file); ## Destinatination Path $dest_path = $path; if ($path =~ /\/wws_templates$/) { ## translated web templates should not be used because they ## will not fit the new CSS/XHTML web structure $dest_path =~ s/wws_templates/web_tt2.old/; } elsif ($path =~ /\/templates$/) { $dest_path =~ s/templates/mail_tt2/; } elsif ($path =~ /\/expl\//) { $dest_path .= '/mail_tt2'; } else { $dest_path = $path; } ## Destination filename $dest_file = $file; $dest_file =~ s/\.tpl$/\.tt2/; ## Localized template if ($dest_file =~ /^([\w\-]+)\.(\w+)\.tt2$/) { my $lang = $2; $dest_file =~ s/^([\w\-]+)\.(\w+)\.tt2$/$1\.tt2/; $dest_path .= '/' . Sympa::Language::lang2oldlocale($lang); } ## If file has no extension unless ($dest_file =~ /\./) { $dest_file = $file . '.tt2'; } ## Create directory if required unless (-d $dest_path) { printf "Creating $dest_path directory\n"; unless (my_mkdir($dest_path)) { printf STDERR "Error : Cannot create %s directory: %s\n", $dest_path, $ERRNO; next; } unless ( Sympa::Tools::File::set_file_rights( file => $dest_path, user => Sympa::Constants::USER, group => Sympa::Constants::GROUP, mode => 0755, ) ) { $log->syslog('err', 'Unable to set rights on %s', $Conf::Conf{'db_name'}); next; } } my $tt2 = "$dest_path/$dest_file"; convert($tpl, $tt2); $total++; ## Rename old files to .converted unless (rename $tpl, "$tpl.converted") { printf STDERR "Error : failed to rename %s to %s.converted: %s\n", $tpl, $tpl, $ERRNO; next; } } print "\n$total template files have been converted\n"; ## Convert a template file to tt2 sub convert { my ($in_file, $out_file) = @_; ## Convert tpl file unless (open TPL, $in_file) { print STDERR "Cannot open $in_file : $ERRNO\n"; return undef; } if ($out_file) { unless (open TT2, ">$out_file") { print STDERR "Cannot create $out_file : $ERRNO\n"; return undef; } } while () { if ($out_file) { print TT2 _translate($_); } else { print STDOUT _translate($_); } } close TT2 if ($out_file); close TPL; printf "Template file $in_file has been converted to $out_file\n"; unless ( Sympa::Tools::File::set_file_rights( file => $out_file, user => Sympa::Constants::USER, group => Sympa::Constants::GROUP ) ) { $log->syslog('err', 'Unable to set rights on %s', $Conf::Conf{'db_name'}); return undef; } } ## Create root folders if required sub my_mkdir { my $path = shift; $path =~ s/\/$//; unless ($path) { return undef; } if ($path =~ /^(.*)\/[^\/]+$/) { my $root_path = $1; unless (-d $root_path) { unless (mkdir($root_path, 0777)) { printf STDERR "Error : Cannot create directory %s: %s\n", $root_path, $ERRNO; return undef; } } unless (mkdir($path, 0777)) { printf STDERR "Error : Cannot create directory %s: %s\n", $path, $ERRNO; return undef; } } else { return undef; } return 1; } # Old name: Sympa::Template::Compat::_translate() which was originally a part # of tt2.pm. sub _translate { local $_ = join('', @_); # if / endif s/\[\s*(ELSIF|IF)\s+(.*?)\s*=\s*(.*?)\s*\]/[% \U$1\E $2 == '$3' %]/ig; s/\[\s*(ELSIF|IF)\s+(.*?)\s*<>\s*(.*?)\s*\]/[% \U$1\E $2 != '$3' %]/ig; s/\[\s*(ELSIF|IF)\s+(.*?)\s*\]/[% \U$1\E $2 %]/ig; s/\[\s*ELSE\s*\]/[% ELSE %]/ig; s/\[\s*ENDIF\s*\]/[% END %]/ig; # parse -> process s/\[\s*PARSE\s*('.*?')\s*\]/[% PROCESS $1 %]/ig; s/\[\s*PARSE\s*(.*?)\]/[% PROCESS \$$1 IF $1 %]/ig; # variable access while (s/\[(.*?)([^\]-]+?)->(\d+)(.*)\]/[$1$2.item('$3')$4]/g) { } while (s/\[(.*?)([^\]-]+?)->(\w+)(.*)\]/[$1$2.$3$4]/g) { } s/\[\s*SET\s+(\w+)=(.*?)\s*\]/[% SET $1 = $2 %]/ig; # foreach s/\[\s*FOREACH\s*(\w+)\s*IN\s*([\w.()\'\/]+)\s*\]/[% FOREACH $1 = $2 %] [% SET tmp = $1.key $1 = $1.value $1.NAME = tmp IF $1.key.defined %]/ig; s/\[\s*END\s*\]/[% END %]/ig; # sanity check before including file s/\[\s*INCLUDE\s*('.*?')\s*\]/[% INSERT $1 %]/ig; s/\[\s*INCLUDE\s*(\w+?)\s*\]/[% INSERT \$$1 IF $1 %]/ig; ## Be careful to absolute path if (/\[%\s*(PROCESS|INSERT)\s*\'(\S+)\'\s*%\]/) { my $file = $2; my $new_file = $file; $new_file =~ s/\.tpl$/\.tt2/; my @path = split /\//, $new_file; $new_file = $path[$#path]; s/\'$file\'/\'$new_file\'/; } # setoption s/\[\s*SETOPTION\s(escape_)?html.*?\]/[% FILTER html_entity %]/ig; s/\[\s*SETOPTION\signore_undef.*?\]/[% IF 1 %]/ig; s/\[\s*UNSETOPTION.*?\]/[% END %]/ig; s/\[\s*([\w.()\'\/]+)\s*\]/[% $1 %]/g; s/\[\s*(STOP|START)PARSE\s*\]//ig; $_; }