/
main.c
411 lines (381 loc) · 12.8 KB
1
/*
2
* Copyright (C) 2013-2016 Jolla Ltd.
3
* Contact: Slava Monich <slava.monich@jolla.com>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <syslog.h>
#include <glib-unix.h>
#include "mms_engine.h"
#include "mms_lib_log.h"
#include "mms_lib_util.h"
21
#include "mms_settings.h"
22
23
#ifdef SAILFISH
24
25
26
27
28
# include "mms_connman_nemo_log.h"
#else
# include "mms_connman_ofono_log.h"
#endif
29
30
#include <gutil_log.h>
31
32
33
#define RET_OK (0)
#define RET_ERR (1)
34
35
36
/* Options configurable from the command line */
typedef struct mms_app_options {
GBusType bus_type;
37
int flags;
38
39
MMSConfigCopy global;
MMSSettingsSimDataCopy settings;
40
41
42
43
} MMSAppOptions;
/* All known log modules */
static MMSLogModule* mms_app_log_modules[] = {
44
&gutil_log_default,
45
46
#define MMS_LIB_LOG_MODULE(m) &(m),
MMS_LIB_LOG_MODULES(MMS_LIB_LOG_MODULE)
47
MMS_CONNMAN_LOG_MODULES(MMS_LIB_LOG_MODULE)
48
49
50
51
52
53
54
55
56
#undef MMS_LIB_LOG_MODULE
};
/* Signal handler */
static
gboolean
mms_app_signal(
gpointer arg)
{
57
MMSEngine* engine = arg;
58
GINFO("Caught signal, shutting down...");
59
60
mms_engine_stop(engine);
return TRUE;
61
62
63
64
65
66
67
68
69
70
71
72
}
/* D-Bus event handlers */
static
void
mms_app_bus_acquired(
GDBusConnection* bus,
const gchar* name,
gpointer arg)
{
MMSEngine* engine = arg;
GError* error = NULL;
73
GDEBUG("Bus acquired, starting...");
74
if (!mms_engine_register(engine, bus, &error)) {
75
GERR("Could not start: %s", GERRMSG(error));
76
77
78
79
80
81
82
83
84
85
86
87
g_error_free(error);
mms_engine_stop(engine);
}
}
static
void
mms_app_name_acquired(
GDBusConnection* bus,
const gchar* name,
gpointer arg)
{
88
GDEBUG("Acquired service name '%s'", name);
89
90
91
92
93
94
95
96
97
98
}
static
void
mms_app_name_lost(
GDBusConnection* bus,
const gchar* name,
gpointer arg)
{
MMSEngine* engine = arg;
99
GERR("'%s' service already running or access denied", name);
100
101
102
103
104
105
106
107
108
109
110
111
mms_engine_stop(engine);
}
/* Option parsing callbacks */
static
gboolean
mms_app_option_loglevel(
const gchar* name,
const gchar* value,
gpointer data,
GError** error)
{
112
return gutil_log_parse_option(value, mms_app_log_modules,
113
114
115
116
117
118
119
120
121
122
123
G_N_ELEMENTS(mms_app_log_modules), error);
}
static
gboolean
mms_app_option_logtype(
const gchar* name,
const gchar* value,
gpointer data,
GError** error)
{
124
if (gutil_log_set_type(value, MMS_APP_LOG_PREFIX)) {
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
return TRUE;
} else {
if (error) {
*error = g_error_new(G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
"Invalid log type \'%s\'", value);
}
return FALSE;
}
}
static
gboolean
mms_app_option_verbose(
const gchar* name,
const gchar* value,
gpointer data,
GError** error)
{
143
gutil_log_default.level = GLOG_LEVEL_VERBOSE;
144
145
146
return TRUE;
}
147
148
149
150
151
/**
* Parses command line and sets up application options. Returns TRUE if
* we should go ahead and run the application, FALSE if we should exit
* immediately.
*/
152
153
154
155
156
static
gboolean
mms_app_parse_options(
MMSAppOptions* opt,
int argc,
157
158
char* argv[],
int* result)
159
160
161
162
{
gboolean ok;
GError* error = NULL;
gboolean session_bus = FALSE;
163
char* config_file = NULL;
164
#ifdef MMS_VERSION_STRING
165
166
gboolean print_version = FALSE;
#endif
167
168
169
char* ua = NULL;
char* uaprof = NULL;
char* root_dir = NULL;
170
gboolean log_modules = FALSE;
171
172
173
gboolean keep_running = FALSE;
gint size_limit_kb = -1;
gdouble megapixels = -1;
174
175
char* root_dir_help = g_strdup_printf(
"Root directory for MMS files [%s]",
176
opt->global.config.root_dir);
177
178
char* retry_secs_help = g_strdup_printf(
"Retry period in seconds [%d]",
179
opt->global.config.retry_secs);
180
181
char* idle_secs_help = g_strdup_printf(
"Inactivity timeout in seconds [%d]",
182
opt->global.config.idle_secs);
183
char* description = gutil_log_description(NULL, 0);
184
185
186
187
188
GOptionContext* options;
GOptionEntry entries[] = {
{ "session", 0, 0, G_OPTION_ARG_NONE, &session_bus,
"Use session bus (default is system)", NULL },
189
190
191
192
#define OPT_CONFIG_INDEX 1
{ "config", 'c', 0, G_OPTION_ARG_FILENAME,
&config_file, "Use the specified config file ["
MMS_ENGINE_CONFIG_FILE "]", "FILE" },
193
{ "root-dir", 'd', 0, G_OPTION_ARG_FILENAME,
194
&root_dir, root_dir_help, "DIR" },
195
{ "retry-secs", 'r', 0, G_OPTION_ARG_INT,
196
&opt->global.config.retry_secs, retry_secs_help, "SEC" },
197
{ "idle-secs", 'i', 0, G_OPTION_ARG_INT,
198
&opt->global.config.idle_secs, idle_secs_help, "SEC" },
199
{ "size-limit", 's', 0, G_OPTION_ARG_INT,
200
&size_limit_kb, "Maximum size for outgoing messages", "KB" },
201
{ "pix-limit", 'p', 0, G_OPTION_ARG_DOUBLE,
202
&megapixels, "Maximum pixel count for outgoing images", "MPIX" },
203
{ "user-agent", 'u', 0, G_OPTION_ARG_STRING,
204
&ua, "The value of the User-Agent header", "STRING" },
205
{ "x-wap-profile", 'x', 0, G_OPTION_ARG_STRING,
206
&uaprof, "User agent profile", "URL" },
207
{ "keep-running", 'k', 0, G_OPTION_ARG_NONE, &keep_running,
208
209
"Keep running after everything is done", NULL },
{ "keep-temp-files", 't', 0, G_OPTION_ARG_NONE,
210
&opt->global.config.keep_temp_files,
211
212
"Don't delete temporary files", NULL },
{ "attic", 'a', 0, G_OPTION_ARG_NONE,
213
&opt->global.config.attic_enabled,
214
"Store unrecognized push messages in the attic", NULL },
215
#define OPT_VERBOSE_INDEX 12
216
217
218
219
{ "verbose", 'v', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
mms_app_option_verbose, "Be verbose (equivalent to -l=verbose)",
NULL },
{ "log-output", 'o', 0, G_OPTION_ARG_CALLBACK, mms_app_option_logtype,
220
"Log output (stdout|syslog|glib) [stdout]", "TYPE" },
221
222
{ "log-level", 'l', 0, G_OPTION_ARG_CALLBACK, mms_app_option_loglevel,
"Set log level (repeatable)", "[MODULE:]LEVEL" },
223
224
{ "log-modules", 0, 0, G_OPTION_ARG_NONE, &log_modules,
"List available log modules", NULL },
225
#ifdef MMS_VERSION_STRING
226
227
228
{ "version", 0, 0, G_OPTION_ARG_NONE, &print_version,
"Print program version and exit", NULL },
#endif
229
230
231
{ NULL }
};
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
/*
* First pre-parse the command line to get the config file name.
* Only then we can initialize the defaults and parse the rest.
* Verbose option is handled here too, in order to allow verbose
* logging during config file parsing.
*/
GOptionContext* config_options;
GOptionEntry config_entries[3];
memset(config_entries, 0, sizeof(config_entries));
config_entries[0] = entries[OPT_VERBOSE_INDEX];
config_entries[1] = entries[OPT_CONFIG_INDEX];
/*
* Initialize the main parsing context. We would still need it
* even if the preparsing fails - to print the help
*/
248
249
250
options = g_option_context_new("- part of Jolla MMS system");
g_option_context_add_main_entries(options, entries, NULL);
g_option_context_set_description(options, description);
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
/* Pre-parsing context */
config_options = g_option_context_new(NULL);
g_option_context_add_main_entries(config_options, config_entries, NULL);
g_option_context_set_help_enabled(config_options, FALSE);
g_option_context_set_ignore_unknown_options(config_options, TRUE);
ok = g_option_context_parse(config_options, &argc, &argv, &error);
/*
* If pre-parsing succeeds, we need to read the config before
* parsing the rest of the command line, to allow command line
* options to overwrite those specified in the config file.
*/
if (ok) {
if (config_file) {
/* Config file was specified on the command line */
ok = mms_settings_load_defaults(config_file,
&opt->global, &opt->settings, &error);
} else {
/* The default config file may be (and usually is) missing */
if (g_file_test(MMS_ENGINE_CONFIG_FILE, G_FILE_TEST_EXISTS)) {
mms_settings_load_defaults(MMS_ENGINE_CONFIG_FILE,
&opt->global, &opt->settings, NULL);
}
}
if (ok) {
/* Parse the rest of the command line */
ok = g_option_context_parse(options, &argc, &argv, &error);
} else if (error) {
/* Improve error message by prepending the file name */
GError* details = g_error_new(error->domain, error->code,
"%s: %s", config_file, error->message);
g_error_free(error);
error = details;
}
}
288
g_option_context_free(options);
289
290
g_option_context_free(config_options);
g_free(config_file);
291
292
293
294
295
g_free(root_dir_help);
g_free(retry_secs_help);
g_free(idle_secs_help);
g_free(description);
296
if (!ok) {
297
fprintf(stderr, "%s\n", GERRMSG(error));
298
299
300
301
302
303
304
305
g_error_free(error);
*result = RET_ERR;
} else if (log_modules) {
unsigned int i;
for (i=0; i<G_N_ELEMENTS(mms_app_log_modules); i++) {
printf("%s\n", mms_app_log_modules[i]->name);
}
*result = RET_OK;
306
ok = FALSE;
307
#ifdef MMS_VERSION_STRING
308
} else if (print_version) {
309
printf("MMS engine %s\n", MMS_VERSION_STRING);
310
*result = RET_OK;
311
ok = FALSE;
312
#endif
313
} else {
314
#ifdef MMS_VERSION_STRING
315
GINFO("Version %s starting", MMS_VERSION_STRING);
316
#else
317
GINFO("Starting");
318
#endif
319
if (size_limit_kb >= 0) {
320
opt->settings.data.size_limit = size_limit_kb * 1024;
321
opt->flags |= MMS_ENGINE_FLAG_OVERRIDE_SIZE_LIMIT;
322
323
}
if (megapixels >= 0) {
324
opt->settings.data.max_pixels = (int)(megapixels*1000)*1000;
325
326
opt->flags |= MMS_ENGINE_FLAG_OVERRIDE_MAX_PIXELS;
}
327
328
329
if (ua) {
g_free(opt->settings.user_agent);
opt->settings.data.user_agent = opt->settings.user_agent = ua;
330
opt->flags |= MMS_ENGINE_FLAG_OVERRIDE_USER_AGENT;
331
ua = NULL;
332
}
333
334
335
if (uaprof) {
g_free(opt->settings.uaprof);
opt->settings.data.uaprof = opt->settings.uaprof = uaprof;
336
opt->flags |= MMS_ENGINE_FLAG_OVERRIDE_UAPROF;
337
338
339
340
341
342
uaprof = NULL;
}
if (root_dir) {
g_free(opt->global.root_dir);
opt->global.config.root_dir = opt->global.root_dir = root_dir;
root_dir = NULL;
343
}
344
if (keep_running) opt->flags |= MMS_ENGINE_FLAG_KEEP_RUNNING;
345
if (session_bus) {
346
GDEBUG("Attaching to session bus");
347
348
opt->bus_type = G_BUS_TYPE_SESSION;
} else {
349
GDEBUG("Attaching to system bus");
350
351
opt->bus_type = G_BUS_TYPE_SYSTEM;
}
352
*result = RET_OK;
353
}
354
355
356
357
358
g_free(ua);
g_free(uaprof);
g_free(root_dir);
return ok;
359
360
361
362
}
int main(int argc, char* argv[])
{
363
int result = RET_ERR;
364
365
366
367
MMSAppOptions opt;
MMSConfig* config = &opt.global.config;
MMSSettingsSimData* settings = &opt.settings.data;
368
mms_lib_init(argv[0]);
369
gofono_log.name = "mms-ofono";
370
gutil_log_default.name = MMS_APP_LOG_PREFIX;
371
372
373
memset(&opt, 0, sizeof(opt));
mms_lib_default_config(config);
mms_settings_sim_data_default(settings);
374
if (mms_app_parse_options(&opt, argc, argv, &result)) {
375
376
377
MMSEngine* engine;
/* Create engine instance. This may fail */
378
engine = mms_engine_new(config, settings, opt.flags,
379
380
381
382
383
mms_app_log_modules, G_N_ELEMENTS(mms_app_log_modules));
if (engine) {
/* Setup main loop */
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
384
385
guint sigtrm = g_unix_signal_add(SIGTERM, mms_app_signal, engine);
guint sigint = g_unix_signal_add(SIGINT, mms_app_signal, engine);
386
387
/* Acquire name, don't allow replacement */
388
guint name_id = g_bus_own_name(opt.bus_type, MMS_ENGINE_SERVICE,
389
390
391
392
393
394
395
G_BUS_NAME_OWNER_FLAGS_REPLACE, mms_app_bus_acquired,
mms_app_name_acquired, mms_app_name_lost, engine, NULL);
/* Run the main loop */
mms_engine_run(engine, loop);
/* Cleanup and exit */
396
397
if (sigtrm) g_source_remove(sigtrm);
if (sigint) g_source_remove(sigint);
398
399
400
401
g_bus_unown_name(name_id);
g_main_loop_unref(loop);
mms_engine_unref(engine);
}
402
GINFO("Exiting");
403
}
404
if (gutil_log_func == gutil_log_syslog) {
405
406
closelog();
}
407
408
g_free(opt.global.root_dir);
mms_settings_sim_data_reset(&opt.settings);
409
mms_lib_deinit();
410
411
return result;
}