Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / src / server.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* server.c
3  *
4  * Copyright (C) 2000-2003, Ximian, Inc.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of version 2 of the GNU Lesser General Public
8  * License as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  * Author: Nat Friedman (nat@ximian.com)
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 /* define this if you need/want to be able to send USR2 to server and
28    get a list of the active backends */
29 /*#define DEBUG_BACKENDS*/
30
31 #include <stdlib.h>
32 #include <signal.h>
33 #include <unistd.h>
34 #include <pthread.h>
35
36 #include <glib.h>
37 #include <glib/gi18n.h>
38 #include <libgnome/gnome-init.h>
39 #include <bonobo-activation/bonobo-activation.h>
40 #include <libgnomevfs/gnome-vfs-init.h>
41 #include <bonobo/bonobo-main.h>
42 #include <bonobo/bonobo-exception.h>
43 #include <bonobo/bonobo-generic-factory.h>
44 #include <gconf/gconf-client.h>
45
46 #include <libedataserver/e-data-server-module.h>
47 #include <libedata-book/e-data-book-factory.h>
48 #if ENABLE_CALENDAR
49 #include <libedata-cal/e-data-cal-factory.h>
50 #endif
51
52 #ifdef G_OS_WIN32
53 #include <libedataserver/e-data-server-util.h>
54 #endif
55
56 #include "server-interface-check.h"
57 #include "server-logging.h"
58 #include "offline-listener.h"
59
60 #define E_DATA_SERVER_INTERFACE_CHECK_OAF_ID "OAFIID:GNOME_Evolution_DataServer_InterfaceCheck"
61 #define E_DATA_SERVER_LOGGING_OAF_ID "OAFIID:GNOME_Evolution_DataServer_Logging"
62
63 #define E_DATA_CAL_FACTORY_OAF_ID "OAFIID:GNOME_Evolution_DataServer_CalFactory:" API_VERSION
64 #define E_DATA_BOOK_FACTORY_OAF_ID "OAFIID:GNOME_Evolution_DataServer_BookFactory:" API_VERSION
65
66 /* The and addressbook calendar factories */
67
68 #if ENABLE_CALENDAR
69 static EDataCalFactory *e_data_cal_factory;
70 #endif
71
72 static EDataBookFactory *e_data_book_factory;
73
74 /* The other interfaces we implement */
75
76 static ServerLogging *logging_iface;
77 static ServerInterfaceCheck *interface_check_iface;
78
79 /* Timeout interval in milliseconds for termination */
80 #define EXIT_TIMEOUT 5000
81
82 /* Timeout ID for termination handler */
83 static guint termination_handler_id;
84
85 static GStaticMutex termination_lock = G_STATIC_MUTEX_INIT;
86
87 #ifndef G_OS_WIN32
88 static pthread_mutex_t segv_mutex = PTHREAD_MUTEX_INITIALIZER;
89 static pthread_t main_thread;
90
91 static void
92 gnome_segv_handler (int signo)
93 {
94         const char *gnome_segv_path;
95         static int in_segv = 0;
96         char *exec;
97
98         if (pthread_self() != main_thread) {
99                 /* deadlock intentionally in the sub-threads */
100                 pthread_kill(main_thread, signo);
101                 pthread_mutex_lock(&segv_mutex);
102         }
103
104         in_segv++;
105         if (in_segv > 2) {
106                 /* The fprintf() was segfaulting, we are just totally hosed */
107                 _exit (1);
108         } else if (in_segv > 1) {
109                 /* dialog display isn't working out */
110                 fprintf (stderr, _("Multiple segmentation faults occurred; cannot display error dialog\n"));
111                 _exit (1);
112         }
113         
114         gnome_segv_path = GNOMEUI_SERVERDIR "/gnome_segv2";
115         
116         exec = g_strdup_printf ("%s \"" PACKAGE "-" BASE_VERSION "\" %d \"" VERSION "\"",
117                                 gnome_segv_path, signo);
118         system (exec);
119         g_free (exec);
120
121         _exit(1);
122 }
123
124 static void
125 setup_segv_handler (void)
126 {
127         struct sigaction sa;
128         
129         sa.sa_flags = 0;
130         sigemptyset (&sa.sa_mask);
131         sa.sa_handler = gnome_segv_handler;
132         sigaction (SIGSEGV, &sa, NULL);
133         sigaction (SIGBUS, &sa, NULL);
134         sigaction (SIGFPE, &sa, NULL);
135
136         main_thread = pthread_self();
137         pthread_mutex_lock(&segv_mutex);
138 }
139
140 #endif
141
142 /* Termination */
143
144 /* Termination handler.  Checks if both factories have zero running backends,
145  * and if so terminates the program.
146  */
147 static gboolean
148 termination_handler (gpointer data)
149 {
150         int count = 0;
151
152 #if ENABLE_CALENDAR
153         count += e_data_cal_factory_get_n_backends (e_data_cal_factory);
154 #endif
155         count += e_data_book_factory_get_n_backends (e_data_book_factory);
156
157         if (count == 0) {
158                 g_message ("termination_handler(): Terminating the Server.  Have a nice day.");
159                 bonobo_main_quit ();
160         }
161
162         termination_handler_id = 0;
163         return FALSE;
164 }
165
166 /* Queues a timeout for handling termination of Server */
167 static void
168 queue_termination (void)
169 {
170         g_static_mutex_lock (&termination_lock);
171         if (termination_handler_id)
172                 g_source_remove (termination_handler_id);
173
174         termination_handler_id = g_timeout_add (EXIT_TIMEOUT, termination_handler, NULL);
175         g_static_mutex_unlock (&termination_lock);
176 }
177
178 \f
179
180 static void
181 last_book_gone_cb (EDataBookFactory *factory, gpointer data)
182 {
183         queue_termination ();
184 }
185
186 static gboolean
187 setup_books (void)
188 {
189         e_data_book_factory = e_data_book_factory_new ();
190
191         if (!e_data_book_factory)
192                 return FALSE;
193
194         e_data_book_factory_register_backends (e_data_book_factory);
195
196         g_signal_connect (e_data_book_factory,
197                           "last_book_gone",
198                           G_CALLBACK (last_book_gone_cb),
199                           NULL);
200
201         if (!e_data_book_factory_activate (e_data_book_factory, E_DATA_BOOK_FACTORY_OAF_ID)) {
202                 bonobo_object_unref (BONOBO_OBJECT (e_data_book_factory));
203                 e_data_book_factory = NULL;
204                 return FALSE;
205         }
206
207         return TRUE;
208 }
209
210 \f
211 /* Personal calendar server */
212
213 #if ENABLE_CALENDAR
214 /* Callback used when the calendar factory has no more running backends */
215 static void
216 last_calendar_gone_cb (EDataCalFactory *factory, gpointer data)
217 {
218         queue_termination ();
219 }
220
221 /* Creates the calendar factory object and registers it */
222 static gboolean
223 setup_cals (void)
224 {
225         e_data_cal_factory = e_data_cal_factory_new ();
226
227         if (!e_data_cal_factory) {
228                 g_warning (G_STRLOC ": Could not create the calendar factory");
229                 return FALSE;
230         }
231
232         e_data_cal_factory_register_backends (e_data_cal_factory);
233
234         if (!e_data_cal_factory_register_storage (e_data_cal_factory, E_DATA_CAL_FACTORY_OAF_ID)) {
235                 bonobo_object_unref (BONOBO_OBJECT (e_data_cal_factory));
236                 e_data_cal_factory = NULL;
237                 return FALSE;
238         }
239
240         g_signal_connect (G_OBJECT (e_data_cal_factory),
241                           "last_calendar_gone",
242                           G_CALLBACK (last_calendar_gone_cb),
243                           NULL);
244
245         return TRUE;
246
247 }
248 #else
249 static gboolean
250 setup_cals (void)
251 {
252         return TRUE;
253 }
254 #endif
255
256 \f
257 /* Logging iface.  */
258 static gboolean
259 setup_logging (void)
260 {
261         int result;
262
263         logging_iface = server_logging_new ();
264
265         server_logging_register_domain (logging_iface, NULL);
266         server_logging_register_domain (logging_iface, "Gdk");
267         server_logging_register_domain (logging_iface, "Gtk");
268         server_logging_register_domain (logging_iface, "GdkPixbuf");
269         server_logging_register_domain (logging_iface, "GLib");
270         server_logging_register_domain (logging_iface, "GModule");
271         server_logging_register_domain (logging_iface, "GLib-GObject");
272         server_logging_register_domain (logging_iface, "GThread");
273
274         server_logging_register_domain (logging_iface, "evolution-data-server");
275         server_logging_register_domain (logging_iface, "libebookbackend");
276         server_logging_register_domain (logging_iface, "libecalbackendfile");
277
278         result = bonobo_activation_active_server_register (E_DATA_SERVER_LOGGING_OAF_ID,
279                                                            BONOBO_OBJREF (logging_iface));
280
281         return result == Bonobo_ACTIVATION_REG_SUCCESS;
282 }
283
284 \f
285 /* Interface check iface.  */
286
287 static gboolean
288 setup_interface_check (void)
289 {
290         int result;
291
292         interface_check_iface = server_interface_check_new ();
293         result = bonobo_activation_active_server_register (E_DATA_SERVER_INTERFACE_CHECK_OAF_ID,
294                                                            BONOBO_OBJREF (interface_check_iface));
295
296         return result == Bonobo_ACTIVATION_REG_SUCCESS;
297 }
298
299
300 #ifdef DEBUG_BACKENDS
301 static void
302 dump_backends (int signal)
303 {
304         e_data_book_factory_dump_active_backends (e_data_book_factory);
305 #if ENABLE_CALENDAR
306         e_data_cal_factory_dump_active_backends (e_data_cal_factory);
307 #endif
308 }
309 #endif
310
311 #ifdef G_OS_WIN32
312 #undef EVOLUTION_LOCALEDIR
313 #define EVOLUTION_LOCALEDIR e_util_get_localedir ()
314
315 /* Used in GNOME_PROGRAM_STANDARD_PROPERTIES: */
316 #undef PREFIX
317 #define PREFIX e_util_get_prefix ()
318
319 static const char *
320 sysconfdir (void)
321 {
322         return e_util_replace_prefix (PREFIX,
323                                       e_util_get_prefix (),
324                                       SYSCONFDIR);
325 }
326 #undef SYSCONFDIR
327 #define SYSCONFDIR sysconfdir ()
328
329 static const char *
330 datadir (void)
331 {
332         return e_util_replace_prefix (PREFIX,
333                                       e_util_get_prefix (),
334                                       DATADIR);
335 }
336 #undef DATADIR
337 #define DATADIR datadir ()
338
339 static const char *
340 libdir (void)
341 {
342         return e_util_replace_prefix (PREFIX,
343                                       e_util_get_prefix (),
344                                       LIBDIR);
345 }
346 #undef LIBDIR
347 #define LIBDIR libdir ()
348
349 #endif
350
351 int
352 main (int argc, char **argv)
353 {
354         gboolean did_books=FALSE, did_cals=FALSE;
355         OfflineListener *offline_listener = NULL;
356         
357         bindtextdomain (GETTEXT_PACKAGE, EVOLUTION_LOCALEDIR);
358         bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
359         textdomain (GETTEXT_PACKAGE);
360
361         printf ("evolution-data-server-Message: Starting server\n");
362
363 #ifdef DEBUG_BACKENDS
364         signal (SIGUSR2, dump_backends);
365 #endif
366
367         gnome_program_init (PACKAGE, VERSION,
368                             LIBGNOME_MODULE,
369                             argc, argv,
370                             GNOME_PROGRAM_STANDARD_PROPERTIES, NULL);
371
372         bonobo_init_full (&argc, argv,
373                           bonobo_activation_orb_get(),
374                           CORBA_OBJECT_NIL,
375                           CORBA_OBJECT_NIL);
376 #ifndef G_OS_WIN32
377         setup_segv_handler ();
378 #endif
379         e_data_server_module_init ();
380
381         if (!( (did_books = setup_books ())
382                && (did_cals = setup_cals ())
383                     )) {
384
385                 const gchar *failed = NULL;
386
387                 if (!did_books)
388                         failed = "BOOKS";
389                 else if (!did_cals)
390                         failed = "CALS";
391
392                 g_warning (G_STRLOC ": could not initialize Server service \"%s\"; terminating", failed);
393
394                 if (e_data_book_factory) {
395                         bonobo_object_unref (BONOBO_OBJECT (e_data_book_factory));
396                         e_data_book_factory = NULL;
397                 }
398
399 #if ENABLE_CALENDAR
400                 if (e_data_cal_factory) {
401                         bonobo_object_unref (BONOBO_OBJECT (e_data_cal_factory));
402                         e_data_cal_factory = NULL;
403                 }
404 #endif
405                 exit (EXIT_FAILURE);
406         }
407
408 #if ENABLE_CALENDAR
409         offline_listener = offline_listener_new (e_data_book_factory, e_data_cal_factory);
410 #else
411         offline_listener = offline_listener_new (e_data_book_factory);
412 #endif
413         
414         if ( setup_logging ()) {
415                         if ( setup_interface_check ()) {
416                                 g_message ("Server up and running");
417                                 
418                                 bonobo_main ();
419                         } else
420                                 g_error (G_STRLOC "Cannot register DataServer::InterfaceCheck object");
421         } else
422                 g_error (G_STRLOC "Cannot register DataServer::Logging object");
423
424         g_object_unref (offline_listener);
425
426 #if ENABLE_CALENDAR
427         bonobo_object_unref (BONOBO_OBJECT (e_data_cal_factory));
428         e_data_cal_factory = NULL;
429 #endif
430
431         bonobo_object_unref (BONOBO_OBJECT (e_data_book_factory));
432         e_data_book_factory = NULL;
433
434         bonobo_object_unref (BONOBO_OBJECT (logging_iface));
435         logging_iface = NULL;
436
437         bonobo_object_unref (BONOBO_OBJECT (interface_check_iface));
438         interface_check_iface = NULL;
439         
440         gnome_vfs_shutdown ();
441
442         return 0;
443 }