Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / obexd / 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 <sys/socket.h>
33 #include <inttypes.h>
34
35 #include "gdbus/gdbus.h"
36 #include "gobex/gobex.h"
37
38 #include "btio/btio.h"
39 #include "obexd.h"
40 #include "obex.h"
41 #include "obex-priv.h"
42 #include "server.h"
43 #include "manager.h"
44 #include "log.h"
45 #include "service.h"
46
47 #define OBEX_BASE_PATH "/org/bluez/obex"
48 #define SESSION_BASE_PATH OBEX_BASE_PATH "/server"
49 #define OBEX_MANAGER_INTERFACE OBEXD_SERVICE ".AgentManager1"
50 #define ERROR_INTERFACE OBEXD_SERVICE ".Error"
51 #define TRANSFER_INTERFACE OBEXD_SERVICE ".Transfer1"
52 #define SESSION_INTERFACE OBEXD_SERVICE ".Session1"
53 #define AGENT_INTERFACE OBEXD_SERVICE ".Agent1"
54
55 #define TIMEOUT 60*1000 /* Timeout for user response (miliseconds) */
56
57 struct agent {
58         char *bus_name;
59         char *path;
60         gboolean auth_pending;
61         char *new_name;
62         char *new_folder;
63         unsigned int watch_id;
64 };
65
66 enum {
67         TRANSFER_STATUS_QUEUED = 0,
68         TRANSFER_STATUS_ACTIVE,
69         TRANSFER_STATUS_COMPLETE,
70         TRANSFER_STATUS_ERROR
71 };
72
73 struct obex_transfer {
74         uint8_t status;
75         char *path;
76         struct obex_session *session;
77 };
78
79 static struct agent *agent = NULL;
80
81 static DBusConnection *connection = NULL;
82
83 static void agent_free(struct agent *agent)
84 {
85         if (!agent)
86                 return;
87
88         g_free(agent->new_folder);
89         g_free(agent->new_name);
90         g_free(agent->bus_name);
91         g_free(agent->path);
92         g_free(agent);
93 }
94
95 static inline DBusMessage *invalid_args(DBusMessage *msg)
96 {
97         return g_dbus_create_error(msg,
98                         ERROR_INTERFACE ".InvalidArguments",
99                         "Invalid arguments in method call");
100 }
101
102 static inline DBusMessage *not_supported(DBusMessage *msg)
103 {
104         return g_dbus_create_error(msg,
105                         ERROR_INTERFACE ".NotSupported",
106                         "Operation is not supported");
107 }
108
109 static inline DBusMessage *agent_already_exists(DBusMessage *msg)
110 {
111         return g_dbus_create_error(msg,
112                         ERROR_INTERFACE ".AlreadyExists",
113                         "Agent already exists");
114 }
115
116 static inline DBusMessage *agent_does_not_exist(DBusMessage *msg)
117 {
118         return g_dbus_create_error(msg,
119                         ERROR_INTERFACE ".DoesNotExist",
120                         "Agent does not exist");
121 }
122
123 static inline DBusMessage *not_authorized(DBusMessage *msg)
124 {
125         return g_dbus_create_error(msg,
126                         ERROR_INTERFACE ".NotAuthorized",
127                         "Not authorized");
128 }
129
130 static void agent_disconnected(DBusConnection *conn, void *user_data)
131 {
132         DBG("Agent exited");
133         agent_free(agent);
134         agent = NULL;
135 }
136
137 static DBusMessage *register_agent(DBusConnection *conn,
138                                         DBusMessage *msg, void *data)
139 {
140         const char *path, *sender;
141
142         if (agent)
143                 return agent_already_exists(msg);
144
145         if (!dbus_message_get_args(msg, NULL,
146                                 DBUS_TYPE_OBJECT_PATH, &path,
147                                 DBUS_TYPE_INVALID))
148                 return invalid_args(msg);
149
150         sender = dbus_message_get_sender(msg);
151         agent = g_new0(struct agent, 1);
152         agent->bus_name = g_strdup(sender);
153         agent->path = g_strdup(path);
154
155         agent->watch_id = g_dbus_add_disconnect_watch(conn, sender,
156                                         agent_disconnected, NULL, NULL);
157
158         DBG("Agent registered");
159
160         return dbus_message_new_method_return(msg);
161 }
162
163 static DBusMessage *unregister_agent(DBusConnection *conn,
164                                         DBusMessage *msg, void *data)
165 {
166         const char *path, *sender;
167
168         if (!agent)
169                 return agent_does_not_exist(msg);
170
171         if (!dbus_message_get_args(msg, NULL,
172                                 DBUS_TYPE_OBJECT_PATH, &path,
173                                 DBUS_TYPE_INVALID))
174                 return invalid_args(msg);
175
176         if (strcmp(agent->path, path) != 0)
177                 return agent_does_not_exist(msg);
178
179         sender = dbus_message_get_sender(msg);
180         if (strcmp(agent->bus_name, sender) != 0)
181                 return not_authorized(msg);
182
183         g_dbus_remove_watch(conn, agent->watch_id);
184
185         agent_free(agent);
186         agent = NULL;
187
188         DBG("Agent unregistered");
189
190         return dbus_message_new_method_return(msg);
191 }
192
193 #ifdef __TIZEN_PATCH__
194 static DBusMessage *set_root(DBusConnection *conn, DBusMessage *msg,
195                                         const char *root, void *data)
196 {
197         DBG("new_root: %s", root);
198
199         /* Change the option root path (using in filesystem) */
200         obex_option_set_root_folder(root);
201
202         return dbus_message_new_method_return(msg);
203 }
204
205 static DBusMessage *set_property(DBusConnection *conn,
206                                         DBusMessage *msg, void *data)
207 {
208         DBusMessageIter iter;
209         DBusMessageIter sub;
210         const char *property;
211
212         if (!dbus_message_iter_init(msg, &iter))
213                 return invalid_args(msg);
214
215         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
216                 return invalid_args(msg);
217
218         dbus_message_iter_get_basic(&iter, &property);
219         dbus_message_iter_next(&iter);
220
221         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
222                 return invalid_args(msg);
223         dbus_message_iter_recurse(&iter, &sub);
224
225         if (g_str_equal("Root", property)) {
226                 const char *root;
227
228                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)
229                         return invalid_args(msg);
230                 dbus_message_iter_get_basic(&sub, &root);
231
232                 return set_root(conn, msg, root, data);
233         }
234
235         return invalid_args(msg);
236 }
237 #endif
238
239 static gboolean get_source(const GDBusPropertyTable *property,
240                                         DBusMessageIter *iter, void *data)
241 {
242         struct obex_session *os = data;
243         char *s;
244
245         s = os->src;
246         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &s);
247
248         return TRUE;
249 }
250
251 static gboolean get_destination(const GDBusPropertyTable *property,
252                                         DBusMessageIter *iter, void *data)
253 {
254         struct obex_session *os = data;
255         char *s;
256
257         s = os->dst;
258         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &s);
259
260         return TRUE;
261 }
262
263 static gboolean session_target_exists(const GDBusPropertyTable *property,
264                                                                 void *data)
265 {
266         struct obex_session *os = data;
267
268         return os->service->target ? TRUE : FALSE;
269 }
270
271 static char *target2str(const uint8_t *t)
272 {
273         if (!t)
274                 return NULL;
275
276         return g_strdup_printf("%02X%02X%02X%02X-%02X%02X-%02X%02X-"
277                                 "%02X%02X-%02X%02X%02X%02X%02X%02X",
278                                 t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7],
279                                 t[8], t[9], t[10], t[11], t[12], t[13], t[14],
280                                 t[15]);
281 }
282
283 static gboolean get_target(const GDBusPropertyTable *property,
284                                         DBusMessageIter *iter, void *data)
285 {
286         struct obex_session *os = data;
287         char *uuid;
288
289         uuid = target2str(os->service->target);
290         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
291         g_free(uuid);
292
293         return TRUE;
294 }
295
296 static gboolean get_root(const GDBusPropertyTable *property,
297                                         DBusMessageIter *iter, void *data)
298 {
299         const char *root;
300
301         root = obex_option_root_folder();
302         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &root);
303
304         return TRUE;
305 }
306
307 static DBusMessage *transfer_cancel(DBusConnection *connection,
308                                 DBusMessage *msg, void *user_data)
309 {
310         struct obex_transfer *transfer = user_data;
311         struct obex_session *os = transfer->session;
312         const char *sender;
313
314         if (!os)
315                 return invalid_args(msg);
316
317         sender = dbus_message_get_sender(msg);
318         if (strcmp(agent->bus_name, sender) != 0)
319                 return not_authorized(msg);
320
321         os->aborted = TRUE;
322
323         return dbus_message_new_method_return(msg);
324 }
325
326 static const char *status2str(uint8_t status)
327 {
328         switch (status) {
329         case TRANSFER_STATUS_QUEUED:
330                 return "queued";
331         case TRANSFER_STATUS_ACTIVE:
332                 return "active";
333         case TRANSFER_STATUS_COMPLETE:
334                 return "complete";
335         case TRANSFER_STATUS_ERROR:
336         default:
337                 return "error";
338         }
339 }
340
341 static gboolean transfer_get_status(const GDBusPropertyTable *property,
342                                         DBusMessageIter *iter, void *data)
343 {
344         struct obex_transfer *transfer = data;
345         const char *status = status2str(transfer->status);
346
347         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &status);
348
349         return TRUE;
350 }
351
352 static gboolean transfer_get_session(const GDBusPropertyTable *property,
353                                         DBusMessageIter *iter, void *data)
354 {
355         struct obex_transfer *transfer = data;
356         struct obex_session *session = transfer->session;
357         char *path;
358
359         if (session == NULL)
360                 return FALSE;
361
362         path = g_strdup_printf("%s/session%u", SESSION_BASE_PATH, session->id);
363
364         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
365
366         g_free(path);
367
368         return TRUE;
369 }
370
371 static gboolean transfer_name_exists(const GDBusPropertyTable *property,
372                                                                 void *data)
373 {
374         struct obex_transfer *transfer = data;
375         struct obex_session *session = transfer->session;
376
377         return session->name != NULL;
378 }
379
380 static gboolean transfer_get_name(const GDBusPropertyTable *property,
381                                         DBusMessageIter *iter, void *data)
382 {
383         struct obex_transfer *transfer = data;
384         struct obex_session *session = transfer->session;
385
386         if (session->name == NULL)
387                 return FALSE;
388
389         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &session->name);
390
391         return TRUE;
392 }
393
394 static gboolean transfer_type_exists(const GDBusPropertyTable *property,
395                                                                 void *data)
396 {
397         struct obex_transfer *transfer = data;
398         struct obex_session *session = transfer->session;
399
400         return session->type != NULL;
401 }
402
403 static gboolean transfer_get_type(const GDBusPropertyTable *property,
404                                         DBusMessageIter *iter, void *data)
405 {
406         struct obex_transfer *transfer = data;
407         struct obex_session *session = transfer->session;
408
409         if (session->type == NULL)
410                 return FALSE;
411
412         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &session->type);
413
414         return TRUE;
415 }
416
417 static gboolean transfer_size_exists(const GDBusPropertyTable *property,
418                                                                 void *data)
419 {
420         struct obex_transfer *transfer = data;
421         struct obex_session *session = transfer->session;
422
423         return session->size != OBJECT_SIZE_UNKNOWN;
424 }
425
426 static gboolean transfer_get_size(const GDBusPropertyTable *property,
427                                         DBusMessageIter *iter, void *data)
428 {
429         struct obex_transfer *transfer = data;
430         struct obex_session *session = transfer->session;
431
432         if (session->size == OBJECT_SIZE_UNKNOWN)
433                 return FALSE;
434
435         dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &session->size);
436
437         return TRUE;
438 }
439
440 static gboolean transfer_time_exists(const GDBusPropertyTable *property,
441                                                                 void *data)
442 {
443         struct obex_transfer *transfer = data;
444         struct obex_session *session = transfer->session;
445
446         return session->time != 0;
447 }
448
449 static gboolean transfer_get_time(const GDBusPropertyTable *property,
450                                         DBusMessageIter *iter, void *data)
451 {
452         struct obex_transfer *transfer = data;
453         struct obex_session *session = transfer->session;
454         dbus_uint64_t time_u64;
455
456         if (session->size == 0)
457                 return FALSE;
458
459         time_u64 = session->time;
460
461         dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &time_u64);
462
463         return TRUE;
464 }
465
466 static gboolean transfer_filename_exists(const GDBusPropertyTable *property,
467                                                                 void *data)
468 {
469         struct obex_transfer *transfer = data;
470         struct obex_session *session = transfer->session;
471
472         return session->path != NULL;
473 }
474
475 static gboolean transfer_get_filename(const GDBusPropertyTable *property,
476                                         DBusMessageIter *iter, void *data)
477 {
478         struct obex_transfer *transfer = data;
479         struct obex_session *session = transfer->session;
480
481         if (session->path == NULL)
482                 return FALSE;
483
484         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &session->path);
485
486         return TRUE;
487 }
488
489 #ifdef __TIZEN_PATCH__
490 static gboolean transfer_operation_exists(const GDBusPropertyTable *property,
491                                                                 void *data)
492 {
493         struct obex_transfer *transfer = data;
494         struct obex_session *session = transfer->session;
495
496         if (session->cmd == G_OBEX_OP_PUT &&
497                                 session->size != OBJECT_SIZE_DELETE)
498                 return TRUE;
499         else if (session->cmd == G_OBEX_OP_GET)
500                 return TRUE;
501         else
502                 return FALSE;
503 }
504
505 static gboolean transfer_get_operation(const GDBusPropertyTable *property,
506                                         DBusMessageIter *iter, void *data)
507 {
508         struct obex_transfer *transfer = data;
509         struct obex_session *session = transfer->session;
510         const char *operation;
511
512         if (session->cmd == G_OBEX_OP_PUT &&
513                                 session->size != OBJECT_SIZE_DELETE)
514                 operation = "PUT";
515         else if (session->cmd == G_OBEX_OP_GET)
516                 operation = "GET";
517         else
518                 return FALSE;
519
520         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &operation);
521
522         return TRUE;
523 }
524
525 static gboolean transfer_address_exists(const GDBusPropertyTable *property,
526                 void *data)
527 {
528         struct obex_transfer *transfer = data;
529         struct obex_session *session = transfer->session;
530         char *address;
531         int err;
532
533         err = obex_getpeername(session, &address);
534         if (err < 0)
535                 return FALSE;
536
537         g_free(address);
538
539         return TRUE;
540 }
541
542 static gboolean transfer_get_address(const GDBusPropertyTable *property,
543                                         DBusMessageIter *iter, void *data)
544 {
545         struct obex_transfer *transfer = data;
546         struct obex_session *session = transfer->session;
547         char *address;
548         int err;
549
550         err = obex_getpeername(session, &address);
551         if (err < 0)
552                 return FALSE;
553
554         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &address);
555         g_free(address);
556
557         return TRUE;
558 }
559
560 #endif
561
562 static gboolean transfer_get_transferred(const GDBusPropertyTable *property,
563                                         DBusMessageIter *iter, void *data)
564 {
565         struct obex_transfer *transfer = data;
566         struct obex_session *session = transfer->session;
567
568         dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64,
569                                                         &session->offset);
570
571         return TRUE;
572 }
573
574 static const GDBusMethodTable manager_methods[] = {
575         { GDBUS_METHOD("RegisterAgent",
576                         GDBUS_ARGS({ "agent", "o" }), NULL, register_agent) },
577         { GDBUS_METHOD("UnregisterAgent",
578                         GDBUS_ARGS({ "agent", "o" }), NULL, unregister_agent) },
579 #ifdef __TIZEN_PATCH__
580         { GDBUS_METHOD("SetProperty",
581                         GDBUS_ARGS({ "property", "sv" }), NULL, set_property) },
582 #endif
583         { }
584 };
585
586 static const GDBusMethodTable transfer_methods[] = {
587         { GDBUS_METHOD("Cancel", NULL, NULL, transfer_cancel) },
588         { }
589 };
590
591 static const GDBusPropertyTable transfer_properties[] = {
592         { "Status", "s", transfer_get_status },
593         { "Session", "o", transfer_get_session },
594         { "Name", "s", transfer_get_name, NULL, transfer_name_exists },
595         { "Type", "s", transfer_get_type, NULL, transfer_type_exists },
596         { "Size", "t", transfer_get_size, NULL, transfer_size_exists },
597         { "Time", "t", transfer_get_time, NULL, transfer_time_exists },
598         { "Filename", "s", transfer_get_filename, NULL,
599                                                 transfer_filename_exists },
600 #ifdef __TIZEN_PATCH__
601         { "Operation", "s", transfer_get_operation, NULL,
602                                         transfer_operation_exists },
603         { "Address", "s", transfer_get_address, NULL,
604                                         transfer_address_exists },
605 #endif
606         { "Transferred", "t", transfer_get_transferred },
607         { }
608 };
609
610 static const GDBusPropertyTable session_properties[] = {
611         { "Source", "s", get_source },
612         { "Destination", "s", get_destination },
613         { "Target", "s", get_target, NULL, session_target_exists },
614         { "Root", "s", get_root },
615         { }
616 };
617
618 gboolean manager_init(void)
619 {
620         DBusError err;
621
622         DBG("");
623
624         dbus_error_init(&err);
625
626         connection = g_dbus_setup_bus(DBUS_BUS_SESSION, OBEXD_SERVICE, &err);
627         if (connection == NULL) {
628                 if (dbus_error_is_set(&err) == TRUE) {
629                         fprintf(stderr, "%s\n", err.message);
630                         dbus_error_free(&err);
631                 } else
632                         fprintf(stderr, "Can't register with session bus\n");
633                 return FALSE;
634         }
635
636         g_dbus_attach_object_manager(connection);
637
638         return g_dbus_register_interface(connection, OBEX_BASE_PATH,
639                                         OBEX_MANAGER_INTERFACE,
640                                         manager_methods, NULL, NULL,
641                                         NULL, NULL);
642 }
643
644 void manager_cleanup(void)
645 {
646         DBG("");
647
648         g_dbus_unregister_interface(connection, OBEX_BASE_PATH,
649                                                 OBEX_MANAGER_INTERFACE);
650
651         /* FIXME: Release agent? */
652
653         agent_free(agent);
654
655         g_dbus_detach_object_manager(connection);
656
657         dbus_connection_unref(connection);
658 }
659
660 void manager_emit_transfer_started(struct obex_transfer *transfer)
661 {
662         transfer->status = TRANSFER_STATUS_ACTIVE;
663
664         g_dbus_emit_property_changed(connection, transfer->path,
665                                         TRANSFER_INTERFACE, "Status");
666 }
667
668 static void emit_transfer_completed(struct obex_transfer *transfer,
669                                                         gboolean success)
670 {
671         if (transfer->path == NULL)
672                 return;
673
674         transfer->status = success ? TRANSFER_STATUS_COMPLETE :
675                                                 TRANSFER_STATUS_ERROR;
676
677         g_dbus_emit_property_changed(connection, transfer->path,
678                                         TRANSFER_INTERFACE, "Status");
679 }
680
681 static void emit_transfer_progress(struct obex_transfer *transfer,
682                                         uint32_t total, uint32_t transferred)
683 {
684         if (transfer->path == NULL)
685                 return;
686
687         g_dbus_emit_property_changed(connection, transfer->path,
688                                         TRANSFER_INTERFACE, "Transferred");
689 }
690
691 static void transfer_free(struct obex_transfer *transfer)
692 {
693         g_free(transfer->path);
694         g_free(transfer);
695 }
696
697 struct obex_transfer *manager_register_transfer(struct obex_session *os)
698 {
699         struct obex_transfer *transfer;
700         static unsigned int id = 0;
701
702         transfer = g_new0(struct obex_transfer, 1);
703         transfer->path = g_strdup_printf("%s/session%u/transfer%u",
704                                         SESSION_BASE_PATH, os->id, id++);
705         transfer->session = os;
706
707         if (!g_dbus_register_interface(connection, transfer->path,
708                                 TRANSFER_INTERFACE,
709                                 transfer_methods, NULL,
710                                 transfer_properties, transfer, NULL)) {
711                 error("Cannot register Transfer interface.");
712                 transfer_free(transfer);
713                 return NULL;
714         }
715
716         return transfer;
717 }
718
719 void manager_unregister_transfer(struct obex_transfer *transfer)
720 {
721         struct obex_session *os;
722
723         if (transfer == NULL)
724                 return;
725
726         os = transfer->session;
727
728         if (transfer->status == TRANSFER_STATUS_ACTIVE)
729                 emit_transfer_completed(transfer, os->offset == os->size);
730
731         g_dbus_unregister_interface(connection, transfer->path,
732                                                         TRANSFER_INTERFACE);
733
734         transfer_free(transfer);
735 }
736
737 static void agent_cancel(void)
738 {
739         DBusMessage *msg;
740
741         if (agent == NULL)
742                 return;
743
744         msg = dbus_message_new_method_call(agent->bus_name, agent->path,
745                                                 AGENT_INTERFACE, "Cancel");
746
747         g_dbus_send_message(connection, msg);
748 }
749
750 static void agent_reply(DBusPendingCall *call, void *user_data)
751 {
752         DBusMessage *reply = dbus_pending_call_steal_reply(call);
753         const char *name;
754         DBusError derr;
755         gboolean *got_reply = user_data;
756
757         *got_reply = TRUE;
758
759         /* Received a reply after the agent exited */
760         if (!agent)
761                 return;
762
763         agent->auth_pending = FALSE;
764
765         dbus_error_init(&derr);
766         if (dbus_set_error_from_message(&derr, reply)) {
767                 error("Agent replied with an error: %s, %s",
768                                 derr.name, derr.message);
769
770                 if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY))
771                         agent_cancel();
772
773                 dbus_error_free(&derr);
774                 dbus_message_unref(reply);
775                 return;
776         }
777
778         if (dbus_message_get_args(reply, NULL,
779                                 DBUS_TYPE_STRING, &name,
780                                 DBUS_TYPE_INVALID)) {
781                 /* Splits folder and name */
782                 const char *slash = strrchr(name, '/');
783                 DBG("Agent replied with %s", name);
784                 if (!slash) {
785                         agent->new_name = g_strdup(name);
786                         agent->new_folder = NULL;
787                 } else {
788                         agent->new_name = g_strdup(slash + 1);
789                         agent->new_folder = g_strndup(name, slash - name);
790                 }
791         }
792
793         dbus_message_unref(reply);
794 }
795
796 static gboolean auth_error(GIOChannel *io, GIOCondition cond, void *user_data)
797 {
798         agent->auth_pending = FALSE;
799
800         return FALSE;
801 }
802
803 int manager_request_authorization(struct obex_transfer *transfer,
804                                         char **new_folder, char **new_name)
805 {
806         struct obex_session *os = transfer->session;
807         DBusMessage *msg;
808         DBusPendingCall *call;
809         unsigned int watch;
810         gboolean got_reply;
811
812         if (!agent)
813                 return -1;
814
815         if (agent->auth_pending)
816                 return -EPERM;
817
818         if (!new_folder || !new_name)
819                 return -EINVAL;
820
821         msg = dbus_message_new_method_call(agent->bus_name, agent->path,
822                                                         AGENT_INTERFACE,
823                                                         "AuthorizePush");
824
825         dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &transfer->path,
826                                                         DBUS_TYPE_INVALID);
827
828         if (!g_dbus_send_message_with_reply(connection, msg, &call, TIMEOUT)) {
829                 dbus_message_unref(msg);
830                 return -EPERM;
831         }
832
833         dbus_message_unref(msg);
834
835         agent->auth_pending = TRUE;
836         got_reply = FALSE;
837
838         /* Catches errors before authorization response comes */
839         watch = g_io_add_watch_full(os->io, G_PRIORITY_DEFAULT,
840                         G_IO_HUP | G_IO_ERR | G_IO_NVAL,
841                         auth_error, NULL, NULL);
842
843         dbus_pending_call_set_notify(call, agent_reply, &got_reply, NULL);
844
845         /* Workaround: process events while agent doesn't reply */
846         while (agent && agent->auth_pending)
847                 g_main_context_iteration(NULL, TRUE);
848
849         g_source_remove(watch);
850
851         if (!got_reply) {
852                 dbus_pending_call_cancel(call);
853                 agent_cancel();
854         }
855
856         dbus_pending_call_unref(call);
857
858         if (!agent || !agent->new_name)
859                 return -EPERM;
860
861         *new_folder = agent->new_folder;
862         *new_name = agent->new_name;
863         agent->new_folder = NULL;
864         agent->new_name = NULL;
865
866         return 0;
867 }
868
869 static DBusMessage *session_get_capabilities(DBusConnection *connection,
870                                         DBusMessage *message, void *user_data)
871 {
872         return not_supported(message);
873 }
874
875 static const GDBusMethodTable session_methods[] = {
876         { GDBUS_ASYNC_METHOD("GetCapabilities",
877                                 NULL, GDBUS_ARGS({ "capabilities", "s" }),
878                                 session_get_capabilities) },
879         { }
880 };
881
882 void manager_register_session(struct obex_session *os)
883 {
884         char *path;
885
886         path = g_strdup_printf("%s/session%u", SESSION_BASE_PATH, os->id);
887
888         if (!g_dbus_register_interface(connection, path,
889                                 SESSION_INTERFACE,
890                                 session_methods, NULL,
891                                 session_properties, os, NULL))
892                 error("Cannot register Session interface.");
893
894         g_free(path);
895 }
896
897 void manager_unregister_session(struct obex_session *os)
898 {
899         char *path;
900
901         path = g_strdup_printf("%s/session%u", SESSION_BASE_PATH, os->id);
902
903         g_dbus_unregister_interface(connection, path, SESSION_INTERFACE);
904
905         g_free(path);
906 }
907
908 void manager_emit_transfer_progress(struct obex_transfer *transfer)
909 {
910         emit_transfer_progress(transfer, transfer->session->size,
911                                                 transfer->session->offset);
912 }
913
914 void manager_emit_transfer_completed(struct obex_transfer *transfer)
915 {
916         struct obex_session *session;
917
918         if (transfer == NULL)
919                 return;
920
921         session = transfer->session;
922
923         if (session == NULL || session->object == NULL)
924                 return;
925
926         emit_transfer_completed(transfer, !session->aborted);
927 }
928
929 DBusConnection *manager_dbus_get_connection(void)
930 {
931         if (connection == NULL)
932                 return NULL;
933
934         return dbus_connection_ref(connection);
935 }