1#
2# This file is part of the LibreOffice project.
3#
4# This Source Code Form is subject to the terms of the Mozilla Public
5# License, v. 2.0. If a copy of the MPL was not distributed with this
6# file, You can obtain one at http://mozilla.org/MPL/2.0/.
7#
8# This file incorporates work covered by the following license notice:
9#
10#   Licensed to the Apache Software Foundation (ASF) under one or more
11#   contributor license agreements. See the NOTICE file distributed
12#   with this work for additional information regarding copyright
13#   ownership. The ASF licenses this file to you under the Apache
14#   License, Version 2.0 (the "License"); you may not use this file
15#   except in compliance with the License. You may obtain a copy of
16#   the License at http://www.apache.org/licenses/LICENSE-2.0 .
17#
18
19package installer::control;
20
21use Cwd;
22use installer::converter;
23use installer::exiter;
24use installer::files;
25use installer::globals;
26use installer::pathanalyzer;
27use installer::scriptitems;
28use installer::systemactions;
29
30#########################################################
31# Function that can be used for additional controls.
32# Search happens in $installer::globals::patharray.
33#########################################################
34
35sub check_needed_files_in_path
36{
37    my ( $filesref ) = @_;
38
39    foreach $onefile ( @{$filesref} )
40    {
41        installer::logger::print_message( "... searching $onefile ..." );
42
43        my $fileref = installer::scriptitems::get_sourcepath_from_filename_and_includepath_classic(\$onefile, $installer::globals::patharray , 0);
44
45        if ( $$fileref eq "" )
46        {
47            $error = 1;
48            installer::logger::print_error( "$onefile not found\n" );
49        }
50        else
51        {
52            installer::logger::print_message( "\tFound: $$fileref\n" );
53        }
54    }
55
56    if ( $error )
57    {
58        installer::exiter::exit_program("ERROR: Could not find all needed files in path!", "check_needed_files_in_path");
59    }
60}
61
62#########################################################
63# Checking the local system
64# Checking existence of needed files in include path
65#########################################################
66
67sub check_system_path
68{
69    # The following files have to be found in the environment variable PATH
70    # All platforms: zip
71    # Windows only: "msiinfo.exe", "msidb.exe", "uuidgen.exe", "makecab.exe", "msitran.exe", "expand.exe" for msi database and packaging
72
73    my $onefile;
74    my $error = 0;
75    my $pathvariable = $ENV{'PATH'};
76    my $local_pathseparator = $installer::globals::pathseparator;
77
78    if( $^O =~ /cygwin/i )
79    {
80        # When using cygwin's perl the PATH variable is POSIX style and
81        # has to be converted to DOS style for further use.
82        $pathvariable = join ';',
83                        map { $dir = qx{cygpath -m "$_"}; chomp($dir); $dir }
84                        split /\Q$local_pathseparator\E\s*/, $pathvariable;
85        $local_pathseparator = ';';
86    }
87    my $patharrayref = installer::converter::convert_stringlist_into_array(\$pathvariable, $local_pathseparator);
88
89    $installer::globals::patharray = $patharrayref;
90
91    my @needed_files_in_path = ();
92
93    if (($installer::globals::iswin) && ($installer::globals::iswindowsbuild))
94    {
95        @needed_files_in_path = ("zip.exe", "msiinfo.exe", "msidb.exe", "uuidgen", "makecab.exe", "msitran.exe", "expand.exe");
96    }
97    elsif ($installer::globals::iswin)
98    {
99        @needed_files_in_path = ("zip.exe");
100    }
101    else
102    {
103        @needed_files_in_path = ("zip");
104    }
105
106    foreach $onefile ( @needed_files_in_path )
107    {
108        installer::logger::print_message( "... searching $onefile ..." );
109
110        my $fileref = installer::scriptitems::get_sourcepath_from_filename_and_includepath_classic(\$onefile, $patharrayref , 0);
111
112        if ( $$fileref eq "" )
113        {
114            $error = 1;
115            installer::logger::print_error( "$onefile not found\n" );
116        }
117        else
118        {
119            installer::logger::print_message( "\tFound: $$fileref\n" );
120            # Saving the absolute path for msitran.exe. This is required for the determination of the checksum.
121            if ( $onefile eq "msitran.exe" ) { $installer::globals::msitranpath = $$fileref; }
122        }
123    }
124
125    if ( $error )
126    {
127        installer::exiter::exit_program("ERROR: Could not find all needed files in path!", "check_system_path");
128    }
129
130    # checking for epm, which has to be in the path or in the solver
131
132    if (( $installer::globals::call_epm ) && (!($installer::globals::iswindowsbuild)))
133    {
134        my $onefile = "epm";
135        my $fileref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$onefile, $patharrayref , 0);
136        if (!( $$fileref eq "" ))
137        {
138            $installer::globals::epm_in_path = 1;
139
140            if ( $$fileref =~ /^\s*\.\/epm\s*$/ )
141            {
142                my $currentdir = cwd();
143                $$fileref =~ s/\./$currentdir/;
144            }
145
146            $installer::globals::epm_path = $$fileref;
147        }
148    }
149}
150
151######################################################################
152# Determining the version of file makecab.exe
153######################################################################
154
155sub get_makecab_version
156{
157    my $makecabversion = -1;
158
159    my $systemcall = "makecab.exe |";
160    my @makecaboutput = ();
161
162    open (CAB, $systemcall);
163    while (<CAB>) { push(@makecaboutput, $_); }
164    close (CAB);
165
166    my $returnvalue = $?;   # $? contains the return value of the systemcall
167
168    if ($returnvalue)
169    {
170        $infoline = "ERROR: Could not execute \"$systemcall\"!\n";
171        push( @installer::globals::globallogfileinfo, $infoline);
172    }
173    else
174    {
175        $infoline = "Success: Executed \"$systemcall\" successfully!\n";
176        push( @installer::globals::globallogfileinfo, $infoline);
177
178        my $versionline = "";
179
180        for ( my $i = 0; $i <= $#makecaboutput; $i++ )
181        {
182            if ( $makecaboutput[$i] =~ /\bVersion\b/i )
183            {
184                $versionline = $makecaboutput[$i];
185                last;
186            }
187        }
188
189        $infoline = $versionline;
190        push( @installer::globals::globallogfileinfo, $infoline);
191
192        if ( $versionline =~ /\bVersion\b\s+(\d+[\d\.]+\d+)\s+/ )
193        {
194            $makecabversion = $1;
195        }
196
197        # Only using the first number
198
199        if ( $makecabversion =~ /^\s*(\d+?)\D*/ )
200        {
201            $makecabversion = $1;
202        }
203
204        $infoline = "Using version: " . $makecabversion . "\n";
205        push( @installer::globals::globallogfileinfo, $infoline);
206    }
207
208    return $makecabversion;
209}
210
211######################################################################
212# Checking the version of file makecab.exe
213######################################################################
214
215sub check_makecab_version
216{
217    # checking version of makecab.exe
218    # Now it is guaranteed, that makecab.exe is in the path
219
220    my $do_check = 1;
221
222    my $makecabversion = get_makecab_version();
223
224    my $infoline = "Tested version: " . $installer::globals::controlledmakecabversion . "\n";
225    push( @installer::globals::globallogfileinfo, $infoline);
226
227    if ( $makecabversion < 0 ) { $do_check = 0; } # version could not be determined
228
229    if ( $do_check )
230    {
231        if ( $makecabversion < $installer::globals::controlledmakecabversion )
232        {
233            installer::exiter::exit_program("makecab.exe too old. Found version: \"$makecabversion\", required version: \"$installer::globals::controlledmakecabversion\"!", "check_makecab_version");
234        }
235    }
236    else
237    {
238        $infoline = "Warning: No version check of makecab.exe\n";
239        push( @installer::globals::globallogfileinfo, $infoline);
240    }
241}
242
243######################################################################
244# Reading the environment variables for the paths in ziplist.
245# solarenvpath, os, pmiscpath
246######################################################################
247
248sub check_system_environment
249{
250    my %variables = ();
251    my $error = 0;
252
253    my @environmentvariables = qw(
254        LIBO_VERSION_MAJOR
255        LIBO_VERSION_MINOR
256        CPUNAME
257        OS
258        COM
259        PLATFORMID
260        LOCAL_OUT
261        LOCAL_COMMON_OUT
262        WORKDIR
263        SRCDIR
264    );
265
266    for my $key ( @environmentvariables )
267    {
268        $variables{$key} = defined($ENV{$key}) ? $ENV{$key} : "";
269
270        if ( $variables{$key} eq "" )
271        {
272            installer::logger::print_error( "$key not set in environment\n" );
273            $error = 1;
274        }
275    }
276
277    if ( $error )
278    {
279        installer::exiter::exit_program("ERROR: Environment variable not set!", "check_system_environment");
280    }
281
282    return \%variables;
283}
284
285#############################################################
286# Controlling the log file at the end of the
287# packaging process
288#############################################################
289
290sub check_logfile
291{
292    my ($logfile) = @_;
293
294    my @errors = ();
295    my @output = ();
296    my $contains_error = 0;
297
298    my $ignore_error = 0;
299    my $make_error_to_warning = 0;
300
301    for ( my $i = 0; $i <= $#{$logfile}; $i++ )
302    {
303        my $line = ${$logfile}[$i];
304
305        # Errors are all errors, but not the Windows installer table "Error.idt"
306
307        my $compareline = $line;
308        $compareline =~ s/Error\.idt//g;    # removing all occurrences of "Error.idt"
309        $compareline =~ s/Error\.ulf//g;    # removing all occurrences of "Error.ulf"
310        $compareline =~ s/Error\.idl//g;    # removing all occurrences of "Error.idl"
311        $compareline =~ s/Error\.html//g;   # removing all occurrences of "Error.html"
312        $compareline =~ s/error\.py//g;     # removing all occurrences of "error.py"
313        $compareline =~ s/error\.cpython\-3.(\.opt\-.|)\.py[co]//g;  # removing all occurrences of "error-cpython"
314        $compareline =~ s/libgpg-error//g;
315        $compareline =~ s/Error-xref\.html//g;
316
317        if ( $compareline =~ /\bError\b/i )
318        {
319            $contains_error = 1;
320            push(@errors, $line);
321
322            if ( $ignore_error )
323            {
324                $contains_error = 0;
325                $make_error_to_warning = 1;
326            }
327        }
328    }
329
330    if ($contains_error)
331    {
332        my $line = "\n*********************************************************************\n";
333        push(@output, $line);
334        $line = "ERROR: The following errors occurred in packaging process:\n\n";
335        push(@output, $line);
336
337        for ( my $i = 0; $i <= $#errors; $i++ )
338        {
339            $line = "$errors[$i]";
340            push(@output, $line);
341        }
342
343        $line = "*********************************************************************\n";
344        push(@output, $line);
345    }
346    else
347    {
348        my $line = "";
349
350        if ( $make_error_to_warning )
351        {
352            $line = "\n*********************************************************************\n";
353            push(@output, $line);
354            $line = "The following errors in the log file were ignored:\n\n";
355            push(@output, $line);
356
357            for ( my $i = 0; $i <= $#errors; $i++ )
358            {
359                $line = "$errors[$i]";
360                push(@output, $line);
361            }
362
363            $line = "*********************************************************************\n";
364            push(@output, $line);
365        }
366
367        $line = "\n***********************************************************\n";
368        push(@output, $line);
369        $line = "Successful packaging process!\n";
370        push(@output, $line);
371        $line = "***********************************************************\n";
372        push(@output, $line);
373    }
374
375    # printing the output file and adding it to the logfile
376
377    installer::logger::include_header_into_logfile("Summary:");
378
379    my $force = 1; # print this message even in 'quiet' mode
380    for ( my $i = 0; $i <= $#output; $i++ )
381    {
382        my $line = "$output[$i]";
383        installer::logger::print_message( "$line", $force );
384        push( @installer::globals::logfileinfo, $line);
385        push( @installer::globals::errorlogfileinfo, $line);
386    }
387
388    return $contains_error;
389}
390
391#############################################################
392# Reading the Windows list file for Windows language codes
393# Encoding field is no longer used. We use UTF-8 everywhere.
394#############################################################
395
396sub read_lcidlist
397{
398    my ($patharrayref) = @_;
399
400    if ( ! -f $installer::globals::lcidlistname ) { installer::exiter::exit_program("ERROR: Did not find Windows LCID list $installer::globals::lcidlistname!", "read_lcidlist"); }
401
402    my $infoline = "Found LCID file: $installer::globals::lcidlistname\n";
403    push(@installer::globals::globallogfileinfo, $infoline);
404
405    my $lcidlist = installer::files::read_file($installer::globals::lcidlistname);
406    my %msilanguage = ();
407
408    for ( my $i = 0; $i <= $#{$lcidlist}; $i++ )
409    {
410        my $line = ${$lcidlist}[$i];
411        # de-mangle various potential DOS line-ending problems
412        $line =~ s/\r//g;
413        $line =~ s/\n//g;
414        $line =~ s/\s*\#.*$//; # removing comments after "#"
415        if ( $line =~ /^\s*$/ ) { next; }  # this is an empty line
416
417        if ( $line =~ /^\s*([\w-]+)\s+(\d+)\s+(\d+)\s*$/ )
418        {
419            my $onelanguage = $1;
420            my $windowslanguage = $3;
421            $msilanguage{$onelanguage} = $windowslanguage;
422        }
423        else
424        {
425            installer::exiter::exit_program("ERROR: Wrong syntax in Windows LCID list $installer::globals::lcidlistname in line $i: '$line'", "read_lcidlist");
426        }
427    }
428    $installer::globals::msilanguage = \%msilanguage;
429}
430
431#############################################################
432# Only for Windows and Linux (RPM)there is currently
433# a reliable mechanism to register extensions during
434# installation process. Therefore it is for all other
435# platforms forbidden to install oxt files into that
436# directory, in which they are searched for registration.
437#############################################################
438
439sub check_oxtfiles
440{
441    my ( $filesarray ) = @_;
442
443    for ( my $i = 0; $i <= $#{$filesarray}; $i++ )
444    {
445        my $onefile = ${$filesarray}[$i];
446
447        if (( $onefile->{'Name'} ) && ( $onefile->{'Dir'} ))
448        {
449            if (( $onefile->{'Name'} =~ /\.oxt\s*$/ ) && ( $onefile->{'Dir'} eq $installer::globals::extensioninstalldir ))
450            {
451                installer::exiter::exit_program("There is currently only for Linux (RPM) and Windows a reliable mechanism to register extensions during installation.\nPlease remove file \"$onefile->{'gid'}\" from your installation set!\nYou can use \"\#ifdef _WIN32\" and \"\#ifdef LINUX\" in scp.", "check_oxtfiles");
452            }
453        }
454    }
455}
456
457#######################################################################
458# Setting global variable "$installer::globals::addsystemintegration"
459#######################################################################
460
461sub set_addsystemintegration
462{
463    my ($allvariables) = @_;
464
465    if ( $allvariables->{'ADDSYSTEMINTEGRATION'} ) { $installer::globals::addsystemintegration = 1; }
466
467    if ( $installer::globals::languagepack ) { $installer::globals::addsystemintegration = 0; }
468    if ( $installer::globals::helppack ) { $installer::globals::addsystemintegration = 0; }
469
470    my $infoline = "Value of \$installer::globals::addsystemintegration: $installer::globals::addsystemintegration\n";
471    push( @installer::globals::globallogfileinfo, $infoline);
472}
473
4741;
475