2b3614968098eab3b8f76c51e941a2762eb2443a
[platform/upstream/syncevolution.git] / src / syncevo-dbus-server.cpp
1 /*
2  * Copyright (C) 2009 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
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <limits.h>
31
32 #include <dbus/dbus-glib-bindings.h>
33
34 #ifdef USE_GNOME_KEYRING
35 // extern "C" is missing in 2.24.1, leading to
36 // link errors. Specifying it here is a workaround.
37 extern "C" {
38 #include <gnome-keyring.h>
39 }
40 #endif
41
42 #include "EvolutionSyncSource.h"
43 #include "syncevo-dbus-server.h"
44 #include "syncevo-marshal.h"
45
46 static gboolean syncevo_start_sync (SyncevoDBusServer *obj, char *server, GPtrArray *sources, GError **error);
47 static gboolean syncevo_abort_sync (SyncevoDBusServer *obj, char *server, GError **error);
48 static gboolean syncevo_get_templates (SyncevoDBusServer *obj, GPtrArray **templates, GError **error);
49 static gboolean syncevo_get_template_config (SyncevoDBusServer *obj, char *templ, GPtrArray **options, GError **error);
50 static gboolean syncevo_get_servers (SyncevoDBusServer *obj, GPtrArray **servers, GError **error);
51 static gboolean syncevo_get_server_config (SyncevoDBusServer *obj, char *server, GPtrArray **options, GError **error);
52 static gboolean syncevo_set_server_config (SyncevoDBusServer *obj, char *server, GPtrArray *options, GError **error);
53 static gboolean syncevo_remove_server_config (SyncevoDBusServer *obj, char *server, GError **error);
54 static gboolean syncevo_get_sync_reports (SyncevoDBusServer *obj, char *server, int count, GPtrArray **reports, GError **error);
55 #include "syncevo-dbus-glue.h"
56
57 enum SyncevoDBusError{
58         SYNCEVO_DBUS_ERROR_GENERIC_ERROR,
59         SYNCEVO_DBUS_ERROR_NO_SUCH_SERVER,
60         SYNCEVO_DBUS_ERROR_MISSING_ARGS,
61         SYNCEVO_DBUS_ERROR_INVALID_CALL, /* abort called when not syncing, or sync called when already syncing */
62 };
63
64 static GQuark syncevo_dbus_error_quark(void)
65 {
66         static GQuark quark = 0;
67         if (!quark)
68                 quark = g_quark_from_static_string("syncevo-dbus-server");
69         return quark;
70 }
71 #define SYNCEVO_DBUS_ERROR (syncevo_dbus_error_quark())
72
73 static GType
74 syncevo_dbus_error_get_type (void)
75 {
76         static GType etype = 0;
77         if (G_UNLIKELY (etype == 0)) {
78                 static const GEnumValue values[] = {
79                         { SYNCEVO_DBUS_ERROR_GENERIC_ERROR, "SYNCEVO_DBUS_ERROR_GENERIC_ERROR", "GenericError" },
80                         { SYNCEVO_DBUS_ERROR_NO_SUCH_SERVER, "SYNCEVO_DBUS_ERROR_NO_SUCH_SERVER", "NoSuchServer" },
81                         { SYNCEVO_DBUS_ERROR_MISSING_ARGS, "SYNCEVO_DBUS_ERROR_MISSING_ARGS", "MissingArgs" },
82                         { SYNCEVO_DBUS_ERROR_INVALID_CALL, "SYNCEVO_DBUS_ERROR_INVALID_CALL", "InvalidCall" },
83                         { 0 }
84                 };
85                 etype = g_enum_register_static ("SyncevoDBusError", values);
86         }
87         return etype;
88 }
89 #define SYNCEVO_DBUS_ERROR_TYPE (syncevo_dbus_error_get_type ())
90
91
92 #define SYNCEVO_SOURCE_TYPE (dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_INT, G_TYPE_INVALID))
93 typedef GValueArray SyncevoSource;
94 #define SYNCEVO_OPTION_TYPE (dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID))
95 typedef GValueArray SyncevoOption;
96 #define SYNCEVO_SERVER_TYPE (dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INVALID))
97 typedef GValueArray SyncevoServer;
98
99 #define SYNCEVO_REPORT_TYPE (dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INVALID))
100 typedef GValueArray SyncevoReport;
101 #define SYNCEVO_REPORT_ARRAY_TYPE (dbus_g_type_get_struct ("GValueArray", G_TYPE_INT, dbus_g_type_get_collection ("GPtrArray", SYNCEVO_REPORT_TYPE)))
102 typedef GValueArray SyncevoReportArray;
103
104 GMainLoop *loop;
105
106
107 SyncevoSource*
108 syncevo_source_new (char *name, int mode)
109 {
110         GValue val = {0, };
111
112         g_value_init (&val, SYNCEVO_SOURCE_TYPE);
113         g_value_take_boxed (&val, dbus_g_type_specialized_construct (SYNCEVO_SOURCE_TYPE));
114         dbus_g_type_struct_set (&val, 0, name, 1, mode, G_MAXUINT);
115
116         return (SyncevoSource*) g_value_get_boxed (&val);
117 }
118
119 void
120 syncevo_source_get (SyncevoSource *source, const char **name, int *mode)
121 {
122         if (name) {
123                 *name = g_value_get_string (g_value_array_get_nth (source, 0));
124         }
125         if (mode) {
126                 *mode = g_value_get_int (g_value_array_get_nth (source, 1));
127         }
128 }
129
130 static void
131 syncevo_source_add_to_map (SyncevoSource *source, map<string, int> source_map)
132 {
133         const char *str;
134         int mode;
135         
136         syncevo_source_get (source, &str, &mode);
137         source_map.insert (make_pair (str, mode));
138 }
139
140 void
141 syncevo_source_free (SyncevoSource *source)
142 {
143         if (source) {
144                 g_boxed_free (SYNCEVO_SOURCE_TYPE, source);
145         }
146 }
147
148 SyncevoOption*
149 syncevo_option_new (char *ns, char *key, char *value)
150 {
151         GValue val = {0, };
152
153         g_value_init (&val, SYNCEVO_OPTION_TYPE);
154         g_value_take_boxed (&val, dbus_g_type_specialized_construct (SYNCEVO_OPTION_TYPE));
155         dbus_g_type_struct_set (&val, 0, ns, 1, key, 2, value, G_MAXUINT);
156
157         return (SyncevoOption*) g_value_get_boxed (&val);
158 }
159
160 void
161 syncevo_option_get (SyncevoOption *option, const char **ns, const char **key, const char **value)
162 {
163         if (ns) {
164                 *ns = g_value_get_string (g_value_array_get_nth (option, 0));
165         }
166         if (key) {
167                 *key = g_value_get_string (g_value_array_get_nth (option, 1));
168         }
169         if (value) {
170                 *value = g_value_get_string (g_value_array_get_nth (option, 2));
171         }
172 }
173
174 void
175 syncevo_option_free (SyncevoOption *option)
176 {
177         if (option) {
178                 g_boxed_free (SYNCEVO_OPTION_TYPE, option);
179         }
180 }
181
182 SyncevoServer* syncevo_server_new (char *name, char *url, char *icon, gboolean consumer_ready)
183 {
184         GValue val = {0, };
185
186         g_value_init (&val, SYNCEVO_SERVER_TYPE);
187         g_value_take_boxed (&val, dbus_g_type_specialized_construct (SYNCEVO_SERVER_TYPE));
188         dbus_g_type_struct_set (&val,
189                                 0, name,
190                                 1, url,
191                                 2, icon,
192                                 3, consumer_ready,
193                                 G_MAXUINT);
194
195         return (SyncevoServer*) g_value_get_boxed (&val);
196 }
197
198 void syncevo_server_get (SyncevoServer *server, const char **name, const char **url, const char **icon, gboolean *consumer_ready)
199 {
200         if (name) {
201                 *name = g_value_get_string (g_value_array_get_nth (server, 0));
202         }
203         if (url) {
204                 *url = g_value_get_string (g_value_array_get_nth (server, 1));
205         }
206         if (icon) {
207                 *icon = g_value_get_string (g_value_array_get_nth (server, 2));
208         }
209         if (consumer_ready) {
210                 *consumer_ready = g_value_get_boolean (g_value_array_get_nth (server, 3));
211         }
212 }
213
214 void syncevo_server_free (SyncevoServer *server)
215 {
216         if (server) {
217                 g_boxed_free (SYNCEVO_SERVER_TYPE, server);
218         }
219 }
220
221 SyncevoReport* 
222 syncevo_report_new (char *source)
223 {
224         GValue val = {0, };
225
226         g_value_init (&val, SYNCEVO_REPORT_TYPE);
227         g_value_take_boxed (&val, dbus_g_type_specialized_construct (SYNCEVO_REPORT_TYPE));
228         dbus_g_type_struct_set (&val,
229                                 0, source,
230                                 G_MAXUINT);
231
232         return (SyncevoReport*) g_value_get_boxed (&val);
233 }
234
235 static void
236 insert_int (SyncevoReport *report, int index, int value)
237 {
238         GValue val = {0};
239
240         g_value_init (&val, G_TYPE_INT);
241         g_value_set_int (&val, value);
242         g_value_array_insert (report, index, &val);
243 }
244
245 void
246 syncevo_report_set_io (SyncevoReport *report, 
247                        int sent_bytes, int received_bytes)
248 {
249         g_return_if_fail (report);
250
251         insert_int (report, 1, sent_bytes);
252         insert_int (report, 2, received_bytes);
253 }
254
255
256 void 
257 syncevo_report_set_local (SyncevoReport *report, 
258                           int adds, int updates, int removes, int rejects)
259 {
260         g_return_if_fail (report);
261
262         insert_int (report, 3, adds);
263         insert_int (report, 4, updates);
264         insert_int (report, 5, removes);
265         insert_int (report, 6, rejects);
266 }
267
268 void
269 syncevo_report_set_remote (SyncevoReport *report, 
270                            int adds, int updates, int removes, int rejects)
271 {
272         g_return_if_fail (report);
273
274         insert_int (report, 7, adds);
275         insert_int (report, 8, updates);
276         insert_int (report, 9, removes);
277         insert_int (report, 10, rejects);
278 }
279
280 void
281 syncevo_report_set_conflicts (SyncevoReport *report, 
282                               int local_won, int remote_won, int duplicated)
283 {
284         g_return_if_fail (report);
285
286         insert_int (report, 11, local_won);
287         insert_int (report, 12, remote_won);
288         insert_int (report, 13, duplicated);
289 }
290
291 const char*
292 syncevo_report_get_name (SyncevoReport *report)
293 {
294         g_return_val_if_fail (report, NULL);
295
296         return g_value_get_string (g_value_array_get_nth (report, 0));
297
298 }
299
300 void
301 syncevo_report_get_io (SyncevoReport *report, 
302                        int *bytes_sent, int *bytes_received)
303 {
304         g_return_if_fail (report);
305
306         if (bytes_sent) {
307                 *bytes_sent = g_value_get_int (g_value_array_get_nth (report, 1));
308         }
309         if (bytes_received) {
310                 *bytes_received = g_value_get_int (g_value_array_get_nth (report, 2));
311         }
312 }
313
314 void
315 syncevo_report_get_local (SyncevoReport *report, 
316                           int *adds, int *updates, int *removes, int *rejects)
317 {
318         g_return_if_fail (report);
319
320         if (adds) {
321                 *adds = g_value_get_int (g_value_array_get_nth (report, 3));
322         }
323         if (updates) {
324                 *updates = g_value_get_int (g_value_array_get_nth (report, 4));
325         }
326         if (removes) {
327                 *removes = g_value_get_int (g_value_array_get_nth (report, 5));
328         }
329         if (rejects) {
330                 *rejects = g_value_get_int (g_value_array_get_nth (report, 6));
331         }
332 }
333
334 void
335 syncevo_report_get_remote (SyncevoReport *report, 
336                            int *adds, int *updates, int *removes, int *rejects)
337 {
338         g_return_if_fail (report);
339
340         if (adds) {
341                 *adds = g_value_get_int (g_value_array_get_nth (report, 7));
342         }
343         if (updates) {
344                 *updates = g_value_get_int (g_value_array_get_nth (report, 8));
345         }
346         if (removes) {
347                 *removes = g_value_get_int (g_value_array_get_nth (report, 9));
348         }
349         if (rejects) {
350                 *rejects = g_value_get_int (g_value_array_get_nth (report, 10));
351         }
352 }
353
354 void
355 syncevo_report_get_conflicts (SyncevoReport *report, 
356                               int *local_won, int *remote_won, int *duplicated)
357 {
358         g_return_if_fail (report);
359
360         if (local_won) {
361                 *local_won = g_value_get_int (g_value_array_get_nth (report, 11));
362         }
363         if (remote_won) {
364                 *remote_won = g_value_get_int (g_value_array_get_nth (report, 12));
365         }
366         if (duplicated) {
367                 *duplicated = g_value_get_int (g_value_array_get_nth (report, 13));
368         }
369 }
370
371 void
372 syncevo_report_free (SyncevoReport *report)
373 {
374         if (report) {
375                 g_boxed_free (SYNCEVO_REPORT_TYPE, report);
376         }
377 }
378
379 SyncevoReportArray* syncevo_report_array_new (int end_time, GPtrArray *reports)
380 {
381         GValue val = {0, };
382
383         g_value_init (&val, SYNCEVO_REPORT_ARRAY_TYPE);
384         g_value_take_boxed (&val, dbus_g_type_specialized_construct (SYNCEVO_REPORT_ARRAY_TYPE));
385         dbus_g_type_struct_set (&val,
386                                 0, end_time,
387                                 1, reports,
388                                 G_MAXUINT);
389         return (SyncevoReportArray*) g_value_get_boxed (&val);
390 }
391
392 void syncevo_report_array_get (SyncevoReportArray *array, int *end_time, GPtrArray **reports)
393 {
394         g_return_if_fail (array);
395
396         if (end_time) {
397                 *end_time = g_value_get_int (g_value_array_get_nth (array, 0));
398         }
399         if (reports) {
400                 *reports = (GPtrArray*)g_value_get_boxed (g_value_array_get_nth (array, 1));
401         }
402 }
403
404 void
405 syncevo_report_array_free (SyncevoReportArray *array)
406 {
407         if (array) {
408                 g_boxed_free (SYNCEVO_REPORT_ARRAY_TYPE, array);
409         }
410 }
411
412
413 enum {
414         PROGRESS,
415         SERVER_MESSAGE,
416         LAST_SIGNAL
417 };
418 static guint signals[LAST_SIGNAL] = {0};
419
420 G_DEFINE_TYPE (SyncevoDBusServer, syncevo_dbus_server, G_TYPE_OBJECT);
421
422 static gboolean
423 shutdown ()
424 {
425         g_main_loop_quit (loop);
426
427         return FALSE;
428 }
429
430 static void
431 update_shutdown_timer (SyncevoDBusServer *obj)
432 {
433         if (obj->shutdown_timeout_src > 0)
434                 g_source_remove (obj->shutdown_timeout_src);
435
436         obj->shutdown_timeout_src = g_timeout_add_seconds (120,
437                                                            (GSourceFunc)shutdown,
438                                                            NULL);
439 }
440
441 void
442 emit_progress (const char *source,
443                       int type,
444                       int extra1,
445                       int extra2,
446                       int extra3,
447                       gpointer data)
448 {
449         SyncevoDBusServer *obj = (SyncevoDBusServer *)data;
450
451         g_signal_emit (obj, signals[PROGRESS], 0,
452                        obj->server,
453                        source,
454                        type,
455                        extra1,
456                        extra2,
457                        extra3);
458 }
459
460 void
461 emit_server_message (const char *message,
462                      gpointer data)
463 {
464         SyncevoDBusServer *obj = (SyncevoDBusServer *)data;
465
466         g_signal_emit (obj, signals[SERVER_MESSAGE], 0,
467                        obj->server,
468                        message);
469 }
470
471 #ifdef USE_GNOME_KEYRING
472 char*
473 need_password (const char *username,
474                const char *server_url,
475                gpointer data)
476 {
477         char *password = NULL;
478         char *server = NULL;
479         GnomeKeyringResult res;
480
481         server = strstr (server_url, "://");
482         if (server)
483                 server = server + 3;
484
485         if (!server)
486                 return NULL;
487
488         res = gnome_keyring_find_password_sync (GNOME_KEYRING_NETWORK_PASSWORD,
489                                                 &password,
490                                                 "user", username,
491                                                 "server", server,
492                                                 NULL);
493
494         switch (res) {
495         case GNOME_KEYRING_RESULT_OK:
496         case GNOME_KEYRING_RESULT_NO_MATCH:
497                 break;
498         default:
499                 g_warning ("Failed to get password from keyring: %s", 
500                            gnome_keyring_result_to_message (res));
501                 break;
502         }
503
504         return password;
505 }
506 #endif
507
508 gboolean 
509 check_for_suspend (gpointer data)
510 {
511         SyncevoDBusServer *obj = (SyncevoDBusServer *)data;
512
513         return obj->aborted;
514 }
515
516 static gboolean 
517 do_sync (SyncevoDBusServer *obj)
518 {
519         int ret;
520
521         try {
522                 SyncReport report;
523                 ret = (*obj->client).sync(&report);
524                 if (ret != 0) {
525                         g_printerr ("sync returned error %d\n", ret);
526                 }
527         } catch (...) {
528                 g_printerr ("sync failed (non-existing server?)\n");
529                 ret = -1;
530         }
531
532         /* adding a progress signal on top of synthesis ones */
533         g_signal_emit (obj, signals[PROGRESS], 0,
534                        obj->server,
535                        NULL,
536                        -1,
537                        ret,
538                        0,
539                        0);
540
541         delete obj->client;
542         g_free (obj->server);
543         obj->server = NULL;
544         obj->sources = NULL;
545
546         /* shutdown after a moment of inactivity */
547         update_shutdown_timer (obj);
548
549         return FALSE;
550 }
551
552 static gboolean  
553 syncevo_start_sync (SyncevoDBusServer *obj, 
554                     char *server,
555                     GPtrArray *sources,
556                     GError **error)
557 {
558         if (obj->server) {
559                 *error = g_error_new (SYNCEVO_DBUS_ERROR,
560                                       SYNCEVO_DBUS_ERROR_INVALID_CALL,
561                                       "Sync already in progress. Concurrent syncs are currently not supported");
562                 return FALSE;
563         }
564         if (!server) {
565                 *error = g_error_new (SYNCEVO_DBUS_ERROR,
566                                       SYNCEVO_DBUS_ERROR_MISSING_ARGS, 
567                                       "Server argument must be set");
568                 return FALSE;
569         }
570
571         /* don't auto-shutdown while syncing */
572         if (obj->shutdown_timeout_src > 0) {
573                 g_source_remove (obj->shutdown_timeout_src);
574                 obj->shutdown_timeout_src = 0;
575         }
576
577         obj->aborted = FALSE;
578         obj->server = g_strdup (server);
579
580         map<string,int> source_map;
581         g_ptr_array_foreach (sources, (GFunc)syncevo_source_add_to_map, &source_map);
582
583 #ifdef USE_GNOME_KEYRING
584         obj->client = new DBusSyncClient (string (server), source_map, 
585                                           emit_progress, emit_server_message, need_password, check_for_suspend,
586                                           obj);
587 #else
588         obj->client = new DBusSyncClient (string (server), source_map, 
589                                           emit_progress, emit_server_message, NULL, check_for_suspend,
590                                           obj);
591 #endif
592
593         g_idle_add ((GSourceFunc)do_sync, obj); 
594
595         return TRUE;
596 }
597
598 static gboolean 
599 syncevo_abort_sync (SyncevoDBusServer *obj,
600                             char *server,
601                             GError **error)
602 {
603         if (!server) {
604                 *error = g_error_new (SYNCEVO_DBUS_ERROR,
605                                       SYNCEVO_DBUS_ERROR_MISSING_ARGS, 
606                                       "Server variable must be set");
607                 return FALSE;
608         }
609
610         if ((!obj->server) || strcmp (server, obj->server) != 0) {
611                 *error = g_error_new (SYNCEVO_DBUS_ERROR,
612                                       SYNCEVO_DBUS_ERROR_INVALID_CALL, 
613                                       "Not syncing server '%s'", server);
614                 return FALSE;
615         }
616
617         obj->aborted = TRUE;
618
619         return TRUE;
620 }
621
622 static gboolean 
623 syncevo_get_servers (SyncevoDBusServer *obj,
624                      GPtrArray **servers,
625                      GError **error)
626 {
627         if (!servers) {
628                 *error = g_error_new (SYNCEVO_DBUS_ERROR,
629                                       SYNCEVO_DBUS_ERROR_MISSING_ARGS, 
630                                       "servers argument must be set");
631                 return FALSE;
632         }
633
634         *servers = g_ptr_array_new ();
635
636         EvolutionSyncConfig::ServerList list = EvolutionSyncConfig::getServers();
637
638         BOOST_FOREACH(const EvolutionSyncConfig::ServerList::value_type &server,list) {
639                 char *name = NULL;
640                 char *url = NULL;
641                 char *icon = NULL;
642                 gboolean ready = TRUE;
643                 SyncevoServer *srv;
644
645                 boost::shared_ptr<EvolutionSyncConfig> config (EvolutionSyncConfig::createServerTemplate (server.first));
646                 url = icon = NULL;
647                 if (config.get()) {
648                         url = g_strdup (config->getWebURL().c_str());
649                         icon = g_strdup (config->getIconURI().c_str());
650                         ready = config->getConsumerReady();
651                 }
652                 name = g_strdup (server.first.c_str());
653                 srv = syncevo_server_new (name, url, icon, ready);
654
655                 g_ptr_array_add (*servers, srv);
656         }
657
658         update_shutdown_timer (obj);
659
660         return TRUE;
661 }
662
663 static gboolean 
664 syncevo_get_templates (SyncevoDBusServer *obj,
665                        GPtrArray **templates,
666                        GError **error)
667 {
668         if (!templates) {
669                 *error = g_error_new (SYNCEVO_DBUS_ERROR,
670                                       SYNCEVO_DBUS_ERROR_MISSING_ARGS, 
671                                       "templates argument must be set");
672                 return FALSE;
673         }
674
675         *templates = g_ptr_array_new ();
676
677         EvolutionSyncConfig::ServerList list = EvolutionSyncConfig::getServerTemplates();
678
679         BOOST_FOREACH(const EvolutionSyncConfig::ServerList::value_type &server,list) {
680                 char *name, *url, *icon;
681                 gboolean ready;
682                 SyncevoServer *temp;
683
684                 boost::shared_ptr<EvolutionSyncConfig> config (EvolutionSyncConfig::createServerTemplate (server.first));
685                 name = g_strdup (server.first.c_str());
686                 url = g_strdup (config->getWebURL().c_str());
687                 icon = g_strdup (config->getIconURI().c_str());
688                 ready = config->getConsumerReady();
689                 temp = syncevo_server_new (name, url, icon, ready);
690
691                 g_ptr_array_add (*templates, temp);
692         }
693
694         update_shutdown_timer (obj);
695
696         return TRUE;
697 }
698
699 static gboolean 
700 syncevo_get_template_config (SyncevoDBusServer *obj, 
701                              char *templ, 
702                              GPtrArray **options, 
703                              GError **error)
704 {
705         SyncevoOption *option;
706         const char *ready;
707
708         if (!templ || !options) {
709                 if (options)
710                         *options = NULL;
711
712                 *error = g_error_new (SYNCEVO_DBUS_ERROR,
713                                       SYNCEVO_DBUS_ERROR_MISSING_ARGS, 
714                                       "Template and options arguments must be given");
715                 return FALSE;
716         }
717
718         boost::shared_ptr<EvolutionSyncConfig> config (EvolutionSyncConfig::createServerTemplate (string (templ)));
719         if (!config.get()) {
720                 *options = NULL;
721                 *error = g_error_new (SYNCEVO_DBUS_ERROR,
722                                       SYNCEVO_DBUS_ERROR_NO_SUCH_SERVER, 
723                                       "No template '%s' found", templ);
724                 return FALSE;
725         }
726
727         *options = g_ptr_array_new ();
728         option = syncevo_option_new (NULL, g_strdup ("syncURL"), g_strdup(config->getSyncURL()));
729         g_ptr_array_add (*options, option);
730         option = syncevo_option_new (NULL, g_strdup("username"), g_strdup(config->getUsername()));
731         g_ptr_array_add (*options, option);
732         option = syncevo_option_new (NULL, g_strdup("webURL"), g_strdup(config->getWebURL().c_str()));
733         g_ptr_array_add (*options, option);
734         option = syncevo_option_new (NULL, g_strdup("iconURI"), g_strdup(config->getIconURI().c_str()));
735         g_ptr_array_add (*options, option);
736
737         ready = (config->getConsumerReady() ? "yes" : "no");
738         option = syncevo_option_new (NULL, g_strdup("consumerReady"), g_strdup(ready));
739         g_ptr_array_add (*options, option);
740
741         option = syncevo_option_new (NULL, g_strdup("fromTemplate"), g_strdup("yes"));
742         g_ptr_array_add (*options, option);
743
744         list<string> sources = config->getSyncSources();
745         BOOST_FOREACH(const string &name, sources) {
746                 gboolean local;
747
748                 boost::shared_ptr<EvolutionSyncSourceConfig> source_config = config->getSyncSourceConfig(name);
749
750                 option = syncevo_option_new (g_strdup (name.c_str()), g_strdup ("sync"), g_strdup (source_config->getSync()));
751                 g_ptr_array_add (*options, option);
752                 option = syncevo_option_new (g_strdup (name.c_str()), g_strdup ("uri"), g_strdup (source_config->getURI()));
753                 g_ptr_array_add (*options, option);
754
755                 /* check whether we have support locally */
756                 EvolutionSyncSourceParams params(name, config->getSyncSourceNodes(name), "");
757                 auto_ptr<EvolutionSyncSource> syncSource(EvolutionSyncSource::createSource(params, false));
758                 try {
759                         local = FALSE;
760                         if (syncSource.get()) {
761                                 syncSource->open();
762                                 local = TRUE;
763                         }
764                 } catch (...) {}
765                 option = syncevo_option_new (g_strdup (name.c_str()), 
766                                              g_strdup ("localDB"), 
767                                              g_strdup_printf ("%d", local));
768                 g_ptr_array_add (*options, option);
769         }
770
771         update_shutdown_timer (obj);
772
773         return TRUE;
774 }
775
776 static gboolean 
777 syncevo_get_server_config (SyncevoDBusServer *obj,
778                            char *server,
779                            GPtrArray **options,
780                            GError **error)
781 {
782         SyncevoOption *option;
783
784         if (!server || !options) {
785                 if (options)
786                         *options = NULL;
787                 *error = g_error_new (SYNCEVO_DBUS_ERROR,
788                                       SYNCEVO_DBUS_ERROR_MISSING_ARGS, 
789                                       "Server and options arguments must be given");
790                 return FALSE;
791         }
792
793         boost::shared_ptr<EvolutionSyncConfig> from(new EvolutionSyncConfig (string (server)));
794         /* if config does not exist, create from template */
795         if (!from->exists()) {
796                 from = EvolutionSyncConfig::createServerTemplate( string (server));
797                 if (!from.get()) {
798                         *options = NULL;
799                         *error = g_error_new (SYNCEVO_DBUS_ERROR,
800                                               SYNCEVO_DBUS_ERROR_NO_SUCH_SERVER,
801                                               "No server or template '%s' found", server);
802                         return FALSE;
803                 }
804         }
805
806         *options = g_ptr_array_new ();
807         boost::shared_ptr<EvolutionSyncConfig> config(new EvolutionSyncConfig(string (server)));
808         config->copy(*from, NULL);
809
810         option = syncevo_option_new (NULL, g_strdup ("syncURL"), g_strdup(config->getSyncURL()));
811         g_ptr_array_add (*options, option);
812         option = syncevo_option_new (NULL, g_strdup("username"), g_strdup(config->getUsername()));
813         g_ptr_array_add (*options, option);
814
815         /* get template options if template exists */
816         boost::shared_ptr<EvolutionSyncConfig> templ = EvolutionSyncConfig::createServerTemplate( string (server));
817         if (templ.get()) {
818                 const char *ready;
819
820                 option = syncevo_option_new (NULL, g_strdup("fromTemplate"), g_strdup("yes"));
821                 g_ptr_array_add (*options, option);
822                 option = syncevo_option_new (NULL, g_strdup("webURL"), g_strdup(templ->getWebURL().c_str()));
823                 g_ptr_array_add (*options, option);
824                 option = syncevo_option_new (NULL, g_strdup("iconURI"), g_strdup(templ->getIconURI().c_str()));
825                 g_ptr_array_add (*options, option);
826
827                 ready = templ->getConsumerReady() ? "yes" : "no";
828                 option = syncevo_option_new (NULL, g_strdup("consumerReady"), g_strdup (ready));
829                 g_ptr_array_add (*options, option);
830         }
831
832         list<string> sources = config->getSyncSources();
833         BOOST_FOREACH(const string &name, sources) {
834                 gboolean local;
835
836                 boost::shared_ptr<EvolutionSyncSourceConfig> source_config = config->getSyncSourceConfig(name);
837
838                 option = syncevo_option_new (g_strdup (name.c_str()), g_strdup ("sync"), g_strdup (source_config->getSync()));
839                 g_ptr_array_add (*options, option);
840                 option = syncevo_option_new (g_strdup (name.c_str()), g_strdup ("uri"), g_strdup (source_config->getURI()));
841                 g_ptr_array_add (*options, option);
842
843                 /* check whether we have support locally */
844                 EvolutionSyncSourceParams params(name, config->getSyncSourceNodes(name), "");
845                 auto_ptr<EvolutionSyncSource> syncSource(EvolutionSyncSource::createSource(params, false));
846                 try {
847                         local = FALSE;
848                         if (syncSource.get()) {
849                                 syncSource->open();
850                                 local = TRUE;
851                         }
852                 } catch (...) {}
853                 option = syncevo_option_new (g_strdup (name.c_str()), 
854                                              g_strdup ("localDB"), 
855                                              g_strdup_printf ("%d", local));
856                 g_ptr_array_add (*options, option);
857
858         }
859
860
861
862         update_shutdown_timer (obj);
863
864         return TRUE;
865 }
866
867
868 static gboolean 
869 syncevo_set_server_config (SyncevoDBusServer *obj,
870                            char *server,
871                            GPtrArray *options,
872                            GError **error)
873 {
874         int i;
875         
876         if (!server || !options) {
877                 *error = g_error_new (SYNCEVO_DBUS_ERROR,
878                                       SYNCEVO_DBUS_ERROR_MISSING_ARGS, 
879                                       "Server and options parameters must be given");
880                 return FALSE;
881         }
882
883         if (obj->server) {
884                 *error = g_error_new (SYNCEVO_DBUS_ERROR,
885                                       SYNCEVO_DBUS_ERROR_GENERIC_ERROR, 
886                                       "GetServers is currently not supported when a sync is in progress");
887                 return FALSE;
888         }
889
890         boost::shared_ptr<EvolutionSyncConfig> from(new EvolutionSyncConfig (string (server)));
891         /* if config does not exist, create from template */
892         if (!from->exists()) {
893                 from = EvolutionSyncConfig::createServerTemplate( string (server));
894                 if (!from.get()) {
895                         from = EvolutionSyncConfig::createServerTemplate( string ("default"));
896                 }
897         }
898         boost::shared_ptr<EvolutionSyncConfig> config(new EvolutionSyncConfig(string (server)));
899         config->copy(*from, NULL);
900         
901         for (i = 0; i < (int)options->len; i++) {
902                 const char *ns, *key, *value;
903                 SyncevoOption *option = (SyncevoOption*)g_ptr_array_index (options, i);
904
905                 syncevo_option_get (option, &ns, &key, &value);
906
907                 if ((!ns || strlen (ns) == 0) && key) {
908                         if (strcmp (key, "syncURL") == 0) {
909                                 config->setSyncURL (string (value));
910                         } else if (strcmp (key, "username") == 0) {
911                                 config->setUsername (string (value));
912                         } else if (strcmp (key, "password") == 0) {
913                                 config->setPassword (string (value));
914                         } else if (strcmp (key, "webURL") == 0) {
915                                 config->setWebURL (string (value));
916                         } else if (strcmp (key, "iconURI") == 0) {
917                                 config->setIconURI (string (value));
918                         }
919                 } else if (ns && key) {
920                         boost::shared_ptr<EvolutionSyncSourceConfig> source_config = config->getSyncSourceConfig(ns);
921                         if (strcmp (key, "sync") == 0) {
922                                 source_config->setSync (string (value));
923                         } else if (strcmp (key, "uri") == 0) {
924                                 source_config->setURI (string (value));
925                         }
926                 }
927         }
928         config->flush();
929
930         update_shutdown_timer (obj);
931
932         return TRUE;
933 }
934
935 static gboolean 
936 syncevo_remove_server_config (SyncevoDBusServer *obj,
937                               char *server,
938                               GError **error)
939 {
940         if (!server) {
941                 *error = g_error_new (SYNCEVO_DBUS_ERROR,
942                                       SYNCEVO_DBUS_ERROR_MISSING_ARGS, 
943                                       "Server argument must be given");
944                 return FALSE;
945         }
946
947         if (obj->server) {
948                 *error = g_error_new (SYNCEVO_DBUS_ERROR,
949                                       SYNCEVO_DBUS_ERROR_GENERIC_ERROR, 
950                                       "RemoveServerConfig is not supported when a sync is in progress");
951                 return FALSE;
952         }
953
954         boost::shared_ptr<EvolutionSyncConfig> config(new EvolutionSyncConfig (string (server)));
955         if (!config->exists()) {
956                 *error = g_error_new (SYNCEVO_DBUS_ERROR,
957                                       SYNCEVO_DBUS_ERROR_NO_SUCH_SERVER,
958                                       "No server '%s' found", server);
959                 return FALSE;
960         }
961         config->remove();
962
963         update_shutdown_timer (obj);
964
965         return TRUE;
966 }
967
968 static gboolean 
969 syncevo_get_sync_reports (SyncevoDBusServer *obj, 
970                           char *server, 
971                           int count,
972                           GPtrArray **reports,
973                           GError **error)
974 {
975         if (!server) {
976                 *error = g_error_new (SYNCEVO_DBUS_ERROR,
977                                       SYNCEVO_DBUS_ERROR_MISSING_ARGS, 
978                                       "Server argument must be given");
979                 return FALSE;
980         }
981
982         if (!reports) {
983                 *error = g_error_new (SYNCEVO_DBUS_ERROR,
984                                       SYNCEVO_DBUS_ERROR_MISSING_ARGS, 
985                                       "reports argument must be given");
986                 return FALSE;
987         }
988
989         EvolutionSyncClient client (string (server), false);
990         vector<string> dirs;
991         *reports = g_ptr_array_new ();
992
993         client.getSessions (dirs);
994         int start_from = dirs.size () - count;
995         int index = 0;
996
997         BOOST_FOREACH (const string &dir, dirs) {
998                 if (index < start_from) {
999                         index++;
1000                 } else {
1001                         SyncevoReportArray * session_report;
1002                         GPtrArray *source_reports;
1003                         SyncReport report;
1004
1005                         client.readSessionInfo (dir, report);
1006                         source_reports = g_ptr_array_new ();
1007
1008                         for (SyncReport::iterator it = report.begin(); it != report.end(); ++it) {
1009                                 SyncevoReport *source_report;
1010
1011                                 SyncSourceReport srcrep = it->second;
1012                                 source_report = syncevo_report_new (g_strdup (it->first.c_str ()));
1013
1014                                 syncevo_report_set_io (source_report,
1015                                                        srcrep.getItemStat (SyncSourceReport::ITEM_LOCAL, 
1016                                                                            SyncSourceReport::ITEM_ANY, 
1017                                                                            SyncSourceReport::ITEM_SENT_BYTES),
1018                                                        srcrep.getItemStat (SyncSourceReport::ITEM_LOCAL, 
1019                                                                            SyncSourceReport::ITEM_ANY, 
1020                                                                            SyncSourceReport::ITEM_RECEIVED_BYTES));
1021                                 syncevo_report_set_local (source_report, 
1022                                                           srcrep.getItemStat (SyncSourceReport::ITEM_LOCAL, 
1023                                                                               SyncSourceReport::ITEM_ADDED, 
1024                                                                               SyncSourceReport::ITEM_TOTAL),
1025                                                           srcrep.getItemStat (SyncSourceReport::ITEM_LOCAL, 
1026                                                                               SyncSourceReport::ITEM_UPDATED, 
1027                                                                               SyncSourceReport::ITEM_TOTAL),
1028                                                           srcrep.getItemStat (SyncSourceReport::ITEM_LOCAL, 
1029                                                                               SyncSourceReport::ITEM_REMOVED, 
1030                                                                               SyncSourceReport::ITEM_TOTAL),
1031                                                           srcrep.getItemStat (SyncSourceReport::ITEM_LOCAL, 
1032                                                                               SyncSourceReport::ITEM_ANY, 
1033                                                                               SyncSourceReport::ITEM_REJECT));
1034                                 syncevo_report_set_remote (source_report, 
1035                                                            srcrep.getItemStat (SyncSourceReport::ITEM_REMOTE, 
1036                                                                                SyncSourceReport::ITEM_ADDED, 
1037                                                                                SyncSourceReport::ITEM_TOTAL),
1038                                                            srcrep.getItemStat (SyncSourceReport::ITEM_REMOTE, 
1039                                                                                SyncSourceReport::ITEM_UPDATED, 
1040                                                                                SyncSourceReport::ITEM_TOTAL),
1041                                                            srcrep.getItemStat (SyncSourceReport::ITEM_REMOTE, 
1042                                                                                SyncSourceReport::ITEM_REMOVED, 
1043                                                                                SyncSourceReport::ITEM_TOTAL),
1044                                                            srcrep.getItemStat (SyncSourceReport::ITEM_REMOTE, 
1045                                                                                SyncSourceReport::ITEM_ANY, 
1046                                                                                SyncSourceReport::ITEM_REJECT));
1047                                 syncevo_report_set_conflicts (source_report,
1048                                                               srcrep.getItemStat (SyncSourceReport::ITEM_REMOTE, 
1049                                                                                   SyncSourceReport::ITEM_ANY, 
1050                                                                                   SyncSourceReport::ITEM_CONFLICT_CLIENT_WON),
1051                                                               srcrep.getItemStat (SyncSourceReport::ITEM_REMOTE, 
1052                                                                                   SyncSourceReport::ITEM_ANY, 
1053                                                                                   SyncSourceReport::ITEM_CONFLICT_SERVER_WON),
1054                                                               srcrep.getItemStat (SyncSourceReport::ITEM_REMOTE, 
1055                                                                                   SyncSourceReport::ITEM_ANY, 
1056                                                                                   SyncSourceReport::ITEM_CONFLICT_DUPLICATED));
1057                                 g_ptr_array_add (source_reports, source_report);
1058                         }
1059                         session_report = syncevo_report_array_new (report.getEnd (), source_reports);
1060                         g_ptr_array_add (*reports, session_report);
1061                 }
1062         }
1063
1064         update_shutdown_timer (obj);
1065
1066         return TRUE;
1067 }
1068
1069 static void
1070 syncevo_dbus_server_class_init(SyncevoDBusServerClass *klass)
1071 {
1072         GError *error = NULL;
1073
1074         klass->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
1075         if (klass->connection == NULL)
1076         {
1077                 g_warning("Unable to connect to dbus: %s", error->message);
1078                 g_error_free (error);
1079                 return;
1080         }
1081
1082         signals[PROGRESS] = g_signal_new ("progress",
1083                                           G_TYPE_FROM_CLASS (klass),
1084                                           (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE),
1085                                           G_STRUCT_OFFSET (SyncevoDBusServerClass, progress),
1086                                           NULL, NULL,
1087                                           syncevo_marshal_VOID__STRING_STRING_INT_INT_INT_INT,
1088                                           G_TYPE_NONE, 
1089                                           6, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
1090         signals[SERVER_MESSAGE] = g_signal_new ("server-message",
1091                                           G_TYPE_FROM_CLASS (klass),
1092                                           (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE),
1093                                           G_STRUCT_OFFSET (SyncevoDBusServerClass, server_message),
1094                                           NULL, NULL,
1095                                           syncevo_marshal_VOID__STRING_STRING,
1096                                           G_TYPE_NONE, 
1097                                           2, G_TYPE_STRING, G_TYPE_STRING);
1098
1099         /* dbus_glib_syncevo_object_info is provided in the generated glue file */
1100         dbus_g_object_type_install_info (SYNCEVO_TYPE_DBUS_SERVER, &dbus_glib_syncevo_object_info);
1101
1102         /* register error domain so clients get proper error names with dbus_g_error_get_name() */
1103         dbus_g_error_domain_register (SYNCEVO_DBUS_ERROR, NULL, SYNCEVO_DBUS_ERROR_TYPE);
1104 }
1105
1106 static void
1107 syncevo_dbus_server_init(SyncevoDBusServer *obj)
1108 {
1109         GError *error = NULL;
1110         DBusGProxy *proxy;
1111         guint request_ret;
1112         SyncevoDBusServerClass *klass = SYNCEVO_DBUS_SERVER_GET_CLASS (obj);
1113
1114         dbus_g_connection_register_g_object (klass->connection,
1115                                              "/org/Moblin/SyncEvolution",
1116                                              G_OBJECT (obj));
1117
1118         proxy = dbus_g_proxy_new_for_name (klass->connection,
1119                                            DBUS_SERVICE_DBUS,
1120                                            DBUS_PATH_DBUS,
1121                                            DBUS_INTERFACE_DBUS);
1122
1123         if(!org_freedesktop_DBus_request_name (proxy,
1124                                                "org.Moblin.SyncEvolution",
1125                                                0, &request_ret,
1126                                                &error)) {
1127                 g_warning("Unable to register service: %s", error->message);
1128                 g_error_free (error);
1129         }
1130         g_object_unref (proxy);
1131
1132         update_shutdown_timer (obj);
1133 }
1134
1135 void niam(int sig)
1136 {
1137         g_main_loop_quit (loop);
1138 }
1139
1140 int main()
1141 {
1142         SyncevoDBusServer *server;
1143
1144         signal(SIGTERM, niam);
1145         signal(SIGINT, niam);
1146
1147         g_type_init ();
1148         g_thread_init (NULL);
1149         g_set_application_name ("SyncEvolution");
1150
1151         server = (SyncevoDBusServer*)g_object_new (SYNCEVO_TYPE_DBUS_SERVER, NULL);
1152
1153         loop = g_main_loop_new (NULL, FALSE);
1154         g_main_loop_run (loop);
1155
1156         g_main_loop_unref (loop);
1157         g_object_unref (server);
1158         return 0;
1159 }