upgrade obexd to 0.47
[profile/ivi/obexd.git] / gobex / gobex.c
1 /*
2  *
3  *  OBEX library with GLib integration
4  *
5  *  Copyright (C) 2011  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25
26 #include <unistd.h>
27 #include <string.h>
28 #include <errno.h>
29
30 #include "gobex.h"
31 #include "gobex-debug.h"
32
33 #define G_OBEX_DEFAULT_MTU      4096
34 #define G_OBEX_MINIMUM_MTU      255
35 #define G_OBEX_MAXIMUM_MTU      65535
36
37 #define G_OBEX_DEFAULT_TIMEOUT  10
38 #define G_OBEX_ABORT_TIMEOUT    5
39
40 #define G_OBEX_OP_NONE          0xff
41
42 #define FINAL_BIT               0x80
43
44 #define CONNID_INVALID          0xffffffff
45
46 guint gobex_debug = 0;
47
48 struct srm_config {
49         guint8 op;
50         gboolean enabled;
51         guint8 srm;
52         guint8 srmp;
53         gboolean outgoing;
54 };
55
56 struct _GObex {
57         gint ref_count;
58         GIOChannel *io;
59         guint io_source;
60
61         gboolean (*read) (GObex *obex, GError **err);
62         gboolean (*write) (GObex *obex, GError **err);
63
64         guint8 *rx_buf;
65         size_t rx_data;
66         guint16 rx_pkt_len;
67         guint8 rx_last_op;
68
69         guint8 *tx_buf;
70         size_t tx_data;
71         size_t tx_sent;
72
73         gboolean suspended;
74         gboolean use_srm;
75
76         struct srm_config *srm;
77
78         guint write_source;
79
80         gssize io_rx_mtu;
81         gssize io_tx_mtu;
82
83         guint16 rx_mtu;
84         guint16 tx_mtu;
85
86         guint32 conn_id;
87
88         GQueue *tx_queue;
89
90         GSList *req_handlers;
91
92         GObexFunc disconn_func;
93         gpointer disconn_func_data;
94
95         struct pending_pkt *pending_req;
96 };
97
98 struct pending_pkt {
99         guint id;
100         GObex *obex;
101         GObexPacket *pkt;
102         guint timeout;
103         guint timeout_id;
104         GObexResponseFunc rsp_func;
105         gpointer rsp_data;
106         gboolean cancelled;
107 };
108
109 struct req_handler {
110         guint id;
111         guint8 opcode;
112         GObexRequestFunc func;
113         gpointer user_data;
114 };
115
116 struct connect_data {
117         guint8 version;
118         guint8 flags;
119         guint16 mtu;
120 } __attribute__ ((packed));
121
122 struct setpath_data {
123         guint8 flags;
124         guint8 constants;
125 } __attribute__ ((packed));
126
127 static struct error_code {
128         guint8 code;
129         const char *name;
130 } obex_errors[] = {
131         { G_OBEX_RSP_CONTINUE,                  "Continue" },
132         { G_OBEX_RSP_SUCCESS,                   "Success" },
133         { G_OBEX_RSP_CREATED,                   "Created" },
134         { G_OBEX_RSP_ACCEPTED,                  "Accepted" },
135         { G_OBEX_RSP_NON_AUTHORITATIVE,         "Non Authoritative" },
136         { G_OBEX_RSP_NO_CONTENT,                "No Content" },
137         { G_OBEX_RSP_RESET_CONTENT,             "Reset Content" },
138         { G_OBEX_RSP_PARTIAL_CONTENT,           "Partial Content" },
139         { G_OBEX_RSP_MULTIPLE_CHOICES,          "Multiple Choices" },
140         { G_OBEX_RSP_MOVED_PERMANENTLY,         "Moved Permanently" },
141         { G_OBEX_RSP_MOVED_TEMPORARILY,         "Moved Temporarily" },
142         { G_OBEX_RSP_SEE_OTHER,                 "See Other" },
143         { G_OBEX_RSP_NOT_MODIFIED,              "Not Modified" },
144         { G_OBEX_RSP_USE_PROXY,                 "Use Proxy" },
145         { G_OBEX_RSP_BAD_REQUEST,               "Bad Request" },
146         { G_OBEX_RSP_UNAUTHORIZED,              "Unauthorized" },
147         { G_OBEX_RSP_PAYMENT_REQUIRED,          "Payment Required" },
148         { G_OBEX_RSP_FORBIDDEN,                 "Forbidden" },
149         { G_OBEX_RSP_NOT_FOUND,                 "Not Found" },
150         { G_OBEX_RSP_METHOD_NOT_ALLOWED,        "Method Not Allowed" },
151         { G_OBEX_RSP_NOT_ACCEPTABLE,            "Not Acceptable" },
152         { G_OBEX_RSP_PROXY_AUTH_REQUIRED,       "Proxy Authentication Required" },
153         { G_OBEX_RSP_REQUEST_TIME_OUT,          "Request Time Out" },
154         { G_OBEX_RSP_CONFLICT,                  "Conflict" },
155         { G_OBEX_RSP_GONE,                      "Gone" },
156         { G_OBEX_RSP_LENGTH_REQUIRED,           "Length Required" },
157         { G_OBEX_RSP_PRECONDITION_FAILED,       "Precondition Failed" },
158         { G_OBEX_RSP_REQ_ENTITY_TOO_LARGE,      "Request Entity Too Large" },
159         { G_OBEX_RSP_REQ_URL_TOO_LARGE,         "Request URL Too Large" },
160         { G_OBEX_RSP_UNSUPPORTED_MEDIA_TYPE,    "Unsupported Media Type" },
161         { G_OBEX_RSP_INTERNAL_SERVER_ERROR,     "Internal Server Error" },
162         { G_OBEX_RSP_NOT_IMPLEMENTED,           "Not Implemented" },
163         { G_OBEX_RSP_BAD_GATEWAY,               "Bad Gateway" },
164         { G_OBEX_RSP_SERVICE_UNAVAILABLE,       "Service Unavailable" },
165         { G_OBEX_RSP_GATEWAY_TIMEOUT,           "Gateway Timeout" },
166         { G_OBEX_RSP_VERSION_NOT_SUPPORTED,     "Version Not Supported" },
167         { G_OBEX_RSP_DATABASE_FULL,             "Database Full" },
168         { G_OBEX_RSP_DATABASE_LOCKED,           "Database Locked" },
169         { 0x00,                                 NULL }
170 };
171
172 const char *g_obex_strerror(guint8 err_code)
173 {
174         struct error_code *error;
175
176         for (error = obex_errors; error->name != NULL; error++) {
177                 if (error->code == err_code)
178                         return error->name;
179         }
180
181         return "<unknown>";
182 }
183
184 static ssize_t req_header_offset(guint8 opcode)
185 {
186         switch (opcode) {
187         case G_OBEX_OP_CONNECT:
188                 return sizeof(struct connect_data);
189         case G_OBEX_OP_SETPATH:
190                 return sizeof(struct setpath_data);
191         case G_OBEX_OP_DISCONNECT:
192         case G_OBEX_OP_PUT:
193         case G_OBEX_OP_GET:
194         case G_OBEX_OP_SESSION:
195         case G_OBEX_OP_ABORT:
196         case G_OBEX_OP_ACTION:
197                 return 0;
198         default:
199                 return -1;
200         }
201 }
202
203 static ssize_t rsp_header_offset(guint8 opcode)
204 {
205         switch (opcode) {
206         case G_OBEX_OP_CONNECT:
207                 return sizeof(struct connect_data);
208         case G_OBEX_OP_SETPATH:
209         case G_OBEX_OP_DISCONNECT:
210         case G_OBEX_OP_PUT:
211         case G_OBEX_OP_GET:
212         case G_OBEX_OP_SESSION:
213         case G_OBEX_OP_ABORT:
214         case G_OBEX_OP_ACTION:
215                 return 0;
216         default:
217                 return -1;
218         }
219 }
220
221 static void pending_pkt_free(struct pending_pkt *p)
222 {
223         if (p->obex != NULL)
224                 g_obex_unref(p->obex);
225
226         if (p->timeout_id > 0)
227                 g_source_remove(p->timeout_id);
228
229         g_obex_packet_free(p->pkt);
230
231         g_free(p);
232 }
233
234 static gboolean req_timeout(gpointer user_data)
235 {
236         GObex *obex = user_data;
237         struct pending_pkt *p = obex->pending_req;
238         GError *err;
239
240         g_assert(p != NULL);
241
242         obex->pending_req = NULL;
243
244         err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_TIMEOUT,
245                                         "Timed out waiting for response");
246
247         g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
248
249         if (p->rsp_func)
250                 p->rsp_func(obex, err, NULL, p->rsp_data);
251
252         g_error_free(err);
253         pending_pkt_free(p);
254
255         return FALSE;
256 }
257
258 static gboolean write_stream(GObex *obex, GError **err)
259 {
260         GIOStatus status;
261         gsize bytes_written;
262         gchar *buf;
263
264         buf = (gchar *) &obex->tx_buf[obex->tx_sent];
265         status = g_io_channel_write_chars(obex->io, buf, obex->tx_data,
266                                                         &bytes_written, err);
267         if (status != G_IO_STATUS_NORMAL)
268                 return FALSE;
269
270         g_obex_dump("<", buf, bytes_written);
271
272         obex->tx_sent += bytes_written;
273         obex->tx_data -= bytes_written;
274
275         return TRUE;
276 }
277
278 static gboolean write_packet(GObex *obex, GError **err)
279 {
280         GIOStatus status;
281         gsize bytes_written;
282         gchar *buf;
283
284         buf = (gchar *) &obex->tx_buf[obex->tx_sent];
285         status = g_io_channel_write_chars(obex->io, buf, obex->tx_data,
286                                                         &bytes_written, err);
287         if (status != G_IO_STATUS_NORMAL)
288                 return FALSE;
289
290         if (bytes_written != obex->tx_data)
291                 return FALSE;
292
293         g_obex_dump("<", buf, bytes_written);
294
295         obex->tx_sent += bytes_written;
296         obex->tx_data -= bytes_written;
297
298         return TRUE;
299 }
300
301 static void set_srmp(GObex *obex, guint8 srmp, gboolean outgoing)
302 {
303         struct srm_config *config = obex->srm;
304
305         if (config == NULL)
306                 return;
307
308         /* Dont't reset if direction doesn't match */
309         if (srmp > G_OBEX_SRMP_NEXT_WAIT && config->outgoing != outgoing)
310                 return;
311
312         config->srmp = srmp;
313         config->outgoing = outgoing;
314 }
315
316 static void set_srm(GObex *obex, guint8 op, guint8 srm)
317 {
318         struct srm_config *config = obex->srm;
319         gboolean enable;
320
321         if (config == NULL) {
322                 if (srm == G_OBEX_SRM_DISABLE)
323                         return;
324
325                 config = g_new0(struct srm_config, 1);
326                 config->op = op;
327                 config->srm = srm;
328                 obex->srm = config;
329                 return;
330         }
331
332         /* Indicate response, treat it as request */
333         if (config->srm == G_OBEX_SRM_INDICATE) {
334                 if (srm != G_OBEX_SRM_ENABLE)
335                         goto done;
336                 config->srm = srm;
337                 return;
338         }
339
340         enable = (srm == G_OBEX_SRM_ENABLE);
341         if (config->enabled == enable)
342                 goto done;
343
344         config->enabled = enable;
345
346         g_obex_debug(G_OBEX_DEBUG_COMMAND, "SRM %s", config->enabled ?
347                                                 "Enabled" : "Disabled");
348
349 done:
350         if (config->enabled)
351                 return;
352
353         g_free(obex->srm);
354         obex->srm = NULL;
355 }
356
357 static void check_srm_final(GObex *obex, guint8 op)
358 {
359         if (obex->srm == NULL || !obex->srm->enabled)
360                 return;
361
362         switch (obex->srm->op) {
363         case G_OBEX_OP_CONNECT:
364                 return;
365         default:
366                 if (op <= G_OBEX_RSP_CONTINUE)
367                         return;
368         }
369
370         set_srm(obex, op, G_OBEX_SRM_DISABLE);
371 }
372
373 static void setup_srm(GObex *obex, GObexPacket *pkt, gboolean outgoing)
374 {
375         GObexHeader *hdr;
376         guint8 op;
377         gboolean final;
378
379         if (!obex->use_srm)
380                 return;
381
382         op = g_obex_packet_get_operation(pkt, &final);
383
384         hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_SRM);
385         if (hdr != NULL) {
386                 guint8 srm;
387                 g_obex_header_get_uint8(hdr, &srm);
388                 g_obex_debug(G_OBEX_DEBUG_COMMAND, "srm 0x%02x", srm);
389                 set_srm(obex, op, srm);
390         }
391
392         hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_SRMP);
393         if (hdr != NULL) {
394                 guint8 srmp;
395                 g_obex_header_get_uint8(hdr, &srmp);
396                 g_obex_debug(G_OBEX_DEBUG_COMMAND, "srmp 0x%02x", srmp);
397                 set_srmp(obex, srmp, outgoing);
398         } else
399                 set_srmp(obex, -1, outgoing);
400
401         if (final)
402                 check_srm_final(obex, op);
403 }
404
405 static gboolean write_data(GIOChannel *io, GIOCondition cond,
406                                                         gpointer user_data)
407 {
408         GObex *obex = user_data;
409
410         if (cond & G_IO_NVAL)
411                 return FALSE;
412
413         if (cond & (G_IO_HUP | G_IO_ERR))
414                 goto stop_tx;
415
416         if (obex->tx_data == 0) {
417                 struct pending_pkt *p = g_queue_pop_head(obex->tx_queue);
418                 ssize_t len;
419
420                 if (p == NULL)
421                         goto stop_tx;
422
423                 setup_srm(obex, p->pkt, TRUE);
424
425                 if (g_obex_srm_active(obex))
426                         goto encode;
427
428                 /* Can't send a request while there's a pending one */
429                 if (obex->pending_req && p->id > 0) {
430                         g_queue_push_head(obex->tx_queue, p);
431                         goto stop_tx;
432                 }
433
434 encode:
435                 len = g_obex_packet_encode(p->pkt, obex->tx_buf, obex->tx_mtu);
436                 if (len == -EAGAIN) {
437                         g_queue_push_head(obex->tx_queue, p);
438                         g_obex_suspend(obex);
439                         goto stop_tx;
440                 }
441
442                 if (len < 0) {
443                         pending_pkt_free(p);
444                         goto done;
445                 }
446
447                 if (p->id > 0) {
448                         if (obex->pending_req != NULL)
449                                 pending_pkt_free(obex->pending_req);
450                         obex->pending_req = p;
451                         p->timeout_id = g_timeout_add_seconds(p->timeout,
452                                                         req_timeout, obex);
453                 } else {
454                         /* During packet encode final bit can be set */
455                         if (obex->tx_buf[0] & FINAL_BIT)
456                                 check_srm_final(obex,
457                                                 obex->tx_buf[0] & ~FINAL_BIT);
458                         pending_pkt_free(p);
459                 }
460
461                 obex->tx_data = len;
462                 obex->tx_sent = 0;
463         }
464
465         if (obex->suspended) {
466                 obex->write_source = 0;
467                 return FALSE;
468         }
469
470         if (!obex->write(obex, NULL))
471                 goto stop_tx;
472
473 done:
474         if (obex->tx_data > 0 || g_queue_get_length(obex->tx_queue) > 0)
475                 return TRUE;
476
477 stop_tx:
478         obex->rx_last_op = G_OBEX_OP_NONE;
479         obex->tx_data = 0;
480         obex->write_source = 0;
481         return FALSE;
482 }
483
484 static void enable_tx(GObex *obex)
485 {
486         GIOCondition cond;
487
488         if (obex->suspended)
489                 return;
490
491         if (obex->write_source > 0)
492                 return;
493
494         cond = G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
495         obex->write_source = g_io_add_watch(obex->io, cond, write_data, obex);
496 }
497
498 static gboolean g_obex_send_internal(GObex *obex, struct pending_pkt *p,
499                                                                 GError **err)
500 {
501
502         if (obex->io == NULL) {
503                 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_DISCONNECTED,
504                                         "The transport is not connected");
505                 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
506                 return FALSE;
507         }
508
509         if (g_obex_packet_get_operation(p->pkt, NULL) == G_OBEX_OP_ABORT)
510                 g_queue_push_head(obex->tx_queue, p);
511         else
512                 g_queue_push_tail(obex->tx_queue, p);
513
514         if (obex->pending_req == NULL || p->id == 0)
515                 enable_tx(obex);
516
517         return TRUE;
518 }
519
520 static void init_connect_data(GObex *obex, struct connect_data *data)
521 {
522         guint16 u16;
523
524         memset(data, 0, sizeof(*data));
525
526         data->version = 0x10;
527         data->flags = 0;
528
529         u16 = g_htons(obex->rx_mtu);
530         memcpy(&data->mtu, &u16, sizeof(u16));
531 }
532
533 static void prepare_connect_rsp(GObex *obex, GObexPacket *rsp)
534 {
535         GObexHeader *connid;
536         struct connect_data data;
537         static guint32 next_connid = 1;
538
539         init_connect_data(obex, &data);
540         g_obex_packet_set_data(rsp, &data, sizeof(data), G_OBEX_DATA_COPY);
541
542         connid = g_obex_packet_get_header(rsp, G_OBEX_HDR_CONNECTION);
543         if (connid != NULL) {
544                 g_obex_header_get_uint32(connid, &obex->conn_id);
545                 return;
546         }
547
548         obex->conn_id = next_connid++;
549
550         connid = g_obex_header_new_uint32(G_OBEX_HDR_CONNECTION,
551                                                         obex->conn_id);
552         g_obex_packet_prepend_header(rsp, connid);
553 }
554
555 static void prepare_srm_rsp(GObex *obex, GObexPacket *pkt)
556 {
557         GObexHeader *hdr;
558
559         if (!obex->use_srm || obex->srm == NULL)
560                 return;
561
562         if (obex->srm->enabled)
563                 return;
564
565         hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_SRM);
566         if (hdr != NULL)
567                 return;
568
569         hdr = g_obex_header_new_uint8(G_OBEX_HDR_SRM, G_OBEX_SRM_ENABLE);
570         g_obex_packet_prepend_header(pkt, hdr);
571 }
572
573 gboolean g_obex_send(GObex *obex, GObexPacket *pkt, GError **err)
574 {
575         struct pending_pkt *p;
576         gboolean ret;
577
578         g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
579
580         if (obex == NULL || pkt == NULL) {
581                 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_INVALID_ARGS,
582                                 "Invalid arguments");
583                 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
584                 return FALSE;
585         }
586
587         switch (obex->rx_last_op) {
588         case G_OBEX_OP_CONNECT:
589                 prepare_connect_rsp(obex, pkt);
590                 break;
591         case G_OBEX_OP_GET:
592         case G_OBEX_OP_PUT:
593                 prepare_srm_rsp(obex, pkt);
594                 break;
595         }
596
597         p = g_new0(struct pending_pkt, 1);
598         p->pkt = pkt;
599
600         ret = g_obex_send_internal(obex, p, err);
601         if (ret == FALSE)
602                 pending_pkt_free(p);
603
604         return ret;
605 }
606
607 static void prepare_srm_req(GObex *obex, GObexPacket *pkt)
608 {
609         GObexHeader *hdr;
610
611         if (!obex->use_srm)
612                 return;
613
614         if (obex->srm != NULL && obex->srm->enabled)
615                 return;
616
617         hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_SRM);
618         if (hdr != NULL)
619                 return;
620
621         hdr = g_obex_header_new_uint8(G_OBEX_HDR_SRM, G_OBEX_SRM_ENABLE);
622         g_obex_packet_prepend_header(pkt, hdr);
623 }
624
625 guint g_obex_send_req(GObex *obex, GObexPacket *req, gint timeout,
626                         GObexResponseFunc func, gpointer user_data,
627                         GError **err)
628 {
629         GObexHeader *hdr;
630         struct pending_pkt *p;
631         static guint id = 1;
632         guint8 op;
633
634         g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
635
636         op = g_obex_packet_get_operation(req, NULL);
637         if (op == G_OBEX_OP_PUT || op == G_OBEX_OP_GET) {
638                 /* Only enable SRM automatically for GET and PUT */
639                 prepare_srm_req(obex, req);
640         }
641
642         if (obex->conn_id == CONNID_INVALID)
643                 goto create_pending;
644
645         if (obex->rx_last_op == G_OBEX_RSP_CONTINUE)
646                 goto create_pending;
647
648         if (g_obex_srm_active(obex) && obex->pending_req != NULL)
649                 goto create_pending;
650
651         hdr = g_obex_packet_get_header(req, G_OBEX_HDR_CONNECTION);
652         if (hdr != NULL)
653                 goto create_pending;
654
655         hdr = g_obex_header_new_uint32(G_OBEX_HDR_CONNECTION, obex->conn_id);
656         g_obex_packet_prepend_header(req, hdr);
657
658 create_pending:
659         p = g_new0(struct pending_pkt, 1);
660
661         p->pkt = req;
662         p->id = id++;
663         p->rsp_func = func;
664         p->rsp_data = user_data;
665
666         if (timeout < 0)
667                 p->timeout = G_OBEX_DEFAULT_TIMEOUT;
668         else
669                 p->timeout = timeout;
670
671         if (!g_obex_send_internal(obex, p, err)) {
672                 pending_pkt_free(p);
673                 return 0;
674         }
675
676         return p->id;
677 }
678
679 static gint pending_pkt_cmp(gconstpointer a, gconstpointer b)
680 {
681         const struct pending_pkt *p = a;
682         guint id = GPOINTER_TO_UINT(b);
683
684         return (p->id - id);
685 }
686
687 gboolean g_obex_pending_req_abort(GObex *obex, GError **err)
688 {
689         struct pending_pkt *p = obex->pending_req;
690         GObexPacket *req;
691
692         if (p->cancelled)
693                 return TRUE;
694
695         p->cancelled = TRUE;
696
697         g_source_remove(p->timeout_id);
698         p->timeout = G_OBEX_ABORT_TIMEOUT;
699         p->timeout_id = g_timeout_add_seconds(p->timeout, req_timeout, obex);
700
701         req = g_obex_packet_new(G_OBEX_OP_ABORT, TRUE, G_OBEX_HDR_INVALID);
702
703         return g_obex_send(obex, req, err);
704 }
705
706 static gboolean cancel_complete(gpointer user_data)
707 {
708         struct pending_pkt *p = user_data;
709         GObex *obex = p->obex;
710         GError *err;
711
712         g_assert(p->rsp_func != NULL);
713
714         err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
715                                         "The request was cancelled");
716         p->rsp_func(obex, err, NULL, p->rsp_data);
717
718         g_error_free(err);
719
720         pending_pkt_free(p);
721
722         return FALSE;
723 }
724
725 gboolean g_obex_cancel_req(GObex *obex, guint req_id, gboolean remove_callback)
726 {
727         GList *match;
728         struct pending_pkt *p;
729
730         if (obex->pending_req && obex->pending_req->id == req_id) {
731                 if (!g_obex_pending_req_abort(obex, NULL)) {
732                         p = obex->pending_req;
733                         obex->pending_req = NULL;
734                         goto immediate_completion;
735                 }
736
737                 if (remove_callback)
738                         obex->pending_req->rsp_func = NULL;
739
740                 return TRUE;
741         }
742
743         match = g_queue_find_custom(obex->tx_queue, GUINT_TO_POINTER(req_id),
744                                                         pending_pkt_cmp);
745         if (match == NULL)
746                 return FALSE;
747
748         p = match->data;
749
750         g_queue_delete_link(obex->tx_queue, match);
751
752 immediate_completion:
753         p->cancelled = TRUE;
754         p->obex = g_obex_ref(obex);
755
756         if (remove_callback || p->rsp_func == NULL)
757                 pending_pkt_free(p);
758         else
759                 g_idle_add(cancel_complete, p);
760
761         return TRUE;
762 }
763
764 gboolean g_obex_send_rsp(GObex *obex, guint8 rspcode, GError **err,
765                                                 guint8 first_hdr_type, ...)
766 {
767         GObexPacket *rsp;
768         va_list args;
769
770         va_start(args, first_hdr_type);
771         rsp = g_obex_packet_new_valist(rspcode, TRUE, first_hdr_type, args);
772         va_end(args);
773
774         return g_obex_send(obex, rsp, err);
775 }
776
777 void g_obex_set_disconnect_function(GObex *obex, GObexFunc func,
778                                                         gpointer user_data)
779 {
780         obex->disconn_func = func;
781         obex->disconn_func_data = user_data;
782 }
783
784 static gint req_handler_cmpop(gconstpointer a, gconstpointer b)
785 {
786         const struct req_handler *handler = a;
787         guint opcode = GPOINTER_TO_UINT(b);
788
789         return (gint) handler->opcode - (gint) opcode;
790 }
791
792 static gint req_handler_cmpid(gconstpointer a, gconstpointer b)
793 {
794         const struct req_handler *handler = a;
795         guint id = GPOINTER_TO_UINT(b);
796
797         return (gint) handler->id - (gint) id;
798 }
799
800 guint g_obex_add_request_function(GObex *obex, guint8 opcode,
801                                                 GObexRequestFunc func,
802                                                 gpointer user_data)
803 {
804         struct req_handler *handler;
805         static guint next_id = 1;
806
807         handler = g_new0(struct req_handler, 1);
808         handler->id = next_id++;
809         handler->opcode = opcode;
810         handler->func = func;
811         handler->user_data = user_data;
812
813         obex->req_handlers = g_slist_prepend(obex->req_handlers, handler);
814
815         return handler->id;
816 }
817
818 gboolean g_obex_remove_request_function(GObex *obex, guint id)
819 {
820         struct req_handler *handler;
821         GSList *match;
822
823         match = g_slist_find_custom(obex->req_handlers, GUINT_TO_POINTER(id),
824                                                         req_handler_cmpid);
825         if (match == NULL)
826                 return FALSE;
827
828         handler = match->data;
829
830         obex->req_handlers = g_slist_delete_link(obex->req_handlers, match);
831         g_free(handler);
832
833         return TRUE;
834 }
835
836 void g_obex_suspend(GObex *obex)
837 {
838         g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
839
840         if (obex->write_source > 0) {
841                 g_source_remove(obex->write_source);
842                 obex->write_source = 0;
843         }
844
845         obex->suspended = TRUE;
846 }
847
848 void g_obex_resume(GObex *obex)
849 {
850         g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
851
852         obex->suspended = FALSE;
853
854         if (g_queue_get_length(obex->tx_queue) > 0 || obex->tx_data > 0)
855                 enable_tx(obex);
856 }
857
858 gboolean g_obex_srm_active(GObex *obex)
859 {
860         gboolean ret = FALSE;
861
862         if (!obex->use_srm)
863                 return FALSE;
864
865         if (obex->srm == NULL || !obex->srm->enabled)
866                 goto done;
867
868         if (obex->srm->srmp <= G_OBEX_SRMP_NEXT_WAIT)
869                 goto done;
870
871         ret = TRUE;
872 done:
873         g_obex_debug(G_OBEX_DEBUG_COMMAND, "%s", ret ? "yes" : "no");
874         return ret;
875 }
876
877 static void parse_connect_data(GObex *obex, GObexPacket *pkt)
878 {
879         const struct connect_data *data;
880         GObexHeader *connid;
881         guint16 u16;
882         size_t data_len;
883
884         data = g_obex_packet_get_data(pkt, &data_len);
885         if (data == NULL || data_len != sizeof(*data))
886                 return;
887
888         memcpy(&u16, &data->mtu, sizeof(u16));
889
890         obex->tx_mtu = g_ntohs(u16);
891         if (obex->io_tx_mtu > 0 && obex->tx_mtu > obex->io_tx_mtu)
892                 obex->tx_mtu = obex->io_tx_mtu;
893         obex->tx_buf = g_realloc(obex->tx_buf, obex->tx_mtu);
894
895         connid = g_obex_packet_get_header(pkt, G_OBEX_HDR_CONNECTION);
896         if (connid != NULL)
897                 g_obex_header_get_uint32(connid, &obex->conn_id);
898 }
899
900 static gboolean parse_response(GObex *obex, GObexPacket *rsp)
901 {
902         struct pending_pkt *p = obex->pending_req;
903         guint8 opcode, rspcode;
904         gboolean final;
905
906         rspcode = g_obex_packet_get_operation(rsp, &final);
907
908         opcode = g_obex_packet_get_operation(p->pkt, NULL);
909         if (opcode == G_OBEX_OP_CONNECT)
910                 parse_connect_data(obex, rsp);
911
912         setup_srm(obex, rsp, FALSE);
913
914         if (!g_obex_srm_active(obex))
915                 return final;
916
917         /*
918          * Resposes have final bit set but in case of GET with SRM
919          * we should not remove the request since the remote side will
920          * continue sending responses until the transfer is finished
921          */
922         if (opcode == G_OBEX_OP_GET && rspcode == G_OBEX_RSP_CONTINUE) {
923                 g_source_remove(p->timeout_id);
924                 p->timeout_id = g_timeout_add_seconds(p->timeout, req_timeout,
925                                                                         obex);
926                 return FALSE;
927         }
928
929         return final;
930 }
931
932 static void handle_response(GObex *obex, GError *err, GObexPacket *rsp)
933 {
934         struct pending_pkt *p = obex->pending_req;
935         gboolean disconn = err ? TRUE : FALSE, final_rsp = TRUE;
936
937         if (rsp != NULL)
938                 final_rsp = parse_response(obex, rsp);
939
940         if (p->cancelled)
941                 err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
942                                         "The operation was cancelled");
943
944         if (err)
945                 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
946
947         if (p->rsp_func) {
948                 p->rsp_func(obex, err, rsp, p->rsp_data);
949
950                 /* Check if user callback removed the request */
951                 if (p != obex->pending_req)
952                         return;
953         }
954
955         if (p->cancelled)
956                 g_error_free(err);
957
958         if (final_rsp) {
959                 pending_pkt_free(p);
960                 obex->pending_req = NULL;
961         }
962
963         if (!disconn && g_queue_get_length(obex->tx_queue) > 0)
964                 enable_tx(obex);
965 }
966
967 static gboolean check_connid(GObex *obex, GObexPacket *pkt)
968 {
969         GObexHeader *hdr;
970         guint32 id;
971
972         if (obex->conn_id == CONNID_INVALID)
973                 return TRUE;
974
975         hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_CONNECTION);
976         if (hdr == NULL)
977                 return TRUE;
978
979         g_obex_header_get_uint32(hdr, &id);
980
981         return obex->conn_id == id;
982 }
983
984 static int parse_request(GObex *obex, GObexPacket *req)
985 {
986         guint8 op;
987         gboolean final;
988
989         op = g_obex_packet_get_operation(req, &final);
990         switch (op) {
991         case G_OBEX_OP_CONNECT:
992                 parse_connect_data(obex, req);
993                 break;
994         case G_OBEX_OP_ABORT:
995                 break;
996         default:
997                 if (check_connid(obex, req))
998                         break;
999
1000                 return -G_OBEX_RSP_SERVICE_UNAVAILABLE;
1001         }
1002
1003         setup_srm(obex, req, FALSE);
1004
1005         return op;
1006 }
1007
1008 static void handle_request(GObex *obex, GObexPacket *req)
1009 {
1010         GSList *match;
1011         int op;
1012
1013         op = parse_request(obex, req);
1014         if (op < 0)
1015                 goto fail;
1016
1017         match = g_slist_find_custom(obex->req_handlers, GUINT_TO_POINTER(op),
1018                                                         req_handler_cmpop);
1019         if (match) {
1020                 struct req_handler *handler = match->data;
1021                 handler->func(obex, req, handler->user_data);
1022                 return;
1023         }
1024
1025         op = -G_OBEX_RSP_NOT_IMPLEMENTED;
1026
1027 fail:
1028         g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", g_obex_strerror(-op));
1029         g_obex_send_rsp(obex, -op, NULL, G_OBEX_HDR_INVALID);
1030 }
1031
1032 static gboolean read_stream(GObex *obex, GError **err)
1033 {
1034         GIOChannel *io = obex->io;
1035         GIOStatus status;
1036         gsize rbytes, toread;
1037         guint16 u16;
1038         gchar *buf;
1039
1040         if (obex->rx_data >= 3)
1041                 goto read_body;
1042
1043         rbytes = 0;
1044         toread = 3 - obex->rx_data;
1045         buf = (gchar *) &obex->rx_buf[obex->rx_data];
1046
1047         status = g_io_channel_read_chars(io, buf, toread, &rbytes, NULL);
1048         if (status != G_IO_STATUS_NORMAL)
1049                 return TRUE;
1050
1051         obex->rx_data += rbytes;
1052         if (obex->rx_data < 3)
1053                 goto done;
1054
1055         memcpy(&u16, &buf[1], sizeof(u16));
1056         obex->rx_pkt_len = g_ntohs(u16);
1057
1058         if (obex->rx_pkt_len > obex->rx_mtu) {
1059                 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
1060                                 "Too big incoming packet");
1061                 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
1062                 return FALSE;
1063         }
1064
1065 read_body:
1066         if (obex->rx_data >= obex->rx_pkt_len)
1067                 goto done;
1068
1069         do {
1070                 toread = obex->rx_pkt_len - obex->rx_data;
1071                 buf = (gchar *) &obex->rx_buf[obex->rx_data];
1072
1073                 status = g_io_channel_read_chars(io, buf, toread, &rbytes, NULL);
1074                 if (status != G_IO_STATUS_NORMAL)
1075                         goto done;
1076
1077                 obex->rx_data += rbytes;
1078         } while (rbytes > 0 && obex->rx_data < obex->rx_pkt_len);
1079
1080 done:
1081         g_obex_dump(">", obex->rx_buf, obex->rx_data);
1082
1083         return TRUE;
1084 }
1085
1086 static gboolean read_packet(GObex *obex, GError **err)
1087 {
1088         GIOChannel *io = obex->io;
1089         GError *read_err = NULL;
1090         GIOStatus status;
1091         gsize rbytes;
1092         guint16 u16;
1093
1094         if (obex->rx_data > 0) {
1095                 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
1096                                 "RX buffer not empty before reading packet");
1097                 goto fail;
1098         }
1099
1100         status = g_io_channel_read_chars(io, (gchar *) obex->rx_buf,
1101                                         obex->rx_mtu, &rbytes, &read_err);
1102         if (status != G_IO_STATUS_NORMAL) {
1103                 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
1104                                 "Unable to read data: %s", read_err->message);
1105                 g_error_free(read_err);
1106                 goto fail;
1107         }
1108
1109         obex->rx_data += rbytes;
1110
1111         if (rbytes < 3) {
1112                 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
1113                                 "Incomplete packet received");
1114                 goto fail;
1115         }
1116
1117         memcpy(&u16, &obex->rx_buf[1], sizeof(u16));
1118         obex->rx_pkt_len = g_ntohs(u16);
1119
1120         if (obex->rx_pkt_len != rbytes) {
1121                 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
1122                         "Data size doesn't match packet size (%zu != %u)",
1123                         rbytes, obex->rx_pkt_len);
1124                 return FALSE;
1125         }
1126
1127         g_obex_dump(">", obex->rx_buf, obex->rx_data);
1128
1129         return TRUE;
1130 fail:
1131         g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
1132         return FALSE;
1133 }
1134
1135 static gboolean incoming_data(GIOChannel *io, GIOCondition cond,
1136                                                         gpointer user_data)
1137 {
1138         GObex *obex = user_data;
1139         GObexPacket *pkt;
1140         ssize_t header_offset;
1141         GError *err = NULL;
1142         guint8 opcode;
1143
1144         if (cond & G_IO_NVAL)
1145                 return FALSE;
1146
1147         if (cond & (G_IO_HUP | G_IO_ERR)) {
1148                 err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_DISCONNECTED,
1149                                         "Transport got disconnected");
1150                 goto failed;
1151         }
1152
1153         if (!obex->read(obex, &err))
1154                 goto failed;
1155
1156         if (obex->rx_data < 3 || obex->rx_data < obex->rx_pkt_len)
1157                 return TRUE;
1158
1159         obex->rx_last_op = obex->rx_buf[0] & ~FINAL_BIT;
1160
1161         if (obex->pending_req) {
1162                 struct pending_pkt *p = obex->pending_req;
1163                 opcode = g_obex_packet_get_operation(p->pkt, NULL);
1164                 header_offset = rsp_header_offset(opcode);
1165         } else {
1166                 opcode = obex->rx_last_op;
1167                 /* Unexpected response -- fail silently */
1168                 if (opcode > 0x1f && opcode != G_OBEX_OP_ABORT) {
1169                         obex->rx_data = 0;
1170                         return TRUE;
1171                 }
1172                 header_offset = req_header_offset(opcode);
1173         }
1174
1175         if (header_offset < 0) {
1176                 err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
1177                                 "Unknown header offset for opcode 0x%02x",
1178                                 opcode);
1179                 goto failed;
1180         }
1181
1182         pkt = g_obex_packet_decode(obex->rx_buf, obex->rx_data, header_offset,
1183                                                         G_OBEX_DATA_REF, &err);
1184         if (pkt == NULL)
1185                 goto failed;
1186
1187         /* Protect against user callback freeing the object */
1188         g_obex_ref(obex);
1189
1190         if (obex->pending_req)
1191                 handle_response(obex, NULL, pkt);
1192         else
1193                 handle_request(obex, pkt);
1194
1195         obex->rx_data = 0;
1196
1197         g_obex_unref(obex);
1198
1199         if (err != NULL)
1200                 g_error_free(err);
1201
1202         if (pkt != NULL)
1203                 g_obex_packet_free(pkt);
1204
1205         return TRUE;
1206
1207 failed:
1208         if (err)
1209                 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
1210
1211         g_io_channel_unref(obex->io);
1212         obex->io = NULL;
1213         obex->io_source = 0;
1214         obex->rx_data = 0;
1215
1216         /* Protect against user callback freeing the object */
1217         g_obex_ref(obex);
1218
1219         if (obex->pending_req)
1220                 handle_response(obex, err, NULL);
1221
1222         if (obex->disconn_func)
1223                 obex->disconn_func(obex, err, obex->disconn_func_data);
1224
1225         g_obex_unref(obex);
1226
1227         g_error_free(err);
1228
1229         return FALSE;
1230 }
1231
1232 static GDebugKey keys[] = {
1233         { "error",      G_OBEX_DEBUG_ERROR },
1234         { "command",    G_OBEX_DEBUG_COMMAND },
1235         { "transfer",   G_OBEX_DEBUG_TRANSFER },
1236         { "header",     G_OBEX_DEBUG_HEADER },
1237         { "packet",     G_OBEX_DEBUG_PACKET },
1238         { "data",       G_OBEX_DEBUG_DATA },
1239 };
1240
1241 GObex *g_obex_new(GIOChannel *io, GObexTransportType transport_type,
1242                                         gssize io_rx_mtu, gssize io_tx_mtu)
1243 {
1244         GObex *obex;
1245         GIOCondition cond;
1246
1247         if (gobex_debug == 0) {
1248                 const char *env = g_getenv("GOBEX_DEBUG");
1249                 if (env)
1250                         gobex_debug = g_parse_debug_string(env, keys, 6);
1251                 else
1252                         gobex_debug = G_OBEX_DEBUG_NONE;
1253         }
1254
1255         g_obex_debug(G_OBEX_DEBUG_COMMAND, "");
1256
1257         if (io == NULL)
1258                 return NULL;
1259
1260         if (io_rx_mtu >= 0 && io_rx_mtu < G_OBEX_MINIMUM_MTU)
1261                 return NULL;
1262
1263         if (io_tx_mtu >= 0 && io_tx_mtu < G_OBEX_MINIMUM_MTU)
1264                 return NULL;
1265
1266         obex = g_new0(GObex, 1);
1267
1268         obex->io = g_io_channel_ref(io);
1269         obex->ref_count = 1;
1270         obex->conn_id = CONNID_INVALID;
1271         obex->rx_last_op = G_OBEX_OP_NONE;
1272
1273         obex->io_rx_mtu = io_rx_mtu;
1274         obex->io_tx_mtu = io_tx_mtu;
1275
1276         if (io_rx_mtu > G_OBEX_MAXIMUM_MTU)
1277                 obex->rx_mtu = G_OBEX_MAXIMUM_MTU;
1278         else if (io_rx_mtu < G_OBEX_MINIMUM_MTU)
1279                 obex->rx_mtu = G_OBEX_DEFAULT_MTU;
1280         else
1281                 obex->rx_mtu = io_rx_mtu;
1282
1283         obex->tx_mtu = G_OBEX_MINIMUM_MTU;
1284
1285         obex->tx_queue = g_queue_new();
1286         obex->rx_buf = g_malloc(obex->rx_mtu);
1287         obex->tx_buf = g_malloc(obex->tx_mtu);
1288
1289         switch (transport_type) {
1290         case G_OBEX_TRANSPORT_STREAM:
1291                 obex->read = read_stream;
1292                 obex->write = write_stream;
1293                 break;
1294         case G_OBEX_TRANSPORT_PACKET:
1295                 obex->use_srm = TRUE;
1296                 obex->read = read_packet;
1297                 obex->write = write_packet;
1298                 break;
1299         default:
1300                 g_obex_unref(obex);
1301                 return NULL;
1302         }
1303
1304         g_io_channel_set_encoding(io, NULL, NULL);
1305         g_io_channel_set_buffered(io, FALSE);
1306         cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
1307         obex->io_source = g_io_add_watch(io, cond, incoming_data, obex);
1308
1309         return obex;
1310 }
1311
1312 GObex *g_obex_ref(GObex *obex)
1313 {
1314         if (obex == NULL)
1315                 return NULL;
1316
1317         g_atomic_int_inc(&obex->ref_count);
1318
1319         g_obex_debug(G_OBEX_DEBUG_COMMAND, "ref %u", obex->ref_count);
1320
1321         return obex;
1322 }
1323
1324 void g_obex_unref(GObex *obex)
1325 {
1326         gboolean last_ref;
1327
1328         last_ref = g_atomic_int_dec_and_test(&obex->ref_count);
1329
1330         g_obex_debug(G_OBEX_DEBUG_COMMAND, "ref %u", obex->ref_count);
1331
1332         if (!last_ref)
1333                 return;
1334
1335         g_slist_free_full(obex->req_handlers, g_free);
1336
1337         g_queue_foreach(obex->tx_queue, (GFunc) pending_pkt_free, NULL);
1338         g_queue_free(obex->tx_queue);
1339
1340         if (obex->io != NULL)
1341                 g_io_channel_unref(obex->io);
1342
1343         if (obex->io_source > 0)
1344                 g_source_remove(obex->io_source);
1345
1346         if (obex->write_source > 0)
1347                 g_source_remove(obex->write_source);
1348
1349         g_free(obex->rx_buf);
1350         g_free(obex->tx_buf);
1351         g_free(obex->srm);
1352
1353         if (obex->pending_req)
1354                 pending_pkt_free(obex->pending_req);
1355
1356         g_free(obex);
1357 }
1358
1359 /* Higher level functions */
1360
1361 guint g_obex_connect(GObex *obex, GObexResponseFunc func, gpointer user_data,
1362                                         GError **err, guint8 first_hdr_id, ...)
1363 {
1364         GObexPacket *req;
1365         struct connect_data data;
1366         va_list args;
1367
1368         g_obex_debug(G_OBEX_DEBUG_COMMAND, "");
1369
1370         va_start(args, first_hdr_id);
1371         req = g_obex_packet_new_valist(G_OBEX_OP_CONNECT, TRUE,
1372                                                         first_hdr_id, args);
1373         va_end(args);
1374
1375         init_connect_data(obex, &data);
1376         g_obex_packet_set_data(req, &data, sizeof(data), G_OBEX_DATA_COPY);
1377
1378         return g_obex_send_req(obex, req, -1, func, user_data, err);
1379 }
1380
1381 guint g_obex_setpath(GObex *obex, const char *path, GObexResponseFunc func,
1382                                         gpointer user_data, GError **err)
1383 {
1384         GObexPacket *req;
1385         struct setpath_data data;
1386         const char *folder;
1387
1388         g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
1389
1390         req = g_obex_packet_new(G_OBEX_OP_SETPATH, TRUE, G_OBEX_HDR_INVALID);
1391
1392         memset(&data, 0, sizeof(data));
1393
1394         if (path != NULL && strncmp("..", path, 2) == 0) {
1395                 data.flags = 0x03;
1396                 folder = (path[2] == '/') ? &path[3] : NULL;
1397         } else {
1398                 data.flags = 0x02;
1399                 folder = path;
1400         }
1401
1402         if (folder != NULL) {
1403                 GObexHeader *hdr;
1404                 hdr = g_obex_header_new_unicode(G_OBEX_HDR_NAME, folder);
1405                 g_obex_packet_add_header(req, hdr);
1406         }
1407
1408         g_obex_packet_set_data(req, &data, sizeof(data), G_OBEX_DATA_COPY);
1409
1410         return g_obex_send_req(obex, req, -1, func, user_data, err);
1411 }
1412
1413 guint g_obex_mkdir(GObex *obex, const char *path, GObexResponseFunc func,
1414                                         gpointer user_data, GError **err)
1415 {
1416         GObexPacket *req;
1417         struct setpath_data data;
1418
1419         g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
1420
1421         req = g_obex_packet_new(G_OBEX_OP_SETPATH, TRUE, G_OBEX_HDR_NAME, path,
1422                                                         G_OBEX_HDR_INVALID);
1423
1424         memset(&data, 0, sizeof(data));
1425         g_obex_packet_set_data(req, &data, sizeof(data), G_OBEX_DATA_COPY);
1426
1427         return g_obex_send_req(obex, req, -1, func, user_data, err);
1428 }
1429
1430 guint g_obex_delete(GObex *obex, const char *name, GObexResponseFunc func,
1431                                         gpointer user_data, GError **err)
1432 {
1433         GObexPacket *req;
1434
1435         g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
1436
1437         req = g_obex_packet_new(G_OBEX_OP_PUT, TRUE, G_OBEX_HDR_NAME, name,
1438                                                         G_OBEX_HDR_INVALID);
1439
1440         return g_obex_send_req(obex, req, -1, func, user_data, err);
1441 }
1442
1443 guint g_obex_copy(GObex *obex, const char *name, const char *dest,
1444                         GObexResponseFunc func, gpointer user_data,
1445                         GError **err)
1446 {
1447         GObexPacket *req;
1448
1449         g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
1450
1451         req = g_obex_packet_new(G_OBEX_OP_ACTION, TRUE,
1452                                         G_OBEX_HDR_ACTION, G_OBEX_ACTION_COPY,
1453                                         G_OBEX_HDR_NAME, name,
1454                                         G_OBEX_HDR_DESTNAME, dest,
1455                                         G_OBEX_HDR_INVALID);
1456
1457         return g_obex_send_req(obex, req, -1, func, user_data, err);
1458 }
1459
1460 guint g_obex_move(GObex *obex, const char *name, const char *dest,
1461                         GObexResponseFunc func, gpointer user_data,
1462                         GError **err)
1463 {
1464         GObexPacket *req;
1465
1466         g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
1467
1468         req = g_obex_packet_new(G_OBEX_OP_ACTION, TRUE,
1469                                         G_OBEX_HDR_ACTION, G_OBEX_ACTION_MOVE,
1470                                         G_OBEX_HDR_NAME, name,
1471                                         G_OBEX_HDR_DESTNAME, dest,
1472                                         G_OBEX_HDR_INVALID);
1473
1474         return g_obex_send_req(obex, req, -1, func, user_data, err);
1475 }
1476
1477 guint8 g_obex_errno_to_rsp(int err)
1478 {
1479         switch (err) {
1480         case 0:
1481                 return G_OBEX_RSP_SUCCESS;
1482         case -EPERM:
1483         case -EACCES:
1484                 return G_OBEX_RSP_FORBIDDEN;
1485         case -ENOENT:
1486                 return G_OBEX_RSP_NOT_FOUND;
1487         case -EINVAL:
1488         case -EBADR:
1489                 return G_OBEX_RSP_BAD_REQUEST;
1490         case -EFAULT:
1491                 return G_OBEX_RSP_SERVICE_UNAVAILABLE;
1492         case -ENOSYS:
1493                 return G_OBEX_RSP_NOT_IMPLEMENTED;
1494         case -ENOTEMPTY:
1495         case -EEXIST:
1496                 return G_OBEX_RSP_PRECONDITION_FAILED;
1497         default:
1498                 return G_OBEX_RSP_INTERNAL_SERVER_ERROR;
1499         }
1500 }