5 * Copyright (C) 2007-2010 Marcel Holtmann <marcel@holtmann.org>
6 * Copyright (C) 2011-2012 BMW Car IT GmbH. All rights reserved.
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
39 #include "gdbus/gdbus.h"
40 #include "gobex/gobex.h"
42 #include "obexd/src/log.h"
46 #ifdef __TIZEN_PATCH__
50 #include "transport.h"
52 #define SESSION_INTERFACE "org.bluez.obex.Session1"
53 #define ERROR_INTERFACE "org.bluez.obex.Error"
54 #define SESSION_BASEPATH "/org/bluez/obex/client"
56 #define OBEX_IO_ERROR obex_io_error_quark()
57 #define OBEX_IO_ERROR_FIRST (0xff + 1)
60 OBEX_IO_DISCONNECTED = OBEX_IO_ERROR_FIRST,
64 static guint64 counter = 0;
66 struct callback_data {
67 struct obc_session *session;
69 session_callback_t func;
73 struct pending_request;
74 typedef int (*session_process_t) (struct pending_request *p, GError **err);
75 typedef void (*destroy_t) (void *data);
77 struct pending_request {
80 struct obc_session *session;
81 session_process_t process;
82 struct obc_transfer *transfer;
83 session_callback_t func;
91 session_callback_t func;
98 session_callback_t func;
108 struct obc_transport *transport;
109 struct obc_driver *driver;
110 char *path; /* Session path */
111 DBusConnection *conn;
113 struct pending_request *p;
114 char *owner; /* Session owner */
119 struct callback_data *callback;
122 static GSList *sessions = NULL;
124 static void session_process_queue(struct obc_session *session);
125 static void session_terminate_transfer(struct obc_session *session,
126 struct obc_transfer *transfer,
128 static void transfer_complete(struct obc_transfer *transfer,
129 GError *err, void *user_data);
131 static GQuark obex_io_error_quark(void)
133 return g_quark_from_static_string("obex-io-error-quark");
136 struct obc_session *obc_session_ref(struct obc_session *session)
138 int refs = __sync_add_and_fetch(&session->refcount, 1);
140 DBG("%p: ref=%d", session, refs);
145 static void session_unregistered(struct obc_session *session)
149 if (session->driver && session->driver->remove)
150 session->driver->remove(session);
152 path = session->path;
153 session->path = NULL;
155 g_dbus_unregister_interface(session->conn, path, SESSION_INTERFACE);
157 DBG("Session(%p) unregistered %s", session, path);
162 static struct pending_request *pending_request_new(struct obc_session *session,
163 session_process_t process,
164 struct obc_transfer *transfer,
165 session_callback_t func,
169 struct pending_request *p;
172 p = g_new0(struct pending_request, 1);
174 p->session = obc_session_ref(session);
175 p->process = process;
176 p->destroy = destroy;
177 p->transfer = transfer;
184 static void pending_request_free(struct pending_request *p)
187 g_obex_cancel_req(p->session->obex, p->req_id, TRUE);
193 obc_transfer_unregister(p->transfer);
196 obc_session_unref(p->session);
201 static void setpath_data_free(void *process_data)
203 struct setpath_data *data = process_data;
205 g_strfreev(data->remaining);
209 static void file_data_free(void *process_data)
211 struct file_data *data = process_data;
213 g_free(data->srcname);
214 g_free(data->destname);
218 static void session_free(struct obc_session *session)
222 if (session->process_id != 0)
223 g_source_remove(session->process_id);
225 if (session->queue) {
226 g_queue_foreach(session->queue, (GFunc) pending_request_free,
228 g_queue_free(session->queue);
232 g_dbus_remove_watch(session->conn, session->watch);
235 g_obex_set_disconnect_function(session->obex, NULL, NULL);
236 g_obex_unref(session->obex);
239 if (session->id > 0 && session->transport != NULL)
240 session->transport->disconnect(session->id);
243 session_unregistered(session);
246 dbus_connection_unref(session->conn);
249 pending_request_free(session->p);
251 g_free(session->path);
252 g_free(session->owner);
253 g_free(session->source);
254 g_free(session->destination);
255 g_free(session->folder);
259 static void disconnect_complete(GObex *obex, GError *err, GObexPacket *rsp,
262 struct obc_session *session = user_data;
267 error("%s", err->message);
269 /* Disconnect transport */
270 if (session->id > 0 && session->transport != NULL) {
271 session->transport->disconnect(session->id);
275 session_free(session);
278 void obc_session_unref(struct obc_session *session)
282 refs = __sync_sub_and_fetch(&session->refcount, 1);
284 DBG("%p: ref=%d", session, refs);
289 sessions = g_slist_remove(sessions, session);
294 /* Wait OBEX Disconnect to complete if command succeed otherwise
295 * proceed with transport disconnection since there is nothing else to
297 if (g_obex_disconnect(session->obex, disconnect_complete, session,
302 /* Disconnect transport */
303 if (session->id > 0 && session->transport != NULL) {
304 session->transport->disconnect(session->id);
308 session_free(session);
311 static void callback_destroy(struct callback_data *callback, GError *err)
313 struct obc_session *session = callback->session;
315 if (callback->id > 0)
316 g_obex_cancel_req(session->obex, callback->id, TRUE);
318 callback->func(session, NULL, err, callback->data);
320 session->callback = NULL;
321 obc_session_unref(session);
324 static void connect_cb(GObex *obex, GError *err, GObexPacket *rsp,
327 struct callback_data *callback = user_data;
334 error("connect_cb: %s", err->message);
335 gerr = g_error_copy(err);
339 rsp_code = g_obex_packet_get_operation(rsp, NULL);
340 if (rsp_code != G_OBEX_RSP_SUCCESS)
341 gerr = g_error_new(OBEX_IO_ERROR, -EIO,
342 "OBEX Connect failed with 0x%02x", rsp_code);
345 callback_destroy(callback, gerr);
350 static void session_disconnected(GObex *obex, GError *err, gpointer user_data)
352 struct obc_session *session = user_data;
355 error("%s", err->message);
356 #ifdef __TIZEN_PATCH__
357 release_session(session);
359 obc_session_shutdown(session);
363 static void transport_func(GIOChannel *io, GError *err, gpointer user_data)
365 struct callback_data *callback = user_data;
366 struct obc_session *session = callback->session;
367 struct obc_driver *driver = session->driver;
368 struct obc_transport *transport = session->transport;
370 GObexApparam *apparam;
371 GObexTransportType type;
378 error("%s", err->message);
382 g_io_channel_set_close_on_unref(io, FALSE);
384 if (transport->getpacketopt &&
385 transport->getpacketopt(io, &tx_mtu, &rx_mtu) == 0)
386 type = G_OBEX_TRANSPORT_PACKET;
388 type = G_OBEX_TRANSPORT_STREAM;
390 obex = g_obex_new(io, type, tx_mtu, rx_mtu);
394 g_io_channel_set_close_on_unref(io, TRUE);
398 if (driver->supported_features)
399 apparam = driver->supported_features(session);
405 len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
407 callback->id = g_obex_connect(obex, connect_cb,
410 driver->target, driver->target_len,
415 callback->id = g_obex_connect(obex, connect_cb,
417 G_OBEX_HDR_APPARAM, buf, len,
419 g_obex_apparam_free(apparam);
420 } else if (driver->target)
421 callback->id = g_obex_connect(obex, connect_cb, callback, &err,
422 G_OBEX_HDR_TARGET, driver->target, driver->target_len,
425 callback->id = g_obex_connect(obex, connect_cb, callback,
426 &err, G_OBEX_HDR_INVALID);
429 error("%s", err->message);
434 session->obex = obex;
435 sessions = g_slist_prepend(sessions, session);
437 g_obex_set_disconnect_function(obex, session_disconnected, session);
441 callback_destroy(callback, err);
444 static void owner_disconnected(DBusConnection *connection, void *user_data)
446 struct obc_session *session = user_data;
452 * If connection still connecting notify the callback to destroy the
455 if (session->callback) {
456 err = g_error_new(OBEX_IO_ERROR, OBEX_IO_DISCONNECTED,
457 "Session closed by user");
458 callback_destroy(session->callback, err);
463 obc_session_shutdown(session);
466 int obc_session_set_owner(struct obc_session *session, const char *name,
467 GDBusWatchFunction func)
473 g_dbus_remove_watch(session->conn, session->watch);
475 session->watch = g_dbus_add_disconnect_watch(session->conn, name, func,
477 if (session->watch == 0)
480 session->owner = g_strdup(name);
486 static struct obc_session *session_find(const char *source,
487 const char *destination,
494 for (l = sessions; l; l = l->next) {
495 struct obc_session *session = l->data;
497 if (g_strcmp0(session->destination, destination))
500 if (g_strcmp0(service, session->driver->service))
503 if (source && g_strcmp0(session->source, source))
506 if (channel && session->channel != channel)
509 if (g_strcmp0(owner, session->owner))
518 static gboolean connection_complete(gpointer data)
520 struct callback_data *cb = data;
522 cb->func(cb->session, NULL, NULL, cb->data);
524 obc_session_unref(cb->session);
531 static int session_connect(struct obc_session *session,
532 session_callback_t function, void *user_data)
534 struct callback_data *callback;
535 struct obc_transport *transport = session->transport;
536 struct obc_driver *driver = session->driver;
538 callback = g_try_malloc0(sizeof(*callback));
539 if (callback == NULL)
542 callback->func = function;
543 callback->data = user_data;
544 callback->session = obc_session_ref(session);
546 /* Connection completed */
548 g_idle_add(connection_complete, callback);
552 /* Ongoing connection */
553 if (session->id > 0) {
554 obc_session_unref(callback->session);
559 session->id = transport->connect(session->source, session->destination,
560 driver->uuid, session->channel,
561 transport_func, callback);
562 if (session->id == 0) {
563 obc_session_unref(callback->session);
568 session->callback = callback;
573 struct obc_session *obc_session_create(const char *source,
574 const char *destination,
578 session_callback_t function,
581 DBusConnection *conn;
582 struct obc_session *session;
583 struct obc_transport *transport;
584 struct obc_driver *driver;
586 if (destination == NULL)
589 session = session_find(source, destination, service, channel, owner);
593 /* FIXME: Do proper transport lookup when the API supports it */
594 transport = obc_transport_find("Bluetooth");
595 if (transport == NULL)
598 driver = obc_driver_find(service);
602 conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
606 session = g_try_malloc0(sizeof(*session));
610 session->refcount = 1;
611 session->transport = transport;
612 session->driver = driver;
613 session->conn = conn;
614 session->source = g_strdup(source);
615 session->destination = g_strdup(destination);
616 session->channel = channel;
617 session->queue = g_queue_new();
618 session->folder = g_strdup("/");
621 obc_session_set_owner(session, owner, owner_disconnected);
624 if (session_connect(session, function, user_data) < 0) {
625 obc_session_unref(session);
629 DBG("session %p transport %s driver %s", session,
630 session->transport->name, session->driver->service);
635 void obc_session_shutdown(struct obc_session *session)
637 struct pending_request *p;
642 obc_session_ref(session);
644 /* Unregister any pending transfer */
645 err = g_error_new(OBEX_IO_ERROR, OBEX_IO_DISCONNECTED,
646 "Session closed by user");
648 if (session->p != NULL && session->p->id != 0) {
653 p->func(session, p->transfer, err, p->data);
655 pending_request_free(p);
658 while ((p = g_queue_pop_head(session->queue))) {
660 p->func(session, p->transfer, err, p->data);
662 pending_request_free(p);
667 /* Unregister interfaces */
669 session_unregistered(session);
671 obc_session_unref(session);
674 static void capabilities_complete_callback(struct obc_session *session,
675 struct obc_transfer *transfer,
676 GError *err, void *user_data)
678 DBusMessage *message = user_data;
684 DBusMessage *error = g_dbus_create_error(message,
685 ERROR_INTERFACE ".Failed",
687 g_dbus_send_message(session->conn, error);
691 perr = obc_transfer_get_contents(transfer, &contents, &size);
693 DBusMessage *error = g_dbus_create_error(message,
694 ERROR_INTERFACE ".Failed",
695 "Error reading contents: %s",
697 g_dbus_send_message(session->conn, error);
701 g_dbus_send_reply(session->conn, message,
702 DBUS_TYPE_STRING, &contents,
707 dbus_message_unref(message);
710 static DBusMessage *get_capabilities(DBusConnection *connection,
711 DBusMessage *message, void *user_data)
713 struct obc_session *session = user_data;
714 struct obc_transfer *pull;
718 pull = obc_transfer_get("x-obex/capability", NULL, NULL, &gerr);
722 if (!obc_session_queue(session, pull, capabilities_complete_callback,
726 dbus_message_ref(message);
731 reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
738 static gboolean get_source(const GDBusPropertyTable *property,
739 DBusMessageIter *iter, void *data)
741 struct obc_session *session = data;
743 if (session->source == NULL)
746 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
752 static gboolean source_exists(const GDBusPropertyTable *property, void *data)
754 struct obc_session *session = data;
756 return session->source != NULL;
759 static gboolean get_destination(const GDBusPropertyTable *property,
760 DBusMessageIter *iter, void *data)
762 struct obc_session *session = data;
764 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
765 &session->destination);
770 static gboolean get_channel(const GDBusPropertyTable *property,
771 DBusMessageIter *iter, void *data)
773 struct obc_session *session = data;
775 dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE,
781 static const GDBusMethodTable session_methods[] = {
782 { GDBUS_ASYNC_METHOD("GetCapabilities",
783 NULL, GDBUS_ARGS({ "capabilities", "s" }),
788 static gboolean get_target(const GDBusPropertyTable *property,
789 DBusMessageIter *iter, void *data)
791 struct obc_session *session = data;
793 if (session->driver->uuid == NULL)
796 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
797 &session->driver->uuid);
802 static gboolean target_exists(const GDBusPropertyTable *property, void *data)
804 struct obc_session *session = data;
806 return session->driver->uuid != NULL;
809 static const GDBusPropertyTable session_properties[] = {
810 { "Source", "s", get_source, NULL, source_exists },
811 { "Destination", "s", get_destination },
812 { "Channel", "y", get_channel },
813 { "Target", "s", get_target, NULL, target_exists },
817 static gboolean session_process(gpointer data)
819 struct obc_session *session = data;
821 session->process_id = 0;
823 session_process_queue(session);
828 static void session_queue(struct pending_request *p)
830 g_queue_push_tail(p->session->queue, p);
832 if (p->session->process_id == 0)
833 p->session->process_id = g_idle_add(session_process,
837 static int session_process_transfer(struct pending_request *p, GError **err)
839 if (!obc_transfer_start(p->transfer, p->session->obex, err))
842 DBG("Tranfer(%p) started", p->transfer);
847 guint obc_session_queue(struct obc_session *session,
848 struct obc_transfer *transfer,
849 session_callback_t func, void *user_data,
852 struct pending_request *p;
854 if (session->obex == NULL) {
855 obc_transfer_unregister(transfer);
856 g_set_error(err, OBEX_IO_ERROR, -ENOTCONN,
857 "Session not connected");
861 if (!obc_transfer_register(transfer, session->conn, session->path,
862 session->owner, err)) {
863 obc_transfer_unregister(transfer);
867 obc_transfer_set_callback(transfer, transfer_complete, session);
869 p = pending_request_new(session, session_process_transfer, transfer,
870 func, user_data, NULL);
875 static void session_process_queue(struct obc_session *session)
877 struct pending_request *p;
879 if (session->p != NULL)
882 if (session->queue == NULL || g_queue_is_empty(session->queue))
885 obc_session_ref(session);
887 while ((p = g_queue_pop_head(session->queue))) {
890 if (p->process(p, &gerr) == 0)
894 p->func(session, p->transfer, gerr, p->data);
896 g_clear_error(&gerr);
898 pending_request_free(p);
901 obc_session_unref(session);
904 static int pending_transfer_cmptransfer(gconstpointer a, gconstpointer b)
906 const struct pending_request *p = a;
907 const struct obc_transfer *transfer = b;
909 if (p->transfer == transfer)
915 static void session_terminate_transfer(struct obc_session *session,
916 struct obc_transfer *transfer,
919 struct pending_request *p = session->p;
921 if (p == NULL || p->transfer != transfer) {
924 match = g_list_find_custom(session->queue->head, transfer,
925 pending_transfer_cmptransfer);
930 g_queue_delete_link(session->queue, match);
934 obc_session_ref(session);
937 p->func(session, p->transfer, gerr, p->data);
939 pending_request_free(p);
941 if (session->p == NULL)
942 session_process_queue(session);
944 obc_session_unref(session);
947 static void session_notify_complete(struct obc_session *session,
948 struct obc_transfer *transfer)
950 DBG("Transfer(%p) complete", transfer);
952 session_terminate_transfer(session, transfer, NULL);
955 static void session_notify_error(struct obc_session *session,
956 struct obc_transfer *transfer,
959 error("Transfer(%p) Error: %s", transfer, err->message);
961 session_terminate_transfer(session, transfer, err);
964 static void transfer_complete(struct obc_transfer *transfer,
965 GError *err, void *user_data)
967 struct obc_session *session = user_data;
972 session_notify_complete(session, transfer);
977 session_notify_error(session, transfer, err);
980 const char *obc_session_register(struct obc_session *session,
981 GDBusDestroyFunction destroy)
984 return session->path;
986 session->path = g_strdup_printf("%s/session%ju",
987 SESSION_BASEPATH, counter++);
989 if (g_dbus_register_interface(session->conn, session->path,
990 SESSION_INTERFACE, session_methods,
991 NULL, session_properties, session,
995 if (session->driver->probe && session->driver->probe(session) < 0) {
996 g_dbus_unregister_interface(session->conn, session->path,
1001 DBG("Session(%p) registered %s", session, session->path);
1003 return session->path;
1006 g_free(session->path);
1007 session->path = NULL;
1011 const void *obc_session_get_attribute(struct obc_session *session,
1014 if (session == NULL || session->id == 0)
1017 return session->transport->getattribute(session->id, attribute_id);
1020 const char *obc_session_get_owner(struct obc_session *session)
1022 if (session == NULL)
1025 return session->owner;
1028 const char *obc_session_get_destination(struct obc_session *session)
1030 return session->destination;
1033 const char *obc_session_get_path(struct obc_session *session)
1035 return session->path;
1038 const char *obc_session_get_target(struct obc_session *session)
1040 return session->driver->target;
1043 const char *obc_session_get_folder(struct obc_session *session)
1045 return session->folder;
1048 static void setpath_complete(struct obc_session *session,
1049 struct obc_transfer *transfer,
1050 GError *err, void *user_data)
1052 struct pending_request *p = user_data;
1055 p->func(session, NULL, err, p->data);
1057 if (session->p == p)
1060 pending_request_free(p);
1062 session_process_queue(session);
1065 static void setpath_op_complete(struct obc_session *session,
1066 struct obc_transfer *transfer,
1067 GError *err, void *user_data)
1069 struct setpath_data *data = user_data;
1072 data->func(session, NULL, err, data->user_data);
1075 static void setpath_set_folder(struct obc_session *session, const char *cur)
1077 char *folder = NULL;
1080 delim = strrchr(session->folder, '/');
1081 if (strlen(cur) == 0 || delim == NULL ||
1082 (strcmp(cur, "..") == 0 && delim == session->folder)) {
1083 folder = g_strdup("/");
1085 if (strcmp(cur, "..") == 0) {
1086 folder = g_strndup(session->folder,
1087 delim - session->folder);
1089 if (g_str_has_suffix(session->folder, "/"))
1090 folder = g_strconcat(session->folder,
1093 folder = g_strconcat(session->folder, "/",
1097 g_free(session->folder);
1098 session->folder = folder;
1101 static void setpath_cb(GObex *obex, GError *err, GObexPacket *rsp,
1104 struct pending_request *p = user_data;
1105 struct setpath_data *data = p->data;
1113 setpath_complete(p->session, NULL, err, user_data);
1117 code = g_obex_packet_get_operation(rsp, NULL);
1118 if (code != G_OBEX_RSP_SUCCESS) {
1119 GError *gerr = NULL;
1120 g_set_error(&gerr, OBEX_IO_ERROR, code, "%s",
1121 g_obex_strerror(code));
1122 setpath_complete(p->session, NULL, gerr, user_data);
1123 g_clear_error(&gerr);
1127 current = data->remaining[data->index - 1];
1128 setpath_set_folder(p->session, current);
1130 /* Ignore empty folder names to avoid resetting the current path */
1131 while ((next = data->remaining[data->index]) && strlen(next) == 0)
1135 setpath_complete(p->session, NULL, NULL, user_data);
1141 p->req_id = g_obex_setpath(obex, next, setpath_cb, p, &err);
1143 setpath_complete(p->session, NULL, err, user_data);
1148 static int session_process_setpath(struct pending_request *p, GError **err)
1150 struct setpath_data *req = p->data;
1151 const char *first = "";
1154 if (req->remaining[0][0] != '/')
1155 first = req->remaining[req->index];
1158 p->req_id = g_obex_setpath(p->session->obex, first, setpath_cb, p, err);
1160 return (*err)->code;
1167 guint obc_session_setpath(struct obc_session *session, const char *path,
1168 session_callback_t func, void *user_data,
1171 struct setpath_data *data;
1172 struct pending_request *p;
1174 if (session->obex == NULL) {
1175 g_set_error(err, OBEX_IO_ERROR, OBEX_IO_DISCONNECTED,
1176 "Session disconnected");
1180 data = g_new0(struct setpath_data, 1);
1182 data->user_data = user_data;
1183 data->remaining = g_strsplit(strlen(path) ? path : "/", "/", 0);
1185 if (!data->remaining || !data->remaining[0]) {
1186 error("obc_session_setpath: invalid path %s", path);
1187 g_set_error(err, OBEX_IO_ERROR, -EINVAL, "Invalid argument");
1188 #ifdef __TIZEN_PATCH__
1189 setpath_data_free(data);
1194 p = pending_request_new(session, session_process_setpath, NULL,
1195 setpath_op_complete, data, setpath_data_free);
1200 static void async_cb(GObex *obex, GError *err, GObexPacket *rsp,
1203 struct pending_request *p = user_data;
1204 struct obc_session *session = p->session;
1205 GError *gerr = NULL;
1212 p->func(p->session, NULL, err, p->data);
1216 code = g_obex_packet_get_operation(rsp, NULL);
1217 if (code != G_OBEX_RSP_SUCCESS)
1218 g_set_error(&gerr, OBEX_IO_ERROR, code, "%s",
1219 g_obex_strerror(code));
1222 p->func(p->session, NULL, gerr, p->data);
1225 g_clear_error(&gerr);
1228 pending_request_free(p);
1231 session_process_queue(session);
1234 static void file_op_complete(struct obc_session *session,
1235 struct obc_transfer *transfer,
1236 GError *err, void *user_data)
1238 struct file_data *data = user_data;
1241 data->func(session, NULL, err, data->user_data);
1244 static int session_process_mkdir(struct pending_request *p, GError **err)
1246 struct file_data *req = p->data;
1248 p->req_id = g_obex_mkdir(p->session->obex, req->srcname, async_cb, p,
1251 return (*err)->code;
1258 guint obc_session_mkdir(struct obc_session *session, const char *folder,
1259 session_callback_t func, void *user_data,
1262 struct file_data *data;
1263 struct pending_request *p;
1265 if (session->obex == NULL) {
1266 g_set_error(err, OBEX_IO_ERROR, OBEX_IO_DISCONNECTED,
1267 "Session disconnected");
1271 data = g_new0(struct file_data, 1);
1272 data->srcname = g_strdup(folder);
1274 data->user_data = user_data;
1276 p = pending_request_new(session, session_process_mkdir, NULL,
1277 file_op_complete, data, file_data_free);
1282 static int session_process_copy(struct pending_request *p, GError **err)
1284 struct file_data *req = p->data;
1286 p->req_id = g_obex_copy(p->session->obex, req->srcname, req->destname,
1289 return (*err)->code;
1296 guint obc_session_copy(struct obc_session *session, const char *srcname,
1297 const char *destname, session_callback_t func,
1298 void *user_data, GError **err)
1300 struct file_data *data;
1301 struct pending_request *p;
1303 if (session->obex == NULL) {
1304 g_set_error(err, OBEX_IO_ERROR, OBEX_IO_DISCONNECTED,
1305 "Session disconnected");
1309 data = g_new0(struct file_data, 1);
1310 data->srcname = g_strdup(srcname);
1311 data->destname = g_strdup(destname);
1313 data->user_data = user_data;
1315 p = pending_request_new(session, session_process_copy, NULL,
1316 file_op_complete, data, file_data_free);
1321 static int session_process_move(struct pending_request *p, GError **err)
1323 struct file_data *req = p->data;
1325 p->req_id = g_obex_move(p->session->obex, req->srcname, req->destname,
1328 return (*err)->code;
1335 guint obc_session_move(struct obc_session *session, const char *srcname,
1336 const char *destname, session_callback_t func,
1337 void *user_data, GError **err)
1339 struct file_data *data;
1340 struct pending_request *p;
1342 if (session->obex == NULL) {
1343 g_set_error(err, OBEX_IO_ERROR, OBEX_IO_DISCONNECTED,
1344 "Session disconnected");
1348 data = g_new0(struct file_data, 1);
1349 data->srcname = g_strdup(srcname);
1350 data->destname = g_strdup(destname);
1352 data->user_data = user_data;
1354 p = pending_request_new(session, session_process_move, NULL,
1355 file_op_complete, data, file_data_free);
1360 static int session_process_delete(struct pending_request *p, GError **err)
1362 struct file_data *req = p->data;
1364 p->req_id = g_obex_delete(p->session->obex, req->srcname, async_cb, p,
1367 return (*err)->code;
1374 guint obc_session_delete(struct obc_session *session, const char *file,
1375 session_callback_t func, void *user_data,
1378 struct file_data *data;
1379 struct pending_request *p;
1381 if (session->obex == NULL) {
1382 g_set_error(err, OBEX_IO_ERROR, OBEX_IO_DISCONNECTED,
1383 "Session disconnected");
1387 data = g_new0(struct file_data, 1);
1388 data->srcname = g_strdup(file);
1390 data->user_data = user_data;
1392 p = pending_request_new(session, session_process_delete, NULL,
1393 file_op_complete, data, file_data_free);
1398 void obc_session_cancel(struct obc_session *session, guint id,
1401 struct pending_request *p = session->p;
1403 if (p == NULL || p->id != id)
1409 g_obex_cancel_req(session->obex, p->req_id, remove);
1415 pending_request_free(p);
1418 session_process_queue(session);