upgrade obexd to 0.47
[profile/ivi/obexd.git] / client / map.c
1 /*
2  *
3  *  OBEX Client
4  *
5  *  Copyright (C) 2011  Bartosz Szatkowski <bulislaw@linux.com> for Comarch
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <errno.h>
28 #include <string.h>
29 #include <glib.h>
30 #include <gdbus.h>
31
32 #include "dbus.h"
33 #include "log.h"
34
35 #include "map.h"
36 #include "transfer.h"
37 #include "session.h"
38 #include "driver.h"
39
40 #define OBEX_MAS_UUID \
41         "\xBB\x58\x2B\x40\x42\x0C\x11\xDB\xB0\xDE\x08\x00\x20\x0C\x9A\x66"
42 #define OBEX_MAS_UUID_LEN 16
43
44 #define MAP_INTERFACE "org.bluez.obex.MessageAccess"
45 #define MAP_MSG_INTERFACE "org.bluez.obex.Message"
46 #define ERROR_INTERFACE "org.bluez.obex.Error"
47 #define MAS_UUID "00001132-0000-1000-8000-00805f9b34fb"
48
49 struct map_data {
50         struct obc_session *session;
51         DBusMessage *msg;
52         GHashTable *messages;
53 };
54
55 #define MAP_MSG_FLAG_PRIORITY   0x01
56 #define MAP_MSG_FLAG_READ       0x02
57 #define MAP_MSG_FLAG_SENT       0x04
58 #define MAP_MSG_FLAG_PROTECTED  0x08
59
60 struct map_msg {
61         struct map_data *data;
62         char *path;
63         char *handle;
64         char *subject;
65         char *timestamp;
66         char *sender;
67         char *sender_address;
68         char *replyto;
69         char *recipient;
70         char *recipient_address;
71         char *type;
72         uint64_t size;
73         char *status;
74         uint8_t flags;
75 };
76
77 struct map_parser {
78         struct map_data *data;
79         DBusMessageIter *iter;
80 };
81
82 static DBusConnection *conn = NULL;
83
84 static void simple_cb(struct obc_session *session,
85                                                 struct obc_transfer *transfer,
86                                                 GError *err, void *user_data)
87 {
88         DBusMessage *reply;
89         struct map_data *map = user_data;
90
91         if (err != NULL)
92                 reply = g_dbus_create_error(map->msg,
93                                                 ERROR_INTERFACE ".Failed",
94                                                 "%s", err->message);
95         else
96                 reply = dbus_message_new_method_return(map->msg);
97
98         g_dbus_send_message(conn, reply);
99         dbus_message_unref(map->msg);
100 }
101
102 static DBusMessage *map_setpath(DBusConnection *connection,
103                                         DBusMessage *message, void *user_data)
104 {
105         struct map_data *map = user_data;
106         const char *folder;
107         GError *err = NULL;
108
109         if (dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &folder,
110                                                 DBUS_TYPE_INVALID) == FALSE)
111                 return g_dbus_create_error(message,
112                                         ERROR_INTERFACE ".InvalidArguments",
113                                         NULL);
114
115         obc_session_setpath(map->session, folder, simple_cb, map, &err);
116         if (err != NULL) {
117                 DBusMessage *reply;
118                 reply =  g_dbus_create_error(message,
119                                                 ERROR_INTERFACE ".Failed",
120                                                 "%s", err->message);
121                 g_error_free(err);
122                 return reply;
123         }
124
125         map->msg = dbus_message_ref(message);
126
127         return NULL;
128 }
129
130 static void folder_element(GMarkupParseContext *ctxt, const gchar *element,
131                                 const gchar **names, const gchar **values,
132                                 gpointer user_data, GError **gerr)
133 {
134         DBusMessageIter dict, *iter = user_data;
135         const gchar *key;
136         gint i;
137
138         if (strcasecmp("folder", element) != 0)
139                 return;
140
141         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
142                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
143                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
144                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
145
146         for (i = 0, key = names[i]; key; key = names[++i]) {
147                 if (strcasecmp("name", key) == 0)
148                         obex_dbus_dict_append(&dict, "Name", DBUS_TYPE_STRING,
149                                                                 &values[i]);
150         }
151
152         dbus_message_iter_close_container(iter, &dict);
153 }
154
155 static const GMarkupParser folder_parser = {
156         folder_element,
157         NULL,
158         NULL,
159         NULL,
160         NULL
161 };
162
163 static void folder_listing_cb(struct obc_session *session,
164                                                 struct obc_transfer *transfer,
165                                                 GError *err, void *user_data)
166 {
167         struct map_data *map = user_data;
168         GMarkupParseContext *ctxt;
169         DBusMessage *reply;
170         DBusMessageIter iter, array;
171         char *contents;
172         size_t size;
173         int perr;
174
175         if (err != NULL) {
176                 reply = g_dbus_create_error(map->msg,
177                                                 ERROR_INTERFACE ".Failed",
178                                                 "%s", err->message);
179                 goto done;
180         }
181
182         perr = obc_transfer_get_contents(transfer, &contents, &size);
183         if (perr < 0) {
184                 reply = g_dbus_create_error(map->msg,
185                                                 ERROR_INTERFACE ".Failed",
186                                                 "Error reading contents: %s",
187                                                 strerror(-perr));
188                 goto done;
189         }
190
191         reply = dbus_message_new_method_return(map->msg);
192         if (reply == NULL)
193                 return;
194
195         dbus_message_iter_init_append(reply, &iter);
196         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
197                         DBUS_TYPE_ARRAY_AS_STRING
198                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
199                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
200                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
201         ctxt = g_markup_parse_context_new(&folder_parser, 0, &array, NULL);
202         g_markup_parse_context_parse(ctxt, contents, size, NULL);
203         g_markup_parse_context_free(ctxt);
204         dbus_message_iter_close_container(&iter, &array);
205         g_free(contents);
206
207 done:
208         g_dbus_send_message(conn, reply);
209         dbus_message_unref(map->msg);
210 }
211
212 static DBusMessage *map_get_folder_listing(DBusConnection *connection,
213                                         DBusMessage *message, void *user_data)
214 {
215         struct map_data *map = user_data;
216         struct obc_transfer *transfer;
217         GError *err = NULL;
218         DBusMessage *reply;
219
220         transfer = obc_transfer_get("x-obex/folder-listing", NULL, NULL, &err);
221         if (transfer == NULL)
222                 goto fail;
223
224         if (obc_session_queue(map->session, transfer, folder_listing_cb, map,
225                                                                 &err)) {
226                 map->msg = dbus_message_ref(message);
227                 return NULL;
228         }
229
230 fail:
231         reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
232                                                                 err->message);
233         g_error_free(err);
234         return reply;
235 }
236
237 static void map_msg_free(void *data)
238 {
239         struct map_msg *msg = data;
240
241         g_free(msg->path);
242         g_free(msg->subject);
243         g_free(msg->handle);
244         g_free(msg->timestamp);
245         g_free(msg->sender);
246         g_free(msg->sender_address);
247         g_free(msg->replyto);
248         g_free(msg->recipient);
249         g_free(msg->recipient_address);
250         g_free(msg->type);
251         g_free(msg->status);
252         g_free(msg);
253 }
254
255 static DBusMessage *map_msg_get(DBusConnection *connection,
256                                         DBusMessage *message, void *user_data)
257 {
258         struct map_msg *msg = user_data;
259         struct obc_transfer *transfer;
260         const char *target_file;
261         GError *err = NULL;
262         DBusMessage *reply;
263
264         if (dbus_message_get_args(message, NULL,
265                                 DBUS_TYPE_STRING, &target_file,
266                                 DBUS_TYPE_INVALID) == FALSE)
267                 return g_dbus_create_error(message,
268                                 ERROR_INTERFACE ".InvalidArguments", NULL);
269
270         transfer = obc_transfer_get("x-bt/message", msg->handle, target_file,
271                                                                         &err);
272         if (transfer == NULL)
273                 goto fail;
274
275         if (!obc_session_queue(msg->data->session, transfer, NULL, NULL, &err))
276                 goto fail;
277
278         return obc_transfer_create_dbus_reply(transfer, message);
279
280 fail:
281         reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
282                                                                 err->message);
283         g_error_free(err);
284         return reply;
285 }
286
287 static const GDBusMethodTable map_msg_methods[] = {
288         { GDBUS_METHOD("Get",
289                         GDBUS_ARGS({ "targetfile", "s" }),
290                         GDBUS_ARGS({ "transfer", "o" },
291                                                 { "properties", "a{sv}" }),
292                         map_msg_get) },
293         { }
294 };
295
296 static struct map_msg *map_msg_create(struct map_data *data, const char *handle)
297 {
298         struct map_msg *msg;
299
300         msg = g_new0(struct map_msg, 1);
301         msg->data = data;
302         msg->path = g_strdup_printf("%s/message%s",
303                                         obc_session_get_path(data->session),
304                                         handle);
305
306         if (!g_dbus_register_interface(conn, msg->path, MAP_MSG_INTERFACE,
307                                                 map_msg_methods, NULL, NULL,
308                                                 msg, map_msg_free)) {
309                 map_msg_free(msg);
310                 return NULL;
311         }
312
313         msg->handle = g_strdup(handle);
314         g_hash_table_insert(data->messages, msg->handle, msg);
315
316         return msg;
317 }
318
319 static void parse_subject(struct map_msg *msg, const char *value,
320                                                         DBusMessageIter *iter)
321 {
322         g_free(msg->subject);
323         msg->subject = g_strdup(value);
324         obex_dbus_dict_append(iter, "Subject", DBUS_TYPE_STRING, &value);
325 }
326
327 static void parse_datetime(struct map_msg *msg, const char *value,
328                                                         DBusMessageIter *iter)
329 {
330         g_free(msg->timestamp);
331         msg->timestamp = g_strdup(value);
332         obex_dbus_dict_append(iter, "Timestamp", DBUS_TYPE_STRING, &value);
333 }
334
335 static void parse_sender(struct map_msg *msg, const char *value,
336                                                         DBusMessageIter *iter)
337 {
338         g_free(msg->sender);
339         msg->sender = g_strdup(value);
340         obex_dbus_dict_append(iter, "Sender", DBUS_TYPE_STRING, &value);
341 }
342
343 static void parse_sender_address(struct map_msg *msg, const char *value,
344                                                         DBusMessageIter *iter)
345 {
346         g_free(msg->sender_address);
347         msg->sender_address = g_strdup(value);
348         obex_dbus_dict_append(iter, "SenderAddress", DBUS_TYPE_STRING,
349                                                                 &value);
350 }
351
352 static void parse_replyto(struct map_msg *msg, const char *value,
353                                                         DBusMessageIter *iter)
354 {
355         g_free(msg->replyto);
356         msg->replyto = g_strdup(value);
357         obex_dbus_dict_append(iter, "ReplyTo", DBUS_TYPE_STRING, &value);
358 }
359
360 static void parse_recipient(struct map_msg *msg, const char *value,
361                                                         DBusMessageIter *iter)
362 {
363         g_free(msg->recipient);
364         msg->recipient = g_strdup(value);
365         obex_dbus_dict_append(iter, "Recipient", DBUS_TYPE_STRING, &value);
366 }
367
368 static void parse_recipient_address(struct map_msg *msg, const char *value,
369                                                         DBusMessageIter *iter)
370 {
371         g_free(msg->recipient_address);
372         msg->recipient_address = g_strdup(value);
373         obex_dbus_dict_append(iter, "RecipientAddress", DBUS_TYPE_STRING,
374                                                                 &value);
375 }
376
377 static void parse_type(struct map_msg *msg, const char *value,
378                                                         DBusMessageIter *iter)
379 {
380         g_free(msg->type);
381         msg->type = g_strdup(value);
382         obex_dbus_dict_append(iter, "Type", DBUS_TYPE_STRING, &value);
383 }
384
385 static void parse_status(struct map_msg *msg, const char *value,
386                                                         DBusMessageIter *iter)
387 {
388         g_free(msg->status);
389         msg->status = g_strdup(value);
390         obex_dbus_dict_append(iter, "Status", DBUS_TYPE_STRING, &value);
391 }
392
393 static void parse_size(struct map_msg *msg, const char *value,
394                                                         DBusMessageIter *iter)
395 {
396         msg->size = g_ascii_strtoll(value, NULL, 10);
397         obex_dbus_dict_append(iter, "Size", DBUS_TYPE_UINT64, &msg->size);
398 }
399
400 static void parse_priority(struct map_msg *msg, const char *value,
401                                                         DBusMessageIter *iter)
402 {
403         gboolean flag = strcasecmp(value, "no");
404
405         if (flag)
406                 msg->flags |= MAP_MSG_FLAG_PRIORITY;
407         else
408                 msg->flags &= ~MAP_MSG_FLAG_PRIORITY;
409
410         obex_dbus_dict_append(iter, "Priority", DBUS_TYPE_BOOLEAN, &flag);
411 }
412
413 static void parse_read(struct map_msg *msg, const char *value,
414                                                         DBusMessageIter *iter)
415 {
416         gboolean flag = strcasecmp(value, "no");
417
418         if (flag)
419                 msg->flags |= MAP_MSG_FLAG_READ;
420         else
421                 msg->flags &= ~MAP_MSG_FLAG_READ;
422
423         obex_dbus_dict_append(iter, "Read", DBUS_TYPE_BOOLEAN, &flag);
424 }
425
426 static void parse_sent(struct map_msg *msg, const char *value,
427                                                         DBusMessageIter *iter)
428 {
429         gboolean flag = strcasecmp(value, "no");
430
431         if (flag)
432                 msg->flags |= MAP_MSG_FLAG_SENT;
433         else
434                 msg->flags &= ~MAP_MSG_FLAG_SENT;
435
436         obex_dbus_dict_append(iter, "Sent", DBUS_TYPE_BOOLEAN, &flag);
437 }
438
439 static void parse_protected(struct map_msg *msg, const char *value,
440                                                         DBusMessageIter *iter)
441 {
442         gboolean flag = strcasecmp(value, "no");
443
444         if (flag)
445                 msg->flags |= MAP_MSG_FLAG_PROTECTED;
446         else
447                 msg->flags &= ~MAP_MSG_FLAG_PROTECTED;
448
449         obex_dbus_dict_append(iter, "Protected", DBUS_TYPE_BOOLEAN, &flag);
450 }
451
452 static struct map_msg_parser {
453         const char *name;
454         void (*func) (struct map_msg *msg, const char *value,
455                                                         DBusMessageIter *iter);
456 } msg_parsers[] = {
457                 { "subject", parse_subject },
458                 { "datetime", parse_datetime },
459                 { "sender_name", parse_sender },
460                 { "sender_addressing", parse_sender_address },
461                 { "replyto_addressing", parse_replyto },
462                 { "recipient_name", parse_recipient },
463                 { "recipient_addressing", parse_recipient_address },
464                 { "type", parse_type },
465                 { "reception_status", parse_status },
466                 { "size", parse_size },
467                 { "priority", parse_priority },
468                 { "read", parse_read },
469                 { "sent", parse_sent },
470                 { "protected", parse_protected },
471                 { }
472 };
473
474 static void msg_element(GMarkupParseContext *ctxt, const gchar *element,
475                                 const gchar **names, const gchar **values,
476                                 gpointer user_data, GError **gerr)
477 {
478         struct map_parser *parser = user_data;
479         struct map_data *data = parser->data;
480         DBusMessageIter entry, dict, *iter = parser->iter;
481         struct map_msg *msg;
482         const gchar *key;
483         gint i;
484
485         if (strcasecmp("msg", element) != 0)
486                 return;
487
488         for (i = 0, key = names[i]; key; key = names[++i]) {
489                 if (strcasecmp(key, "handle") == 0)
490                         break;
491         }
492
493         msg = g_hash_table_lookup(data->messages, key);
494         if (msg == NULL) {
495                 msg = map_msg_create(data, values[i]);
496                 if (msg == NULL)
497                         return;
498         }
499
500         dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL,
501                                                                 &entry);
502
503         dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
504                                                                 &msg->path);
505
506         dbus_message_iter_open_container(&entry, DBUS_TYPE_ARRAY,
507                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
508                                         DBUS_TYPE_STRING_AS_STRING
509                                         DBUS_TYPE_VARIANT_AS_STRING
510                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
511                                         &dict);
512
513         for (i = 0, key = names[i]; key; key = names[++i]) {
514                 struct map_msg_parser *parser;
515
516                 for (parser = msg_parsers; parser && parser->name; parser++) {
517                         if (strcasecmp(key, parser->name) == 0) {
518                                 parser->func(msg, values[i], &dict);
519                                 break;
520                         }
521                 }
522         }
523
524         dbus_message_iter_close_container(&entry, &dict);
525         dbus_message_iter_close_container(iter, &entry);
526 }
527
528 static const GMarkupParser msg_parser = {
529         msg_element,
530         NULL,
531         NULL,
532         NULL,
533         NULL
534 };
535
536 static void message_listing_cb(struct obc_session *session,
537                                                 struct obc_transfer *transfer,
538                                                 GError *err, void *user_data)
539 {
540         struct map_data *map = user_data;
541         struct map_parser *parser;
542         GMarkupParseContext *ctxt;
543         DBusMessage *reply;
544         DBusMessageIter iter, array;
545         char *contents;
546         size_t size;
547         int perr;
548
549         if (err != NULL) {
550                 reply = g_dbus_create_error(map->msg,
551                                                 ERROR_INTERFACE ".Failed",
552                                                 "%s", err->message);
553                 goto done;
554         }
555
556         perr = obc_transfer_get_contents(transfer, &contents, &size);
557         if (perr < 0) {
558                 reply = g_dbus_create_error(map->msg,
559                                                 ERROR_INTERFACE ".Failed",
560                                                 "Error reading contents: %s",
561                                                 strerror(-perr));
562                 goto done;
563         }
564
565         reply = dbus_message_new_method_return(map->msg);
566         if (reply == NULL)
567                 return;
568
569         dbus_message_iter_init_append(reply, &iter);
570         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
571                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
572                                         DBUS_TYPE_OBJECT_PATH_AS_STRING
573                                         DBUS_TYPE_ARRAY_AS_STRING
574                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
575                                         DBUS_TYPE_STRING_AS_STRING
576                                         DBUS_TYPE_VARIANT_AS_STRING
577                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING
578                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
579                                         &array);
580
581         parser = g_new(struct map_parser, 1);
582         parser->data = map;
583         parser->iter = &array;
584
585         ctxt = g_markup_parse_context_new(&msg_parser, 0, parser, NULL);
586         g_markup_parse_context_parse(ctxt, contents, size, NULL);
587         g_markup_parse_context_free(ctxt);
588         dbus_message_iter_close_container(&iter, &array);
589         g_free(contents);
590         g_free(parser);
591
592 done:
593         g_dbus_send_message(conn, reply);
594         dbus_message_unref(map->msg);
595 }
596
597 static DBusMessage *map_get_message_listing(DBusConnection *connection,
598                                         DBusMessage *message, void *user_data)
599 {
600         struct map_data *map = user_data;
601         struct obc_transfer *transfer;
602         const char *folder;
603         DBusMessageIter msg_iter;
604         GError *err = NULL;
605         DBusMessage *reply;
606
607         dbus_message_iter_init(message, &msg_iter);
608
609         if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_STRING)
610                 return g_dbus_create_error(message,
611                                 ERROR_INTERFACE ".InvalidArguments", NULL);
612
613         dbus_message_iter_get_basic(&msg_iter, &folder);
614
615         transfer = obc_transfer_get("x-bt/MAP-msg-listing", folder, NULL, &err);
616         if (transfer == NULL)
617                 goto fail;
618
619         if (obc_session_queue(map->session, transfer, message_listing_cb, map,
620                                                                 &err)) {
621                 map->msg = dbus_message_ref(message);
622                 return NULL;
623         }
624
625 fail:
626         reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
627                                                                 err->message);
628         g_error_free(err);
629         return reply;
630 }
631
632 static const GDBusMethodTable map_methods[] = {
633         { GDBUS_ASYNC_METHOD("SetFolder",
634                                 GDBUS_ARGS({ "name", "s" }), NULL,
635                                 map_setpath) },
636         { GDBUS_ASYNC_METHOD("GetFolderListing",
637                                         GDBUS_ARGS({ "filter", "a{ss}" }),
638                                         GDBUS_ARGS({ "content", "aa{sv}" }),
639                                         map_get_folder_listing) },
640         { GDBUS_ASYNC_METHOD("GetMessageListing",
641                         GDBUS_ARGS({ "folder", "s" }, { "filter", "a{ss}" }),
642                         GDBUS_ARGS({ "messages", "a{oa{sv}}" }),
643                         map_get_message_listing) },
644         { }
645 };
646
647 static void map_msg_remove(void *data)
648 {
649         struct map_msg *msg = data;
650         char *path;
651
652         path = msg->path;
653         msg->path = NULL;
654         g_dbus_unregister_interface(conn, path, MAP_MSG_INTERFACE);
655         g_free(path);
656 }
657
658 static void map_free(void *data)
659 {
660         struct map_data *map = data;
661
662         obc_session_unref(map->session);
663         g_hash_table_unref(map->messages);
664         g_free(map);
665 }
666
667 static int map_probe(struct obc_session *session)
668 {
669         struct map_data *map;
670         const char *path;
671
672         path = obc_session_get_path(session);
673
674         DBG("%s", path);
675
676         map = g_try_new0(struct map_data, 1);
677         if (!map)
678                 return -ENOMEM;
679
680         map->session = obc_session_ref(session);
681         map->messages = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
682                                                                 map_msg_remove);
683
684         if (!g_dbus_register_interface(conn, path, MAP_INTERFACE, map_methods,
685                                         NULL, NULL, map, map_free)) {
686                 map_free(map);
687
688                 return -ENOMEM;
689         }
690
691         return 0;
692 }
693
694 static void map_remove(struct obc_session *session)
695 {
696         const char *path = obc_session_get_path(session);
697
698         DBG("%s", path);
699
700         g_dbus_unregister_interface(conn, path, MAP_INTERFACE);
701 }
702
703 static struct obc_driver map = {
704         .service = "MAP",
705         .uuid = MAS_UUID,
706         .target = OBEX_MAS_UUID,
707         .target_len = OBEX_MAS_UUID_LEN,
708         .probe = map_probe,
709         .remove = map_remove
710 };
711
712 int map_init(void)
713 {
714         int err;
715
716         DBG("");
717
718         conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
719         if (!conn)
720                 return -EIO;
721
722         err = obc_driver_register(&map);
723         if (err < 0) {
724                 dbus_connection_unref(conn);
725                 conn = NULL;
726                 return err;
727         }
728
729         return 0;
730 }
731
732 void map_exit(void)
733 {
734         DBG("");
735
736         dbus_connection_unref(conn);
737         conn = NULL;
738
739         obc_driver_unregister(&map);
740 }