summaryrefslogtreecommitdiffstats
path: root/src/mobilesync.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mobilesync.c')
-rw-r--r--src/mobilesync.c585
1 files changed, 585 insertions, 0 deletions
diff --git a/src/mobilesync.c b/src/mobilesync.c
index b5b9453..db437c4 100644
--- a/src/mobilesync.c
+++ b/src/mobilesync.c
@@ -2,6 +2,7 @@
2 * mobilesync.c 2 * mobilesync.c
3 * Contains functions for the built-in MobileSync client. 3 * Contains functions for the built-in MobileSync client.
4 * 4 *
5 * Copyright (c) 2010 Bryan Forbes All Rights Reserved.
5 * Copyright (c) 2009 Jonathan Beck All Rights Reserved. 6 * Copyright (c) 2009 Jonathan Beck All Rights Reserved.
6 * 7 *
7 * This library is free software; you can redistribute it and/or 8 * This library is free software; you can redistribute it and/or
@@ -19,9 +20,14 @@
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */ 21 */
21 22
23#define _GNU_SOURCE 1
24#define __USE_GNU 1
25
22#include <plist/plist.h> 26#include <plist/plist.h>
23#include <string.h> 27#include <string.h>
24#include <stdlib.h> 28#include <stdlib.h>
29#include <stdio.h>
30#include <glib.h>
25 31
26#include "mobilesync.h" 32#include "mobilesync.h"
27#include "device_link_service.h" 33#include "device_link_service.h"
@@ -30,6 +36,8 @@
30#define MSYNC_VERSION_INT1 100 36#define MSYNC_VERSION_INT1 100
31#define MSYNC_VERSION_INT2 100 37#define MSYNC_VERSION_INT2 100
32 38
39#define EMPTY_PARAMETER_STRING "___EmptyParameterString___"
40
33/** 41/**
34 * Convert an device_link_service_error_t value to an mobilesync_error_t value. 42 * Convert an device_link_service_error_t value to an mobilesync_error_t value.
35 * Used internally to get correct error codes when using device_link_service stuff. 43 * Used internally to get correct error codes when using device_link_service stuff.
@@ -84,6 +92,8 @@ mobilesync_error_t mobilesync_client_new(idevice_t device, uint16_t port,
84 92
85 mobilesync_client_t client_loc = (mobilesync_client_t) malloc(sizeof(struct mobilesync_client_private)); 93 mobilesync_client_t client_loc = (mobilesync_client_t) malloc(sizeof(struct mobilesync_client_private));
86 client_loc->parent = dlclient; 94 client_loc->parent = dlclient;
95 client_loc->direction = MOBILESYNC_SYNC_DIR_DEVICE_TO_COMPUTER;
96 client_loc->data_class = NULL;
87 97
88 /* perform handshake */ 98 /* perform handshake */
89 ret = mobilesync_error(device_link_service_version_exchange(dlclient, MSYNC_VERSION_INT1, MSYNC_VERSION_INT2)); 99 ret = mobilesync_error(device_link_service_version_exchange(dlclient, MSYNC_VERSION_INT1, MSYNC_VERSION_INT2));
@@ -150,3 +160,578 @@ mobilesync_error_t mobilesync_send(mobilesync_client_t client, plist_t plist)
150 return MOBILESYNC_E_INVALID_ARG; 160 return MOBILESYNC_E_INVALID_ARG;
151 return mobilesync_error(device_link_service_send(client->parent, plist)); 161 return mobilesync_error(device_link_service_send(client->parent, plist));
152} 162}
163
164mobilesync_error_t mobilesync_start(mobilesync_client_t client, const char *data_class, mobilesync_anchors_t anchors, mobilesync_sync_type_t *sync_type, uint64_t *data_class_version)
165{
166 if (!client || client->data_class || !data_class ||
167 !anchors || !anchors->computer_anchor) {
168 return MOBILESYNC_E_INVALID_ARG;
169 }
170
171 mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR;
172 char *response_type = NULL;
173 char *sync_type_str = NULL;
174 plist_t msg = NULL;
175 plist_t response_type_node = NULL;
176
177 msg = plist_new_array();
178 plist_array_append_item(msg, plist_new_string("SDMessageSyncDataClassWithDevice"));
179 plist_array_append_item(msg, plist_new_string(data_class));
180 if (anchors->device_anchor) {
181 plist_array_append_item(msg, plist_new_string(anchors->device_anchor));
182 } else {
183 plist_array_append_item(msg, plist_new_string("---"));
184 }
185 plist_array_append_item(msg, plist_new_string(anchors->computer_anchor));
186 plist_array_append_item(msg, plist_new_uint(*data_class_version));
187 plist_array_append_item(msg, plist_new_string(EMPTY_PARAMETER_STRING));
188
189 err = mobilesync_send(client, msg);
190
191 if (err != MOBILESYNC_E_SUCCESS) {
192 goto out;
193 }
194
195 plist_free(msg);
196 msg = NULL;
197
198 err = mobilesync_receive(client, &msg);
199
200 if (err != MOBILESYNC_E_SUCCESS) {
201 goto out;
202 }
203
204 response_type_node = plist_array_get_item(msg, 0);
205 if (!response_type_node) {
206 err = MOBILESYNC_E_PLIST_ERROR;
207 goto out;
208 }
209
210 plist_get_string_val(response_type_node, &response_type);
211 if (!response_type) {
212 err = MOBILESYNC_E_PLIST_ERROR;
213 goto out;
214 }
215
216 if (!strcmp(response_type, "SDMessageRefuseToSyncDataClassWithComputer")) {
217 char *reason = NULL;
218 err = MOBILESYNC_E_SYNC_REFUSED;
219 plist_get_string_val(plist_array_get_item(msg, 2), &reason);
220 debug_info("Device refused sync: %s", reason);
221 free(reason);
222 reason = NULL;
223 goto out;
224 }
225
226 if (!strcmp(response_type, "SDMessageCancelSession")) {
227 char *reason = NULL;
228 err = MOBILESYNC_E_CANCELLED;
229 plist_get_string_val(plist_array_get_item(msg, 2), &reason);
230 debug_info("Device cancelled: %s", reason);
231 free(reason);
232 reason = NULL;
233 goto out;
234 }
235
236 if (sync_type != NULL) {
237 plist_t sync_type_node = plist_array_get_item(msg, 4);
238 if (!sync_type_node) {
239 err = MOBILESYNC_E_PLIST_ERROR;
240 goto out;
241 }
242
243 plist_get_string_val(sync_type_node, &sync_type_str);
244 if (!sync_type_str) {
245 err = MOBILESYNC_E_PLIST_ERROR;
246 goto out;
247 }
248
249 if (!strcmp(sync_type_str, "SDSyncTypeFast")) {
250 *sync_type = MOBILESYNC_SYNC_TYPE_FAST;
251 } else if (!strcmp(sync_type_str, "SDSyncTypeSlow")) {
252 *sync_type = MOBILESYNC_SYNC_TYPE_SLOW;
253 } else if (!strcmp(sync_type_str, "SDSyncTypeReset")) {
254 *sync_type = MOBILESYNC_SYNC_TYPE_RESET;
255 } else {
256 err = MOBILESYNC_E_PLIST_ERROR;
257 goto out;
258 }
259 }
260
261 if (data_class_version != NULL) {
262 plist_t data_class_version_node = plist_array_get_item(msg, 5);
263 if (!data_class_version_node) {
264 err = MOBILESYNC_E_PLIST_ERROR;
265 goto out;
266 }
267
268 plist_get_uint_val(data_class_version_node, data_class_version);
269 }
270
271 err = MOBILESYNC_E_SUCCESS;
272
273 out:
274 if (sync_type_str) {
275 free(sync_type_str);
276 sync_type_str = NULL;
277 }
278 if (response_type) {
279 free(response_type);
280 response_type = NULL;
281 }
282 if (msg) {
283 plist_free(msg);
284 msg = NULL;
285 }
286
287 client->data_class = strdup(data_class);
288 client->direction = MOBILESYNC_SYNC_DIR_DEVICE_TO_COMPUTER;
289 return err;
290}
291
292mobilesync_error_t mobilesync_finish(mobilesync_client_t client)
293{
294 if (!client || !client->data_class) {
295 return MOBILESYNC_E_INVALID_ARG;
296 }
297
298 mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR;
299
300 plist_t msg = NULL;
301 plist_t response_type_node = NULL;
302 char *response_type = NULL;
303
304 msg = plist_new_array();
305 plist_array_append_item(msg, plist_new_string("SDMessageFinishSessionOnDevice"));
306 plist_array_append_item(msg, plist_new_string(client->data_class));
307
308 err = mobilesync_send(client, msg);
309
310 if (err != MOBILESYNC_E_SUCCESS) {
311 goto out;
312 }
313
314 plist_free(msg);
315 msg = NULL;
316
317 err = mobilesync_receive(client, &msg);
318
319 if (err != MOBILESYNC_E_SUCCESS) {
320 goto out;
321 }
322
323 response_type_node = plist_array_get_item(msg, 0);
324 if (!response_type_node) {
325 err = MOBILESYNC_E_PLIST_ERROR;
326 goto out;
327 }
328
329 plist_get_string_val(response_type_node, &response_type);
330 if (!response_type) {
331 err = MOBILESYNC_E_PLIST_ERROR;
332 goto out;
333 }
334
335 if (!strcmp(response_type, "SDMessageDeviceFinishedSession")) {
336 err = MOBILESYNC_E_SUCCESS;
337 }
338
339 out:
340 if (response_type) {
341 free(response_type);
342 response_type = NULL;
343 }
344 if (msg) {
345 plist_free(msg);
346 msg = NULL;
347 }
348
349 free(client->data_class);
350 client->data_class = NULL;
351 client->direction = MOBILESYNC_SYNC_DIR_DEVICE_TO_COMPUTER;
352 return err;
353}
354
355static mobilesync_error_t mobilesync_get_records(mobilesync_client_t client, const char *operation)
356{
357 if (!client || !client->data_class || !operation) {
358 return MOBILESYNC_E_INVALID_ARG;
359 }
360
361 mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR;
362 plist_t msg = NULL;
363
364 msg = plist_new_array();
365 plist_array_append_item(msg, plist_new_string(operation));
366 plist_array_append_item(msg, plist_new_string(client->data_class));
367
368 err = mobilesync_send(client, msg);
369
370 if (msg) {
371 plist_free(msg);
372 msg = NULL;
373 }
374 return err;
375}
376
377mobilesync_error_t mobilesync_get_all_records_from_device(mobilesync_client_t client)
378{
379 return mobilesync_get_records(client, "SDMessageGetAllRecordsFromDevice");
380}
381
382mobilesync_error_t mobilesync_get_changes_from_device(mobilesync_client_t client)
383{
384 return mobilesync_get_records(client, "SDMessageGetChangesFromDevice");
385}
386
387mobilesync_error_t mobilesync_receive_changes(mobilesync_client_t client, plist_t *entities, uint8_t *is_last_record, plist_t *actions)
388{
389 if (!client || !client->data_class) {
390 return MOBILESYNC_E_INVALID_ARG;
391 }
392
393 plist_t msg = NULL;
394 plist_t response_type_node = NULL;
395 plist_t actions_node = NULL;
396 char *response_type = NULL;
397 uint8_t has_more_changes = 0;
398
399 mobilesync_error_t err = mobilesync_receive(client, &msg);
400 if (err != MOBILESYNC_E_SUCCESS) {
401 goto out;
402 }
403
404 response_type_node = plist_array_get_item(msg, 0);
405 if (!response_type_node) {
406 err = MOBILESYNC_E_PLIST_ERROR;
407 goto out;
408 }
409
410 plist_get_string_val(response_type_node, &response_type);
411 if (!response_type) {
412 err = MOBILESYNC_E_PLIST_ERROR;
413 goto out;
414 }
415
416 if (!strcmp(response_type, "SDMessageCancelSession")) {
417 char *reason = NULL;
418 err = MOBILESYNC_E_CANCELLED;
419 plist_get_string_val(plist_array_get_item(msg, 2), &reason);
420 debug_info("Device cancelled: %s", reason);
421 free(reason);
422 goto out;
423 }
424
425 *entities = plist_copy(plist_array_get_item(msg, 2));
426
427 plist_get_bool_val(plist_array_get_item(msg, 3), &has_more_changes);
428 *is_last_record = (has_more_changes > 0 ? 0 : 1);
429
430 actions_node = plist_array_get_item(msg, 4);
431 if (plist_get_node_type(actions) == PLIST_DICT)
432 *actions = plist_copy(actions_node);
433 else
434 *actions = NULL;
435
436 out:
437 if (response_type) {
438 free(response_type);
439 response_type = NULL;
440 }
441 if (msg) {
442 plist_free(msg);
443 msg = NULL;
444 }
445 return err;
446}
447
448mobilesync_error_t mobilesync_acknowledge_changes_from_device(mobilesync_client_t client)
449{
450 if (!client || !client->data_class) {
451 return MOBILESYNC_E_INVALID_ARG;
452 }
453
454 plist_t msg = NULL;
455 mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR;
456
457 msg = plist_new_array();
458 plist_array_append_item(msg, plist_new_string("SDMessageAcknowledgeChangesFromDevice"));
459 plist_array_append_item(msg, plist_new_string(client->data_class));
460
461 err = mobilesync_send(client, msg);
462 plist_free(msg);
463 return err;
464}
465
466static plist_t create_process_changes_message(const char *data_class, plist_t entities, uint8_t more_changes, plist_t actions)
467{
468 plist_t msg = plist_new_array();
469 plist_array_append_item(msg, plist_new_string("SDMessageProcessChanges"));
470 plist_array_append_item(msg, plist_copy(entities));
471 plist_array_append_item(msg, plist_new_bool(more_changes));
472 plist_array_append_item(msg, plist_copy(actions));
473
474 return msg;
475}
476
477mobilesync_error_t mobilesync_ready_to_send_changes_from_computer(mobilesync_client_t client)
478{
479 if (!client || !client->data_class) {
480 return MOBILESYNC_E_INVALID_ARG;
481 }
482
483 if (client->direction != MOBILESYNC_SYNC_DIR_DEVICE_TO_COMPUTER) {
484 return MOBILESYNC_E_WRONG_DIRECTION;
485 }
486
487 plist_t msg = NULL;
488 plist_t response_type_node = NULL;
489 char *response_type = NULL;
490 mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR;
491
492 err = mobilesync_receive(client, &msg);
493 if (err != MOBILESYNC_E_SUCCESS) {
494 goto out;
495 }
496
497 response_type_node = plist_array_get_item(msg, 0);
498 if (!response_type_node) {
499 err = MOBILESYNC_E_PLIST_ERROR;
500 goto out;
501 }
502
503 plist_get_string_val(response_type_node, &response_type);
504 if (!response_type) {
505 err = MOBILESYNC_E_PLIST_ERROR;
506 goto out;
507 }
508
509 if (!strcmp(response_type, "SDMessageCancelSession")) {
510 char *reason = NULL;
511 err = MOBILESYNC_E_CANCELLED;
512 plist_get_string_val(plist_array_get_item(msg, 2), &reason);
513 debug_info("Device cancelled: %s", reason);
514 free(reason);
515 goto out;
516 }
517
518 if (strcmp(response_type, "SDMessageDeviceReadyToReceiveChanges") != 0) {
519 err = MOBILESYNC_E_NOT_READY;
520 goto out;
521 }
522
523 err = mobilesync_error(device_link_service_send_ping(client->parent, "Preparing to get changes for device"));
524 if (err != MOBILESYNC_E_SUCCESS) {
525 goto out;
526 }
527
528 client->direction = MOBILESYNC_SYNC_DIR_COMPUTER_TO_DEVICE;
529 err = MOBILESYNC_E_SUCCESS;
530
531 out:
532 if (msg) {
533 plist_free(msg);
534 msg = NULL;
535 }
536
537 return err;
538}
539
540mobilesync_error_t mobilesync_send_changes(mobilesync_client_t client, plist_t entities, uint8_t is_last_record, plist_t actions)
541{
542 if (!client || !client->data_class || !entities) {
543 return MOBILESYNC_E_INVALID_ARG;
544 }
545
546 if (plist_get_node_type(entities) != PLIST_DICT) {
547 return MOBILESYNC_E_INVALID_ARG;
548 }
549
550 if (client->direction != MOBILESYNC_SYNC_DIR_COMPUTER_TO_DEVICE) {
551 return MOBILESYNC_E_WRONG_DIRECTION;
552 }
553
554 mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR;
555 plist_t msg = NULL;
556
557 msg = create_process_changes_message(client->data_class, entities, (is_last_record > 0 ? 0 : 1), actions);
558 err = mobilesync_send(client, msg);
559
560 if (msg) {
561 plist_free(msg);
562 msg = NULL;
563 }
564
565 return err;
566}
567
568mobilesync_error_t mobilesync_remap_identifiers(mobilesync_client_t client, plist_t *mapping)
569{
570 if (!client || !client->data_class) {
571 return MOBILESYNC_E_INVALID_ARG;
572 }
573
574 if (client->direction == MOBILESYNC_SYNC_DIR_DEVICE_TO_COMPUTER) {
575 return MOBILESYNC_E_WRONG_DIRECTION;
576 }
577
578 plist_t msg = NULL;
579 plist_t response_type_node = NULL;
580 char *response_type = NULL;
581
582 mobilesync_error_t err = mobilesync_receive(client, &msg);
583 if (err != MOBILESYNC_E_SUCCESS) {
584 goto out;
585 }
586
587 response_type_node = plist_array_get_item(msg, 0);
588 if (!response_type_node) {
589 err = MOBILESYNC_E_PLIST_ERROR;
590 goto out;
591 }
592
593 plist_get_string_val(response_type_node, &response_type);
594 if (!response_type) {
595 err = MOBILESYNC_E_PLIST_ERROR;
596 goto out;
597 }
598
599 if (!strcmp(response_type, "SDMessageCancelSession")) {
600 char *reason = NULL;
601 err = MOBILESYNC_E_CANCELLED;
602 plist_get_string_val(plist_array_get_item(msg, 2), &reason);
603 debug_info("Device cancelled: %s", reason);
604 free(reason);
605 goto out;
606 }
607
608 if (strcmp(response_type, "SDMessageRemapRecordIdentifiers") != 0) {
609 err = MOBILESYNC_E_PLIST_ERROR;
610 goto out;
611 }
612
613 if (mapping != NULL) {
614 plist_t map = plist_array_get_item(msg, 2);
615 if (plist_get_node_type(map) == PLIST_DICT) {
616 *mapping = plist_copy(map);
617 } else {
618 *mapping = NULL;
619 }
620 }
621
622 err = MOBILESYNC_E_SUCCESS;
623
624 out:
625 if (response_type) {
626 free(response_type);
627 response_type = NULL;
628 }
629 if (msg) {
630 plist_free(msg);
631 msg = NULL;
632 }
633
634 return err;
635}
636
637mobilesync_error_t mobilesync_cancel(mobilesync_client_t client, const char* reason)
638{
639 if (!client || !client->data_class || !reason) {
640 return MOBILESYNC_E_INVALID_ARG;
641 }
642
643 mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR;
644 plist_t msg = NULL;
645
646 msg = plist_new_array();
647 plist_array_append_item(msg, plist_new_string("SDMessageCancelSession"));
648 plist_array_append_item(msg, plist_new_string(client->data_class));
649 plist_array_append_item(msg, plist_new_string(reason));
650
651 err = mobilesync_send(client, msg);
652
653 plist_free(msg);
654 msg = NULL;
655
656 free(client->data_class);
657 client->data_class = NULL;
658 client->direction = MOBILESYNC_SYNC_DIR_DEVICE_TO_COMPUTER;
659
660 return err;
661}
662
663mobilesync_anchors_t mobilesync_anchors_new(const char *device_anchor, const char *computer_anchor)
664{
665 mobilesync_anchors_t anchors = (mobilesync_anchors_t) malloc(sizeof(mobilesync_anchors));
666 if (device_anchor != NULL) {
667 anchors->device_anchor = strdup(device_anchor);
668 } else {
669 anchors->device_anchor = NULL;
670 }
671 if (computer_anchor != NULL) {
672 anchors->computer_anchor = strdup(computer_anchor);
673 } else {
674 anchors->computer_anchor = NULL;
675 }
676
677 return anchors;
678}
679
680void mobilesync_anchors_free(mobilesync_anchors_t anchors)
681{
682 if (anchors->device_anchor != NULL) {
683 free(anchors->device_anchor);
684 anchors->device_anchor = NULL;
685 }
686 if (anchors->computer_anchor != NULL) {
687 free(anchors->computer_anchor);
688 anchors->computer_anchor = NULL;
689 }
690 free(anchors);
691 anchors = NULL;
692}
693
694plist_t mobilesync_actions_new()
695{
696 return plist_new_dict();
697}
698
699void mobilesync_actions_add(plist_t actions, ...)
700{
701 if (!actions)
702 return;
703 va_list args;
704 va_start(args, actions);
705 char *arg = va_arg(args, char*);
706 while (arg) {
707 char *key = strdup(arg);
708 if (!strcmp(key, "SyncDeviceLinkEntityNamesKey")) {
709 char **entity_names = va_arg(args, char**);
710 int entity_names_length = va_arg(args, int);
711 int i = 0;
712
713 plist_t array = plist_new_array();
714
715 for (i = 0; i < entity_names_length; i++) {
716 plist_array_append_item(array, plist_new_string(entity_names[i]));
717 }
718
719 plist_dict_insert_item(actions, key, array);
720 } else if (!strcmp(key, "SyncDeviceLinkAllRecordsOfPulledEntityTypeSentKey")) {
721 int link_records = va_arg(args, int);
722 plist_dict_insert_item(actions, key, plist_new_bool(link_records));
723 }
724 free(key);
725 key = NULL;
726 arg = va_arg(args, char*);
727 }
728 va_end(args);
729}
730
731void mobilesync_actions_free(plist_t actions)
732{
733 if (actions) {
734 plist_free(actions);
735 actions = NULL;
736 }
737}