/src/bluez/gobex/gobex-transfer.c
Line | Count | Source (jump to first uncovered line) |
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 <string.h> |
15 | | #include <errno.h> |
16 | | |
17 | | #include "gobex/gobex.h" |
18 | | #include "gobex/gobex-debug.h" |
19 | | |
20 | 0 | #define FIRST_PACKET_TIMEOUT 60 |
21 | | |
22 | | static GSList *transfers = NULL; |
23 | | |
24 | | static void transfer_response(GObex *obex, GError *err, GObexPacket *rsp, |
25 | | gpointer user_data); |
26 | | |
27 | | struct transfer { |
28 | | guint id; |
29 | | guint8 opcode; |
30 | | |
31 | | GObex *obex; |
32 | | |
33 | | guint req_id; |
34 | | |
35 | | guint put_id; |
36 | | guint get_id; |
37 | | guint abort_id; |
38 | | |
39 | | GObexDataProducer data_producer; |
40 | | GObexDataConsumer data_consumer; |
41 | | GObexFunc complete_func; |
42 | | |
43 | | gpointer user_data; |
44 | | }; |
45 | | |
46 | | static void transfer_free(struct transfer *transfer) |
47 | 0 | { |
48 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id); |
49 | |
|
50 | 0 | transfers = g_slist_remove(transfers, transfer); |
51 | |
|
52 | 0 | if (transfer->req_id > 0) |
53 | 0 | g_obex_cancel_req(transfer->obex, transfer->req_id, TRUE); |
54 | |
|
55 | 0 | if (transfer->put_id > 0) |
56 | 0 | g_obex_remove_request_function(transfer->obex, |
57 | 0 | transfer->put_id); |
58 | |
|
59 | 0 | if (transfer->get_id > 0) |
60 | 0 | g_obex_remove_request_function(transfer->obex, |
61 | 0 | transfer->get_id); |
62 | |
|
63 | 0 | if (transfer->abort_id > 0) |
64 | 0 | g_obex_remove_request_function(transfer->obex, |
65 | 0 | transfer->abort_id); |
66 | |
|
67 | 0 | g_obex_unref(transfer->obex); |
68 | 0 | g_free(transfer); |
69 | 0 | } |
70 | | |
71 | | static struct transfer *find_transfer(guint id) |
72 | 0 | { |
73 | 0 | GSList *l; |
74 | |
|
75 | 0 | for (l = transfers; l != NULL; l = g_slist_next(l)) { |
76 | 0 | struct transfer *t = l->data; |
77 | 0 | if (t->id == id) |
78 | 0 | return t; |
79 | 0 | } |
80 | | |
81 | 0 | return NULL; |
82 | 0 | } |
83 | | |
84 | | static void transfer_complete(struct transfer *transfer, GError *err) |
85 | 0 | { |
86 | 0 | guint id = transfer->id; |
87 | |
|
88 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", id); |
89 | |
|
90 | 0 | if (err) { |
91 | | /* No further tx must be performed */ |
92 | 0 | g_obex_drop_tx_queue(transfer->obex); |
93 | 0 | } |
94 | |
|
95 | 0 | transfer->complete_func(transfer->obex, err, transfer->user_data); |
96 | | /* Check if the complete_func removed the transfer */ |
97 | 0 | if (find_transfer(id) == NULL) |
98 | 0 | return; |
99 | | |
100 | 0 | transfer_free(transfer); |
101 | 0 | } |
102 | | |
103 | | static void transfer_abort_response(GObex *obex, GError *err, GObexPacket *rsp, |
104 | | gpointer user_data) |
105 | 0 | { |
106 | 0 | struct transfer *transfer = user_data; |
107 | |
|
108 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id); |
109 | |
|
110 | 0 | transfer->req_id = 0; |
111 | | |
112 | | /* Intentionally override error */ |
113 | 0 | err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED, |
114 | 0 | "Operation was aborted"); |
115 | 0 | g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message); |
116 | 0 | transfer_complete(transfer, err); |
117 | 0 | g_error_free(err); |
118 | 0 | } |
119 | | |
120 | | |
121 | | static gssize put_get_data(void *buf, gsize len, gpointer user_data) |
122 | 0 | { |
123 | 0 | struct transfer *transfer = user_data; |
124 | 0 | GObexPacket *req; |
125 | 0 | GError *err = NULL; |
126 | 0 | gssize ret; |
127 | |
|
128 | 0 | ret = transfer->data_producer(buf, len, transfer->user_data); |
129 | 0 | if (ret == 0 || ret == -EAGAIN) |
130 | 0 | return ret; |
131 | | |
132 | 0 | if (ret > 0) { |
133 | | /* Check if SRM is active */ |
134 | 0 | if (!g_obex_srm_active(transfer->obex)) |
135 | 0 | return ret; |
136 | | |
137 | | /* Generate next packet */ |
138 | 0 | req = g_obex_packet_new(transfer->opcode, FALSE, |
139 | 0 | G_OBEX_HDR_INVALID); |
140 | 0 | g_obex_packet_add_body(req, put_get_data, transfer); |
141 | 0 | transfer->req_id = g_obex_send_req(transfer->obex, req, -1, |
142 | 0 | transfer_response, transfer, |
143 | 0 | &err); |
144 | 0 | goto done; |
145 | 0 | } |
146 | | |
147 | 0 | transfer->req_id = g_obex_abort(transfer->obex, transfer_abort_response, |
148 | 0 | transfer, &err); |
149 | 0 | done: |
150 | 0 | if (err != NULL) { |
151 | 0 | transfer_complete(transfer, err); |
152 | 0 | g_error_free(err); |
153 | 0 | } |
154 | |
|
155 | 0 | return ret; |
156 | 0 | } |
157 | | |
158 | | static gboolean handle_get_body(struct transfer *transfer, GObexPacket *rsp, |
159 | | GError **err) |
160 | 0 | { |
161 | 0 | GObexHeader *body = g_obex_packet_get_body(rsp); |
162 | 0 | gboolean ret; |
163 | 0 | const guint8 *buf; |
164 | 0 | gsize len; |
165 | |
|
166 | 0 | if (body == NULL) |
167 | 0 | return TRUE; |
168 | | |
169 | 0 | g_obex_header_get_bytes(body, &buf, &len); |
170 | 0 | if (len == 0) |
171 | 0 | return TRUE; |
172 | | |
173 | 0 | ret = transfer->data_consumer(buf, len, transfer->user_data); |
174 | 0 | if (ret == FALSE) |
175 | 0 | g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED, |
176 | 0 | "Data consumer callback failed"); |
177 | |
|
178 | 0 | return ret; |
179 | 0 | } |
180 | | |
181 | | static void transfer_response(GObex *obex, GError *err, GObexPacket *rsp, |
182 | | gpointer user_data) |
183 | 0 | { |
184 | 0 | struct transfer *transfer = user_data; |
185 | 0 | GObexPacket *req; |
186 | 0 | gboolean rspcode, final; |
187 | 0 | guint id; |
188 | |
|
189 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id); |
190 | |
|
191 | 0 | id = transfer->req_id; |
192 | 0 | transfer->req_id = 0; |
193 | |
|
194 | 0 | if (err != NULL) { |
195 | 0 | transfer_complete(transfer, err); |
196 | 0 | return; |
197 | 0 | } |
198 | | |
199 | 0 | rspcode = g_obex_packet_get_operation(rsp, &final); |
200 | 0 | if (rspcode != G_OBEX_RSP_SUCCESS && rspcode != G_OBEX_RSP_CONTINUE) { |
201 | 0 | err = g_error_new(G_OBEX_ERROR, rspcode, "%s", |
202 | 0 | g_obex_strerror(rspcode)); |
203 | 0 | goto failed; |
204 | 0 | } |
205 | | |
206 | 0 | if (transfer->opcode == G_OBEX_OP_GET) { |
207 | 0 | handle_get_body(transfer, rsp, &err); |
208 | 0 | if (err != NULL) |
209 | 0 | goto failed; |
210 | 0 | } |
211 | | |
212 | 0 | if (rspcode == G_OBEX_RSP_SUCCESS) { |
213 | 0 | transfer_complete(transfer, NULL); |
214 | 0 | return; |
215 | 0 | } |
216 | | |
217 | 0 | if (transfer->opcode == G_OBEX_OP_PUT) { |
218 | 0 | req = g_obex_packet_new(transfer->opcode, FALSE, |
219 | 0 | G_OBEX_HDR_INVALID); |
220 | 0 | g_obex_packet_add_body(req, put_get_data, transfer); |
221 | 0 | } else if (!g_obex_srm_active(transfer->obex)) { |
222 | 0 | req = g_obex_packet_new(transfer->opcode, TRUE, |
223 | 0 | G_OBEX_HDR_INVALID); |
224 | 0 | } else { |
225 | | /* Keep id since request still outstanting */ |
226 | 0 | transfer->req_id = id; |
227 | 0 | return; |
228 | 0 | } |
229 | | |
230 | 0 | transfer->req_id = g_obex_send_req(obex, req, -1, transfer_response, |
231 | 0 | transfer, &err); |
232 | 0 | failed: |
233 | 0 | if (err != NULL) { |
234 | 0 | g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message); |
235 | 0 | transfer_complete(transfer, err); |
236 | 0 | g_error_free(err); |
237 | 0 | } |
238 | 0 | } |
239 | | |
240 | | static struct transfer *transfer_new(GObex *obex, guint8 opcode, |
241 | | GObexFunc complete_func, gpointer user_data) |
242 | 0 | { |
243 | 0 | static guint next_id = 1; |
244 | 0 | struct transfer *transfer; |
245 | |
|
246 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p opcode %u", obex, opcode); |
247 | |
|
248 | 0 | transfer = g_new0(struct transfer, 1); |
249 | |
|
250 | 0 | transfer->id = next_id++; |
251 | 0 | transfer->opcode = opcode; |
252 | 0 | transfer->obex = g_obex_ref(obex); |
253 | 0 | transfer->complete_func = complete_func; |
254 | 0 | transfer->user_data = user_data; |
255 | |
|
256 | 0 | transfers = g_slist_append(transfers, transfer); |
257 | |
|
258 | 0 | return transfer; |
259 | 0 | } |
260 | | |
261 | | guint g_obex_put_req_pkt(GObex *obex, GObexPacket *req, |
262 | | GObexDataProducer data_func, GObexFunc complete_func, |
263 | | gpointer user_data, GError **err) |
264 | 0 | { |
265 | 0 | struct transfer *transfer; |
266 | |
|
267 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex); |
268 | |
|
269 | 0 | if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_PUT) |
270 | 0 | return 0; |
271 | | |
272 | 0 | transfer = transfer_new(obex, G_OBEX_OP_PUT, complete_func, user_data); |
273 | 0 | transfer->data_producer = data_func; |
274 | |
|
275 | 0 | g_obex_packet_add_body(req, put_get_data, transfer); |
276 | |
|
277 | 0 | transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT, |
278 | 0 | transfer_response, transfer, err); |
279 | 0 | if (transfer->req_id == 0) { |
280 | 0 | transfer_free(transfer); |
281 | 0 | return 0; |
282 | 0 | } |
283 | | |
284 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id); |
285 | |
|
286 | 0 | return transfer->id; |
287 | 0 | } |
288 | | |
289 | | guint g_obex_put_req(GObex *obex, GObexDataProducer data_func, |
290 | | GObexFunc complete_func, gpointer user_data, |
291 | | GError **err, guint first_hdr_id, ...) |
292 | 0 | { |
293 | 0 | GObexPacket *req; |
294 | 0 | va_list args; |
295 | |
|
296 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex); |
297 | |
|
298 | 0 | va_start(args, first_hdr_id); |
299 | 0 | req = g_obex_packet_new_valist(G_OBEX_OP_PUT, FALSE, |
300 | 0 | first_hdr_id, args); |
301 | 0 | va_end(args); |
302 | |
|
303 | 0 | return g_obex_put_req_pkt(obex, req, data_func, complete_func, |
304 | 0 | user_data, err); |
305 | 0 | } |
306 | | |
307 | | static void transfer_abort_req(GObex *obex, GObexPacket *req, gpointer user_data) |
308 | 0 | { |
309 | 0 | struct transfer *transfer = user_data; |
310 | 0 | GObexPacket *rsp; |
311 | 0 | GError *err; |
312 | |
|
313 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id); |
314 | |
|
315 | 0 | err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED, |
316 | 0 | "Request was aborted"); |
317 | 0 | rsp = g_obex_packet_new(G_OBEX_RSP_SUCCESS, TRUE, G_OBEX_HDR_INVALID); |
318 | 0 | g_obex_send(obex, rsp, NULL); |
319 | |
|
320 | 0 | transfer_complete(transfer, err); |
321 | 0 | g_error_free(err); |
322 | 0 | } |
323 | | |
324 | | static guint8 put_get_bytes(struct transfer *transfer, GObexPacket *req) |
325 | 0 | { |
326 | 0 | GObexHeader *body; |
327 | 0 | gboolean final; |
328 | 0 | guint8 rsp; |
329 | 0 | const guint8 *buf; |
330 | 0 | gsize len; |
331 | |
|
332 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id); |
333 | |
|
334 | 0 | g_obex_packet_get_operation(req, &final); |
335 | 0 | if (final) |
336 | 0 | rsp = G_OBEX_RSP_SUCCESS; |
337 | 0 | else |
338 | 0 | rsp = G_OBEX_RSP_CONTINUE; |
339 | |
|
340 | 0 | body = g_obex_packet_get_body(req); |
341 | 0 | if (body == NULL) |
342 | 0 | return rsp; |
343 | | |
344 | 0 | g_obex_header_get_bytes(body, &buf, &len); |
345 | 0 | if (len == 0) |
346 | 0 | return rsp; |
347 | | |
348 | 0 | if (transfer->data_consumer(buf, len, transfer->user_data) == FALSE) |
349 | 0 | rsp = G_OBEX_RSP_FORBIDDEN; |
350 | |
|
351 | 0 | return rsp; |
352 | 0 | } |
353 | | |
354 | | static void transfer_put_req_first(struct transfer *transfer, GObexPacket *req, |
355 | | guint8 first_hdr_id, va_list args) |
356 | 0 | { |
357 | 0 | GError *err = NULL; |
358 | 0 | GObexPacket *rsp; |
359 | 0 | guint8 rspcode; |
360 | |
|
361 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id); |
362 | |
|
363 | 0 | rspcode = put_get_bytes(transfer, req); |
364 | |
|
365 | 0 | rsp = g_obex_packet_new_valist(rspcode, TRUE, first_hdr_id, args); |
366 | |
|
367 | 0 | if (!g_obex_send(transfer->obex, rsp, &err)) { |
368 | 0 | transfer_complete(transfer, err); |
369 | 0 | g_error_free(err); |
370 | 0 | return; |
371 | 0 | } |
372 | | |
373 | 0 | if (rspcode != G_OBEX_RSP_CONTINUE) |
374 | 0 | transfer_complete(transfer, NULL); |
375 | 0 | } |
376 | | |
377 | | static void transfer_put_req(GObex *obex, GObexPacket *req, gpointer user_data) |
378 | 0 | { |
379 | 0 | struct transfer *transfer = user_data; |
380 | 0 | GError *err = NULL; |
381 | 0 | GObexPacket *rsp; |
382 | 0 | guint8 rspcode; |
383 | |
|
384 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id); |
385 | |
|
386 | 0 | rspcode = put_get_bytes(transfer, req); |
387 | | |
388 | | /* Don't send continue while SRM is active */ |
389 | 0 | if (g_obex_srm_active(transfer->obex) && |
390 | 0 | rspcode == G_OBEX_RSP_CONTINUE) |
391 | 0 | goto done; |
392 | | |
393 | 0 | rsp = g_obex_packet_new(rspcode, TRUE, G_OBEX_HDR_INVALID); |
394 | |
|
395 | 0 | if (!g_obex_send(obex, rsp, &err)) { |
396 | 0 | transfer_complete(transfer, err); |
397 | 0 | g_error_free(err); |
398 | 0 | return; |
399 | 0 | } |
400 | | |
401 | 0 | done: |
402 | 0 | if (rspcode != G_OBEX_RSP_CONTINUE) |
403 | 0 | transfer_complete(transfer, NULL); |
404 | 0 | } |
405 | | |
406 | | guint g_obex_put_rsp(GObex *obex, GObexPacket *req, |
407 | | GObexDataConsumer data_func, GObexFunc complete_func, |
408 | | gpointer user_data, GError **err, |
409 | | guint first_hdr_id, ...) |
410 | 0 | { |
411 | 0 | struct transfer *transfer; |
412 | 0 | va_list args; |
413 | 0 | guint id; |
414 | |
|
415 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex); |
416 | |
|
417 | 0 | transfer = transfer_new(obex, G_OBEX_OP_PUT, complete_func, user_data); |
418 | 0 | transfer->data_consumer = data_func; |
419 | |
|
420 | 0 | va_start(args, first_hdr_id); |
421 | 0 | transfer_put_req_first(transfer, req, first_hdr_id, args); |
422 | 0 | va_end(args); |
423 | 0 | if (!g_slist_find(transfers, transfer)) |
424 | 0 | return 0; |
425 | | |
426 | 0 | id = g_obex_add_request_function(obex, G_OBEX_OP_PUT, transfer_put_req, |
427 | 0 | transfer); |
428 | 0 | transfer->put_id = id; |
429 | |
|
430 | 0 | id = g_obex_add_request_function(obex, G_OBEX_OP_ABORT, |
431 | 0 | transfer_abort_req, transfer); |
432 | 0 | transfer->abort_id = id; |
433 | |
|
434 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id); |
435 | |
|
436 | 0 | return transfer->id; |
437 | 0 | } |
438 | | |
439 | | guint g_obex_get_req_pkt(GObex *obex, GObexPacket *req, |
440 | | GObexDataConsumer data_func, GObexFunc complete_func, |
441 | | gpointer user_data, GError **err) |
442 | 0 | { |
443 | 0 | struct transfer *transfer; |
444 | |
|
445 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex); |
446 | |
|
447 | 0 | if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_GET) |
448 | 0 | return 0; |
449 | | |
450 | 0 | transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data); |
451 | 0 | transfer->data_consumer = data_func; |
452 | 0 | transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT, |
453 | 0 | transfer_response, transfer, err); |
454 | 0 | if (transfer->req_id == 0) { |
455 | 0 | transfer_free(transfer); |
456 | 0 | return 0; |
457 | 0 | } |
458 | | |
459 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id); |
460 | |
|
461 | 0 | return transfer->id; |
462 | 0 | } |
463 | | |
464 | | guint g_obex_get_req(GObex *obex, GObexDataConsumer data_func, |
465 | | GObexFunc complete_func, gpointer user_data, |
466 | | GError **err, guint first_hdr_id, ...) |
467 | 0 | { |
468 | 0 | struct transfer *transfer; |
469 | 0 | GObexPacket *req; |
470 | 0 | va_list args; |
471 | |
|
472 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex); |
473 | |
|
474 | 0 | transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data); |
475 | 0 | transfer->data_consumer = data_func; |
476 | |
|
477 | 0 | va_start(args, first_hdr_id); |
478 | 0 | req = g_obex_packet_new_valist(G_OBEX_OP_GET, TRUE, |
479 | 0 | first_hdr_id, args); |
480 | 0 | va_end(args); |
481 | |
|
482 | 0 | transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT, |
483 | 0 | transfer_response, transfer, err); |
484 | 0 | if (transfer->req_id == 0) { |
485 | 0 | transfer_free(transfer); |
486 | 0 | return 0; |
487 | 0 | } |
488 | | |
489 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id); |
490 | |
|
491 | 0 | return transfer->id; |
492 | 0 | } |
493 | | |
494 | | static gssize get_get_data(void *buf, gsize len, gpointer user_data) |
495 | 0 | { |
496 | 0 | struct transfer *transfer = user_data; |
497 | 0 | GObexPacket *req, *rsp; |
498 | 0 | GError *err = NULL; |
499 | 0 | gssize ret; |
500 | 0 | guint8 op; |
501 | |
|
502 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id); |
503 | |
|
504 | 0 | ret = transfer->data_producer(buf, len, transfer->user_data); |
505 | 0 | if (ret > 0) { |
506 | 0 | if (!g_obex_srm_active(transfer->obex)) |
507 | 0 | return ret; |
508 | | |
509 | | /* Generate next response */ |
510 | 0 | rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE, |
511 | 0 | G_OBEX_HDR_INVALID); |
512 | 0 | g_obex_packet_add_body(rsp, get_get_data, transfer); |
513 | |
|
514 | 0 | if (!g_obex_send(transfer->obex, rsp, &err)) { |
515 | 0 | transfer_complete(transfer, err); |
516 | 0 | g_error_free(err); |
517 | 0 | } |
518 | |
|
519 | 0 | return ret; |
520 | 0 | } |
521 | | |
522 | 0 | if (ret == -EAGAIN) |
523 | 0 | return ret; |
524 | | |
525 | 0 | if (ret == 0) { |
526 | 0 | transfer_complete(transfer, NULL); |
527 | 0 | return ret; |
528 | 0 | } |
529 | | |
530 | 0 | op = g_obex_errno_to_rsp(ret); |
531 | |
|
532 | 0 | req = g_obex_packet_new(op, TRUE, G_OBEX_HDR_INVALID); |
533 | 0 | g_obex_send(transfer->obex, req, NULL); |
534 | |
|
535 | 0 | err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED, |
536 | 0 | "Data producer function failed"); |
537 | 0 | g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message); |
538 | 0 | transfer_complete(transfer, err); |
539 | 0 | g_error_free(err); |
540 | |
|
541 | 0 | return ret; |
542 | 0 | } |
543 | | |
544 | | static gboolean transfer_get_req_first(struct transfer *transfer, |
545 | | GObexPacket *rsp) |
546 | 0 | { |
547 | 0 | GError *err = NULL; |
548 | |
|
549 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id); |
550 | |
|
551 | 0 | g_obex_packet_add_body(rsp, get_get_data, transfer); |
552 | |
|
553 | 0 | if (!g_obex_send(transfer->obex, rsp, &err)) { |
554 | 0 | transfer_complete(transfer, err); |
555 | 0 | g_error_free(err); |
556 | 0 | return FALSE; |
557 | 0 | } |
558 | | |
559 | 0 | return TRUE; |
560 | 0 | } |
561 | | |
562 | | static void transfer_get_req(GObex *obex, GObexPacket *req, gpointer user_data) |
563 | 0 | { |
564 | 0 | struct transfer *transfer = user_data; |
565 | 0 | GError *err = NULL; |
566 | 0 | GObexPacket *rsp; |
567 | |
|
568 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id); |
569 | |
|
570 | 0 | rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE, G_OBEX_HDR_INVALID); |
571 | 0 | g_obex_packet_add_body(rsp, get_get_data, transfer); |
572 | |
|
573 | 0 | if (!g_obex_send(obex, rsp, &err)) { |
574 | 0 | transfer_complete(transfer, err); |
575 | 0 | g_error_free(err); |
576 | 0 | } |
577 | 0 | } |
578 | | |
579 | | guint g_obex_get_rsp_pkt(GObex *obex, GObexPacket *rsp, |
580 | | GObexDataProducer data_func, GObexFunc complete_func, |
581 | | gpointer user_data, GError **err) |
582 | 0 | { |
583 | 0 | struct transfer *transfer; |
584 | 0 | guint id; |
585 | |
|
586 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex); |
587 | |
|
588 | 0 | transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data); |
589 | 0 | transfer->data_producer = data_func; |
590 | |
|
591 | 0 | if (!transfer_get_req_first(transfer, rsp)) |
592 | 0 | return 0; |
593 | | |
594 | 0 | if (!g_slist_find(transfers, transfer)) |
595 | 0 | return 0; |
596 | | |
597 | 0 | id = g_obex_add_request_function(obex, G_OBEX_OP_GET, transfer_get_req, |
598 | 0 | transfer); |
599 | 0 | transfer->get_id = id; |
600 | |
|
601 | 0 | id = g_obex_add_request_function(obex, G_OBEX_OP_ABORT, |
602 | 0 | transfer_abort_req, transfer); |
603 | 0 | transfer->abort_id = id; |
604 | |
|
605 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id); |
606 | |
|
607 | 0 | return transfer->id; |
608 | 0 | } |
609 | | |
610 | | guint g_obex_get_rsp(GObex *obex, GObexDataProducer data_func, |
611 | | GObexFunc complete_func, gpointer user_data, |
612 | | GError **err, guint first_hdr_id, ...) |
613 | 0 | { |
614 | 0 | GObexPacket *rsp; |
615 | 0 | va_list args; |
616 | |
|
617 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex); |
618 | |
|
619 | 0 | va_start(args, first_hdr_id); |
620 | 0 | rsp = g_obex_packet_new_valist(G_OBEX_RSP_CONTINUE, TRUE, |
621 | 0 | first_hdr_id, args); |
622 | 0 | va_end(args); |
623 | |
|
624 | 0 | return g_obex_get_rsp_pkt(obex, rsp, data_func, complete_func, |
625 | 0 | user_data, err); |
626 | 0 | } |
627 | | |
628 | | gboolean g_obex_cancel_transfer(guint id, GObexFunc complete_func, |
629 | | gpointer user_data) |
630 | 0 | { |
631 | 0 | struct transfer *transfer = NULL; |
632 | 0 | gboolean ret = TRUE; |
633 | |
|
634 | 0 | g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", id); |
635 | |
|
636 | 0 | transfer = find_transfer(id); |
637 | |
|
638 | 0 | if (transfer == NULL) |
639 | 0 | return FALSE; |
640 | | |
641 | 0 | if (complete_func == NULL) |
642 | 0 | goto done; |
643 | | |
644 | 0 | transfer->complete_func = complete_func; |
645 | 0 | transfer->user_data = user_data; |
646 | |
|
647 | 0 | if (!transfer->req_id) { |
648 | 0 | transfer->req_id = g_obex_abort(transfer->obex, |
649 | 0 | transfer_abort_response, |
650 | 0 | transfer, NULL); |
651 | 0 | if (transfer->req_id) |
652 | 0 | return TRUE; |
653 | 0 | } |
654 | | |
655 | 0 | ret = g_obex_cancel_req(transfer->obex, transfer->req_id, FALSE); |
656 | 0 | if (ret) |
657 | 0 | return TRUE; |
658 | | |
659 | 0 | done: |
660 | 0 | transfer_free(transfer); |
661 | 0 | return ret; |
662 | 0 | } |