Subversion Repositories tpanel

Rev

Rev 11 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 11 Rev 21
Line 1... Line 1...
1
/*
1
/*
2
 * Copyright (C) 2020 by Andreas Theofilu <andreas@theosys.at>
2
 * Copyright (C) 2020, 2021 by Andreas Theofilu <andreas@theosys.at>
3
 *
3
 *
4
 * This program is free software; you can redistribute it and/or modify
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
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
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
7
 * (at your option) any later version.
Line 14... Line 14...
14
 * You should have received a copy of the GNU General Public License
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,
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
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
17
 */
17
 */
18
#include "tconfig.h"
18
#include "tconfig.h"
-
 
19
 
19
#include <fstream>
20
#include <fstream>
20
#include <vector>
21
#include <vector>
21
#include <iterator>
22
#include <iterator>
22
#include <unistd.h>
23
#include <unistd.h>
-
 
24
#include <sys/stat.h>
-
 
25
#include <sys/types.h>
-
 
26
 
23
#include "terror.h"
27
#include "terror.h"
24
 
28
 
25
using std::string;
29
using std::string;
26
using std::ifstream;
30
using std::ifstream;
-
 
31
using std::ofstream;
27
using std::fstream;
32
using std::fstream;
28
using std::vector;
33
using std::vector;
-
 
34
using std::cout;
-
 
35
using std::cerr;
-
 
36
using std::endl;
29
 
37
 
-
 
38
/**
-
 
39
 * @struct SETTINGS
-
 
40
 * @brief The SETTINGS struct bundles the configuration options.
-
 
41
 *
-
 
42
 * This structure contains variables for all possible configuration options.
-
 
43
 * It is used by the class TConfig. Through this class it's possible to
-
 
44
 * access all configuration options.
-
 
45
 */
30
struct SETTINGS
46
struct SETTINGS
31
{
47
{
32
    string pname{"tpanel"};    // Name of the program (default "tpanel")
48
    string pname{"tpanel"};     //!< Name of the program (default "tpanel")
33
    string path;               // The path where the configuration file is located
49
    string path;                //!< The path where the configuration file is located
34
    string name;               // The name of the configuration file
50
    string name;                //!< The name of the configuration file
35
    string project;            // The path where the original project files are located
51
    string project;             //!< The path where the original project files are located
36
    string server;             // The name or IP address of the server to connect
52
    string server;              //!< The name or IP address of the server to connect
37
    int system{0};             // The number of the AMX system
53
    int system{0};              //!< The number of the AMX system
38
    int port{0};               // The port number
54
    int port{0};                //!< The port number
39
    int ID{0};                 // the panel ID (a number starting by 10000)
55
    int ID{0};                  //!< the panel ID (a number starting by 10000)
40
    string ptype;              // The type of the panel (android, ipad, iphone, ...)
56
    string ptype;               //!< The type of the panel (android, ipad, iphone, ...)
41
    string version;            // The "firmware" version
57
    string version;             //!< The "firmware" version
42
    string logFile;            // Optional path and name of a logfile
58
    string logFile;             //!< Optional path and name of a logfile
43
    string logLevel;           // The log level(s).
59
    string logLevel;            //!< The log level(s).
44
    bool longformat{false};    // TRUE = long format
60
    bool longformat{false};     //!< TRUE = long format
45
    bool noBanner{false};      // Startup without showing a banner on the command line.
61
    bool noBanner{false};       //!< Startup without showing a banner on the command line.
-
 
62
    bool certCheck{false};      //!< TRUE = Check certificate for SSL connection
46
};
63
};
47
 
64
 
48
typedef struct SETTINGS settings_t;
65
typedef struct SETTINGS settings_t;
49
static settings_t localSettings;
66
static settings_t localSettings;    //!< Global defines settings used in class TConfig.
50
 
67
 
-
 
68
/**
-
 
69
 * @brief TConfig::TConfig constructor
-
 
70
 *
-
 
71
 * @param path  A path and name of a configuration file.
-
 
72
 */
51
TConfig::TConfig(const std::string& path)
73
TConfig::TConfig(const std::string& path)
52
	: mPath(path)
74
	: mPath(path)
53
{
75
{
54
	if (findConfig())
76
	if (findConfig())
55
		readConfig();
77
		readConfig();
56
}
78
}
57
 
79
 
-
 
80
/**
-
 
81
 * @brief TConfig::setProgName Sets the name of the application.
-
 
82
 * @param pname The name of the application.
-
 
83
 */
58
void TConfig::setProgName(const std::string& pname)
84
void TConfig::setProgName(const std::string& pname)
59
{
85
{
60
	localSettings.pname = pname;
86
	localSettings.pname = pname;
61
}
87
}
62
 
88
 
-
 
89
/**
-
 
90
 * @brief TConfig::getProgName Retrieves the prevously stored application name.
-
 
91
 * @return The name of this application.
-
 
92
 */
63
std::string & TConfig::getProgName()
93
std::string & TConfig::getProgName()
64
{
94
{
65
	return localSettings.pname;
95
	return localSettings.pname;
66
}
96
}
67
 
97
 
-
 
98
/**
-
 
99
 * @brief TConfig::getChannel returns the AMX channel to use.
-
 
100
 *
-
 
101
 * The AMX channels an AMX panel can use start at 10000. This method returns
-
 
102
 * the channel number found in the configuration file. If there was no
-
 
103
 * channel defination found, it returns the default channel 10001.
-
 
104
 *
-
 
105
 * @return The AMX channel number to use.
-
 
106
 */
68
int TConfig::getChannel()
107
int TConfig::getChannel()
69
{
108
{
70
	return localSettings.ID;
109
	return localSettings.ID;
71
}
110
}
72
 
111
 
-
 
112
/**
-
 
113
 * @brief TConfig::getConfigFileName returns the name of the configuration file.
-
 
114
 *
-
 
115
 * @return The name of the configuration file.
-
 
116
 */
73
std::string& TConfig::getConfigFileName()
117
std::string& TConfig::getConfigFileName()
74
{
118
{
75
	return localSettings.name;
119
	return localSettings.name;
76
}
120
}
77
 
121
 
-
 
122
/**
-
 
123
 * @brief TConfig::getConfigPath returns the path configuration file.
-
 
124
 *
-
 
125
 * The path was defined on the command line or found by searching the standard
-
 
126
 * directories.
-
 
127
 *
-
 
128
 * @return The path of the configuration file.
-
 
129
 */
78
std::string& TConfig::getConfigPath()
130
std::string& TConfig::getConfigPath()
79
{
131
{
80
	return localSettings.path;
132
	return localSettings.path;
81
}
133
}
82
 
134
 
-
 
135
/**
-
 
136
 * @brief TConfig::getController returns the network name or IP address of the AMX controller.
-
 
137
 *
-
 
138
 * The network name or the IP address was read from the configuration file.
-
 
139
 *
-
 
140
 * @return The network name of the AMX controller.
-
 
141
 */
83
std::string& TConfig::getController()
142
std::string& TConfig::getController()
84
{
143
{
85
	return localSettings.server;
144
	return localSettings.server;
86
}
145
}
87
 
146
 
-
 
147
/**
-
 
148
 * @brief TConfig::getSystem return the AMX system number.
-
 
149
 *
-
 
150
 * This number was read from the configuration file. If there was no system
-
 
151
 * number defined in the configuration file, then the default number 0 is
-
 
152
 * returned.
-
 
153
 *
-
 
154
 * @return The AMX system number.
-
 
155
 */
88
int TConfig::getSystem()
156
int TConfig::getSystem()
89
{
157
{
90
    return localSettings.system;
158
    return localSettings.system;
91
}
159
}
92
 
160
 
-
 
161
/**
-
 
162
 * @brief TConfig::getFirmVersion returns the version of the firmware.
-
 
163
 *
-
 
164
 * This option was read from the configuration file. There can be any version
-
 
165
 * number defined. But you must keep in mind, that the AMX controller may not
-
 
166
 * accept any number. If there was no version number defined, the standard
-
 
167
 * version number 1.0 is returned.
-
 
168
 *
-
 
169
 * @return The firmware version of this panel.
-
 
170
 */
93
std::string& TConfig::getFirmVersion()
171
std::string& TConfig::getFirmVersion()
94
{
172
{
95
	return localSettings.version;
173
	return localSettings.version;
96
}
174
}
97
 
175
 
-
 
176
/**
-
 
177
 * @brief TConfig::getLogFile the path and name of a logfile.
-
 
178
 *
-
 
179
 * If there is a logfile name defined in the configuration file, it is used
-
 
180
 * to write messages there. It depends on the _log level_ what is logged.
-
 
181
 *
-
 
182
 * @return The path and name of a logfile.
-
 
183
 */
98
std::string& TConfig::getLogFile()
184
std::string& TConfig::getLogFile()
99
{
185
{
100
	return localSettings.logFile;
186
	return localSettings.logFile;
101
}
187
}
102
 
188
 
-
 
189
/**
-
 
190
 * @brief TConfig::getLogLevel returns the defined log level.
-
 
191
 *
-
 
192
 * The loglevel can be one of the following values:
-
 
193
 *
-
 
194
 *     NONE         Logs nothing (default for Android)
-
 
195
 *     INFO         Logs only informations
-
 
196
 *     WARNING      Logs only warnings
-
 
197
 *     ERROR        Logs onls errors
-
 
198
 *     TRACE        Logs only trace messages
-
 
199
 *     DEBUG        Logs only debug messages
-
 
200
 *     PROTOCOL     Logs only INFO and ERROR (default if NOT Android)
-
 
201
 *     ALL          Logs everything
-
 
202
 *
-
 
203
 * All log levels can be combined by concatenating them with the | symbol.
-
 
204
 *
-
 
205
 * @return The log level(s) as a string.
-
 
206
 */
103
string& TConfig::getLogLevel()
207
string& TConfig::getLogLevel()
104
{
208
{
105
	return localSettings.logLevel;
209
	return localSettings.logLevel;
106
}
210
}
107
 
211
 
-
 
212
/**
-
 
213
 * @brief TConfig::getPanelType the AMX type name of the panel.
-
 
214
 *
-
 
215
 * The type name of the panel is defined in the configuration file. If this
-
 
216
 * option was not defined, the default panel _android_ is returned.
-
 
217
 *
-
 
218
 * @return The type name of the panel.
-
 
219
 */
108
std::string& TConfig::getPanelType()
220
std::string& TConfig::getPanelType()
109
{
221
{
110
	return localSettings.ptype;
222
	return localSettings.ptype;
111
}
223
}
112
 
224
 
-
 
225
/**
-
 
226
 * @brief TConfig::getPort returnes the AMX port number to connect to.
-
 
227
 *
-
 
228
 * The port number can be defined in the configuration file. If there is no
-
 
229
 * configuration the default number 1319 is returned.
-
 
230
 *
-
 
231
 * @return The AMX network port number.
-
 
232
 */
113
int TConfig::getPort()
233
int TConfig::getPort()
114
{
234
{
115
	return localSettings.port;
235
	return localSettings.port;
116
}
236
}
117
 
237
 
-
 
238
/**
-
 
239
 * @brief TConfig::getProjectPath returns the path to the AMX configuration files.
-
 
240
 *
-
 
241
 * The path was read from the configuration file. This path contains all the
-
 
242
 * files needed to display the elements of the surface.
-
 
243
 *
-
 
244
 * @return The path to the AMX configuration files.
-
 
245
 */
118
std::string& TConfig::getProjectPath()
246
std::string& TConfig::getProjectPath()
119
{
247
{
120
	return localSettings.project;
248
	return localSettings.project;
121
}
249
}
122
 
250
 
-
 
251
/**
-
 
252
 * @brief TConfig::isLongFormat defines the format in the logfile.
-
 
253
 *
-
 
254
 * If this returns `true` the format in the logfile is a long format. This
-
 
255
 * means, that in front of each message is an additional timestamp.
-
 
256
 *
-
 
257
 * @return `true` = long format, `false` = short format (default).
-
 
258
 */
123
bool TConfig::isLongFormat()
259
bool TConfig::isLongFormat()
124
{
260
{
125
	return localSettings.longformat;
261
	return localSettings.longformat;
126
}
262
}
127
 
263
 
-
 
264
/**
-
 
265
 * @brief TConfig::showBanner defines whether the banner should be showed or not.
-
 
266
 *
-
 
267
 * If this method returns `false` the banner on startup is not displayed.
-
 
268
 *
-
 
269
 * @return `true` = display the banner (default), `false` = show no banner.
-
 
270
 */
128
bool TConfig::showBanner()
271
bool TConfig::showBanner()
129
{
272
{
130
	return !localSettings.noBanner;
273
	return !localSettings.noBanner;
131
}
274
}
132
 
275
 
-
 
276
/**
-
 
277
 * @brief TConfig::certCheck check the certificate if the connection is encrypted.
-
 
278
 *
-
 
279
 * Currently not implemented!
-
 
280
 *
-
 
281
 * @return `true` = check the certificate, `false` = accept any certificate (default).
-
 
282
 */
-
 
283
bool TConfig::certCheck()
-
 
284
{
-
 
285
    return localSettings.certCheck;
-
 
286
}
-
 
287
 
-
 
288
/**
-
 
289
 * @brief TConfig::findConfig search for the location of the configuration file.
-
 
290
 *
-
 
291
 * If there was no configuration file given on the command line, this method
-
 
292
 * searches for a configuration file on a few standard directories. This are:
-
 
293
 *
-
 
294
 *     /etc/tpanel.conf
-
 
295
 *     /etc/tpanel/tpanel.conf
-
 
296
 *     /usr/etc/tpanel.conf
-
 
297
 *     $HOME/.tpanel.conf
-
 
298
 *
-
 
299
 * On macOS the following additional directories are searched:
-
 
300
 *
-
 
301
 *     /opt/local/etc/tpanel.conf
-
 
302
 *     /opt/local/etc/tpanel/tpanel.conf
-
 
303
 *     /opt/local/usr/etc/tpanel.conf
-
 
304
 *
-
 
305
 * @return On success `true`, otherwise `false`.
-
 
306
 */
133
bool TConfig::findConfig()
307
bool TConfig::findConfig()
134
{
308
{
135
	char *HOME = nullptr;
309
	char *HOME = nullptr;
136
	string sFileName;
310
	string sFileName;
137
 
311
 
Line 151... Line 325...
151
		mCFile = mPath;
325
		mCFile = mPath;
152
		return !mCFile.empty();
326
		return !mCFile.empty();
153
	}
327
	}
154
 
328
 
155
	localSettings.name = "tpanel.conf";
329
	localSettings.name = "tpanel.conf";
-
 
330
#ifdef __ANDROID__
-
 
331
    char *androidData = getenv("ANDROID_DATA");
-
 
332
    char *androidRoot = getenv("ANDROID_ROOT");
-
 
333
 
-
 
334
    if (!androidData)
-
 
335
    {
-
 
336
        TError::setError();
-
 
337
        cerr << "Missing environment variable ANDROID_DATA!" << endl;
-
 
338
        TError::setErrorMsg(TERRERROR, "Missing environment variable ANDROID_DATA!");
-
 
339
        return false;
-
 
340
    }
-
 
341
 
-
 
342
    if (!androidRoot)
-
 
343
    {
-
 
344
        TError::setError();
-
 
345
        cerr << "Missing environment variable ANDROID_ROOT!" << endl;
-
 
346
        TError::setErrorMsg(TERRERROR, "Missing environment variable ANDROID_ROOT!");
-
 
347
        return false;
-
 
348
    }
-
 
349
 
-
 
350
    localSettings.path = androidData;
-
 
351
    mRoot = androidRoot;
-
 
352
 
-
 
353
    if (access(androidData, F_OK) == -1)    // Does the configuration file exist?
-
 
354
    {                                       // No, than create it and also the directory structure
-
 
355
        try
-
 
356
        {
-
 
357
            sFileName = localSettings.path + "/" + localSettings.name;
-
 
358
            ofstream cfg(sFileName);
-
 
359
 
-
 
360
            string content = "LogFile=" + localSettings.path + "/tpanel.log\n";
-
 
361
            content += "LogLevel=PROTOCOL\n";
-
 
362
            content += "ProjectPath=" + localSettings.path + "/tpanel\n";
-
 
363
            content += "LongFormat=false\n";
-
 
364
            content += "Address=0.0.0.0\n";
-
 
365
            content += "Port=1319\n";
-
 
366
            content += "Channel=10001\n";
-
 
367
            content += "PanelType=Android\n";
-
 
368
            content += "Firmware=1.0.0\n";
-
 
369
            cfg.write(content.c_str(), content.size());
-
 
370
            cfg.close();
156
 
371
 
-
 
372
            string path = localSettings.path + "/tpanel";
-
 
373
            mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
-
 
374
            string syspath = path + "/fonts";
-
 
375
            mkdir(syspath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
-
 
376
            syspath = path + "/images";
-
 
377
            mkdir(syspath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
-
 
378
            syspath = path + "/sounds";
-
 
379
            mkdir(syspath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
-
 
380
            syspath = path + "/__system";
-
 
381
            mkdir(syspath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
-
 
382
        }
-
 
383
        catch (std::exception& e)
-
 
384
        {
-
 
385
            cerr << "Error: " << e.what() << endl;
-
 
386
            TError::setErrorMsg(TERRERROR, string("Error: ") + e.what());
-
 
387
            return false;
-
 
388
        }
-
 
389
    }
-
 
390
#else
157
	if (!(HOME = getenv("HOME")))
391
	if (!(HOME = getenv("HOME")))
158
		std::cerr << "TConfig::findConfig: No environment variable HOME!" << std::endl;
392
		std::cerr << "TConfig::findConfig: No environment variable HOME!" << std::endl;
159
 
393
 
160
	if (!access("/etc/tpanel.conf", R_OK))
394
	if (!access("/etc/tpanel.conf", R_OK))
161
	{
395
	{
Line 209... Line 443...
209
	{
443
	{
210
		sFileName.clear();
444
		sFileName.clear();
211
		localSettings.name.clear();
445
		localSettings.name.clear();
212
		localSettings.path.clear();
446
		localSettings.path.clear();
213
	}
447
	}
214
 
448
#endif
215
	mCFile = sFileName;
449
	mCFile = sFileName;
216
	return !sFileName.empty();
450
	return !sFileName.empty();
217
}
451
}
218
 
452
 
-
 
453
/**
-
 
454
 * @brief TConfig::readConfig reads a config file.
-
 
455
 *
-
 
456
 * This method reads a config file and stores the known options into the
-
 
457
 * struct localSettings.
-
 
458
 *
-
 
459
 * @return `true` on success.\n
-
 
460
 * Returns `false` on error and sets the internal error.
-
 
461
 */
219
bool TConfig::readConfig()
462
bool TConfig::readConfig()
220
{
463
{
221
	ifstream fs;
464
	ifstream fs;
222
 
465
 
223
	// First initialize the defaults
466
	// First initialize the defaults
Line 297... Line 540...
297
					caseCompare(right, "true") == 0)
540
					caseCompare(right, "true") == 0)
298
					localSettings.noBanner = true;
541
					localSettings.noBanner = true;
299
				else
542
				else
300
					localSettings.noBanner = false;
543
					localSettings.noBanner = false;
301
			}
544
			}
302
			else if (caseCompare(left, "Channel") == 0 && !right.empty())
545
			else if (caseCompare(left, "CertCheck") == 0 && !right.empty())
-
 
546
            {
-
 
547
                if (caseCompare(right, "1") == 0 || caseCompare(right, "yes") == 0 ||
-
 
548
                    caseCompare(right, "true") == 0 || caseCompare(right, "on") == 0)
-
 
549
                    localSettings.certCheck = true;
-
 
550
                else
-
 
551
                    localSettings.certCheck = false;
-
 
552
            }
-
 
553
            else if (caseCompare(left, "Channel") == 0 && !right.empty())
303
			{
554
			{
304
				localSettings.ID = atoi(right.c_str());
555
				localSettings.ID = atoi(right.c_str());
305
 
556
 
306
				if (localSettings.ID < 10000 || localSettings.ID >= 11000)
557
				if (localSettings.ID < 10000 || localSettings.ID >= 11000)
307
				{
558
				{
Line 332... Line 583...
332
	}
583
	}
333
 
584
 
334
	return true;
585
	return true;
335
}
586
}
336
 
587
 
-
 
588
/**
-
 
589
 * @brief TConfig::split splitts a string into parts.
-
 
590
 *
-
 
591
 * The method splitts a string into parts separated by \p seps. It puts the
-
 
592
 * parts into a vector array.
-
 
593
 *
-
 
594
 * @param str           The string to split
-
 
595
 * @param seps          The separator(s)
-
 
596
 * @param trimEmpty     `true` = trum the parts.
-
 
597
 *
-
 
598
 * @return A vector array containing the parts of the string \p str.
-
 
599
 */
337
vector<string> TConfig::split(const string& str, const string& seps, const bool trimEmpty)
600
vector<string> TConfig::split(const string& str, const string& seps, const bool trimEmpty)
338
{
601
{
339
	size_t pos = 0, mark = 0;
602
	size_t pos = 0, mark = 0;
340
	vector<string> parts;
603
	vector<string> parts;
341
 
604
 
Line 373... Line 636...
373
	}
636
	}
374
 
637
 
375
	return parts;
638
	return parts;
376
}
639
}
377
 
640
 
-
 
641
/**
-
 
642
 * @brief TConfig::caseCompare compares 2 strings
-
 
643
 *
-
 
644
 * This method compares 2 strings case insensitive. This means that it ignores
-
 
645
 * the case of the letters. For example:
-
 
646
 *
-
 
647
 *     BLAME
-
 
648
 *     blame
-
 
649
 *     Blame
-
 
650
 *
-
 
651
 * are all the same and would return 0, which means _equal_.
-
 
652
 *
-
 
653
 * @param str1  1st string to compare
-
 
654
 * @param str2  2nd string to compare
-
 
655
 *
-
 
656
 * @return 0 if the strings are equal\n
-
 
657
 * less than 0 if the byte of \p str1 is bigger than the byte of \p str2\n
-
 
658
 * grater than 0 if the byte of \p str1 is smaller than the byte of \p str2.
-
 
659
 */
378
int TConfig::caseCompare(const string& str1, const string& str2)
660
int TConfig::caseCompare(const string& str1, const string& str2)
379
{
661
{
380
	size_t i = 0;
662
	size_t i = 0;
381
 
663
 
382
	if (str1.length() != str2.length())
664
	if (str1.length() != str2.length())