a8d8c6d93c10acf486eda1cb51d715c42041bf19
[platform/upstream/syncevolution.git] / src / dbus / server / main.cpp
1 /*
2  * Copyright (C) 2011 Intel Corporation
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) version 3.
8  *
9  * This library 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 GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301  USA
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <iostream>
25 #include <locale.h>
26 #include <glib/gi18n.h>
27
28 #include "server.h"
29 #include "restart.h"
30 #include "session-common.h"
31
32 #include <syncevo/SyncContext.h>
33 #include <syncevo/SuspendFlags.h>
34 #include <syncevo/LogRedirect.h>
35 #include <syncevo/LogSyslog.h>
36 #include <syncevo/GLibSupport.h>
37
38 using namespace SyncEvo;
39 using namespace GDBusCXX;
40
41 namespace {
42     GMainLoop *loop = NULL;
43     bool shutdownRequested = false;
44     const char * const execName = "syncevo-dbus-server";
45     const char * const debugEnv = "SYNCEVOLUTION_DEBUG";
46
47 void niam(int sig)
48 {
49     shutdownRequested = true;
50     SuspendFlags::getSuspendFlags().handleSignal(sig);
51     g_main_loop_quit (loop);
52 }
53
54 bool parseDuration(int &duration, const char* value)
55 {
56     if(value == NULL) {
57         return false;
58     } else if (boost::iequals(value, "unlimited")) {
59         duration = -1;
60         return true;
61     } else if ((duration = atoi(value)) > 0) {
62         return true;
63     } else {
64         return false;
65     }
66 }
67
68 } // anonymous namespace
69
70 static Logger::Level checkLogLevel(const char *option, int logLevel)
71 {
72     switch (logLevel) {
73     case 0: return Logger::NONE;
74     case 1: return Logger::ERROR;
75     case 2: return Logger::INFO;
76     case 3: return Logger::DEBUG;
77     default:
78         SE_THROW(StringPrintf("invalid parameter value %d for %s: must be one of 0, 1, 2 or 3", logLevel, option));
79         return Logger::NONE;
80     }
81 }
82
83 int main(int argc, char **argv, char **envp)
84 {
85     // remember environment for restart
86     boost::shared_ptr<Restart> restart;
87     restart.reset(new Restart(argv, envp));
88
89     // Internationalization for auto sync messages.
90     setlocale(LC_ALL, "");
91     bindtextdomain(GETTEXT_PACKAGE,
92                    getEnv("SYNCEVOLUTION_LOCALE_DIR", SYNCEVOLUTION_LOCALEDIR));
93     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
94     textdomain(GETTEXT_PACKAGE);
95
96     try {
97         gchar *durationString = NULL;
98         int duration = 600;
99         int logLevel = 1;
100         int logLevelDBus = 2;
101         gboolean stdoutEnabled = false;
102         gboolean syslogEnabled = true;
103 #ifdef ENABLE_DBUS_PIM
104         gboolean startPIM = false;
105 #endif
106         static GOptionEntry entries[] = {
107             { "duration", 'd', 0, G_OPTION_ARG_STRING, &durationString, "Shut down automatically when idle for this duration", "seconds/'unlimited'" },
108             { "verbosity", 'v', 0, G_OPTION_ARG_INT, &logLevel,
109               "Choose amount of output, 0 = no output, 1 = errors, 2 = info, 3 = debug; default is 1.",
110               "level" },
111             { "dbus-verbosity", 'v', 0, G_OPTION_ARG_INT, &logLevelDBus,
112               "Choose amount of output via D-Bus signals, 0 = no output, 1 = errors, 2 = info, 3 = debug; default is 2.",
113               "level" },
114             { "stdout", 'o', 0, G_OPTION_ARG_NONE, &stdoutEnabled,
115               "Enable printing to stdout (result of operations) and stderr (errors/info/debug).",
116               NULL },
117             { "no-syslog", 's', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &syslogEnabled, "Disable printing to syslog.", NULL },
118 #ifdef ENABLE_DBUS_PIM
119             { "start-pim", 'p', 0, G_OPTION_ARG_NONE, &startPIM,
120               "Activate the PIM Manager (= unified address book) immediately.",
121               NULL },
122 #endif
123             { NULL }
124         };
125         GErrorCXX gerror;
126         static GOptionContext *context = g_option_context_new("- SyncEvolution D-Bus Server");
127         g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE);
128         bool success = g_option_context_parse(context, &argc, &argv, gerror);
129         PlainGStr durationOwner(durationString);
130         if (!success) {
131             gerror.throwError("parsing command line options");
132         }
133         if (durationString && !parseDuration(duration, durationString)) {
134             SE_THROW(StringPrintf("invalid parameter value '%s' for --duration/-d: must be positive number of seconds or 'unlimited'", durationString));
135         }
136         Logger::Level level = checkLogLevel("--debug", logLevel);
137         Logger::Level levelDBus = checkLogLevel("--dbus-debug", logLevelDBus);
138
139         // Temporarily set G_DBUS_DEBUG. Hopefully GIO will read and
140         // remember it, because we don't want to keep it set
141         // permanently, lest it gets passed on to other processes.
142         const char *gdbus = getenv("SYNCEVOLUTION_DBUS_SERVER_GDBUS");
143         if (gdbus) {
144             setenv("G_DBUS_DEBUG", gdbus, 1);
145         }
146
147         SyncContext::initMain(execName);
148
149         loop = g_main_loop_new (NULL, FALSE);
150
151         setvbuf(stderr, NULL, _IONBF, 0);
152         setvbuf(stdout, NULL, _IONBF, 0);
153
154         // Redirect output and optionally log to syslog.
155         PushLogger<LogRedirect> redirect(new LogRedirect(LogRedirect::STDERR_AND_STDOUT));
156         redirect->setLevel(stdoutEnabled ? level : Logger::NONE);
157         PushLogger<LoggerSyslog> syslogger;
158         if (syslogEnabled && level > Logger::NONE) {
159             syslogger.reset(new LoggerSyslog(execName));
160             syslogger->setLevel(level);
161         }
162
163         // syncevo-dbus-server should hardly ever produce output that
164         // is relevant for end users, so include the somewhat cryptic
165         // process name for developers in this process, and not in
166         // syncevo-dbus-helper.
167         Logger::setProcessName("syncevo-dbus-server");
168
169         SE_LOG_DEBUG(NULL, "syncevo-dbus-server: catch SIGINT/SIGTERM in our own shutdown function");
170         signal(SIGTERM, niam);
171         signal(SIGINT, niam);
172         boost::shared_ptr<SuspendFlags::Guard> guard = SuspendFlags::getSuspendFlags().activate();
173
174         DBusErrorCXX err;
175         DBusConnectionPtr conn = dbus_get_bus_connection("SESSION",
176                                                          SessionCommon::SERVICE_NAME,
177                                                          true,
178                                                          &err);
179         if (!conn) {
180             err.throwFailure("dbus_get_bus_connection()", " failed - server already running?");
181         }
182         // make this object the main owner of the connection
183         boost::scoped_ptr<DBusObject> obj(new DBusObject(conn, "foo", "bar", true));
184
185         boost::shared_ptr<SyncEvo::Server> server(new SyncEvo::Server(loop, shutdownRequested, restart, conn, duration));
186         server->setDBusLogLevel(levelDBus);
187         server->activate();
188
189 #ifdef ENABLE_DBUS_PIM
190         boost::shared_ptr<GDBusCXX::DBusObjectHelper> manager(SyncEvo::CreateContactManager(server, startPIM));
191 #endif
192
193         if (gdbus) {
194             unsetenv("G_DBUS_DEBUG");
195         }
196
197         dbus_bus_connection_undelay(conn);
198         server->run();
199         SE_LOG_DEBUG(NULL, "cleaning up");
200 #ifdef ENABLE_DBUS_PIM
201         manager.reset();
202 #endif
203         server.reset();
204         obj.reset();
205         guard.reset();
206         SE_LOG_DEBUG(NULL, "flushing D-Bus connection");
207         conn.flush();
208         conn.reset();
209         SE_LOG_INFO(NULL, "terminating, closing logging");
210         syslogger.reset();
211         redirect.reset();
212         SE_LOG_INFO(NULL, "terminating");
213         return 0;
214     } catch ( const std::exception &ex ) {
215         SE_LOG_ERROR(NULL, "%s", ex.what());
216     } catch (...) {
217         SE_LOG_ERROR(NULL, "unknown error");
218     }
219
220     return 1;
221 }