5 * Copyright (C) 2007-2010 Intel Corporation
6 * Copyright (C) 2007-2010 Marcel Holtmann <marcel@holtmann.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
32 #include <sys/types.h>
35 #include <dbus/dbus.h>
37 #include "lib/bluetooth.h"
39 #include "gdbus/gdbus.h"
41 #include "btio/btio.h"
42 #include "obexd/src/plugin.h"
43 #include "obexd/src/obex.h"
44 #include "obexd/src/service.h"
45 #include "obexd/src/mimetype.h"
46 #include "obexd/src/log.h"
47 #include "obexd/src/manager.h"
48 #include "obexd/src/obexd.h"
49 #include "filesystem.h"
51 #define SYNCML_TARGET_SIZE 11
53 static const uint8_t SYNCML_TARGET[SYNCML_TARGET_SIZE] = {
54 0x53, 0x59, 0x4E, 0x43, 0x4D, 0x4C, 0x2D, 0x53,
57 #define SYNCEVOLUTION_CHANNEL 19
59 #define SYNCEVOLUTION_RECORD "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\
61 <attribute id=\"0x0001\"> \
63 <uuid value=\"00000002-0000-1000-8000-0002ee000002\"/> \
67 <attribute id=\"0x0004\"> \
70 <uuid value=\"0x0100\"/> \
73 <uuid value=\"0x0003\"/> \
74 <uint8 value=\"%u\" name=\"channel\"/> \
77 <uuid value=\"0x0008\"/> \
82 <attribute id=\"0x0100\"> \
83 <text value=\"%s\" name=\"name\"/> \
87 #define SYNCE_BUS_NAME "org.syncevolution"
88 #define SYNCE_PATH "/org/syncevolution/Server"
89 #define SYNCE_SERVER_INTERFACE "org.syncevolution.Server"
90 #define SYNCE_CONN_INTERFACE "org.syncevolution.Connection"
92 struct synce_context {
93 struct obex_session *os;
94 DBusConnection *dbus_conn;
96 unsigned int reply_watch;
97 unsigned int abort_watch;
103 static void append_dict_entry(DBusMessageIter *dict, const char *key,
106 DBusMessageIter entry;
108 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
110 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
111 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &val);
112 dbus_message_iter_close_container(dict, &entry);
115 static gboolean reply_signal(DBusConnection *conn, DBusMessage *msg,
118 struct synce_context *context = data;
119 const char *path = dbus_message_get_path(msg);
120 DBusMessageIter iter, array_iter;
124 if (strcmp(context->conn_obj, path) != 0) {
125 obex_object_set_io_flags(context, G_IO_ERR, -EPERM);
126 context->lasterr = -EPERM;
130 dbus_message_iter_init(msg, &iter);
132 dbus_message_iter_recurse(&iter, &array_iter);
133 dbus_message_iter_get_fixed_array(&array_iter, &value, &length);
135 context->buffer = g_string_new_len(value, length);
136 obex_object_set_io_flags(context, G_IO_IN, 0);
137 context->lasterr = 0;
142 static gboolean abort_signal(DBusConnection *conn, DBusMessage *msg,
145 struct synce_context *context = data;
147 obex_object_set_io_flags(context, G_IO_ERR, -EPERM);
148 context->lasterr = -EPERM;
153 static void connect_cb(DBusPendingCall *call, void *user_data)
155 struct synce_context *context = user_data;
156 DBusConnection *conn;
161 conn = context->dbus_conn;
163 reply = dbus_pending_call_steal_reply(call);
165 dbus_error_init(&err);
166 if (dbus_message_get_args(reply, &err, DBUS_TYPE_OBJECT_PATH, &path,
167 DBUS_TYPE_INVALID) == FALSE) {
168 error("%s", err.message);
169 dbus_error_free(&err);
173 DBG("Got conn object %s from syncevolution", path);
174 context->conn_obj = g_strdup(path);
176 context->reply_watch = g_dbus_add_signal_watch(conn, NULL, path,
177 SYNCE_CONN_INTERFACE, "Reply",
178 reply_signal, context, NULL);
180 context->abort_watch = g_dbus_add_signal_watch(conn, NULL, path,
181 SYNCE_CONN_INTERFACE, "Abort",
182 abort_signal, context, NULL);
184 dbus_message_unref(reply);
189 obex_object_set_io_flags(context, G_IO_ERR, -EPERM);
190 context->lasterr = -EPERM;
193 static void process_cb(DBusPendingCall *call, void *user_data)
195 struct synce_context *context = user_data;
199 reply = dbus_pending_call_steal_reply(call);
200 dbus_error_init(&derr);
201 if (dbus_set_error_from_message(&derr, reply)) {
202 error("process_cb(): syncevolution replied with an error:"
203 " %s, %s", derr.name, derr.message);
204 dbus_error_free(&derr);
206 obex_object_set_io_flags(context, G_IO_ERR, -EPERM);
207 context->lasterr = -EPERM;
211 obex_object_set_io_flags(context, G_IO_OUT, 0);
212 context->lasterr = 0;
215 dbus_message_unref(reply);
218 static void *synce_connect(struct obex_session *os, int *err)
220 DBusConnection *conn;
221 struct synce_context *context;
224 manager_register_session(os);
226 conn = manager_dbus_get_connection();
230 context = g_new0(struct synce_context, 1);
231 context->dbus_conn = conn;
232 context->lasterr = -EAGAIN;
235 if (obex_getpeername(os, &address) == 0) {
236 context->id = g_strdup_printf("%s+%d", address,
237 SYNCEVOLUTION_CHANNEL);
253 static int synce_put(struct obex_session *os, void *user_data)
258 static int synce_get(struct obex_session *os, void *user_data)
260 return obex_get_stream_start(os, NULL);
263 static void close_cb(DBusPendingCall *call, void *user_data)
268 reply = dbus_pending_call_steal_reply(call);
269 dbus_error_init(&derr);
270 if (dbus_set_error_from_message(&derr, reply)) {
271 error("close_cb(): syncevolution replied with an error:"
272 " %s, %s", derr.name, derr.message);
273 dbus_error_free(&derr);
276 dbus_message_unref(reply);
279 static void synce_disconnect(struct obex_session *os, void *user_data)
281 struct synce_context *context = user_data;
286 static void *synce_open(const char *name, int oflag, mode_t mode,
287 void *user_data, size_t *size, int *err)
289 struct synce_context *context = user_data;
292 *err = context ? 0 : -EFAULT;
297 static int synce_close(void *object)
299 struct synce_context *context = object;
303 DBusPendingCall *call;
305 if (!context->conn_obj)
308 msg = dbus_message_new_method_call(SYNCE_BUS_NAME, context->conn_obj,
309 SYNCE_CONN_INTERFACE, "Close");
315 dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &normal,
316 DBUS_TYPE_STRING, &error, DBUS_TYPE_INVALID);
318 g_dbus_send_message_with_reply(context->dbus_conn, msg, &call, -1);
319 dbus_pending_call_set_notify(call, close_cb, NULL, NULL);
320 dbus_message_unref(msg);
321 dbus_pending_call_unref(call);
324 g_dbus_remove_watch(context->dbus_conn, context->reply_watch);
325 context->reply_watch = 0;
326 g_dbus_remove_watch(context->dbus_conn, context->abort_watch);
327 context->abort_watch = 0;
329 g_free(context->conn_obj);
330 context->conn_obj = NULL;
333 dbus_connection_unref(context->dbus_conn);
338 static ssize_t synce_read(void *object, void *buf, size_t count)
340 struct synce_context *context = object;
341 DBusConnection *conn;
342 char transport[36], transport_description[24];
345 DBusMessageIter iter, dict;
346 gboolean authenticate;
347 DBusPendingCall *call;
350 return string_read(context->buffer, buf, count);
352 conn = manager_dbus_get_connection();
356 msg = dbus_message_new_method_call(SYNCE_BUS_NAME, SYNCE_PATH,
357 SYNCE_SERVER_INTERFACE, "Connect");
361 dbus_message_iter_init_append(msg, &iter);
362 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
363 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
364 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING
365 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
367 append_dict_entry(&dict, "id", DBUS_TYPE_STRING, context->id);
369 snprintf(transport, sizeof(transport), "%s.obexd", OBEXD_SERVICE);
370 append_dict_entry(&dict, "transport", DBUS_TYPE_STRING, transport);
372 snprintf(transport_description, sizeof(transport_description),
373 "version %s", VERSION);
374 append_dict_entry(&dict, "transport_description", DBUS_TYPE_STRING,
375 transport_description);
377 dbus_message_iter_close_container(&iter, &dict);
379 authenticate = FALSE;
381 dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &authenticate,
382 DBUS_TYPE_STRING, &session, DBUS_TYPE_INVALID);
384 if (!g_dbus_send_message_with_reply(conn, msg, &call, -1)) {
385 error("D-Bus call to %s failed.", SYNCE_SERVER_INTERFACE);
386 dbus_message_unref(msg);
390 dbus_pending_call_set_notify(call, connect_cb, context, NULL);
392 dbus_pending_call_unref(call);
393 dbus_message_unref(msg);
398 static ssize_t synce_write(void *object, const void *buf, size_t count)
400 struct synce_context *context = object;
402 DBusMessageIter iter, array_iter;
403 DBusPendingCall *call;
404 const char *type = obex_get_type(context->os);
406 if (context->lasterr == 0)
409 if (!context->conn_obj)
412 msg = dbus_message_new_method_call(SYNCE_BUS_NAME, context->conn_obj,
413 SYNCE_CONN_INTERFACE, "Process");
417 dbus_message_iter_init_append(msg, &iter);
418 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
419 DBUS_TYPE_BYTE_AS_STRING, &array_iter);
421 dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
423 dbus_message_iter_close_container(&iter, &array_iter);
425 dbus_message_append_args(msg, DBUS_TYPE_STRING, &type,
428 if (!g_dbus_send_message_with_reply(context->dbus_conn, msg,
430 error("D-Bus call to %s failed.", SYNCE_CONN_INTERFACE);
431 dbus_message_unref(msg);
435 dbus_pending_call_set_notify(call, process_cb, context, NULL);
437 dbus_message_unref(msg);
438 dbus_pending_call_unref(call);
443 static struct obex_mime_type_driver synce_driver = {
444 .target = SYNCML_TARGET,
445 .target_size = SYNCML_TARGET_SIZE,
447 .close = synce_close,
449 .write = synce_write,
452 static struct obex_service_driver synce = {
453 .name = "OBEX server for SyncML, using SyncEvolution",
454 .service = OBEX_SYNCEVOLUTION,
455 .channel = SYNCEVOLUTION_CHANNEL,
457 .record = SYNCEVOLUTION_RECORD,
458 .target = SYNCML_TARGET,
459 .target_size = SYNCML_TARGET_SIZE,
462 .connect = synce_connect,
463 .disconnect = synce_disconnect,
466 static int synce_init(void)
470 err = obex_mime_type_driver_register(&synce_driver);
474 return obex_service_driver_register(&synce);
477 static void synce_exit(void)
479 obex_service_driver_unregister(&synce);
480 obex_mime_type_driver_unregister(&synce_driver);
483 OBEX_PLUGIN_DEFINE(syncevolution, synce_init, synce_exit)