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