Test Setup Failed
Push — master ( de37f4...b19653 )
by Tomasz
05:59
created

WindowsCommon::translateFile()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 30
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 20
c 2
b 0
f 0
dl 0
loc 30
rs 9.6
cc 4
nc 8
nop 2
1
<?php
2
3
/*
4
 * *****************************************************************************
5
 * Contributions to this work were made on behalf of the GÉANT project, a 
6
 * project that has received funding from the European Union’s Framework 
7
 * Programme 7 under Grant Agreements No. 238875 (GN3) and No. 605243 (GN3plus),
8
 * Horizon 2020 research and innovation programme under Grant Agreements No. 
9
 * 691567 (GN4-1) and No. 731122 (GN4-2).
10
 * On behalf of the aforementioned projects, GEANT Association is the sole owner
11
 * of the copyright in all material which was developed by a member of the GÉANT
12
 * project. GÉANT Vereniging (Association) is registered with the Chamber of 
13
 * Commerce in Amsterdam with registration number 40535155 and operates in the 
14
 * UK as a branch of GÉANT Vereniging.
15
 * 
16
 * Registered office: Hoekenrode 3, 1102BR Amsterdam, The Netherlands. 
17
 * UK branch address: City House, 126-130 Hills Road, Cambridge CB2 1PQ, UK
18
 *
19
 * License: see the web/copyright.inc.php file in the file structure or
20
 *          <base_url>/copyright.php after deploying the software
21
 */
22
23
/**
24
 * This file contains common functions needed by all Windows installers
25
 * @author Tomasz Wolniewicz <[email protected]>
26
 *
27
 * @package ModuleWriting
28
 */
29
30
namespace devices\ms;
31
32
use \Exception;
33
34
/**
35
 * This class defines common functions needed by all Windows installers
36
 * @author Tomasz Wolniewicz <[email protected]>
37
 *
38
 * @package ModuleWriting
39
 */
40
abstract class WindowsCommon extends \core\DeviceConfig
41
{
42
43
    /**
44
     * copies various common files into temp dir for inclusion into installers
45
     * 
46
     * @return void
47
     * @throws Exception
48
     */
49
    public function copyBasicFiles()
50
    {
51
        if (!($this->copyFile('wlan_test.exe') &&
52
                $this->copyFile('check_wired.cmd') &&
53
                $this->copyFile('install_wired.cmd') &&
54
                $this->copyFile('cat_bg.bmp') &&
55
                $this->copyFile('base64.nsh'))) {
56
            throw new Exception("Copying needed files (part 1) failed for at least one file!");
57
        }
58
59
        if (!($this->copyFile('cat32.ico') &&
60
                $this->copyFile('cat_150.bmp') &&
61
                $this->copyFile('WLANSetEAPUserData/WLANSetEAPUserData32.exe', 'WLANSetEAPUserDatax86.exe') &&
62
                $this->copyFile('WLANSetEAPUserData/WLANSetEAPUserData64.exe', 'WLANSetEAPUserDatax64.exe'))) {
63
            throw new Exception("Copying needed files (part 2) failed for at least one file!");
64
        }
65
        if (!$this->translateFile('common.inc', 'common.nsh')) {
66
            throw new Exception("Translating needed file common.inc failed!");
67
        }
68
        return;
69
    }
70
71
    /**
72
     *  Copy a file from the module location to the temporary directory aplying transcoding.
73
     *
74
     * Transcoding is only required for Windows installers, and no Unicode support
75
     * in NSIS (NSIS version below 3)
76
     * Trancoding is only applied if the third optional parameter is set and nonzero
77
     * If CONFIG['NSIS']_VERSION is set to 3 or more, no transcoding will be applied
78
     * regardless of the third parameter value.
79
     * If the second argument is provided and is not equal to 0, then the file will be
80
     * saved under the name taken from this argument.
81
     * If only one parameter is given or the second is equal to 0, source and destination
82
     * filenames are the same.
83
     * The third optional parameter, if nonzero, should be the character set understood by iconv
84
     * This is required by the Windows installer and is expected to go away in the future.
85
     * Source file can be located either in the Files subdirectory or in the sibdirectory of Files
86
     * named the same as device_id. The second option takes precedence.
87
     *
88
     * @param string $source_name The source file name
89
     * @param string $output_name The destination file name
90
     * @return boolean
91
     * @final not to be redefined
92
     */
93
    final protected function translateFile($source_name, $output_name = NULL)
94
    {
95
        // there is no explicit gettext() call in this function, but catalogues
96
        // and translations occur in the varios ".inc" files - so make sure we
97
        // operate in the correct catalogue
98
        \core\common\Entity::intoThePotatoes();
99
        if ($output_name === NULL) {
100
            $output_name = $source_name;
101
        }
102
103
        $this->loggerInstance->debug(5, "translateFile($source_name, $output_name)\n");
104
        ob_start();
105
        $this->loggerInstance->debug(5, $this->module_path . '/Files/' . $this->device_id . '/' . $source_name . "\n");
106
        $source = $this->findSourceFile($source_name);
107
108
        if ($source !== false) { // if there is no file found, don't attempt to include an uninitialised variable
109
            include $source;
110
        }
111
        $output = ob_get_clean();
112
        $fileHandle = fopen("$output_name", "w");
113
        if ($fileHandle === false) {
114
            $this->loggerInstance->debug(2, "translateFile($source, $output_name) failed\n");
115
            \core\common\Entity::outOfThePotatoes();
116
            return false;
117
        }
118
        fwrite($fileHandle, $output);
119
        fclose($fileHandle);
120
        $this->loggerInstance->debug(5, "translateFile($source, $output_name) end\n");
121
        \core\common\Entity::outOfThePotatoes();
122
        return true;
123
    }
124
125
    /**
126
     * Transcode a string adding double quotes escaping
127
     *
128
     * Transcoding is only required for Windows installers, and no Unicode support
129
     * in NSIS (NSIS version below 3)
130
     * Trancoding is only applied if the third optional parameter is set and nonzero
131
     * If CONFIG['NSIS']_VERSION is set to 3 or more, no transcoding will be applied
132
     * regardless of the second parameter value.
133
     * The second optional parameter, if nonzero, should be the character set understood by iconv
134
     * This is required by the Windows installer and is expected to go away in the future.
135
     *
136
     * @param string $source_string The source string
137
     * @param int    $encoding      Set Windows charset if non-zero
138
     * @return string
139
     * @final not to be redefined
140
     */
141
    final protected function translateString($source_string)
142
    {
143
        $this->loggerInstance->debug(5, "translateString input: \"$source_string\"\n");
144
        if (empty($source_string)) {
145
            return $source_string;
146
        }
147
148
        $output_c = $source_string;
149
        $source_string = str_replace('"', '$\\"', $output_c);
150
151
        return $source_string;
152
    }
153
154
155
    /**
156
     * copies GEANTlink files into temp dir for later inclusion into installers
157
     * 
158
     * @return void
159
     * @throws Exception
160
     */
161
    public function copyGeantLinkFiles()
162
    {
163
        if (!($this->copyFile('GEANTLink/GEANTLink-x86.msi', 'GEANTLink-x86.msi') &&
164
                $this->copyFile('GEANTLink/GEANTLink-x64.msi', 'GEANTLink-x64.msi') &&
165
                $this->copyFile('GEANTLink/GEANTLink-ARM64.msi', 'GEANTLink-ARM64.msi') &&
166
                $this->copyFile('GEANTLink/CredWrite.exe', 'CredWrite.exe') &&
167
                $this->copyFile('GEANTLink/MsiUseFeature.exe', 'MsiUseFeature.exe'))) {
168
            throw new Exception("Copying needed files (GEANTLink) failed for at least one file!");
169
        }
170
        if (!$this->translateFile('geant_link.inc', 'cat.NSI')) {
171
            throw new Exception("Translating needed file geant_link.inc failed!");
172
        }
173
    }
174
175
    /**
176
     * function to escape double quotes in a special NSI-compatible way
177
     * 
178
     * @param string $in input string
179
     * @return string
180
     */
181
    public static function echoNsis($in)
182
    {
183
        echo preg_replace('/"/', '$\"', $in);
184
    }
185
186
    /**
187
     * @param string $input input string
188
     * @return string
189
     */
190
    public static function sprintNsis($input)
191
    {
192
        return preg_replace('/"/', '$\"', $input);
193
    }
194
195
    /**
196
     * determine Windows language settings based on requested installer language
197
     * 
198
     * @return void
199
     */
200
    protected function prepareInstallerLang()
201
    {
202
        if (isset($this->LANGS[$this->languageInstance->getLang()])) {
203
            $this->lang = $this->LANGS[$this->languageInstance->getLang()];
204
        } else {
205
            $this->lang = 'English';
206
        }
207
    }
208
209
    /**
210
     * creates HTML code which will be displayed when the "info" button is pressed
211
     * 
212
     * @return string the HTML code
213
     */
214
    public function writeDeviceInfo()
215
    {
216
        $networkList = [];
217
        foreach (array_keys($this->getAttribute('internal:networks')) as $networkName) {
0 ignored issues
show
Bug introduced by
It seems like $this->getAttribute('internal:networks') can also be of type null; however, parameter $array of array_keys() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

217
        foreach (array_keys(/** @scrutinizer ignore-type */ $this->getAttribute('internal:networks')) as $networkName) {
Loading history...
218
            $networkList[] = iconv('UTF-8', 'ASCII//IGNORE', $networkName);
219
        }
220
        $configNetworkList = [];
221
        foreach (array_keys(\config\ConfAssistant::CONSORTIUM['networks']) as $networkName) {
222
            $configNetworkList[] = iconv('UTF-8', 'ASCII//IGNORE', $networkName);
223
        }
224
225
        $configCount = count($configNetworkList);
226
        $networksCount = count($networkList);
227
        $out = "<p>";
228
        $out .= "$networksCount:";
229
        $out .= sprintf(_("%s installer will be in the form of an EXE file. It will configure %s on your device, by creating wireless network profiles.<p>When you click the download button, the installer will be saved by your browser. Copy it to the machine you want to configure and execute."), \config\ConfAssistant::CONSORTIUM['display_name'], \config\ConfAssistant::CONSORTIUM['display_name']);
230
        $out .= "<p>";
231
        if ($networksCount > $configCount) {
232
            $out .= sprintf(ngettext("In addition to <strong>%s</strong> the installer will also configure access to:", "In addition to <strong>%s</strong> the installer will also configure access to the following networks:", $networksCount - $configCount), implode(', ', $configNetworkList)) . " ";
233
            $out .= '<strong>' . join('</strong>, <strong>', array_diff($networkList, $configNetworkList)) . '</strong>';
234
            $out .= "<p>";
235
        }
236
// TODO - change this below
237
        if ($this->selectedEapObject->isClientCertRequired()) {
238
            $out .= _("In order to connect to the network you will need an a personal certificate in the form of a p12 file. You should obtain this certificate from your organisation. Consult the support page to find out how this certificate can be obtained. Such certificate files are password protected. You should have both the file and the password available during the installation process.");
239
            return $out;
240
        }
241
        // not EAP-TLS
242
        $out .= _("In order to connect to the network you will need an account from your organisation. You should consult the support page to find out how this account can be obtained. It is very likely that your account is already activated.");
243
        return $out;
244
    }
245
246
    /**
247
     * scales a logo to the desired size
248
     * @param string $imagePath path to the image
249
     * @param int    $maxSize   maximum size of output image (larger axis counts)
250
     * @return \Imagick|\GMagick *Magick image object
251
     */
252
    private function scaleLogo($imagePath, $maxSize)
253
    {
254
        if (class_exists('\\Gmagick')) { 
255
            $imageObject = new \Gmagick($imagePath); 
256
        } else {
257
            $imageObject = new \Imagick($imagePath);
258
        }
259
        $imageSize = $imageObject->getImageGeometry();
0 ignored issues
show
Bug introduced by
The method getImageGeometry() does not exist on Gmagick. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

259
        /** @scrutinizer ignore-call */ 
260
        $imageSize = $imageObject->getImageGeometry();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
260
        $imageMax = max($imageSize);
261
        $this->loggerInstance->debug(5, "Logo size: ");
262
        $this->loggerInstance->debug(5, $imageSize);
263
        $this->loggerInstance->debug(5, "max=$imageMax\n");
264
// resize logo if necessary
265
        if ($imageMax > $maxSize) {
266
            if ($imageMax == $imageSize['width']) {
267
                $imageObject->scaleImage($maxSize, 0);
268
            } else {
269
                $imageObject->scaleImage(0, $maxSize);
270
            }
271
        }
272
        $imageSize = $imageObject->getImageGeometry();
273
        $this->background['freeHeight'] -= $imageSize['height'];
274
        return($imageObject);
275
    }
276
277
    /**
278
     * combines the inst and federation logo into one image and writes to file
279
     * 
280
     * @param array $logos   inst logo meta info
281
     * @param array $fedLogo fed logo meta info
282
     * @return void
283
     */
284
    protected function combineLogo($logos = NULL, $fedLogo = NULL)
285
    {
286
        // maximum size to which we want to resize the logos
287
288
        $maxSize = 120;
289
        // $freeTop is set to how much vertical space we need to leave at the top
290
        // this will depend on the design of the background
291
        $freeTop = 70;
292
        // $freeBottom is set to how much vertical space we need to leave at the bottom
293
        // this will depend on the design of the background
294
        // we are prefixig the paths with getcwd() wich migh appear unnecessary
295
        // but under some conditions appeared to be required
296
        $freeBottom = 30;
297
        if (class_exists('\\Gmagick')) { 
298
            $bgImage = new \Gmagick(getcwd().'/cat_bg.bmp');
299
        } else {
300
            $bgImage = new \Imagick(getcwd().'/cat_bg.bmp');
301
        }
302
        $bgImage->setFormat('BMP3');
0 ignored issues
show
Bug introduced by
The method setFormat() does not exist on Gmagick. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

302
        $bgImage->/** @scrutinizer ignore-call */ 
303
                  setFormat('BMP3');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
303
        $bgImageSize = $bgImage->getImageGeometry();
304
        $logosToPlace = [];
305
        $this->background = [];
306
        $this->background['freeHeight'] = $bgImageSize['height'] - $freeTop - $freeBottom;
307
308
        if ($this->getAttribute('fed:include_logo_installers') === NULL) {
309
            $fedLogo = NULL;
310
        }
311
        if ($fedLogo != NULL) {
312
            $logosToPlace[] = $this->scaleLogo(getcwd()."/".$fedLogo[0]['name'], $maxSize);
313
        }
314
        if ($logos != NULL) {
315
            $logosToPlace[] = $this->scaleLogo(getcwd()."/".$logos[0]['name'], $maxSize);
316
        }
317
318
        $logoCount = count($logosToPlace);
319
        if ($logoCount > 0) {
320
            $voffset = $freeTop;
321
            $freeSpace = (int) round($this->background['freeHeight'] / ($logoCount + 1));
322
            foreach ($logosToPlace as $logo) {
323
                $voffset += $freeSpace;
324
                $logoSize = $logo->getImageGeometry();
325
                $hoffset = (int) round(($bgImageSize['width'] - $logoSize['width']) / 2);
326
                $bgImage->compositeImage($logo, $logo->getImageCompose(), $hoffset, $voffset);
327
                $voffset += $logoSize['height'];
328
            }
329
        }
330
//new image is saved as the background
331
        $bgImage->writeImage('BMP3:'.getcwd().'/cat_bg.bmp');
332
    }
333
334
    /**
335
     * adds a digital signature to the installer, and returns path to file
336
     * 
337
     * @return string path to signed installer
338
     */
339
    protected function signInstaller()
340
    {
341
        $fileName = $this->installerBasename . '.exe';
342
        if (!$this->sign) {
343
            rename("installer.exe", $fileName);
344
            return $fileName;
345
        }
346
        // are actually signing
347
        $outputFromSigning = system($this->sign . " installer.exe '$fileName' > /dev/null");
348
        if ($outputFromSigning === false) {
349
            $this->loggerInstance->debug(2, "Signing the WindowsCommon installer $fileName FAILED!\n");
350
        }
351
        return $fileName;
352
    }
353
354
    /**
355
     * creates one single installer .exe out of the NSH inputs and other files
356
     * 
357
     * @return void
358
     */
359
    protected function compileNSIS()
360
    {
361
        $makensis = \config\ConfAssistant::PATHS['makensis'] . " -INPUTCHARSET UTF8";
362
        $lcAll = getenv("LC_ALL");
363
        putenv("LC_ALL=en_US.UTF-8");
364
        $command = $makensis . ' -V4 cat.NSI > nsis.log 2>&1';
365
        system($command);
366
        putenv("LC_ALL=" . $lcAll);
367
        $this->loggerInstance->debug(4, "compileNSIS:$command\n");
368
    }
369
370
    /**
371
     * find out where the user can get support
372
     * 
373
     * @param array  $attr list of profile attributes
374
     * @param string $type which type of support resource to we want
375
     * @return string NSH line with the resulting !define
376
     */
377
    private function getSupport($attr, $type)
378
    {
379
        $supportString = [
380
            'email' => 'SUPPORT',
381
            'url' => 'URL',
382
        ];
383
        $s = "support_" . $type . "_substitute";
384
        $substitute = $this->translateString($this->$s);
385
        $returnValue = !empty($attr['support:' . $type][0]) ? $attr['support:' . $type][0] : $substitute;
386
        return '!define ' . $supportString[$type] . ' "' . $returnValue . '"' . "\n";
387
    }
388
389
    /**
390
     * returns various NSH !define statements for later inclusion into main file
391
     * 
392
     * @param array $attr profile attributes
393
     * @return string
394
     */
395
    protected function writeNsisDefines($attr)
396
    {
397
        $fcontents = '';
398
        if ($attr['internal:profile_count'][0] > 1) {
399
            $fcontents .= "\n" . '!define USER_GROUP "' . $this->translateString(str_replace('"', '$\\"', $attr['profile:name'][0])) . '"
400
';
401
        }
402
        $fcontents .= '
403
Caption "' . $this->translateString(sprintf(WindowsCommon::sprintNsis(_("%s installer for %s")), \config\ConfAssistant::CONSORTIUM['display_name'], $attr['general:instname'][0])) . '"
404
!define APPLICATION "' . $this->translateString(sprintf(WindowsCommon::sprintNsis(_("%s installer for %s")), \config\ConfAssistant::CONSORTIUM['display_name'], $attr['general:instname'][0])) . '"
405
!define VERSION "' . \core\CAT::VERSION_MAJOR . '.' . \core\CAT::VERSION_MINOR . '"
406
!define INSTALLER_NAME "installer.exe"
407
!define LANG "' . $this->lang . '"
408
!define LOCALE "' . preg_replace('/\..*$/', '', \config\Master::LANGUAGES[$this->languageInstance->getLang()]['locale']) . '"
409
;--------------------------------
410
!define ORGANISATION "' . $this->translateString($attr['general:instname'][0]) . '"
411
';
412
        $fcontents .= $this->getSupport($attr, 'email');
413
        $fcontents .= $this->getSupport($attr, 'url');
414
        if (\core\common\Entity::getAttributeValue($attr, 'media:wired', 0) == 'on') {
415
            $fcontents .= '!define WIRED
416
        ';
417
        }
418
        $fcontents .= '!define PROVIDERID "urn:UUID:' . $this->deviceUUID . '"
419
';
420
        if (!empty($attr['internal:realm'][0])) {
421
            $fcontents .= '!define REALM "' . $attr['internal:realm'][0] . '"
422
';
423
        }
424
        if (!empty($attr['internal:hint_userinput_suffix'][0]) && $attr['internal:hint_userinput_suffix'][0] == 1) {
425
            $fcontents .= '!define HINT_USER_INPUT "' . $attr['internal:hint_userinput_suffix'][0] . '"
426
';
427
        }
428
        if (!empty($attr['internal:verify_userinput_suffix'][0]) && $attr['internal:verify_userinput_suffix'][0] == 1) {
429
            $fcontents .= '!define VERIFY_USER_REALM_INPUT "' . $attr['internal:verify_userinput_suffix'][0] . '"
430
';
431
        }
432
        $fcontents .= $this->msInfoFile($attr);
433
        return $fcontents;
434
    }
435
436
    /**
437
     * includes NSH commands displaying terms of use file into installer, if any
438
     * 
439
     * @param array $attr profile attributes
440
     * @return string NSH commands
441
     * @throws Exception
442
     */
443
    protected function msInfoFile($attr)
444
    {
445
        $out = '';
446
        if (isset($attr['support:info_file'])) {
447
            $out .= '!define EXTERNAL_INFO "';
448
//  $this->loggerInstance->debug(4,"Info file type ".$attr['support:info_file'][0]['mime']."\n");
449
            if ($attr['internal:info_file'][0]['mime'] == 'rtf') {
450
                $out = '!define LICENSE_FILE "' . $attr['internal:info_file'][0]['name'];
451
            } elseif ($attr['internal:info_file'][0]['mime'] == 'txt') {
452
                $infoFile = file_get_contents($attr['internal:info_file'][0]['name']);
453
                if ($infoFile === false) {
454
                    throw new Exception("We were told this file exists. Failing to read it is not really possible.");
455
                }
456
                $infoFileConverted = $infoFile;
457
458
                if ($infoFileConverted !== false && strlen($infoFileConverted) > 0) {
459
                    file_put_contents('info_f.txt', $infoFileConverted);
460
                    $out = '!define LICENSE_FILE " info_f.txt';
461
                }
462
            } else {
463
                $out = '!define EXTERNAL_INFO "' . $attr['internal:info_file'][0]['name'];
464
            }
465
466
            $out .= "\"\n";
467
        }
468
        $this->loggerInstance->debug(4, "Info file returned: $out");
469
        return $out;
470
    }
471
472
    /**
473
     * writes commands to delete SSIDs, if any, into a file
474
     * 
475
     * @param array $profiles WLAN profiles to delete
476
     * @return void
477
     * @throws Exception
478
     */
479
    protected function writeAdditionalDeletes($profiles)
480
    {
481
        if (count($profiles) == 0) {
482
            return;
483
        }
484
        $fileHandle = fopen('profiles.nsh', 'a');
485
        if ($fileHandle === false) {
486
            throw new Exception("Unable to open possibly pre-existing profiles.nsh to append additional deletes.");
487
        }
488
        fwrite($fileHandle, "!define AdditionalDeletes\n");
489
        foreach ($profiles as $profile) {
490
            fwrite($fileHandle, "!insertmacro define_delete_profile \"$profile\"\n");
491
        }
492
        fclose($fileHandle);
493
    }
494
495
    /**
496
     * writes client certificate into file
497
     * 
498
     * @return void
499
     * @throws Exception
500
     */
501
    protected function writeClientP12File()
502
    {
503
        if (!is_array($this->clientCert)) {
504
            throw new Exception("the client block was called but there is no client certificate!");
505
        }
506
        file_put_contents('SB_cert.p12', $this->clientCert["certdata"]);
507
    }
508
509
    public $LANGS = [
510
        'fr' => "French",
511
        'de' => "German",
512
        'es' => "SpanishInternational",
513
        'it' => "Italian",
514
        'nl' => "Dutch",
515
        'sv' => "Swedish",
516
        'fi' => "Finnish",
517
        'pl' => "Polish",
518
        'ca' => "Catalan",
519
        'sr' => "SerbianLatin",
520
        'hr' => "Croatian",
521
        'sl' => "Slovenian",
522
        'da' => "Danish",
523
        'nb' => "Norwegian",
524
        'nn' => "NorwegianNynorsk",
525
        'el' => "Greek",
526
        'ru' => "Russian",
527
        'pt' => "Portuguese",
528
        'uk' => "Ukrainian",
529
        'cs' => "Czech",
530
        'sk' => "Slovak",
531
        'bg' => "Bulgarian",
532
        'hu' => "Hungarian",
533
        'ro' => "Romanian",
534
        'lv' => "Latvian",
535
        'mk' => "Macedonian",
536
        'et' => "Estonian",
537
        'tr' => "Turkish",
538
        'lt' => "Lithuanian",
539
        'ar' => "Arabic",
540
        'he' => "Hebrew",
541
        'id' => "Indonesian",
542
        'mn' => "Mongolian",
543
        'sq' => "Albanian",
544
        'br' => "Breton",
545
        'be' => "Belarusian",
546
        'is' => "Icelandic",
547
        'ms' => "Malay",
548
        'bs' => "Bosnian",
549
        'ga' => "Irish",
550
        'uz' => "Uzbek",
551
        'gl' => "Galician",
552
        'af' => "Afrikaans",
553
        'ast' => "Asturian",
554
    ];
555
    
556
    /**
557
     * this constant controls if the system generates sepaarate SSID and OI profiles
558
     * or puts all settings into a single profile
559
     */
560
    const separateHS20profiles = true;
0 ignored issues
show
Coding Style introduced by
This class constant is not uppercase (expected SEPARATEHS20PROFILES).
Loading history...
561
    
562
    public $codePage;
563
    public $lang;
564
    public $useGeantLink = false;
565
    private $background;
566
567
}
568