Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
22 andreas 1
/*
2
 * Copyright (C) 2021 by Andreas Theofilu <andreas@theosys.at>
3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software Foundation,
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
17
 */
18
 
19
#include <iostream>
20
#include <fstream>
120 andreas 21
#include <functional>
22 andreas 22
 
118 andreas 23
#include <stdio.h>
50 andreas 24
#include <sys/stat.h>
25
#include <fcntl.h>
26
#include <errno.h>
118 andreas 27
#include <unistd.h>
50 andreas 28
 
22 andreas 29
#include <QFile>
43 andreas 30
#ifdef __ANDROID__
31
#include <QtAndroid>
32
#endif
33
#include <QMap>
34
#include <QHash>
22 andreas 35
 
36
#include "ttpinit.h"
37
#include "terror.h"
50 andreas 38
#include "tvalidatefile.h"
115 andreas 39
#include "tconfig.h"
40
#include "tfsfreader.h"
119 andreas 41
#include "tdirectory.h"
122 andreas 42
#include "tresources.h"
22 andreas 43
 
44
using std::string;
85 andreas 45
using std::vector;
22 andreas 46
using std::ostream;
120 andreas 47
using std::bind;
122 andreas 48
using std::ifstream;
22 andreas 49
 
122 andreas 50
#if __GNUC__ < 9 && !defined(__ANDROID__)
51
#if __cplusplus < 201703L
52
    #warning "Your C++ compiler seems to have no support for C++17 standard!"
53
#endif
54
    #include <experimental/filesystem>
55
    namespace fs = std::experimental::filesystem;
56
#else
57
#  ifdef __ANDROID__
58
#   if _LIBCPP_STD_VER >= 17
59
#       include <filesystem>
60
        namespace fs = std::__fs::filesystem;
61
#   else
62
#       include <experimental/filesystem>
63
        namespace fs = std::__fs::filesystem;
64
#   endif
65
#  else
66
#   include <filesystem>
67
    namespace fs = std::filesystem;
68
#  endif
69
#endif
70
 
71
#define SYSTEM_DEFAULT      "/.system"
72
 
51 andreas 73
TTPInit::TTPInit()
74
{
75
    DECL_TRACER("TTPInit::TTPInit()");
76
}
77
 
22 andreas 78
TTPInit::TTPInit(const string& path)
79
    : mPath(path)
80
{
81
    DECL_TRACER("TTPInit::TTPInit(const string& path)")
82
 
50 andreas 83
    createDirectoryStructure();
22 andreas 84
    createPanelConfigs();
115 andreas 85
    loadSurfaceFromController();
22 andreas 86
}
87
 
88
bool TTPInit::createPanelConfigs()
89
{
90
    DECL_TRACER("TTPInit::createPanelConfigs()");
91
 
113 andreas 92
    vector<string> resFiles = {
93
        ":ressources/external.xma",
94
        ":ressources/fnt.xma",
95
        ":ressources/icon.xma",
96
        ":ressources/_main.xml",
97
        ":ressources/manifest.xma",
98
        ":ressources/map.xma",
99
        ":ressources/pal_001.xma",
100
        ":ressources/prj.xma",
101
        ":ressources/_setup.xml",
102
        ":ressources/table.xma",
103
        ":ressources/fonts/arial.ttf",
104
        ":ressources/images/theosys_logo.png",
105
        ":ressources/__system/graphics/fonts/amxbold_.ttf",
106
        ":ressources/__system/graphics/fonts/arialbd.ttf",
107
        ":ressources/__system/graphics/fonts/arial.ttf",
108
        ":ressources/__system/graphics/fonts/cour.ttf",
109
        ":ressources/__system/graphics/sounds/audioTest.wav",
110
        ":ressources/__system/graphics/sounds/docked.mp3",
111
        ":ressources/__system/graphics/sounds/doubleBeep01.wav",
112
        ":ressources/__system/graphics/sounds/doubleBeep02.wav",
113
        ":ressources/__system/graphics/sounds/doubleBeep03.wav",
114
        ":ressources/__system/graphics/sounds/doubleBeep04.wav",
115
        ":ressources/__system/graphics/sounds/doubleBeep05.wav",
116
        ":ressources/__system/graphics/sounds/doubleBeep06.wav",
117
        ":ressources/__system/graphics/sounds/doubleBeep07.wav",
118
        ":ressources/__system/graphics/sounds/doubleBeep08.wav",
119
        ":ressources/__system/graphics/sounds/doubleBeep09.wav",
120
        ":ressources/__system/graphics/sounds/doubleBeep10.wav",
121
        ":ressources/__system/graphics/sounds/doubleBeep.wav",
122
        ":ressources/__system/graphics/sounds/ringback.wav",
123
        ":ressources/__system/graphics/sounds/ringtone.wav",
124
        ":ressources/__system/graphics/sounds/singleBeep01.wav",
125
        ":ressources/__system/graphics/sounds/singleBeep02.wav",
126
        ":ressources/__system/graphics/sounds/singleBeep03.wav",
127
        ":ressources/__system/graphics/sounds/singleBeep04.wav",
128
        ":ressources/__system/graphics/sounds/singleBeep05.wav",
129
        ":ressources/__system/graphics/sounds/singleBeep06.wav",
130
        ":ressources/__system/graphics/sounds/singleBeep07.wav",
131
        ":ressources/__system/graphics/sounds/singleBeep08.wav",
132
        ":ressources/__system/graphics/sounds/singleBeep09.wav",
133
        ":ressources/__system/graphics/sounds/singleBeep10.wav",
134
        ":ressources/__system/graphics/sounds/singleBeep.wav",
135
        ":ressources/__system/graphics/draw.xma",
136
        ":ressources/__system/graphics/fnt.xma",
137
        ":ressources/__system/graphics/version.xma"
138
    };
139
 
22 andreas 140
    bool err = false;
113 andreas 141
    vector<string>::iterator iter;
22 andreas 142
 
113 andreas 143
    for (iter = resFiles.begin(); iter != resFiles.end(); ++iter)
22 andreas 144
    {
113 andreas 145
        if (!copyFile(*iter))
50 andreas 146
            err = true;
22 andreas 147
    }
148
 
122 andreas 149
    // Mark files as system default files
150
    try
151
    {
152
        string marker = mPath + SYSTEM_DEFAULT;
153
        std::ofstream mark(marker);
154
        time_t t = time(NULL);
155
        mark.write((char *)&t, sizeof(time_t));
156
        mark.close();
157
    }
158
    catch (std::exception& e)
159
    {
160
        MSG_ERROR("Error creating a marker file: " << e.what());
161
        err = true;
162
    }
22 andreas 163
 
164
    return err;
165
}
51 andreas 166
 
117 andreas 167
bool TTPInit::createSystemConfigs()
168
{
169
    DECL_TRACER("TTPInit::createSystemConfigs()");
170
 
171
    vector<string> resFiles = {
172
        ":ressources/__system/graphics/fonts/amxbold_.ttf",
173
        ":ressources/__system/graphics/fonts/arialbd.ttf",
174
        ":ressources/__system/graphics/fonts/arial.ttf",
175
        ":ressources/__system/graphics/fonts/cour.ttf",
176
        ":ressources/__system/graphics/sounds/audioTest.wav",
177
        ":ressources/__system/graphics/sounds/docked.mp3",
178
        ":ressources/__system/graphics/sounds/doubleBeep01.wav",
179
        ":ressources/__system/graphics/sounds/doubleBeep02.wav",
180
        ":ressources/__system/graphics/sounds/doubleBeep03.wav",
181
        ":ressources/__system/graphics/sounds/doubleBeep04.wav",
182
        ":ressources/__system/graphics/sounds/doubleBeep05.wav",
183
        ":ressources/__system/graphics/sounds/doubleBeep06.wav",
184
        ":ressources/__system/graphics/sounds/doubleBeep07.wav",
185
        ":ressources/__system/graphics/sounds/doubleBeep08.wav",
186
        ":ressources/__system/graphics/sounds/doubleBeep09.wav",
187
        ":ressources/__system/graphics/sounds/doubleBeep10.wav",
188
        ":ressources/__system/graphics/sounds/doubleBeep.wav",
189
        ":ressources/__system/graphics/sounds/ringback.wav",
190
        ":ressources/__system/graphics/sounds/ringtone.wav",
191
        ":ressources/__system/graphics/sounds/singleBeep01.wav",
192
        ":ressources/__system/graphics/sounds/singleBeep02.wav",
193
        ":ressources/__system/graphics/sounds/singleBeep03.wav",
194
        ":ressources/__system/graphics/sounds/singleBeep04.wav",
195
        ":ressources/__system/graphics/sounds/singleBeep05.wav",
196
        ":ressources/__system/graphics/sounds/singleBeep06.wav",
197
        ":ressources/__system/graphics/sounds/singleBeep07.wav",
198
        ":ressources/__system/graphics/sounds/singleBeep08.wav",
199
        ":ressources/__system/graphics/sounds/singleBeep09.wav",
200
        ":ressources/__system/graphics/sounds/singleBeep10.wav",
201
        ":ressources/__system/graphics/sounds/singleBeep.wav",
202
        ":ressources/__system/graphics/draw.xma",
203
        ":ressources/__system/graphics/fnt.xma",
204
        ":ressources/__system/graphics/version.xma"
205
    };
206
 
207
    bool err = false;
208
    vector<string>::iterator iter;
209
 
210
    for (iter = resFiles.begin(); iter != resFiles.end(); ++iter)
211
    {
212
        if (!copyFile(*iter))
213
            err = true;
214
    }
215
 
216
    return err;
217
}
218
 
50 andreas 219
bool TTPInit::createDirectoryStructure()
220
{
221
    DECL_TRACER("TTPInit::createDirectoryStructure()");
222
 
51 andreas 223
    if (mPath.empty())
224
    {
225
        MSG_ERROR("Got no path to create the directory structure!");
226
        return false;
227
    }
228
 
50 andreas 229
    string pfad = mPath;
230
 
231
    if (!_makeDir(pfad))
232
        return false;
233
 
234
    pfad = mPath + "/fonts";
235
 
236
    if (!_makeDir(pfad))
237
        return false;
238
 
239
    pfad = mPath + "/images";
240
 
241
    if (!_makeDir(pfad))
242
        return false;
243
 
244
    pfad = mPath + "/sounds";
245
 
246
    if (!_makeDir(pfad))
247
        return false;
248
 
249
    pfad = mPath + "/__system";
250
 
251
    if (!_makeDir(pfad))
252
        return false;
253
 
254
    pfad = mPath + "/__system/graphics";
255
 
256
    if (!_makeDir(pfad))
257
        return false;
258
 
259
    pfad = mPath + "/__system/graphics/fonts";
260
 
261
    if (!_makeDir(pfad))
262
        return false;
263
 
264
    pfad = mPath + "/__system/graphics/images";
265
 
266
    if (!_makeDir(pfad))
267
        return false;
268
 
269
    pfad = mPath + "/__system/graphics/sounds";
270
 
271
    if (!_makeDir(pfad))
272
        return false;
273
 
274
    pfad = mPath + "/__system/graphics/cursors";
275
 
276
    if (!_makeDir(pfad))
277
        return false;
278
 
279
    pfad = mPath + "/__system/graphics/sliders";
280
 
281
    if (!_makeDir(pfad))
282
        return false;
283
 
88 andreas 284
    pfad = mPath + "/__system/graphics/borders";
285
 
286
    if (!_makeDir(pfad))
287
        return false;
288
 
50 andreas 289
    return true;
290
}
291
 
292
bool TTPInit::_makeDir(const std::string& dir)
293
{
294
    DECL_TRACER("TTPInit::_makeDir(const std::string& dir)");
295
 
296
    TValidateFile vf;
297
 
71 andreas 298
    if (!vf.isValidDir(dir))
50 andreas 299
    {
300
        if (mkdir (dir.c_str(), S_IRWXU | S_IRWXG | S_IRWXG) != 0)
301
        {
302
            MSG_ERROR("Directory " << dir << ": " << strerror(errno));
303
            return false;
304
        }
305
    }
306
 
307
    return true;
308
}
309
 
113 andreas 310
bool TTPInit::copyFile(const std::string& fname)
311
{
312
    DECL_TRACER("TTPInit::copyFile(const std::string& fname)");
313
 
314
    bool err = false;
315
    QFile external(fname.c_str());
316
    size_t pos = fname.find_first_of("/");
317
    string bname;
318
 
319
    if (pos != string::npos)
320
        bname = fname.substr(pos);
321
    else
322
        bname = fname;
323
 
324
    if (external.exists())
325
    {
326
        QString path = mPath.c_str();
327
        path += bname.c_str();
118 andreas 328
        bname = path.toStdString();
113 andreas 329
 
118 andreas 330
        // If the target already exists we must delete it first.
331
        if (access(bname.data(), F_OK) == 0)
332
            remove(bname.data());
333
 
113 andreas 334
        if (!external.copy(path))
335
        {
43 andreas 336
#ifdef __ANDROID__
113 andreas 337
            if (!askPermissions())
338
            {
339
                MSG_ERROR("Could not copy \"" << bname << "\" to " << path.toStdString() << " because permission was denied!");
340
                err = true;
341
            }
342
            else if (!external.copy(path))
343
            {
344
                MSG_ERROR("Could not copy \"" << bname << "\" to " << path.toStdString());
345
                err = true;
346
            }
347
#else
348
            MSG_ERROR("Could not copy \"" << bname << "\" to " << path.toStdString());
349
            err = true;
350
#endif
351
        }
352
    }
353
    else
354
    {
355
        MSG_ERROR("File " << external.fileName().toStdString() << " doesn't exist!");
356
        err = true;
357
    }
358
 
359
    return err;
360
}
361
 
115 andreas 362
/**
363
 * This methods checks if there exists a previous downloaded TP4 file. If this
364
 * is the case, nothing happens.
365
 * If there is no previous downloaded file it checks if there is one on the
366
 * controller and downloads it if it exists. After successfull download the
367
 * file is unpacked.
368
 *
369
 * @return TRUE is returned when there was a file successfully downloaded and
370
 * unpacked. In any other case FALSE is returned.
371
 */
372
bool TTPInit::loadSurfaceFromController(bool force)
373
{
374
    DECL_TRACER("TTPInit::loadSurfaceFromController(bool force)");
375
 
376
    TFsfReader reader;
120 andreas 377
    reader.regCallbackProgress(bind(&TTPInit::progressCallback, this, std::placeholders::_1));
115 andreas 378
    string target = mPath + "/" + TConfig::getFtpSurface();
117 andreas 379
    size_t pos = 0;
115 andreas 380
 
117 andreas 381
    if ((pos = mPath.find_last_of("/")) != string::npos)
382
        target = mPath.substr(0, pos) + "/" + TConfig::getFtpSurface();
383
 
115 andreas 384
    if (!force)
385
    {
122 andreas 386
        if (!isVirgin() || TConfig::getFtpDownloadTime() > 0)
115 andreas 387
            return false;
388
    }
389
 
120 andreas 390
    if (_processEvents)
391
        _processEvents();
392
 
119 andreas 393
    // To be sure the target directory tree is empty, we delete all files but
394
    // keep the system directories and their content, if they exist.
395
    dir::TDirectory dir;
396
 
397
    if (dir.exists(mPath))
398
    {
399
        dir.dropDir(mPath);
400
        dir.dropDir(mPath + "/fonts");
401
        dir.dropDir(mPath + "/images");
402
        dir.dropDir(mPath + "/sounds");
403
    }
404
 
115 andreas 405
    if (!reader.copyOverFTP(TConfig::getFtpSurface(), target))
406
        return false;
407
 
120 andreas 408
    if (_processEvents)
409
        _processEvents();
410
 
117 andreas 411
    if (!reader.unpack(target, mPath))
412
    {
413
        MSG_ERROR("Unpacking was not successfull.");
115 andreas 414
        return false;
117 andreas 415
    }
115 andreas 416
 
119 andreas 417
    if (!force || !dir.exists(mPath + "/__system"))
118 andreas 418
    {
419
        createDirectoryStructure();
420
        createSystemConfigs();
421
    }
422
 
120 andreas 423
    if (_processEvents)
424
        _processEvents();
425
 
119 andreas 426
    dir.dropFile(target);       // We remove our traces
122 andreas 427
    dir.dropFile(mPath + SYSTEM_DEFAULT);   // No more system default files
115 andreas 428
    TConfig::saveFtpDownloadTime(time(NULL));
429
    TConfig::saveSettings();
430
    return true;
431
}
432
 
122 andreas 433
vector<string>& TTPInit::getFileList(const string& filter)
434
{
435
    DECL_TRACER("TTPInit::getFileList(const string& filter)");
436
 
437
    ftplib *ftp = new ftplib();
438
 
439
    if (TConfig::getFtpPassive())
440
        ftp->SetConnmode(ftplib::pasv);
441
    else
442
        ftp->SetConnmode(ftplib::port);
443
 
444
    string scon = TConfig::getController() + ":21";
445
    MSG_DEBUG("Trying to connect to " << scon);
446
 
447
    if (!ftp->Connect(scon.c_str()))
448
    {
449
        delete ftp;
450
        return mDirList;
451
    }
452
 
453
    string sUser = TConfig::getFtpUser();
454
    string sPass = TConfig::getFtpPassword();
455
    MSG_DEBUG("Trying to login <" << sUser << ", " << sPass << ">");
456
 
457
    if (!ftp->Login(sUser.c_str(), sPass.c_str()))
458
    {
459
        delete ftp;
460
        return mDirList;
461
    }
462
 
463
    string tmpFile = std::tmpnam(nullptr);
464
    MSG_DEBUG("Reading remote directory / into file " << tmpFile);
465
    ftp->Nlst(tmpFile.c_str(), "/");
466
    ftp->Quit();
467
    delete ftp;
468
    mDirList.clear();
469
 
470
    try
471
    {
472
        char buffer[1024];
473
        string uFilter = toUpper((std::string&)filter);
474
 
475
        std::ifstream ifile(tmpFile);
476
 
477
        while (ifile.getline(buffer, sizeof(buffer)))
478
        {
479
            string buf = buffer;
480
            string fname = trim(buf);
481
 
482
            if (!filter.empty())
483
            {
484
                if (endsWith(toUpper(buf), uFilter))
485
                    mDirList.push_back(trim(fname));
486
            }
487
            else
488
                mDirList.push_back(trim(fname));
489
        }
490
 
491
        ifile.close();
492
    }
493
    catch (std::exception& e)
494
    {
495
        MSG_ERROR("Error opening file " << tmpFile << ": " << e.what());
496
    }
497
 
498
    fs::remove(tmpFile);
499
 
500
    if (mDirList.size() > 0)
501
    {
502
        vector<string>::iterator iter;
503
 
504
        for (iter = mDirList.begin(); iter != mDirList.end(); ++iter)
505
        {
506
            MSG_DEBUG("File: " << *iter);
507
        }
508
    }
509
 
510
    return mDirList;
511
}
512
 
120 andreas 513
int TTPInit::progressCallback(off64_t xfer)
514
{
515
    DECL_TRACER("TTPInit::progressCallback(off64_t xfer)");
516
 
517
    if (_processEvents && xfer > 0)
518
        _processEvents();
519
 
520
    return 1;
521
}
522
 
122 andreas 523
bool TTPInit::isSystemDefault()
524
{
525
    DECL_TRACER("TTPInit::isSystemDefault()");
526
 
527
    try
528
    {
529
        string marker = mPath + SYSTEM_DEFAULT;
530
        return fs::exists(marker);
531
    }
532
    catch (std::exception& e)
533
    {
534
        MSG_ERROR("File system error: " << e.what())
535
        return false;
536
    }
537
 
538
    return true;
539
}
540
 
541
bool TTPInit::isVirgin()
542
{
543
    DECL_TRACER("TTPInit::isVirgin()");
544
 
545
    try
546
    {
547
        if (!fs::exists(mPath) || isSystemDefault())
548
            return true;
549
    }
550
    catch (std::exception& e)
551
    {
552
        MSG_ERROR("File system error: " << e.what());
553
        return true;
554
    }
555
 
556
    return false;
557
}
558
 
113 andreas 559
#ifdef __ANDROID__
43 andreas 560
bool TTPInit::askPermissions()
561
{
115 andreas 562
    DECL_TRACER("TTPInit::askPermissions()");
43 andreas 563
 
564
    QStringList permissions = { "android.permission.READ_EXTERNAL_STORAGE", "android.permission.WRITE_EXTERNAL_STORAGE" };
565
    QtAndroid::PermissionResultMap perms = QtAndroid::requestPermissionsSync(permissions);
566
 
567
    for (auto iter = perms.begin(); iter != perms.end(); ++iter)
568
    {
569
        if (iter.value() == QtAndroid::PermissionResult::Denied)
570
            return false;
571
    }
572
 
573
    return true;
574
}
575
#endif