upload tizen1.0 source
[profile/ivi/obexd.git] / src / manager.c
1 /*
2  *
3  *  OBEX Server
4  *
5  *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
6  *
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <gdbus.h>
33 #include <sys/socket.h>
34 #include <inttypes.h>
35
36 #include <gobex.h>
37
38 #include "obexd.h"
39 #include "obex.h"
40 #include "obex-priv.h"
41 #include "server.h"
42 #include "manager.h"
43 #include "log.h"
44 #include "btio.h"
45 #include "service.h"
46
47 #define OPENOBEX_MANAGER_PATH "/"
48 #define OPENOBEX_MANAGER_INTERFACE OPENOBEX_SERVICE ".Manager"
49 #define ERROR_INTERFACE OPENOBEX_SERVICE ".Error"
50 #define TRANSFER_INTERFACE OPENOBEX_SERVICE ".Transfer"
51 #define SESSION_INTERFACE OPENOBEX_SERVICE ".Session"
52
53 #define TIMEOUT 60*1000 /* Timeout for user response (miliseconds) */
54
55 struct agent {
56         char *bus_name;
57         char *path;
58         gboolean auth_pending;
59         char *new_name;
60         char *new_folder;
61         unsigned int watch_id;
62 };
63
64 static struct agent *agent = NULL;
65
66 static DBusConnection *connection = NULL;
67
68 static void agent_free(struct agent *agent)
69 {
70         if (!agent)
71                 return;
72
73         g_free(agent->new_folder);
74         g_free(agent->new_name);
75         g_free(agent->bus_name);
76         g_free(agent->path);
77         g_free(agent);
78 }
79
80 static inline DBusMessage *invalid_args(DBusMessage *msg)
81 {
82         return g_dbus_create_error(msg,
83                         ERROR_INTERFACE ".InvalidArguments",
84                         "Invalid arguments in method call");
85 }
86
87 static inline DBusMessage *agent_already_exists(DBusMessage *msg)
88 {
89         return g_dbus_create_error(msg,
90                         ERROR_INTERFACE ".AlreadyExists",
91                         "Agent already exists");
92 }
93
94 static inline DBusMessage *agent_does_not_exist(DBusMessage *msg)
95 {
96         return g_dbus_create_error(msg,
97                         ERROR_INTERFACE ".DoesNotExist",
98                         "Agent does not exist");
99 }
100
101 static inline DBusMessage *not_authorized(DBusMessage *msg)
102 {
103         return g_dbus_create_error(msg,
104                         ERROR_INTERFACE ".NotAuthorized",
105                         "Not authorized");
106 }
107
108 static void dbus_message_iter_append_variant(DBusMessageIter *iter,
109                                                 int type, void *val)
110 {
111         DBusMessageIter value;
112         DBusMessageIter array;
113         const char *sig;
114
115         switch (type) {
116         case DBUS_TYPE_STRING:
117                 sig = DBUS_TYPE_STRING_AS_STRING;
118                 break;
119         case DBUS_TYPE_BYTE:
120                 sig = DBUS_TYPE_BYTE_AS_STRING;
121                 break;
122         case DBUS_TYPE_INT16:
123                 sig = DBUS_TYPE_INT16_AS_STRING;
124                 break;
125         case DBUS_TYPE_UINT16:
126                 sig = DBUS_TYPE_UINT16_AS_STRING;
127                 break;
128         case DBUS_TYPE_INT32:
129                 sig = DBUS_TYPE_INT32_AS_STRING;
130                 break;
131         case DBUS_TYPE_UINT32:
132                 sig = DBUS_TYPE_UINT32_AS_STRING;
133                 break;
134 #ifdef TIZEN_PATCH
135         case DBUS_TYPE_UINT64:
136                 sig = DBUS_TYPE_UINT64_AS_STRING;
137                 break;
138 #endif
139         case DBUS_TYPE_BOOLEAN:
140                 sig = DBUS_TYPE_BOOLEAN_AS_STRING;
141                 break;
142         case DBUS_TYPE_ARRAY:
143                 sig = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING;
144                 break;
145         case DBUS_TYPE_OBJECT_PATH:
146                 sig = DBUS_TYPE_OBJECT_PATH_AS_STRING;
147                 break;
148         default:
149                 error("Could not append variant with type %d", type);
150                 return;
151         }
152
153         dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
154
155         if (type == DBUS_TYPE_ARRAY) {
156                 int i;
157                 const char ***str_array = val;
158
159                 dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
160                         DBUS_TYPE_STRING_AS_STRING, &array);
161
162                 for (i = 0; (*str_array)[i]; i++)
163                         dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
164                                                         &((*str_array)[i]));
165
166                 dbus_message_iter_close_container(&value, &array);
167         } else
168                 dbus_message_iter_append_basic(&value, type, val);
169
170         dbus_message_iter_close_container(iter, &value);
171 }
172
173 static void dbus_message_iter_append_dict_entry(DBusMessageIter *dict,
174                                         const char *key, int type, void *val)
175 {
176         DBusMessageIter entry;
177
178         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
179                                         NULL, &entry);
180
181         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
182
183         dbus_message_iter_append_variant(&entry, type, val);
184
185         dbus_message_iter_close_container(dict, &entry);
186 }
187
188 static void agent_disconnected(DBusConnection *conn, void *user_data)
189 {
190         DBG("Agent exited");
191         agent_free(agent);
192         agent = NULL;
193 }
194
195 static DBusMessage *register_agent(DBusConnection *conn,
196                                         DBusMessage *msg, void *data)
197 {
198         const char *path, *sender;
199
200         if (agent)
201                 return agent_already_exists(msg);
202
203         if (!dbus_message_get_args(msg, NULL,
204                                 DBUS_TYPE_OBJECT_PATH, &path,
205                                 DBUS_TYPE_INVALID))
206                 return invalid_args(msg);
207
208         sender = dbus_message_get_sender(msg);
209         agent = g_new0(struct agent, 1);
210         agent->bus_name = g_strdup(sender);
211         agent->path = g_strdup(path);
212
213         agent->watch_id = g_dbus_add_disconnect_watch(conn, sender,
214                                         agent_disconnected, NULL, NULL);
215
216         DBG("Agent registered");
217
218         return dbus_message_new_method_return(msg);
219 }
220
221 static DBusMessage *unregister_agent(DBusConnection *conn,
222                                         DBusMessage *msg, void *data)
223 {
224         const char *path, *sender;
225
226         if (!agent)
227                 return agent_does_not_exist(msg);
228
229         if (!dbus_message_get_args(msg, NULL,
230                                 DBUS_TYPE_OBJECT_PATH, &path,
231                                 DBUS_TYPE_INVALID))
232                 return invalid_args(msg);
233
234         if (strcmp(agent->path, path) != 0)
235                 return agent_does_not_exist(msg);
236
237         sender = dbus_message_get_sender(msg);
238         if (strcmp(agent->bus_name, sender) != 0)
239                 return not_authorized(msg);
240
241         g_dbus_remove_watch(conn, agent->watch_id);
242
243         agent_free(agent);
244         agent = NULL;
245
246         DBG("Agent unregistered");
247
248         return dbus_message_new_method_return(msg);
249 }
250
251 #ifdef TIZEN_PATCH
252 static DBusMessage *set_root(DBusConnection *conn, DBusMessage *msg,
253                                         const char *root, void *data)
254 {
255         DBG("new_root: %s", root);
256
257         /* Change the option root path (using in filesystem) */
258         obex_option_set_root_folder(root);
259
260         return dbus_message_new_method_return(msg);
261 }
262
263 static DBusMessage *set_property(DBusConnection *conn,
264                                 DBusMessage *msg, void *data)
265 {
266         DBusMessageIter iter;
267         DBusMessageIter sub;
268         const char *property;
269
270         if (!dbus_message_iter_init(msg, &iter))
271                 return invalid_args(msg);
272
273         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
274                 return invalid_args(msg);
275
276         dbus_message_iter_get_basic(&iter, &property);
277         dbus_message_iter_next(&iter);
278
279         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
280                 return invalid_args(msg);
281         dbus_message_iter_recurse(&iter, &sub);
282
283         if (g_str_equal("Root", property)) {
284                 const char *root;
285
286                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)
287                         return invalid_args(msg);
288                 dbus_message_iter_get_basic(&sub, &root);
289
290                 return set_root(conn, msg, root, data);
291         }
292
293         return invalid_args(msg);
294 }
295 #endif
296
297
298 static char *target2str(const uint8_t *t)
299 {
300         if (!t)
301                 return NULL;
302
303         return g_strdup_printf("%02X%02X%02X%02X-%02X%02X-%02X%02X-"
304                                 "%02X%02X-%02X%02X%02X%02X%02X%02X",
305                                 t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7],
306                                 t[8], t[9], t[10], t[11], t[12], t[13], t[14], t[15]);
307 }
308
309 static DBusMessage *get_properties(DBusConnection *conn,
310                                 DBusMessage *msg, void *data)
311 {
312         struct obex_session *os = data;
313         DBusMessage *reply;
314         DBusMessageIter iter;
315         DBusMessageIter dict;
316         char *uuid;
317         const char *root;
318
319         reply = dbus_message_new_method_return(msg);
320         if (!reply)
321                 return NULL;
322
323         dbus_message_iter_init_append(reply, &iter);
324         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
325                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
326                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
327                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
328
329         /* Target */
330         uuid = target2str(os->service->target);
331         dbus_message_iter_append_dict_entry(&dict, "Target",
332                                         DBUS_TYPE_STRING, &uuid);
333         g_free(uuid);
334
335         /* Root folder */
336         root = obex_option_root_folder();
337         dbus_message_iter_append_dict_entry(&dict, "Root",
338                                         DBUS_TYPE_STRING, &root);
339
340         /* FIXME: Added Remote Address or USB */
341
342         dbus_message_iter_close_container(&iter, &dict);
343
344         return reply;
345 }
346
347 static DBusMessage *transfer_cancel(DBusConnection *connection,
348                                 DBusMessage *msg, void *user_data)
349 {
350         struct obex_session *os = user_data;
351         const char *sender;
352
353         if (!os)
354                 return invalid_args(msg);
355
356         sender = dbus_message_get_sender(msg);
357         if (strcmp(agent->bus_name, sender) != 0)
358                 return not_authorized(msg);
359
360         os->aborted = TRUE;
361
362         return dbus_message_new_method_return(msg);
363 }
364
365 #ifdef TIZEN_PATCH
366 static char *get_obex_operation(struct obex_session *os)
367 {
368         char *operation = NULL;
369
370         switch (os->cmd) {
371         case G_OBEX_OP_PUT:
372                 if (os->size != OBJECT_SIZE_DELETE)
373                         operation = g_strdup("PUT");
374                 break;
375         case G_OBEX_OP_GET:
376                 operation = g_strdup("GET");
377                 break;
378         default:
379                 break;
380         }
381
382         return operation;
383 }
384
385 static DBusMessage *transfer_get_properties(DBusConnection *connection,
386                                         DBusMessage *message, void *user_data)
387 {
388         struct obex_session *os = user_data;
389         DBusMessage *reply;
390         DBusMessageIter iter, dict;
391         char *operation;
392
393         if (!os)
394                 return invalid_args(message);
395
396         reply = dbus_message_new_method_return(message);
397         if (!reply)
398                 return NULL;
399
400         dbus_message_iter_init_append(reply, &iter);
401
402         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
403                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
404                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
405                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
406
407         if (os->name)
408                 dbus_message_iter_append_dict_entry(&dict, "Filename",
409                                                 DBUS_TYPE_STRING, &os->name);
410
411         dbus_message_iter_append_dict_entry(&dict, "Size",
412                                         DBUS_TYPE_UINT64, &os->size);
413
414         operation = get_obex_operation(os);
415         if (operation) {
416                 dbus_message_iter_append_dict_entry(&dict, "Operation",
417                                                 DBUS_TYPE_STRING, &operation);
418                 g_free(operation);
419         }
420
421         dbus_message_iter_close_container(&iter, &dict);
422
423         return reply;
424 }
425 #endif
426
427 static GDBusMethodTable manager_methods[] = {
428         { "RegisterAgent",      "o",    "",     register_agent          },
429         { "UnregisterAgent",    "o",    "",     unregister_agent        },
430 #ifdef TIZEN_PATCH
431         { "SetProperty",        "sv",   "",     set_property            },
432 #endif
433         { }
434 };
435
436 static GDBusSignalTable manager_signals[] = {
437         { "TransferStarted",    "o"     },
438         { "TransferCompleted",  "ob"    },
439         { "SessionCreated",     "o"     },
440         { "SessionRemoved",     "o"     },
441         { }
442 };
443
444 static GDBusMethodTable transfer_methods[] = {
445         { "Cancel",     "",     "",     transfer_cancel },
446 #ifdef TIZEN_PATCH
447         { "GetProperties",      "",     "{sv}", transfer_get_properties },
448 #endif
449         { }
450 };
451
452 static GDBusSignalTable transfer_signals[] = {
453         { "Progress",   "ii"    },
454         { }
455 };
456
457 static GDBusMethodTable session_methods[] = {
458         { "GetProperties",      "",     "{sv}", get_properties  },
459         { }
460 };
461
462 gboolean manager_init(void)
463 {
464         DBusError err;
465
466         DBG("");
467
468         dbus_error_init(&err);
469         connection = g_dbus_setup_bus(DBUS_BUS_SESSION, OPENOBEX_SERVICE,
470                                                                         &err);
471         if (connection == NULL) {
472                 if (dbus_error_is_set(&err) == TRUE) {
473                         fprintf(stderr, "%s\n", err.message);
474                         dbus_error_free(&err);
475                 } else
476                         fprintf(stderr, "Can't register with session bus\n");
477                 return FALSE;
478         }
479
480         return g_dbus_register_interface(connection, OPENOBEX_MANAGER_PATH,
481                                         OPENOBEX_MANAGER_INTERFACE,
482                                         manager_methods, manager_signals, NULL,
483                                         NULL, NULL);
484 }
485
486 void manager_cleanup(void)
487 {
488         DBG("");
489
490         g_dbus_unregister_interface(connection, OPENOBEX_MANAGER_PATH,
491                                                 OPENOBEX_MANAGER_INTERFACE);
492
493         /* FIXME: Release agent? */
494
495         if (agent)
496                 agent_free(agent);
497
498         dbus_connection_unref(connection);
499 }
500
501 void manager_emit_transfer_started(struct obex_session *os)
502 {
503         char *path = g_strdup_printf("/transfer%u", os->id);
504
505         g_dbus_emit_signal(connection, OPENOBEX_MANAGER_PATH,
506                         OPENOBEX_MANAGER_INTERFACE, "TransferStarted",
507                         DBUS_TYPE_OBJECT_PATH, &path,
508                         DBUS_TYPE_INVALID);
509
510         g_free(path);
511 }
512
513 static void emit_transfer_completed(struct obex_session *os, gboolean success)
514 {
515         char *path = g_strdup_printf("/transfer%u", os->id);
516
517         g_dbus_emit_signal(connection, OPENOBEX_MANAGER_PATH,
518                         OPENOBEX_MANAGER_INTERFACE, "TransferCompleted",
519                         DBUS_TYPE_OBJECT_PATH, &path,
520                         DBUS_TYPE_BOOLEAN, &success,
521                         DBUS_TYPE_INVALID);
522
523         g_free(path);
524 }
525
526 static void emit_transfer_progress(struct obex_session *os, uint32_t total,
527                                                         uint32_t transfered)
528 {
529         char *path = g_strdup_printf("/transfer%u", os->id);
530
531         g_dbus_emit_signal(connection, path,
532                         TRANSFER_INTERFACE, "Progress",
533                         DBUS_TYPE_INT32, &total,
534                         DBUS_TYPE_INT32, &transfered,
535                         DBUS_TYPE_INVALID);
536
537         g_free(path);
538 }
539
540 void manager_register_transfer(struct obex_session *os)
541 {
542         char *path = g_strdup_printf("/transfer%u", os->id);
543
544         if (!g_dbus_register_interface(connection, path,
545                                 TRANSFER_INTERFACE,
546                                 transfer_methods, transfer_signals,
547                                 NULL, os, NULL)) {
548                 error("Cannot register Transfer interface.");
549                 g_free(path);
550                 return;
551         }
552
553         g_free(path);
554 }
555
556 void manager_unregister_transfer(struct obex_session *os)
557 {
558         char *path = g_strdup_printf("/transfer%u", os->id);
559
560         /* Got an error during a transfer. */
561         if (os->object)
562                 emit_transfer_completed(os, os->offset == os->size);
563
564         g_dbus_unregister_interface(connection, path,
565                                 TRANSFER_INTERFACE);
566
567         g_free(path);
568 }
569
570 static void agent_cancel(void)
571 {
572         DBusMessage *msg;
573
574         if (agent == NULL)
575                 return;
576
577         msg = dbus_message_new_method_call(agent->bus_name, agent->path,
578                                         "org.openobex.Agent", "Cancel");
579
580         g_dbus_send_message(connection, msg);
581 }
582
583 static void agent_reply(DBusPendingCall *call, void *user_data)
584 {
585         DBusMessage *reply = dbus_pending_call_steal_reply(call);
586         const char *name;
587         DBusError derr;
588         gboolean *got_reply = user_data;
589
590         *got_reply = TRUE;
591
592         /* Received a reply after the agent exited */
593         if (!agent)
594                 return;
595
596         agent->auth_pending = FALSE;
597
598         dbus_error_init(&derr);
599         if (dbus_set_error_from_message(&derr, reply)) {
600                 error("Agent replied with an error: %s, %s",
601                                 derr.name, derr.message);
602
603                 if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY))
604                         agent_cancel();
605
606                 dbus_error_free(&derr);
607                 dbus_message_unref(reply);
608                 return;
609         }
610
611         if (dbus_message_get_args(reply, NULL,
612                                 DBUS_TYPE_STRING, &name,
613                                 DBUS_TYPE_INVALID)) {
614                 /* Splits folder and name */
615                 const char *slash = strrchr(name, '/');
616                 DBG("Agent replied with %s", name);
617                 if (!slash) {
618                         agent->new_name = g_strdup(name);
619                         agent->new_folder = NULL;
620                 } else {
621                         agent->new_name = g_strdup(slash + 1);
622                         agent->new_folder = g_strndup(name, slash - name);
623                 }
624         }
625
626         dbus_message_unref(reply);
627 }
628
629 static gboolean auth_error(GIOChannel *io, GIOCondition cond, void *user_data)
630 {
631         agent->auth_pending = FALSE;
632
633         return FALSE;
634 }
635
636 int manager_request_authorization(struct obex_session *os, int32_t time,
637                                         char **new_folder, char **new_name)
638 {
639         DBusMessage *msg;
640         DBusPendingCall *call;
641         const char *filename = os->name ? os->name : "";
642         const char *type = os->type ? os->type : "";
643         char *path, *address;
644         unsigned int watch;
645         gboolean got_reply;
646         int err;
647
648         if (!agent)
649                 return -1;
650
651         if (agent->auth_pending)
652                 return -EPERM;
653
654         if (!new_folder || !new_name)
655                 return -EINVAL;
656
657         err = obex_getpeername(os, &address);
658         if (err < 0)
659                 return err;
660
661         path = g_strdup_printf("/transfer%u", os->id);
662
663         msg = dbus_message_new_method_call(agent->bus_name, agent->path,
664                                         "org.openobex.Agent", "Authorize");
665
666         dbus_message_append_args(msg,
667                         DBUS_TYPE_OBJECT_PATH, &path,
668                         DBUS_TYPE_STRING, &address,
669                         DBUS_TYPE_STRING, &filename,
670                         DBUS_TYPE_STRING, &type,
671                         DBUS_TYPE_INT32, &os->size,
672                         DBUS_TYPE_INT32, &time,
673                         DBUS_TYPE_INVALID);
674
675         g_free(path);
676         g_free(address);
677
678         if (!dbus_connection_send_with_reply(connection,
679                                         msg, &call, TIMEOUT)) {
680                 dbus_message_unref(msg);
681                 return -EPERM;
682         }
683
684         dbus_message_unref(msg);
685
686         agent->auth_pending = TRUE;
687         got_reply = FALSE;
688
689         /* Catches errors before authorization response comes */
690         watch = g_io_add_watch_full(os->io, G_PRIORITY_DEFAULT,
691                         G_IO_HUP | G_IO_ERR | G_IO_NVAL,
692                         auth_error, NULL, NULL);
693
694         dbus_pending_call_set_notify(call, agent_reply, &got_reply, NULL);
695
696         /* Workaround: process events while agent doesn't reply */
697         while (agent && agent->auth_pending)
698                 g_main_context_iteration(NULL, TRUE);
699
700         g_source_remove(watch);
701
702         if (!got_reply) {
703                 dbus_pending_call_cancel(call);
704                 agent_cancel();
705         }
706
707         dbus_pending_call_unref(call);
708
709         if (!agent || !agent->new_name)
710                 return -EPERM;
711
712         *new_folder = agent->new_folder;
713         *new_name = agent->new_name;
714         agent->new_folder = NULL;
715         agent->new_name = NULL;
716
717         return 0;
718 }
719
720 void manager_register_session(struct obex_session *os)
721 {
722         char *path = g_strdup_printf("/session%u", GPOINTER_TO_UINT(os));
723
724         if (!g_dbus_register_interface(connection, path,
725                                 SESSION_INTERFACE,
726                                 session_methods, NULL,
727                                 NULL, os, NULL)) {
728                 error("Cannot register Session interface.");
729                 g_free(path);
730                 return;
731         }
732
733         g_dbus_emit_signal(connection, OPENOBEX_MANAGER_PATH,
734                         OPENOBEX_MANAGER_INTERFACE, "SessionCreated",
735                         DBUS_TYPE_OBJECT_PATH, &path,
736                         DBUS_TYPE_INVALID);
737
738         g_free(path);
739 }
740
741 void manager_unregister_session(struct obex_session *os)
742 {
743         char *path = g_strdup_printf("/session%u", GPOINTER_TO_UINT(os));
744
745         g_dbus_emit_signal(connection, OPENOBEX_MANAGER_PATH,
746                         OPENOBEX_MANAGER_INTERFACE, "SessionRemoved",
747                         DBUS_TYPE_OBJECT_PATH, &path,
748                         DBUS_TYPE_INVALID);
749
750         g_dbus_unregister_interface(connection, path,
751                                 SESSION_INTERFACE);
752
753         g_free(path);
754 }
755
756 void manager_emit_transfer_progress(struct obex_session *os)
757 {
758         emit_transfer_progress(os, os->size, os->offset);
759 }
760
761 void manager_emit_transfer_completed(struct obex_session *os)
762 {
763         if (os->object)
764                 emit_transfer_completed(os, !os->aborted);
765 }
766
767 DBusConnection *manager_dbus_get_connection(void)
768 {
769         if (connection == NULL)
770                 return NULL;
771
772         return dbus_connection_ref(connection);
773 }