| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- /*
- *
- * OBEX Client
- *
- * Copyright (C) 2007-2010 Marcel Holtmann <marcel@holtmann.org>
- * Copyright (C) 2011-2012 BMW Car IT GmbH. All rights reserved.
- *
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <stdlib.h>
- #include <stdio.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <inttypes.h>
- #include <glib.h>
- #include "gdbus/gdbus.h"
- #include "gobex/gobex.h"
- #include "obexd/src/log.h"
- #include "transfer.h"
- #define TRANSFER_INTERFACE "org.bluez.obex.Transfer1"
- #define ERROR_INTERFACE "org.bluez.obex.Error"
- #define OBC_TRANSFER_ERROR obc_transfer_error_quark()
- #define FIRST_PACKET_TIMEOUT 60
- static guint64 counter = 0;
- struct transfer_callback {
- transfer_callback_t func;
- void *data;
- };
- enum {
- TRANSFER_STATUS_QUEUED = 0,
- TRANSFER_STATUS_ACTIVE,
- TRANSFER_STATUS_SUSPENDED,
- TRANSFER_STATUS_COMPLETE,
- TRANSFER_STATUS_SUSPENDED_QUEUED,
- TRANSFER_STATUS_ERROR
- };
- struct obc_transfer {
- GObex *obex;
- uint8_t status;
- GObexApparam *apparam;
- guint8 op;
- struct transfer_callback *callback;
- DBusConnection *conn;
- DBusMessage *msg;
- char *session; /* Session path */
- char *owner; /* Transfer initiator */
- char *path; /* Transfer path */
- char *filename; /* Transfer file location */
- char *name; /* Transfer object name */
- char *type; /* Transfer object type */
- int fd;
- guint req;
- guint xfer;
- gint64 size;
- gint64 transferred;
- gint64 progress;
- guint progress_id;
- };
- static GQuark obc_transfer_error_quark(void)
- {
- return g_quark_from_static_string("obc-transfer-error-quark");
- }
- DBusMessage *obc_transfer_create_dbus_reply(struct obc_transfer *transfer,
- DBusMessage *message)
- {
- DBusMessage *reply;
- DBusMessageIter iter;
- reply = dbus_message_new_method_return(message);
- if (reply == NULL)
- return NULL;
- dbus_message_iter_init_append(reply, &iter);
- dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
- &transfer->path);
- g_dbus_get_properties(transfer->conn, transfer->path,
- TRANSFER_INTERFACE, &iter);
- return reply;
- }
- static void abort_complete(GObex *obex, GError *err, gpointer user_data)
- {
- struct obc_transfer *transfer = user_data;
- struct transfer_callback *callback = transfer->callback;
- DBusMessage *reply;
- transfer->xfer = 0;
- reply = dbus_message_new_method_return(transfer->msg);
- if (reply)
- g_dbus_send_message(transfer->conn, reply);
- dbus_message_unref(transfer->msg);
- transfer->msg = NULL;
- if (callback == NULL)
- return;
- if (err) {
- callback->func(transfer, err, callback->data);
- } else {
- GError *abort_err;
- abort_err = g_error_new(OBC_TRANSFER_ERROR, -ECANCELED, "%s",
- "Transfer cancelled by user");
- callback->func(transfer, abort_err, callback->data);
- g_error_free(abort_err);
- }
- }
- static DBusMessage *obc_transfer_cancel(DBusConnection *connection,
- DBusMessage *message, void *user_data)
- {
- struct obc_transfer *transfer = user_data;
- const char *sender;
- sender = dbus_message_get_sender(message);
- if (g_strcmp0(transfer->owner, sender) != 0)
- return g_dbus_create_error(message,
- ERROR_INTERFACE ".NotAuthorized",
- "Not Authorized");
- if (transfer->msg != NULL)
- return g_dbus_create_error(message,
- ERROR_INTERFACE ".InProgress",
- "Cancellation already in progress");
- if (transfer->status == TRANSFER_STATUS_SUSPENDED)
- g_obex_resume(transfer->obex);
- if (transfer->req > 0) {
- if (!g_obex_cancel_req(transfer->obex, transfer->req, TRUE))
- return g_dbus_create_error(message,
- ERROR_INTERFACE ".Failed",
- "Failed");
- transfer->req = 0;
- }
- if (transfer->xfer == 0) {
- struct transfer_callback *callback = transfer->callback;
- if (callback != NULL) {
- GError *err;
- err = g_error_new(OBC_TRANSFER_ERROR, -ECANCELED, "%s",
- "Transfer cancelled by user");
- callback->func(transfer, err, callback->data);
- g_error_free(err);
- }
- return dbus_message_new_method_return(message);
- }
- if (transfer->progress_id != 0) {
- g_source_remove(transfer->progress_id);
- transfer->progress_id = 0;
- }
- if (!g_obex_cancel_transfer(transfer->xfer, abort_complete, transfer))
- return g_dbus_create_error(message,
- ERROR_INTERFACE ".Failed",
- "Failed");
- transfer->msg = dbus_message_ref(message);
- return NULL;
- }
- static void transfer_set_status(struct obc_transfer *transfer, uint8_t status)
- {
- if (transfer->status == status)
- return;
- transfer->status = status;
- g_dbus_emit_property_changed(transfer->conn, transfer->path,
- TRANSFER_INTERFACE, "Status");
- }
- static DBusMessage *obc_transfer_suspend(DBusConnection *connection,
- DBusMessage *message, void *user_data)
- {
- struct obc_transfer *transfer = user_data;
- const char *sender;
- uint8_t status;
- sender = dbus_message_get_sender(message);
- if (g_strcmp0(transfer->owner, sender) != 0)
- return g_dbus_create_error(message,
- ERROR_INTERFACE ".NotAuthorized",
- "Not Authorized");
- switch (transfer->status) {
- case TRANSFER_STATUS_QUEUED:
- status = TRANSFER_STATUS_SUSPENDED_QUEUED;
- break;
- case TRANSFER_STATUS_ACTIVE:
- if (transfer->xfer)
- g_obex_suspend(transfer->obex);
- status = TRANSFER_STATUS_SUSPENDED;
- break;
- default:
- return g_dbus_create_error(message,
- ERROR_INTERFACE ".NotInProgress",
- "Not in progress");
- }
- transfer_set_status(transfer, status);
- return g_dbus_create_reply(message, DBUS_TYPE_INVALID);
- }
- static DBusMessage *obc_transfer_resume(DBusConnection *connection,
- DBusMessage *message, void *user_data)
- {
- struct obc_transfer *transfer = user_data;
- const char *sender;
- uint8_t status;
- sender = dbus_message_get_sender(message);
- if (g_strcmp0(transfer->owner, sender) != 0)
- return g_dbus_create_error(message,
- ERROR_INTERFACE ".NotAuthorized",
- "Not Authorized");
- switch (transfer->status) {
- case TRANSFER_STATUS_SUSPENDED_QUEUED:
- status = TRANSFER_STATUS_QUEUED;
- break;
- case TRANSFER_STATUS_SUSPENDED:
- if (transfer->xfer)
- g_obex_resume(transfer->obex);
- else
- obc_transfer_start(transfer, NULL, NULL);
- status = TRANSFER_STATUS_ACTIVE;
- break;
- default:
- return g_dbus_create_error(message,
- ERROR_INTERFACE ".NotInProgress",
- "Not in progress");
- }
- transfer_set_status(transfer, status);
- return g_dbus_create_reply(message, DBUS_TYPE_INVALID);
- }
- static gboolean name_exists(const GDBusPropertyTable *property, void *data)
- {
- struct obc_transfer *transfer = data;
- return transfer->name != NULL;
- }
- static gboolean get_name(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
- {
- struct obc_transfer *transfer = data;
- if (transfer->name == NULL)
- return FALSE;
- dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
- &transfer->name);
- return TRUE;
- }
- static gboolean get_size(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
- {
- struct obc_transfer *transfer = data;
- dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64,
- &transfer->size);
- return TRUE;
- }
- static gboolean filename_exists(const GDBusPropertyTable *property, void *data)
- {
- struct obc_transfer *transfer = data;
- return transfer->filename != NULL;
- }
- static gboolean get_filename(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
- {
- struct obc_transfer *transfer = data;
- if (transfer->filename == NULL)
- return FALSE;
- dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
- &transfer->filename);
- return TRUE;
- }
- static gboolean transferred_exists(const GDBusPropertyTable *property,
- void *data)
- {
- struct obc_transfer *transfer = data;
- return transfer->obex != NULL;
- }
- static gboolean get_transferred(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
- {
- struct obc_transfer *transfer = data;
- if (transfer->obex == NULL)
- return FALSE;
- dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64,
- &transfer->progress);
- return TRUE;
- }
- static const char *status2str(uint8_t status)
- {
- switch (status) {
- case TRANSFER_STATUS_QUEUED:
- return "queued";
- case TRANSFER_STATUS_ACTIVE:
- return "active";
- case TRANSFER_STATUS_SUSPENDED_QUEUED:
- case TRANSFER_STATUS_SUSPENDED:
- return "suspended";
- case TRANSFER_STATUS_COMPLETE:
- return "complete";
- case TRANSFER_STATUS_ERROR:
- default:
- return "error";
- }
- }
- static gboolean get_status(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
- {
- struct obc_transfer *transfer = data;
- const char *status = status2str(transfer->status);
- dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &status);
- return TRUE;
- }
- static gboolean get_session(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
- {
- struct obc_transfer *transfer = data;
- dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
- &transfer->session);
- return TRUE;
- }
- static const GDBusMethodTable obc_transfer_methods[] = {
- { GDBUS_METHOD("Suspend", NULL, NULL, obc_transfer_suspend) },
- { GDBUS_METHOD("Resume", NULL, NULL, obc_transfer_resume) },
- { GDBUS_ASYNC_METHOD("Cancel", NULL, NULL,
- obc_transfer_cancel) },
- { }
- };
- static const GDBusPropertyTable obc_transfer_properties[] = {
- { "Status", "s", get_status },
- { "Name", "s", get_name, NULL, name_exists },
- { "Size", "t", get_size },
- { "Filename", "s", get_filename, NULL, filename_exists },
- { "Transferred", "t", get_transferred, NULL, transferred_exists },
- { "Session", "o", get_session },
- { }
- };
- static void obc_transfer_free(struct obc_transfer *transfer)
- {
- DBG("%p", transfer);
- if (transfer->status == TRANSFER_STATUS_SUSPENDED)
- g_obex_resume(transfer->obex);
- if (transfer->req > 0)
- g_obex_cancel_req(transfer->obex, transfer->req, TRUE);
- if (transfer->xfer)
- g_obex_cancel_transfer(transfer->xfer, NULL, NULL);
- if (transfer->progress_id != 0) {
- g_source_remove(transfer->progress_id);
- transfer->progress_id = 0;
- }
- if (transfer->op == G_OBEX_OP_GET &&
- transfer->status != TRANSFER_STATUS_COMPLETE &&
- transfer->filename)
- remove(transfer->filename);
- if (transfer->fd > 0)
- close(transfer->fd);
- if (transfer->apparam != NULL)
- g_obex_apparam_free(transfer->apparam);
- if (transfer->conn)
- dbus_connection_unref(transfer->conn);
- if (transfer->msg)
- dbus_message_unref(transfer->msg);
- if (transfer->obex)
- g_obex_unref(transfer->obex);
- g_free(transfer->callback);
- g_free(transfer->owner);
- g_free(transfer->filename);
- g_free(transfer->name);
- g_free(transfer->type);
- g_free(transfer->session);
- g_free(transfer->path);
- g_free(transfer);
- }
- static struct obc_transfer *obc_transfer_create(guint8 op,
- const char *filename,
- const char *name,
- const char *type)
- {
- struct obc_transfer *transfer;
- transfer = g_new0(struct obc_transfer, 1);
- transfer->op = op;
- transfer->filename = g_strdup(filename);
- transfer->name = g_strdup(name);
- transfer->type = g_strdup(type);
- return transfer;
- }
- gboolean obc_transfer_register(struct obc_transfer *transfer,
- DBusConnection *conn,
- const char *session,
- const char *owner,
- GError **err)
- {
- transfer->owner = g_strdup(owner);
- transfer->session = g_strdup(session);
- transfer->path = g_strdup_printf("%s/transfer%ju", session, counter++);
- transfer->conn = dbus_connection_ref(conn);
- if (transfer->conn == NULL) {
- g_set_error(err, OBC_TRANSFER_ERROR, -EFAULT,
- "Unable to connect to D-Bus");
- return FALSE;
- }
- if (g_dbus_register_interface(transfer->conn, transfer->path,
- TRANSFER_INTERFACE,
- obc_transfer_methods, NULL,
- obc_transfer_properties, transfer,
- NULL) == FALSE) {
- g_set_error(err, OBC_TRANSFER_ERROR, -EFAULT,
- "Unable to register to D-Bus");
- return FALSE;
- }
- DBG("%p registered %s", transfer, transfer->path);
- return TRUE;
- }
- static gboolean transfer_open(struct obc_transfer *transfer, int flags,
- mode_t mode, GError **err)
- {
- int fd;
- char *filename;
- if (transfer->filename != NULL && strcmp(transfer->filename, "") != 0) {
- fd = open(transfer->filename, flags, mode);
- if (fd < 0) {
- error("open(): %s(%d)", strerror(errno), errno);
- g_set_error(err, OBC_TRANSFER_ERROR, -errno,
- "Unable to open file");
- return FALSE;
- }
- goto done;
- }
- fd = g_file_open_tmp("obex-clientXXXXXX", &filename, err);
- if (fd < 0) {
- error("g_file_open_tmp(): %s", (*err)->message);
- return FALSE;
- }
- if (transfer->filename == NULL) {
- remove(filename); /* remove always only if NULL was given */
- g_free(filename);
- } else {
- g_free(transfer->filename);
- transfer->filename = filename;
- }
- done:
- transfer->fd = fd;
- return TRUE;
- }
- struct obc_transfer *obc_transfer_get(const char *type, const char *name,
- const char *filename, GError **err)
- {
- struct obc_transfer *transfer;
- int perr;
- transfer = obc_transfer_create(G_OBEX_OP_GET, filename, name, type);
- perr = transfer_open(transfer, O_WRONLY | O_CREAT | O_TRUNC, 0600, err);
- if (perr < 0) {
- obc_transfer_free(transfer);
- return NULL;
- }
- return transfer;
- }
- struct obc_transfer *obc_transfer_put(const char *type, const char *name,
- const char *filename,
- const void *contents, size_t size,
- GError **err)
- {
- struct obc_transfer *transfer;
- struct stat st;
- int perr;
- if ((filename == NULL || strcmp(filename, "") == 0) &&
- contents == NULL) {
- g_set_error(err, OBC_TRANSFER_ERROR, -EINVAL,
- "Invalid filename given");
- return NULL;
- }
- transfer = obc_transfer_create(G_OBEX_OP_PUT, filename, name, type);
- if (contents != NULL) {
- ssize_t w;
- if (!transfer_open(transfer, O_RDWR, 0, err))
- goto fail;
- w = write(transfer->fd, contents, size);
- if (w < 0) {
- perr = errno;
- error("write(): %s(%d)", strerror(perr), perr);
- g_set_error(err, OBC_TRANSFER_ERROR, -perr,
- "Writing to file failed");
- goto fail;
- } else if ((size_t) w != size) {
- error("Unable to write all contents to file");
- g_set_error(err, OBC_TRANSFER_ERROR, -EFAULT,
- "Writing all contents to file failed");
- goto fail;
- }
- lseek(transfer->fd, 0, SEEK_SET);
- } else {
- if (!transfer_open(transfer, O_RDONLY, 0, err))
- goto fail;
- }
- if (fstat(transfer->fd, &st) < 0) {
- perr = errno;
- error("fstat(): %s(%d)", strerror(perr), perr);
- g_set_error(err, OBC_TRANSFER_ERROR, -perr,
- "Unable to get file status");
- goto fail;
- }
- transfer->size = st.st_size;
- return transfer;
- fail:
- obc_transfer_free(transfer);
- return NULL;
- }
- void obc_transfer_unregister(struct obc_transfer *transfer)
- {
- if (transfer->path) {
- g_dbus_unregister_interface(transfer->conn,
- transfer->path, TRANSFER_INTERFACE);
- }
- DBG("%p unregistered %s", transfer, transfer->path);
- obc_transfer_free(transfer);
- }
- static gboolean get_xfer_progress(const void *buf, gsize len,
- gpointer user_data)
- {
- struct obc_transfer *transfer = user_data;
- if (transfer->fd > 0) {
- int w;
- w = write(transfer->fd, buf, len);
- if (w < 0)
- return FALSE;
- transfer->transferred += w;
- }
- return TRUE;
- }
- static void xfer_complete(GObex *obex, GError *err, gpointer user_data)
- {
- struct obc_transfer *transfer = user_data;
- struct transfer_callback *callback = transfer->callback;
- transfer->xfer = 0;
- if (transfer->progress_id != 0) {
- g_source_remove(transfer->progress_id);
- transfer->progress_id = 0;
- }
- if (transfer->status == TRANSFER_STATUS_SUSPENDED)
- g_obex_resume(transfer->obex);
- if (err)
- transfer_set_status(transfer, TRANSFER_STATUS_ERROR);
- else
- transfer_set_status(transfer, TRANSFER_STATUS_COMPLETE);
- if (callback)
- callback->func(transfer, err, callback->data);
- }
- static void get_xfer_progress_first(GObex *obex, GError *err, GObexPacket *rsp,
- gpointer user_data)
- {
- struct obc_transfer *transfer = user_data;
- GObexPacket *req;
- GObexHeader *hdr;
- GObexApparam *apparam;
- const guint8 *buf;
- gsize len;
- guint8 rspcode;
- gboolean final;
- if (err != NULL) {
- xfer_complete(obex, err, transfer);
- return;
- }
- rspcode = g_obex_packet_get_operation(rsp, &final);
- if (rspcode != G_OBEX_RSP_SUCCESS && rspcode != G_OBEX_RSP_CONTINUE) {
- err = g_error_new(OBC_TRANSFER_ERROR, rspcode, "%s",
- g_obex_strerror(rspcode));
- xfer_complete(obex, err, transfer);
- g_error_free(err);
- return;
- }
- hdr = g_obex_packet_get_header(rsp, G_OBEX_HDR_LENGTH);
- if (hdr) {
- uint32_t len;
- if (g_obex_header_get_uint32(hdr, &len)) {
- transfer->size = len;
- g_dbus_emit_property_changed(transfer->conn,
- transfer->path,
- TRANSFER_INTERFACE, "Size");
- }
- }
- hdr = g_obex_packet_get_header(rsp, G_OBEX_HDR_APPARAM);
- if (hdr) {
- apparam = g_obex_header_get_apparam(hdr);
- if (apparam != NULL)
- obc_transfer_set_apparam(transfer, apparam);
- }
- hdr = g_obex_packet_get_body(rsp);
- if (hdr) {
- g_obex_header_get_bytes(hdr, &buf, &len);
- if (len != 0)
- get_xfer_progress(buf, len, transfer);
- }
- if (rspcode == G_OBEX_RSP_SUCCESS) {
- transfer->req = 0;
- xfer_complete(obex, err, transfer);
- return;
- }
- if (g_obex_srm_active(obex) ||
- transfer->status == TRANSFER_STATUS_SUSPENDED)
- return;
- transfer->req = 0;
- req = g_obex_packet_new(G_OBEX_OP_GET, TRUE, G_OBEX_HDR_INVALID);
- transfer->xfer = g_obex_get_req_pkt(obex, req, get_xfer_progress,
- xfer_complete, transfer,
- &err);
- }
- static gssize put_xfer_progress(void *buf, gsize len, gpointer user_data)
- {
- struct obc_transfer *transfer = user_data;
- gssize size;
- size = read(transfer->fd, buf, len);
- if (size <= 0)
- return size;
- transfer->transferred += size;
- return size;
- }
- gboolean obc_transfer_set_callback(struct obc_transfer *transfer,
- transfer_callback_t func,
- void *user_data)
- {
- struct transfer_callback *callback;
- if (transfer->callback != NULL)
- return FALSE;
- callback = g_new0(struct transfer_callback, 1);
- callback->func = func;
- callback->data = user_data;
- transfer->callback = callback;
- return TRUE;
- }
- static gboolean report_progress(gpointer data)
- {
- struct obc_transfer *transfer = data;
- if (transfer->transferred == transfer->progress)
- return TRUE;
- transfer->progress = transfer->transferred;
- if (transfer->transferred == transfer->size) {
- transfer->progress_id = 0;
- return FALSE;
- }
- if (transfer->status != TRANSFER_STATUS_ACTIVE &&
- transfer->status != TRANSFER_STATUS_SUSPENDED)
- transfer_set_status(transfer, TRANSFER_STATUS_ACTIVE);
- g_dbus_emit_property_changed(transfer->conn, transfer->path,
- TRANSFER_INTERFACE, "Transferred");
- return TRUE;
- }
- static gboolean transfer_start_get(struct obc_transfer *transfer, GError **err)
- {
- GObexPacket *req;
- GObexHeader *hdr;
- if (transfer->xfer > 0) {
- g_set_error(err, OBC_TRANSFER_ERROR, -EALREADY,
- "Transfer already started");
- return FALSE;
- }
- req = g_obex_packet_new(G_OBEX_OP_GET, TRUE, G_OBEX_HDR_INVALID);
- if (transfer->name != NULL)
- g_obex_packet_add_unicode(req, G_OBEX_HDR_NAME,
- transfer->name);
- if (transfer->type != NULL)
- g_obex_packet_add_bytes(req, G_OBEX_HDR_TYPE, transfer->type,
- strlen(transfer->type) + 1);
- if (transfer->apparam != NULL) {
- hdr = g_obex_header_new_apparam(transfer->apparam);
- g_obex_packet_add_header(req, hdr);
- }
- transfer->req = g_obex_send_req(transfer->obex, req,
- FIRST_PACKET_TIMEOUT,
- get_xfer_progress_first,
- transfer, err);
- if (transfer->req == 0)
- return FALSE;
- if (transfer->path == NULL)
- return TRUE;
- transfer->progress_id = g_timeout_add_seconds(1, report_progress,
- transfer);
- return TRUE;
- }
- static gboolean transfer_start_put(struct obc_transfer *transfer, GError **err)
- {
- GObexPacket *req;
- GObexHeader *hdr;
- if (transfer->xfer > 0) {
- g_set_error(err, OBC_TRANSFER_ERROR, -EALREADY,
- "Transfer already started");
- return FALSE;
- }
- req = g_obex_packet_new(G_OBEX_OP_PUT, FALSE, G_OBEX_HDR_INVALID);
- if (transfer->name != NULL)
- g_obex_packet_add_unicode(req, G_OBEX_HDR_NAME,
- transfer->name);
- if (transfer->type != NULL)
- g_obex_packet_add_bytes(req, G_OBEX_HDR_TYPE, transfer->type,
- strlen(transfer->type) + 1);
- if (transfer->size < UINT32_MAX)
- g_obex_packet_add_uint32(req, G_OBEX_HDR_LENGTH, transfer->size);
- if (transfer->apparam != NULL) {
- hdr = g_obex_header_new_apparam(transfer->apparam);
- g_obex_packet_add_header(req, hdr);
- }
- transfer->xfer = g_obex_put_req_pkt(transfer->obex, req,
- put_xfer_progress, xfer_complete,
- transfer, err);
- if (transfer->xfer == 0)
- return FALSE;
- if (transfer->path == NULL)
- return TRUE;
- transfer->progress_id = g_timeout_add_seconds(1, report_progress,
- transfer);
- return TRUE;
- }
- gboolean obc_transfer_start(struct obc_transfer *transfer, void *obex,
- GError **err)
- {
- if (!transfer->obex)
- transfer->obex = g_obex_ref(obex);
- if (transfer->status == TRANSFER_STATUS_SUSPENDED_QUEUED) {
- /* Reset status so the transfer can be resumed */
- transfer->status = TRANSFER_STATUS_SUSPENDED;
- return TRUE;
- }
- switch (transfer->op) {
- case G_OBEX_OP_GET:
- return transfer_start_get(transfer, err);
- case G_OBEX_OP_PUT:
- return transfer_start_put(transfer, err);
- }
- g_set_error(err, OBC_TRANSFER_ERROR, -ENOTSUP, "Not supported");
- return FALSE;
- }
- guint8 obc_transfer_get_operation(struct obc_transfer *transfer)
- {
- return transfer->op;
- }
- void obc_transfer_set_apparam(struct obc_transfer *transfer, void *data)
- {
- if (transfer->apparam != NULL)
- g_obex_apparam_free(transfer->apparam);
- if (data == NULL)
- return;
- transfer->apparam = data;
- }
- void *obc_transfer_get_apparam(struct obc_transfer *transfer)
- {
- return transfer->apparam;
- }
- int obc_transfer_get_contents(struct obc_transfer *transfer, char **contents,
- size_t *size)
- {
- struct stat st;
- ssize_t ret;
- if (contents == NULL)
- return -EINVAL;
- if (fstat(transfer->fd, &st) < 0) {
- error("fstat(): %s(%d)", strerror(errno), errno);
- return -errno;
- }
- if (lseek(transfer->fd, 0, SEEK_SET) < 0) {
- error("lseek(): %s(%d)", strerror(errno), errno);
- return -errno;
- }
- *contents = g_malloc(st.st_size + 1);
- ret = read(transfer->fd, *contents, st.st_size);
- if (ret < 0) {
- error("read(): %s(%d)", strerror(errno), errno);
- g_free(*contents);
- return -errno;
- }
- (*contents)[ret] = '\0';
- if (size)
- *size = ret;
- return 0;
- }
- const char *obc_transfer_get_path(struct obc_transfer *transfer)
- {
- return transfer->path;
- }
- gint64 obc_transfer_get_size(struct obc_transfer *transfer)
- {
- return transfer->size;
- }
|