Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 andreas 1
/*
21 andreas 2
 * Copyright (C) 2020, 2021 by Andreas Theofilu <andreas@theosys.at>
2 andreas 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
 */
21 andreas 18
 
2 andreas 19
#include <fstream>
20
#include <vector>
21
#include <iterator>
22
#include <unistd.h>
21 andreas 23
#include <sys/stat.h>
24
#include <sys/types.h>
22 andreas 25
#ifdef __ANDROID__
26
#include <android/log.h>
27
#include "tvalidatefile.h"
28
#include "ttpinit.h"
43 andreas 29
#include "tvalidatefile.h"
22 andreas 30
#endif
31
#include "tconfig.h"
2 andreas 32
#include "terror.h"
73 andreas 33
#include "tresources.h"
2 andreas 34
 
35
using std::string;
36
using std::ifstream;
21 andreas 37
using std::ofstream;
2 andreas 38
using std::fstream;
39
using std::vector;
21 andreas 40
using std::cout;
41
using std::cerr;
42
using std::endl;
2 andreas 43
 
21 andreas 44
/**
45
 * @struct SETTINGS
46
 * @brief The SETTINGS struct bundles the configuration options.
47
 *
48
 * This structure contains variables for all possible configuration options.
49
 * It is used by the class TConfig. Through this class it's possible to
50
 * access all configuration options.
51
 */
2 andreas 52
struct SETTINGS
53
{
21 andreas 54
    string pname{"tpanel"};     //!< Name of the program (default "tpanel")
55
    string path;                //!< The path where the configuration file is located
56
    string name;                //!< The name of the configuration file
57
    string project;             //!< The path where the original project files are located
58
    string server;              //!< The name or IP address of the server to connect
59
    int system{0};              //!< The number of the AMX system
60
    int port{0};                //!< The port number
61
    int ID{0};                  //!< the panel ID (a number starting by 10000)
62
    string ptype;               //!< The type of the panel (android, ipad, iphone, ...)
63
    string version;             //!< The "firmware" version
64
    string logFile;             //!< Optional path and name of a logfile
65
    string logLevel;            //!< The log level(s).
71 andreas 66
    uint logLevelBits;          //!< The numeric bit field of the loglevel
21 andreas 67
    bool longformat{false};     //!< TRUE = long format
68
    bool noBanner{false};       //!< Startup without showing a banner on the command line.
69
    bool certCheck{false};      //!< TRUE = Check certificate for SSL connection
24 andreas 70
    bool scale{false};          //!< TRUE = Images are scaled to fit the whole screen
35 andreas 71
    bool profiling{false};      //!< TRUE = The declaration traces meassure the time and write it to the log
51 andreas 72
    string password1;           //!< First panel password
73
    string password2;           //!< Second panel password
74
    string password3;           //!< Third panel password
75
    string password4;           //!< Fourth panel password
71 andreas 76
    string systemSound;         //!< name of the set system sound played on every touch.
77
    bool systemSoundState{false};   //!< TRUE = play systemsound on every touch
78
    string systemSingleBeep;    //!< name of the system sound file to play a single beep.
79
    string systemDoubleBeep;    //!< name of the system sound file to play a double beep.
112 andreas 80
    // FTP credentials
81
    string ftpUser;             //!< The username for FTP of the controller (default: administrator)
82
    string ftpPassword;         //!< The password for FTP of the controller (default: password)
104 andreas 83
    // SIP settings
84
    string sip_proxy;           //!< The address of the SIP proxy
85
    int sip_port{5060};         //!< Initializes the port of the SIP proxy to 5060
86
    string sip_stun;            //!< STUN address
87
    string sip_domain;          //!< Local domain
88
    string sip_user;            //!< The SIP user to connect.
89
    string sip_password;        //!< The SIP password to connect. Note: This password is saved in plain text!
90
    bool sip_enabled{false};    //!< By default SIP is disabled
2 andreas 91
};
92
 
93
typedef struct SETTINGS settings_t;
21 andreas 94
static settings_t localSettings;    //!< Global defines settings used in class TConfig.
2 andreas 95
 
21 andreas 96
/**
97
 * @brief TConfig::TConfig constructor
98
 *
99
 * @param path  A path and name of a configuration file.
100
 */
2 andreas 101
TConfig::TConfig(const std::string& path)
102
	: mPath(path)
103
{
90 andreas 104
    // Initialize the possible configuration paths
105
    mCfgPaths.push_back("/etc");
106
    mCfgPaths.push_back("/etc/tpanel");
107
    mCfgPaths.push_back("/usr/etc");
108
    mCfgPaths.push_back("/usr/etc/tpanel");
109
#ifdef __APPLE__
110
    mCfgPath.push_back("/opt/local/etc");
111
    mCfgPath.push_back("/opt/local/etc/tpanel");
112
    mCfgPath.push_back("/opt/local/usr/etc");
113
    mCfgPath.push_back("/opt/local/usr/etc/tpanel");
114
#endif
115
    if (findConfig())
116
        readConfig();
2 andreas 117
}
118
 
23 andreas 119
bool TConfig::reReadConfig()
120
{
121
    return readConfig();
122
}
123
 
21 andreas 124
/**
125
 * @brief TConfig::setProgName Sets the name of the application.
126
 * @param pname The name of the application.
127
 */
2 andreas 128
void TConfig::setProgName(const std::string& pname)
129
{
130
	localSettings.pname = pname;
131
}
132
 
21 andreas 133
/**
134
 * @brief TConfig::getProgName Retrieves the prevously stored application name.
135
 * @return The name of this application.
136
 */
2 andreas 137
std::string & TConfig::getProgName()
138
{
139
	return localSettings.pname;
140
}
141
 
21 andreas 142
/**
143
 * @brief TConfig::getChannel returns the AMX channel to use.
144
 *
145
 * The AMX channels an AMX panel can use start at 10000. This method returns
146
 * the channel number found in the configuration file. If there was no
147
 * channel defination found, it returns the default channel 10001.
148
 *
149
 * @return The AMX channel number to use.
150
 */
2 andreas 151
int TConfig::getChannel()
152
{
153
	return localSettings.ID;
154
}
155
 
21 andreas 156
/**
157
 * @brief TConfig::getConfigFileName returns the name of the configuration file.
158
 *
159
 * @return The name of the configuration file.
160
 */
2 andreas 161
std::string& TConfig::getConfigFileName()
162
{
163
	return localSettings.name;
164
}
165
 
21 andreas 166
/**
167
 * @brief TConfig::getConfigPath returns the path configuration file.
168
 *
169
 * The path was defined on the command line or found by searching the standard
170
 * directories.
171
 *
172
 * @return The path of the configuration file.
173
 */
2 andreas 174
std::string& TConfig::getConfigPath()
175
{
176
	return localSettings.path;
177
}
178
 
21 andreas 179
/**
180
 * @brief TConfig::getController returns the network name or IP address of the AMX controller.
181
 *
182
 * The network name or the IP address was read from the configuration file.
183
 *
184
 * @return The network name of the AMX controller.
185
 */
2 andreas 186
std::string& TConfig::getController()
187
{
188
	return localSettings.server;
189
}
190
 
21 andreas 191
/**
192
 * @brief TConfig::getSystem return the AMX system number.
193
 *
194
 * This number was read from the configuration file. If there was no system
195
 * number defined in the configuration file, then the default number 0 is
196
 * returned.
197
 *
198
 * @return The AMX system number.
199
 */
11 andreas 200
int TConfig::getSystem()
201
{
202
    return localSettings.system;
203
}
204
 
21 andreas 205
/**
206
 * @brief TConfig::getFirmVersion returns the version of the firmware.
207
 *
208
 * This option was read from the configuration file. There can be any version
209
 * number defined. But you must keep in mind, that the AMX controller may not
210
 * accept any number. If there was no version number defined, the standard
211
 * version number 1.0 is returned.
212
 *
213
 * @return The firmware version of this panel.
214
 */
2 andreas 215
std::string& TConfig::getFirmVersion()
216
{
217
	return localSettings.version;
218
}
219
 
21 andreas 220
/**
221
 * @brief TConfig::getLogFile the path and name of a logfile.
222
 *
223
 * If there is a logfile name defined in the configuration file, it is used
224
 * to write messages there. It depends on the _log level_ what is logged.
225
 *
226
 * @return The path and name of a logfile.
227
 */
2 andreas 228
std::string& TConfig::getLogFile()
229
{
230
	return localSettings.logFile;
231
}
232
 
21 andreas 233
/**
234
 * @brief TConfig::getLogLevel returns the defined log level.
235
 *
51 andreas 236
 * The loglevel can consist of the following values:
21 andreas 237
 *
238
 *     NONE         Logs nothing (default for Android)
239
 *     INFO         Logs only informations
240
 *     WARNING      Logs only warnings
51 andreas 241
 *     ERROR        Logs only errors
21 andreas 242
 *     TRACE        Logs only trace messages
243
 *     DEBUG        Logs only debug messages
244
 *     PROTOCOL     Logs only INFO and ERROR (default if NOT Android)
245
 *     ALL          Logs everything
246
 *
247
 * All log levels can be combined by concatenating them with the | symbol.
248
 *
249
 * @return The log level(s) as a string.
250
 */
2 andreas 251
string& TConfig::getLogLevel()
252
{
253
	return localSettings.logLevel;
254
}
255
 
21 andreas 256
/**
59 andreas 257
 * @brief TConfig::getLogLevelBits
258
 *
259
 * Returns the raw bit field defining the loglevels selected.
260
 *
261
 * @return The bit field of representing the selected log levels.
262
 */
263
uint TConfig::getLogLevelBits()
264
{
265
    return localSettings.logLevelBits;
266
}
267
/**
21 andreas 268
 * @brief TConfig::getPanelType the AMX type name of the panel.
269
 *
270
 * The type name of the panel is defined in the configuration file. If this
271
 * option was not defined, the default panel _android_ is returned.
272
 *
273
 * @return The type name of the panel.
274
 */
2 andreas 275
std::string& TConfig::getPanelType()
276
{
277
	return localSettings.ptype;
278
}
279
 
21 andreas 280
/**
281
 * @brief TConfig::getPort returnes the AMX port number to connect to.
282
 *
283
 * The port number can be defined in the configuration file. If there is no
284
 * configuration the default number 1319 is returned.
285
 *
286
 * @return The AMX network port number.
287
 */
2 andreas 288
int TConfig::getPort()
289
{
290
	return localSettings.port;
291
}
292
 
21 andreas 293
/**
294
 * @brief TConfig::getProjectPath returns the path to the AMX configuration files.
295
 *
296
 * The path was read from the configuration file. This path contains all the
297
 * files needed to display the elements of the surface.
298
 *
299
 * @return The path to the AMX configuration files.
300
 */
71 andreas 301
string& TConfig::getProjectPath()
2 andreas 302
{
303
	return localSettings.project;
304
}
305
 
112 andreas 306
 
71 andreas 307
string TConfig::getSystemPath(SYSTEMRESOURCE_t sres)
308
{
309
    string p;
310
 
311
    switch(sres)
312
    {
313
        case BORDERS:   p = "/borders"; break;
314
        case FONTS:     p = "/fonts"; break;
315
        case IMAGES:    p = "/images"; break;
316
        case SLIDERS:   p = "/sliders"; break;
317
        case SOUNDS:    p = "/sounds"; break;
318
        default:
319
            p.clear();
320
    }
321
 
322
    return localSettings.project + "/__system/graphics" + p;
323
}
324
 
23 andreas 325
bool TConfig::saveLogFile(const string &file)
326
{
327
    DECL_TRACER("TConfig::saveLogFile(const string &file)");
328
 
329
    if (file.empty() || localSettings.logFile.compare(file) == 0)
330
        return false;
331
 
332
    localSettings.logFile = file;
333
    return true;
334
}
335
 
336
bool TConfig::saveLogLevel(const string &level)
337
{
338
    DECL_TRACER("TConfig::saveLogLevel(const string &level)");
339
 
59 andreas 340
    if (level.find(SLOG_NONE) == string::npos && level.find(SLOG_INFO) == string::npos && level.find(SLOG_WARNING) == string::npos &&
341
            level.find(SLOG_ERROR) == string::npos && level.find(SLOG_TRACE) == string::npos && level.find(SLOG_DEBUG) == string::npos &&
342
            level.find(SLOG_PROTOCOL) == string::npos && level.find(SLOG_ALL) == string::npos)
23 andreas 343
        return false;
344
 
345
    localSettings.logLevel = level;
59 andreas 346
    localSettings.logLevelBits = logLevelStrToBits(level);
347
    MSG_INFO("New log level: " << level);
23 andreas 348
    return true;
349
}
350
 
59 andreas 351
bool TConfig::saveLogLevel(uint level)
352
{
353
    DECL_TRACER("TConfig::saveLogLevel(uint level)");
354
 
355
    if (level != 0 && !(level&HLOG_INFO) && !(level&HLOG_WARNING) &&
356
            !(level&HLOG_ERROR) && !(level&HLOG_TRACE) && !(level&HLOG_DEBUG))
357
        return false;
358
 
359
    localSettings.logLevelBits = level;
360
    localSettings.logLevel = logLevelBitsToString(level);
361
    MSG_INFO("New log level from bits: " << localSettings.logLevel);
362
    return true;
363
}
364
 
23 andreas 365
bool TConfig::saveChannel(int channel)
366
{
367
    DECL_TRACER("TConfig::saveChannel(int channel)");
368
 
369
    if (channel < 10000 || channel > 12000)
370
        return false;
371
 
372
    localSettings.ID = channel;
373
    return true;
374
}
375
 
376
bool TConfig::saveController(const string &cnt)
377
{
378
    DECL_TRACER("TConfig::saveController(const string &cnt)");
379
 
380
    localSettings.server = cnt;
381
    return true;
382
}
383
 
384
bool TConfig::savePanelType(const string &pt)
385
{
386
    DECL_TRACER("TConfig::savePanelType(const string &pt)");
387
 
388
    localSettings.ptype = pt;
389
    return true;
390
}
391
 
392
bool TConfig::savePort(int port)
393
{
394
    DECL_TRACER("TConfig::savePort(int port)");
395
 
396
    if (port < 1024 || port > 32767)
397
        return false;
398
 
399
    localSettings.port = port;
400
    return true;
401
}
402
 
403
bool TConfig::saveProjectPath(const string &path)
404
{
405
    DECL_TRACER("TConfig::saveProjectPath(const string &path)");
406
 
407
    if (path.empty())
408
        return false;
409
 
410
    localSettings.project = path;
411
    return true;
412
}
413
 
414
void TConfig::saveFormat(bool format)
415
{
416
    DECL_TRACER("TConfig::saveFormat(bool format)");
417
 
418
    localSettings.longformat = format;
419
}
420
 
24 andreas 421
void TConfig::saveScale(bool scale)
422
{
423
    DECL_TRACER("TConfig::saveScale(bool scale)");
424
 
425
    localSettings.scale = scale;
426
}
427
 
35 andreas 428
void TConfig::saveProfiling(bool prof)
429
{
430
    localSettings.profiling = prof;
431
}
432
 
51 andreas 433
void TConfig::savePassword1(const std::string& pw)
434
{
435
    localSettings.password1 = pw;
436
}
437
 
438
void TConfig::savePassword2(const std::string& pw)
439
{
440
    localSettings.password2 = pw;
441
}
442
 
443
void TConfig::savePassword3(const std::string& pw)
444
{
445
    localSettings.password3 = pw;
446
}
447
 
448
void TConfig::savePassword4(const std::string& pw)
449
{
450
    localSettings.password4 = pw;
451
}
452
 
71 andreas 453
void TConfig::saveSystemSoundFile(const std::string& snd)
454
{
455
    localSettings.systemSound = snd;
456
}
457
 
458
void TConfig::saveSystemSoundState(bool state)
459
{
460
    localSettings.systemSoundState = state;
461
}
462
 
112 andreas 463
void TConfig::saveFtpUser(const string& user)
464
{
465
    localSettings.ftpUser = user;
466
}
467
 
468
void TConfig::saveFtpPassword(const string& pw)
469
{
470
    localSettings.ftpPassword = pw;
471
}
472
 
104 andreas 473
std::string& TConfig::getSIPproxy()
474
{
475
    return localSettings.sip_proxy;
476
}
477
 
478
void TConfig::setSIPproxy(const std::string& address)
479
{
480
    localSettings.sip_proxy = address;
481
}
482
 
483
int TConfig::getSIPport()
484
{
485
    return localSettings.sip_port;
486
}
487
 
488
void TConfig::setSIPport(int port)
489
{
490
    localSettings.sip_port = port;
491
}
492
 
493
std::string& TConfig::getSIPstun()
494
{
495
    return localSettings.sip_stun;
496
}
497
 
498
void TConfig::setSIPstun(const std::string& address)
499
{
500
    localSettings.sip_stun = address;
501
}
502
 
503
std::string& TConfig::getSIPdomain()
504
{
505
    return localSettings.sip_domain;
506
}
507
 
508
void TConfig::setSIPdomain(const std::string& domain)
509
{
510
    localSettings.sip_domain = domain;
511
}
512
 
513
std::string& TConfig::getSIPuser()
514
{
515
    return localSettings.sip_user;
516
}
517
 
518
void TConfig::setSIPuser(const std::string& user)
519
{
520
    localSettings.sip_user = user;
521
}
522
 
523
std::string& TConfig::getSIPpassword()
524
{
525
    return localSettings.sip_password;
526
}
527
 
528
void TConfig::setSIPpassword(const std::string& pw)
529
{
530
    localSettings.sip_password = pw;
531
}
532
 
533
bool TConfig::getSIPstatus()
534
{
535
    return localSettings.sip_enabled;
536
}
537
 
538
void TConfig::setSIPstatus(bool state)
539
{
540
    localSettings.sip_enabled = state;
541
}
542
 
23 andreas 543
bool TConfig::saveSettings()
544
{
545
    DECL_TRACER("TConfig::saveSettings()");
546
 
547
    try
548
    {
549
        string fname = localSettings.path + "/" + localSettings.name;
550
        ofstream file(fname);
551
        string lines = "LogFile=" + localSettings.logFile + "\n";
552
        lines += "LogLevel=" + localSettings.logLevel + "\n";
553
        lines += "ProjectPath=" + localSettings.project + "\n";
554
        lines += string("NoBanner=") + (localSettings.noBanner ? "true" : "false") + "\n";
555
        lines += string("LongFormat=") + (localSettings.longformat ? "true" : "false") + "\n";
556
        lines += "Address=" + localSettings.server + "\n";
557
        lines += "Port=" + std::to_string(localSettings.port) + "\n";
558
        lines += "Channel=" + std::to_string(localSettings.ID) + "\n";
559
        lines += "System=" + std::to_string(localSettings.system) + "\n";
560
        lines += "PanelType=" + localSettings.ptype + "\n";
561
        lines += "Firmware=" + localSettings.version + "\n";
562
        lines += string("CertCheck=") + (localSettings.certCheck ? "true" : "false") + "\n";
24 andreas 563
        lines += string("Scale=") + (localSettings.scale ? "true" : "false") + "\n";
35 andreas 564
        lines += string("Profiling=") + (localSettings.profiling ? "true" : "false") + "\n";
51 andreas 565
        lines += string("Password1=") + localSettings.password1 + "\n";
566
        lines += string("Password2=") + localSettings.password2 + "\n";
567
        lines += string("Password3=") + localSettings.password3 + "\n";
568
        lines += string("Password4=") + localSettings.password4 + "\n";
71 andreas 569
        lines += string("SystemSoundFile=") + localSettings.systemSound + "\n";
570
        lines += string("SystemSoundState=") + (localSettings.systemSoundState ? "ON" : "OFF") + "\n";
571
        lines += string("SystemSingleBeep=") + localSettings.systemSingleBeep + "\n";
572
        lines += string("SystemDoubleBeep=") + localSettings.systemDoubleBeep + "\n";
112 andreas 573
        // FTP credentials
574
        lines += string("FTPuser=") + localSettings.ftpUser + "\n";
575
        lines += string("FTPpassword=") + localSettings.ftpPassword + "\n";
104 andreas 576
        // SIP settings
577
        lines += string("SIP_DOMAIN") + localSettings.sip_domain + "\n";
578
        lines += string("SIP_PROXY") + localSettings.sip_password + "\n";
579
        lines += string("SIP_PORT") + std::to_string(localSettings.sip_port) + "\n";
580
        lines += string("SIP_STUN") + localSettings.sip_stun + "\n";
581
        lines += string("SIP_USER") + localSettings.sip_user + "\n";
582
        lines += string("SIP_PASSWORD") + localSettings.sip_password + "\n";
583
        lines += string("SIP_ENABLED") + (localSettings.sip_enabled ? "true" : "false") + "\n";
23 andreas 584
        file.write(lines.c_str(), lines.size());
585
        file.close();
59 andreas 586
        MSG_INFO("Actual log level: " << localSettings.logLevel);
23 andreas 587
    }
588
    catch (std::exception& e)
589
    {
590
        MSG_ERROR("Couldn't write configs: " << e.what());
591
        return false;
592
    }
593
 
594
    TError::Current()->setLogFile(localSettings.logFile);
595
    TError::Current()->setLogLevel(localSettings.logLevel);
596
    return true;
597
}
598
 
21 andreas 599
/**
600
 * @brief TConfig::isLongFormat defines the format in the logfile.
601
 *
602
 * If this returns `true` the format in the logfile is a long format. This
603
 * means, that in front of each message is an additional timestamp.
604
 *
605
 * @return `true` = long format, `false` = short format (default).
606
 */
2 andreas 607
bool TConfig::isLongFormat()
608
{
609
	return localSettings.longformat;
610
}
611
 
21 andreas 612
/**
613
 * @brief TConfig::showBanner defines whether the banner should be showed or not.
614
 *
615
 * If this method returns `false` the banner on startup is not displayed.
616
 *
617
 * @return `true` = display the banner (default), `false` = show no banner.
618
 */
2 andreas 619
bool TConfig::showBanner()
620
{
621
	return !localSettings.noBanner;
622
}
623
 
21 andreas 624
/**
24 andreas 625
 * @brief TConfig::getScale returns the scale setting
626
 *
627
 * If this is set to TRUE, all images are scaled to fit the screen.
628
 *
629
 * @return scale state
630
 */
631
bool TConfig::getScale()
632
{
633
    return localSettings.scale;
634
}
635
 
35 andreas 636
bool TConfig::getProfiling()
637
{
638
    return localSettings.profiling;
639
}
640
 
51 andreas 641
string & TConfig::getPassword1()
642
{
643
    return localSettings.password1;
644
}
645
 
646
string & TConfig::getPassword2()
647
{
648
    return localSettings.password2;
649
}
650
 
651
string & TConfig::getPassword3()
652
{
653
    return localSettings.password3;
654
}
655
 
656
string & TConfig::getPassword4()
657
{
658
    return localSettings.password4;
659
}
660
 
71 andreas 661
string & TConfig::getSystemSound()
662
{
663
    return localSettings.systemSound;
664
}
665
 
666
bool TConfig::getSystemSoundState()
667
{
668
    return localSettings.systemSoundState;
669
}
670
 
671
string& TConfig::getSingleBeepSound()
672
{
673
    return localSettings.systemSingleBeep;
674
}
675
 
676
string& TConfig::getDoubleBeepSound()
677
{
678
    return localSettings.systemDoubleBeep;
679
}
680
 
112 andreas 681
string& TConfig::getFtpUser()
682
{
683
    return localSettings.ftpUser;
684
}
685
 
686
string& TConfig::getFtpPassword()
687
{
688
    return localSettings.ftpPassword;
689
}
690
 
24 andreas 691
/**
71 andreas 692
 * Checks a string if it contains a word which may be interpreted as a
693
 * boolean TRUE.
694
 *
695
 * @param boolean   A string containg a word.
696
 *
697
 * @return If the string \p boolean contains a word that can be interpreted as
698
 * a boolean TRUE, it returns TRUE. In any other case it returns FALSE.
699
 */
700
bool TConfig::isTrue(const string& boolean)
701
{
702
    if (caseCompare(boolean, "1") == 0 || caseCompare(boolean, "yes") == 0 ||
703
        caseCompare(boolean, "true") == 0 || caseCompare(boolean, "on") == 0)
704
        return true;
705
 
706
    return false;
707
}
708
 
709
/**
21 andreas 710
 * @brief TConfig::certCheck check the certificate if the connection is encrypted.
711
 *
712
 * Currently not implemented!
713
 *
714
 * @return `true` = check the certificate, `false` = accept any certificate (default).
715
 */
716
bool TConfig::certCheck()
717
{
718
    return localSettings.certCheck;
719
}
720
 
721
/**
59 andreas 722
 * @brief TConfig::logLevelStrToBits
723
 * Converts a string containing one or more loglevels into a bit field.
724
 * @param level A string containing the log levels
725
 * @return A bit field representing the log levels.
726
 */
727
uint TConfig::logLevelStrToBits(const string& level)
728
{
729
    uint l = 0;
730
 
731
    if (level.find("INFO") != string::npos)
732
        l |= HLOG_INFO;
733
 
734
    if (level.find("WARNING") != string::npos)
735
        l |= HLOG_WARNING;
736
 
737
    if (level.find("ERROR") != string::npos)
738
        l |= HLOG_ERROR;
739
 
740
    if (level.find("TRACE") != string::npos)
741
        l |= HLOG_TRACE;
742
 
743
    if (level.find("DEBUG") != string::npos)
744
        l |= HLOG_DEBUG;
745
 
746
    if (level.find("PROTOCOL") != string::npos)
71 andreas 747
        l |= HLOG_PROTOCOL;
59 andreas 748
 
749
    if (level.find("ALL") != string::npos)
750
        l = HLOG_ALL;
751
 
752
    return l;
753
}
754
 
755
string TConfig::logLevelBitsToString(uint level)
756
{
757
    string l;
758
 
759
    if (level == 0)
760
    {
761
        l = SLOG_NONE;
762
        return l;
763
    }
764
 
765
    if (level & HLOG_INFO)
766
    {
767
        if (l.length() > 0)
768
            l.append("|");
769
 
770
        l.append(SLOG_INFO);
771
    }
772
 
773
    if (level & HLOG_WARNING)
774
    {
775
        if (l.length() > 0)
776
            l.append("|");
777
 
778
        l.append(SLOG_WARNING);
779
    }
780
 
781
    if (level & HLOG_ERROR)
782
    {
783
        if (l.length() > 0)
784
            l.append("|");
785
 
786
        l.append(SLOG_ERROR);
787
    }
788
 
789
    if (level & HLOG_TRACE)
790
    {
791
        if (l.length() > 0)
792
            l.append("|");
793
 
794
        l.append(SLOG_TRACE);
795
    }
796
 
797
    if (level & HLOG_DEBUG)
798
    {
799
        if (l.length() > 0)
800
            l.append("|");
801
 
802
        l.append(SLOG_DEBUG);
803
    }
804
 
805
    return l;
806
}
807
/**
21 andreas 808
 * @brief TConfig::findConfig search for the location of the configuration file.
809
 *
810
 * If there was no configuration file given on the command line, this method
811
 * searches for a configuration file on a few standard directories. This are:
812
 *
813
 *     /etc/tpanel.conf
814
 *     /etc/tpanel/tpanel.conf
815
 *     /usr/etc/tpanel.conf
816
 *     $HOME/.tpanel.conf
817
 *
818
 * On macOS the following additional directories are searched:
819
 *
820
 *     /opt/local/etc/tpanel.conf
821
 *     /opt/local/etc/tpanel/tpanel.conf
822
 *     /opt/local/usr/etc/tpanel.conf
823
 *
824
 * @return On success `true`, otherwise `false`.
825
 */
2 andreas 826
bool TConfig::findConfig()
827
{
90 andreas 828
    char *HOME = nullptr;
829
    string sFileName;
22 andreas 830
 
90 andreas 831
    if (!mPath.empty())
832
    {
833
        size_t pos = mPath.find_last_of("/");
2 andreas 834
 
90 andreas 835
        if (pos != string::npos)
836
        {
837
            localSettings.path = mPath.substr(0, pos);
838
            localSettings.name = mPath.substr(pos+1);
839
            mCFile = mPath;
840
            return !mCFile.empty();
841
        }
2 andreas 842
 
90 andreas 843
        localSettings.name = mPath;
844
        mCFile = mPath;
845
        return !mCFile.empty();
846
    }
2 andreas 847
 
90 andreas 848
    localSettings.name = "tpanel.conf";
51 andreas 849
    localSettings.password1 = "1988";
850
    localSettings.password2 = "1988";
851
    localSettings.password3 = "1988";
852
    localSettings.password4 = "1988";
71 andreas 853
    localSettings.systemSound = "singleBeep.wav";
854
    localSettings.systemSoundState = true;
855
    localSettings.systemSingleBeep = "singleBeep01.wav";
856
    localSettings.systemDoubleBeep = "doubleBeep01.wav";
112 andreas 857
    localSettings.ftpUser = "administrator";
858
    localSettings.ftpPassword = "password";
859
    localSettings.sip_port = 5050;
21 andreas 860
#ifdef __ANDROID__
22 andreas 861
    std::stringstream s;
862
    TValidateFile vf;
863
    HOME = getenv("HOME");
2 andreas 864
 
22 andreas 865
    if (!HOME || !*HOME)
21 andreas 866
    {
43 andreas 867
        s << "Error: Environment variable HOME does not exist!";
22 andreas 868
        __android_log_print(ANDROID_LOG_ERROR, "tpanel", "%s", s.str().c_str());
869
        TError::setErrorMsg(s.str());
21 andreas 870
        return false;
871
    }
872
 
22 andreas 873
    localSettings.path = HOME;
874
 
88 andreas 875
    if (!vf.isValidDir(localSettings.path))
21 andreas 876
    {
22 andreas 877
        s << "Error: Path " << localSettings.path << " does not exist!";
878
        __android_log_print(ANDROID_LOG_ERROR, "tpanel", "%s", s.str().c_str());
879
        TError::setErrorMsg(s.str());
21 andreas 880
        return false;
881
    }
882
 
22 andreas 883
    sFileName = localSettings.path + "/" + localSettings.name;
21 andreas 884
 
22 andreas 885
    if (access(sFileName.c_str(), F_OK) == -1)    // Does the configuration file exist?
21 andreas 886
    {                                       // No, than create it and also the directory structure
887
        try
888
        {
889
            ofstream cfg(sFileName);
890
 
891
            string content = "LogFile=" + localSettings.path + "/tpanel.log\n";
23 andreas 892
            content += "LogLevel=NONE\n";
21 andreas 893
            content += "ProjectPath=" + localSettings.path + "/tpanel\n";
894
            content += "LongFormat=false\n";
895
            content += "Address=0.0.0.0\n";
896
            content += "Port=1319\n";
897
            content += "Channel=10001\n";
898
            content += "PanelType=Android\n";
26 andreas 899
            content += string("Firmware=") + VERSION_STRING() + "\n";
38 andreas 900
            content += "Scale=true\n";
35 andreas 901
            content += "Profiling=false\n";
51 andreas 902
            content += "Password1=1988\n";
903
            content += "Password2=1988\n";
904
            content += "Password3=1988\n";
905
            content += "Password4=1988\n";
71 andreas 906
            content += "SystemSoundFile=singleBeep.wav\n";
907
            content += "SystemSoundState=ON\n";
908
            content += "SystemSingleBeep=singleBeep01.wav\n";
909
            content += "SystemDoubleBeep=doubleBeep01.wav\n";
112 andreas 910
            content += "FTPuser=administrator\n";
911
            content += "FTPpassword=password\n";
912
            content += "SIP_PORT=5050\n";
21 andreas 913
            cfg.write(content.c_str(), content.size());
914
            cfg.close();
915
 
916
            string path = localSettings.path + "/tpanel";
22 andreas 917
            TTPInit init(path);
21 andreas 918
        }
919
        catch (std::exception& e)
920
        {
23 andreas 921
            s << "Error: " << e.what();
22 andreas 922
            __android_log_print(ANDROID_LOG_ERROR, "tpanel" , "%s", s.str().c_str());
21 andreas 923
            TError::setErrorMsg(TERRERROR, string("Error: ") + e.what());
924
            return false;
925
        }
926
    }
927
#else
90 andreas 928
    if (!(HOME = getenv("HOME")))
929
        std::cerr << "TConfig::findConfig: No environment variable HOME!" << std::endl;
2 andreas 930
 
90 andreas 931
    vector<string>::iterator iter;
932
    bool found = false;
2 andreas 933
 
90 andreas 934
    for (iter = mCfgPaths.begin(); iter != mCfgPaths.end(); ++iter)
935
    {
936
        string f = *iter + "/tpanel.conf";
937
 
938
        if (!access(f.c_str(), R_OK))
939
        {
940
            sFileName = f;
941
            localSettings.path = *iter;
113 andreas 942
            found = true;
90 andreas 943
            break;
944
        }
945
    }
946
 
947
    // The local configuration file has precedence over the global one.
948
    if (HOME)
949
    {
950
        string f = HOME;
113 andreas 951
#ifndef __ANDROID__
90 andreas 952
        f += "/.tpanel.conf";
113 andreas 953
#else
954
        f += "/tpanel.conf";
955
#endif
90 andreas 956
        if (!access(f.data(), R_OK))
957
        {
958
            sFileName = f;
959
            localSettings.path = HOME;
960
            found = true;
961
        }
962
    }
963
 
964
    if (!found)
965
    {
966
        std::cerr << "TConfig::findConfig: Can't find any configuration file!" << std::endl;
967
        TError::setError();
968
        sFileName.clear();
969
        localSettings.name.clear();
970
        localSettings.path.clear();
971
    }
21 andreas 972
#endif
90 andreas 973
    mCFile = sFileName;
974
    return !sFileName.empty();
2 andreas 975
}
976
 
21 andreas 977
/**
978
 * @brief TConfig::readConfig reads a config file.
979
 *
980
 * This method reads a config file and stores the known options into the
981
 * struct localSettings.
982
 *
983
 * @return `true` on success.\n
984
 * Returns `false` on error and sets the internal error.
985
 */
2 andreas 986
bool TConfig::readConfig()
987
{
35 andreas 988
    ifstream fs;
2 andreas 989
 
35 andreas 990
    // First initialize the defaults
991
    localSettings.ID = 0;
992
    localSettings.port = 1397;
993
    localSettings.ptype = "android";
994
    localSettings.version = "1.0";
995
    localSettings.longformat = false;
43 andreas 996
    localSettings.profiling = false;
71 andreas 997
    localSettings.systemSoundState = true;
998
    localSettings.systemSound = "singleBeep.wav";
999
    localSettings.systemSingleBeep = "singleBeep01.wav";
1000
    localSettings.systemDoubleBeep = "doubleBeep01.wav";
112 andreas 1001
    localSettings.ftpUser = "administrator";
1002
    localSettings.ftpPassword = "password";
1003
    localSettings.sip_port = 5050;
43 andreas 1004
#ifdef __ANDROID__
1005
    localSettings.logLevel = SLOG_NONE;
59 andreas 1006
    localSettings.logLevelBits = HLOG_NONE;
43 andreas 1007
#else
1008
    localSettings.logLevel = SLOG_PROTOCOL;
1009
#endif
2 andreas 1010
 
35 andreas 1011
    // Now get the settings from file
1012
    try
1013
    {
1014
        fs.open(mCFile.c_str(), fstream::in);
1015
    }
1016
    catch (const fstream::failure e)
1017
    {
1018
        std::cerr << "TConfig::readConfig: Error on file " << mCFile << ": " << e.what() << std::endl;
1019
        TError::setError();
1020
        return false;
1021
    }
2 andreas 1022
 
35 andreas 1023
    for (string line; getline(fs, line);)
1024
    {
1025
        size_t pos;
2 andreas 1026
 
35 andreas 1027
        if ((pos = line.find("#")) != string::npos)
1028
        {
1029
            if (pos == 0)
1030
                line.clear();
1031
            else
1032
                line = line.substr(0, pos);
1033
        }
2 andreas 1034
 
35 andreas 1035
        if (line.empty() || line.find("=") == string::npos)
1036
            continue;
2 andreas 1037
 
35 andreas 1038
        vector<string> parts = split(line, "=", true);
2 andreas 1039
 
35 andreas 1040
        if (parts.size() == 2)
1041
        {
1042
            string left = parts[0];
1043
            string right = ltrim(parts[1]);
2 andreas 1044
 
35 andreas 1045
            if (caseCompare(left, "PORT") == 0 && !right.empty())
1046
                localSettings.port = atoi(right.c_str());
1047
            else if (caseCompare(left, "LOGFILE") == 0 && !right.empty())
1048
            {
1049
                localSettings.logFile = right;
23 andreas 1050
                TStreamError::setLogFileOnly(right);
35 andreas 1051
            }
1052
            else if (caseCompare(left, "LOGLEVEL") == 0 && !right.empty())
1053
            {
1054
                TStreamError::setLogLevel(right);
1055
                localSettings.logLevel = right;
59 andreas 1056
                localSettings.logLevelBits = logLevelStrToBits(right);
35 andreas 1057
            }
1058
            else if (caseCompare(left, "ProjectPath") == 0 && !right.empty())
43 andreas 1059
            {
35 andreas 1060
                localSettings.project = right;
43 andreas 1061
#ifdef __ANDROID__
1062
                TValidateFile vf;
1063
 
1064
                if (!vf.isValidFile(right))
1065
                {
1066
                    char *HOME = getenv("HOME");
1067
 
1068
                    if (HOME)
1069
                    {
1070
                        localSettings.project = HOME;
1071
                        localSettings.project += "/tpanel";
1072
                    }
1073
                }
1074
#endif
1075
            }
11 andreas 1076
            else if (caseCompare(left, "System") == 0 && !right.empty())
1077
                localSettings.system = atoi(right.c_str());
1078
            else if (caseCompare(left, "PanelType") == 0 && !right.empty())
35 andreas 1079
                localSettings.ptype = right;
1080
            else if (caseCompare(left, "Address") == 0 && !right.empty())
1081
                localSettings.server = right;
1082
            else if (caseCompare(left, "Firmware") == 0 && !right.empty())
1083
                localSettings.version = right;
1084
            else if (caseCompare(left, "LongFormat") == 0 && !right.empty())
71 andreas 1085
                localSettings.longformat = isTrue(right);
35 andreas 1086
            else if (caseCompare(left, "NoBanner") == 0 && !right.empty())
71 andreas 1087
                localSettings.noBanner = isTrue(right);
35 andreas 1088
            else if (caseCompare(left, "CertCheck") == 0 && !right.empty())
71 andreas 1089
                localSettings.certCheck = isTrue(right);
21 andreas 1090
            else if (caseCompare(left, "Channel") == 0 && !right.empty())
35 andreas 1091
            {
1092
                localSettings.ID = atoi(right.c_str());
2 andreas 1093
 
113 andreas 1094
                if (localSettings.ID < 10000 || localSettings.ID >= 29000)
35 andreas 1095
                {
1096
                    std::cerr << "TConfig::readConfig: Invalid port number " << right << std::endl;
1097
                    localSettings.ID = 0;
1098
                }
1099
            }
26 andreas 1100
            else if (caseCompare(left, "Scale") == 0 && !right.empty())
71 andreas 1101
                localSettings.scale = isTrue(right);
35 andreas 1102
            else if (caseCompare(left, "Profiling") == 0 && !right.empty())
71 andreas 1103
                localSettings.profiling = isTrue(right);
51 andreas 1104
            else if (caseCompare(left, "Password1") == 0 && !right.empty())
1105
                localSettings.password1 = right;
1106
            else if (caseCompare(left, "Password2") == 0 && !right.empty())
1107
                localSettings.password2 = right;
1108
            else if (caseCompare(left, "Password3") == 0 && !right.empty())
1109
                localSettings.password3 = right;
1110
            else if (caseCompare(left, "Password4") == 0 && !right.empty())
1111
                localSettings.password4 = right;
71 andreas 1112
            else if (caseCompare(left, "SystemSoundFile") == 0 && !right.empty())
1113
                localSettings.systemSound = right;
1114
            else if (caseCompare(left, "SystemSoundState") == 0 && !right.empty())
1115
                localSettings.systemSoundState = isTrue(right);
1116
            else if (caseCompare(left, "SystemSingleBeep") == 0 && !right.empty())
1117
                localSettings.systemSingleBeep = right;
1118
            else if (caseCompare(left, "SystemDoubleBeep") == 0 && !right.empty())
1119
                localSettings.systemDoubleBeep = right;
112 andreas 1120
            else if (caseCompare(left, "FTPuser") == 0 && !right.empty())       // FTP credentials
1121
                localSettings.ftpUser = right;
1122
            else if (caseCompare(left, "FTPpassword") == 0 && !right.empty())
1123
                localSettings.ftpPassword = right;
104 andreas 1124
            else if (caseCompare(left, "SIP_PROXY") == 0 && !right.empty())     // SIP settings starting here
1125
                localSettings.sip_proxy = right;
1126
            else if (caseCompare(left, "SIP_PORT") == 0 && !right.empty())
1127
                localSettings.sip_port = atoi(right.c_str());
1128
            else if (caseCompare(left, "SIP_STUN") == 0 && !right.empty())
1129
                localSettings.sip_stun = right;
1130
            else if (caseCompare(left, "SIP_DOMAIN") == 0 && !right.empty())
1131
                localSettings.sip_domain = right;
1132
            else if (caseCompare(left, "SIP_USER") == 0 && !right.empty())
1133
                localSettings.sip_user = right;
1134
            else if (caseCompare(left, "SIP_PASSWORD") == 0 && !right.empty())
1135
                localSettings.sip_password = right;
1136
            else if (caseCompare(left, "SIP_ENABLED") == 0 && !right.empty())
1137
                localSettings.sip_enabled = isTrue(right);
26 andreas 1138
        }
35 andreas 1139
    }
2 andreas 1140
 
35 andreas 1141
    fs.close();
2 andreas 1142
 
23 andreas 1143
    if (TStreamError::checkFilter(HLOG_DEBUG))
35 andreas 1144
    {
1145
        MSG_INFO("Selected Parameters:");
1146
        MSG_INFO("    Path to cfg.: " << localSettings.path);
1147
        MSG_INFO("    Name of cfg.: " << localSettings.name);
23 andreas 1148
#ifndef __ANDROID__
1149
        MSG_INFO("    Logfile:      " << localSettings.logFile);
1150
#endif
26 andreas 1151
        MSG_INFO("    LogLevel:     " << localSettings.logLevel);
35 andreas 1152
        MSG_INFO("    Long format:  " << (localSettings.longformat ? "YES" : "NO"));
1153
        MSG_INFO("    Project path: " << localSettings.project);
23 andreas 1154
#ifndef __ANDROID__
35 andreas 1155
        MSG_INFO("    Show banner:  " << (localSettings.noBanner ? "NO" : "YES"));
23 andreas 1156
#endif
35 andreas 1157
        MSG_INFO("    Controller:   " << localSettings.server);
1158
        MSG_INFO("    Port:         " << localSettings.port);
1159
        MSG_INFO("    Channel:      " << localSettings.ID);
1160
        MSG_INFO("    Panel type:   " << localSettings.ptype);
1161
        MSG_INFO("    Firmware ver. " << localSettings.version);
26 andreas 1162
        MSG_INFO("    Scaling:      " << (localSettings.scale ? "YES" : "NO"));
35 andreas 1163
        MSG_INFO("    Profiling:    " << (localSettings.profiling ? "YES" : "NO"));
71 andreas 1164
        MSG_INFO("    System Sound: " << localSettings.systemSound);
1165
        MSG_INFO("    Sound state:  " << (localSettings.systemSoundState ? "ACTIVATED" : "DEACTIVATED"));
1166
        MSG_INFO("    Single beep:  " << localSettings.systemSingleBeep);
1167
        MSG_INFO("    Double beep:  " << localSettings.systemDoubleBeep);
35 andreas 1168
    }
2 andreas 1169
 
35 andreas 1170
    return true;
2 andreas 1171
}
1172
 
21 andreas 1173
/**
1174
 * @brief TConfig::split splitts a string into parts.
1175
 *
1176
 * The method splitts a string into parts separated by \p seps. It puts the
1177
 * parts into a vector array.
1178
 *
1179
 * @param str           The string to split
1180
 * @param seps          The separator(s)
1181
 * @param trimEmpty     `true` = trum the parts.
1182
 *
1183
 * @return A vector array containing the parts of the string \p str.
1184
 */
2 andreas 1185
vector<string> TConfig::split(const string& str, const string& seps, const bool trimEmpty)
1186
{
1187
	size_t pos = 0, mark = 0;
1188
	vector<string> parts;
1189
 
1190
	for (auto it = str.begin(); it != str.end(); ++it)
1191
	{
1192
		for (auto sepIt = seps.begin(); sepIt != seps.end(); ++sepIt)
1193
		{
1194
			if (*it == *sepIt)
1195
			{
1196
				size_t len = pos - mark;
1197
				parts.push_back(str.substr(mark, len));
1198
				mark = pos + 1;
1199
				break;
1200
			}
1201
		}
1202
 
1203
		pos++;
1204
	}
1205
 
1206
	parts.push_back(str.substr(mark));
1207
 
1208
	if (trimEmpty)
1209
	{
1210
		vector<string> nparts;
1211
 
1212
		for (auto it = parts.begin(); it != parts.end(); ++it)
1213
		{
1214
			if (it->empty())
1215
				continue;
1216
 
1217
			nparts.push_back(*it);
1218
		}
1219
 
1220
		return nparts;
1221
	}
1222
 
1223
	return parts;
1224
}
1225
 
21 andreas 1226
/**
1227
 * @brief TConfig::caseCompare compares 2 strings
1228
 *
1229
 * This method compares 2 strings case insensitive. This means that it ignores
1230
 * the case of the letters. For example:
1231
 *
1232
 *     BLAME
1233
 *     blame
1234
 *     Blame
1235
 *
1236
 * are all the same and would return 0, which means _equal_.
1237
 *
1238
 * @param str1  1st string to compare
1239
 * @param str2  2nd string to compare
1240
 *
1241
 * @return 0 if the strings are equal\n
1242
 * less than 0 if the byte of \p str1 is bigger than the byte of \p str2\n
1243
 * grater than 0 if the byte of \p str1 is smaller than the byte of \p str2.
1244
 */
2 andreas 1245
int TConfig::caseCompare(const string& str1, const string& str2)
1246
{
1247
	size_t i = 0;
1248
 
1249
	if (str1.length() != str2.length())
1250
		return ((str1.length() < str2.length()) ? -1 : 1);
1251
 
1252
	for (auto it = str1.begin(); it != str1.end(); ++it)
1253
	{
1254
		if (tolower(*it) != tolower(str2.at(i)))
1255
			return (int)(*it - str2.at(i));
1256
 
1257
		i++;
1258
	}
1259
 
1260
	return 0;
1261
}