From ce999c67996515b278f49ea88f4e306dc0308ff3 Mon Sep 17 00:00:00 2001
From: Joshua Hill
Date: Sat, 5 Jun 2010 04:02:05 +0800
Subject: Refactoring continued, lots of bug fixes, probably about half way
 through

---
 src/idevicerestore.c | 84 ++++++++++++++++++++--------------------------------
 src/normal.c         | 30 ++++++++++++++++++-
 src/recovery.c       | 41 +++++++++++++++++++++++--
 src/recovery.h       |  1 +
 src/tss.c            |  1 -
 5 files changed, 101 insertions(+), 56 deletions(-)

diff --git a/src/idevicerestore.c b/src/idevicerestore.c
index cc9c4ba..7d382eb 100644
--- a/src/idevicerestore.c
+++ b/src/idevicerestore.c
@@ -94,7 +94,8 @@ int get_device(const char* uuid) {
 
 	switch (idevicerestore_mode) {
 	case NORMAL_MODE:
-		if (normal_get_device(uuid) < 0) {
+		device = normal_get_device(uuid);
+		if (device < 0) {
 			device = UNKNOWN_DEVICE;
 		}
 		break;
@@ -282,6 +283,7 @@ int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest) {
 }
 
 plist_t get_build_identity(plist_t buildmanifest, uint32_t identity) {
+
 	// fetch build identities array from BuildManifest
 	plist_t build_identities_array = plist_dict_get_item(buildmanifest, "BuildIdentities");
 	if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) {
@@ -300,19 +302,25 @@ plist_t get_build_identity(plist_t buildmanifest, uint32_t identity) {
 		return NULL;
 	}
 
-	return build_identity;
+	return plist_copy(build_identity);
 }
 
 int extract_filesystem(const char* ipsw, plist_t build_identity, char** filesystem) {
 	char* filename = NULL;
 
-	plist_t manifest_node = plist_dict_get_item(build_identity, "OS");
+	int sz = 0;
+	char* xml = NULL;
+	plist_to_xml(build_identity, &xml, &sz);
+	debug("%s", xml);
+	free(xml);
+
+	plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest");
 	if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
 		error("ERROR: Unable to find manifest node\n");
 		return -1;
 	}
 
-	plist_t filesystem_node = plist_dict_get_item(build_identity, "OS");
+	plist_t filesystem_node = plist_dict_get_item(manifest_node, "OS");
 	if (!filesystem_node || plist_get_node_type(filesystem_node) != PLIST_DICT) {
 		error("ERROR: Unable to find filesystem node\n");
 		return -1;
@@ -438,7 +446,7 @@ int main(int argc, char* argv[]) {
 	// devices are listed in order from oldest to newest
 	// devices that come after iPod2g require personalized firmwares
 	plist_t tss_request = NULL;
-	plist_t tss_response = NULL;
+	plist_t tss = NULL;
 	if(idevicerestore_device > IPOD2G_DEVICE) {
 
 		info("Creating TSS request\n");
@@ -455,11 +463,10 @@ int main(int argc, char* argv[]) {
 			plist_free(buildmanifest);
 			return -1;
 		}
-		plist_free(buildmanifest);
 
 		info("Sending TSS request\n");
-		tss_response = tss_send_request(tss_request);
-		if (tss_response == NULL) {
+		tss = tss_send_request(tss_request);
+		if (tss == NULL) {
 			error("ERROR: Unable to get response from TSS server\n");
 			plist_free(tss_request);
 			return -1;
@@ -472,7 +479,7 @@ int main(int argc, char* argv[]) {
 	char* filesystem = NULL;
 	if(extract_filesystem(ipsw, build_identity, &filesystem) < 0) {
 		error("ERROR: Unable to extract filesystem from IPSW\n");
-		if(tss_response) plist_free(tss_response);
+		if(tss) plist_free(tss);
 		plist_free(buildmanifest);
 		return -1;
 	}
@@ -482,47 +489,20 @@ int main(int argc, char* argv[]) {
 		info("Entering recovery mode...\n");
 		if (normal_enter_recovery(uuid) < 0) {
 			error("ERROR: Unable to place device into recovery mode\n");
-			plist_free(tss_response);
+			if(tss) plist_free(tss);
+			plist_free(buildmanifest);
 			return -1;
 		}
 	}
 
-	/* upload data to make device boot restore mode */
-	if (recovery_send_ibec(ipsw, tss_response) < 0) {
-		error("ERROR: Unable to send iBEC\n");
-		plist_free(tss_response);
-		return -1;
-	}
-	sleep(1);
-
-	if (recovery_send_applelogo(ipsw, tss_response) < 0) {
-		error("ERROR: Unable to send AppleLogo\n");
-		plist_free(tss_response);
-		return -1;
-	}
-
-	if (recovery_send_devicetree(ipsw, tss_response) < 0) {
-		error("ERROR: Unable to send DeviceTree\n");
-		plist_free(tss_response);
-		return -1;
-	}
-
-	if (recovery_send_ramdisk(ipsw, tss_response) < 0) {
-		error("ERROR: Unable to send Ramdisk\n");
-		plist_free(tss_response);
-		return -1;
-	}
-
-	// for some reason iboot requires a hard reset after ramdisk
-	//   or things start getting wacky
-	printf("Please unplug your device, then plug it back in\n");
-	printf("Hit any key to continue...");
-	getchar();
-
-	if (recovery_send_kernelcache(ipsw, tss_response) < 0) {
-		error("ERROR: Unable to send KernelCache\n");
-		plist_free(tss_response);
-		return -1;
+	// place device into restore mode if required
+	if (idevicerestore_mode == RECOVERY_MODE) {
+		if (recovery_enter_restore(ipsw, tss) < 0) {
+			error("ERROR: Unable to place device into restore mode\n");
+			if(tss) plist_free(tss);
+			plist_free(buildmanifest);
+			return -1;
+		}
 	}
 
 	idevice_event_subscribe(&device_callback, NULL);
@@ -536,7 +516,7 @@ int main(int argc, char* argv[]) {
 	idevice_error_t device_error = idevice_new(&device, uuid);
 	if (device_error != IDEVICE_E_SUCCESS) {
 		error("ERROR: Unable to open device\n");
-		plist_free(tss_response);
+		plist_free(tss);
 		return -1;
 	}
 
@@ -544,7 +524,7 @@ int main(int argc, char* argv[]) {
 	restored_error_t restore_error = restored_client_new(device, &restore, "idevicerestore");
 	if (restore_error != RESTORE_E_SUCCESS) {
 		error("ERROR: Unable to start restored client\n");
-		plist_free(tss_response);
+		plist_free(tss);
 		idevice_free(device);
 		return -1;
 	}
@@ -553,7 +533,7 @@ int main(int argc, char* argv[]) {
 	uint64_t version = 0;
 	if (restored_query_type(restore, &type, &version) != RESTORE_E_SUCCESS) {
 		error("ERROR: Device is not in restore mode. QueryType returned \"%s\"\n", type);
-		plist_free(tss_response);
+		plist_free(tss);
 		restored_client_free(restore);
 		idevice_free(device);
 		return -1;
@@ -587,7 +567,7 @@ int main(int argc, char* argv[]) {
 						} else if (!strcmp(datatype, "KernelCache")) {
 							int kernelcache_size = 0;
 							char* kernelcache_data = NULL;
-							if (get_signed_component_by_name(ipsw, tss_response, "KernelCache", &kernelcache_data, &kernelcache_size) < 0) {
+							if (get_signed_component_by_name(ipsw, tss, "KernelCache", &kernelcache_data, &kernelcache_size) < 0) {
 								error("ERROR: Unable to get kernelcache file\n");
 								return -1;
 							}
@@ -595,7 +575,7 @@ int main(int argc, char* argv[]) {
 							free(kernelcache_data);
 
 						} else if (!strcmp(datatype, "NORData")) {
-							restore_send_nor(restore, ipsw, tss_response);
+							restore_send_nor(restore, ipsw, tss);
 
 						} else {
 							// Unknown DataType!!
@@ -624,7 +604,7 @@ int main(int argc, char* argv[]) {
 	}
 
 	restored_client_free(restore);
-	plist_free(tss_response);
+	plist_free(tss);
 	idevice_free(device);
 	unlink(filesystem);
 	return 0;
diff --git a/src/normal.c b/src/normal.c
index 0420a82..3c2bf5c 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -21,10 +21,12 @@
 
 #include <stdio.h>
 #include <stdint.h>
+#include <libirecovery.h>
 #include <libimobiledevice/lockdown.h>
 #include <libimobiledevice/libimobiledevice.h>
 
 #include "normal.h"
+#include "recovery.h"
 #include "idevicerestore.h"
 
 int normal_check_mode(const char* uuid) {
@@ -112,9 +114,11 @@ int normal_get_device(const char* uuid) {
 
 int normal_enter_recovery(const char* uuid) {
 	idevice_t device = NULL;
+	irecv_client_t recovery = NULL;
 	lockdownd_client_t lockdown = NULL;
+	irecv_error_t recovery_error = IRECV_E_SUCCESS;
 	idevice_error_t device_error = IDEVICE_E_SUCCESS;
-	lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS;
+	lockdownd_error_t lockdown_error = LOCKDOWN_E_SUCCESS;
 
 	device_error = idevice_new(&device, uuid);
 	if (device_error != IDEVICE_E_SUCCESS) {
@@ -141,6 +145,29 @@ int normal_enter_recovery(const char* uuid) {
 	idevice_free(device);
 	lockdown = NULL;
 	device = NULL;
+
+	if(recovery_open_with_timeout(&recovery) < 0) {
+		error("ERROR: Unable to enter recovery mode\n");
+		return -1;
+	}
+
+	recovery_error = irecv_send_command(recovery, "setenv auto-boot true");
+	if (recovery_error != IRECV_E_SUCCESS) {
+		error("ERROR: Unable to reset auto-boot variable\n");
+		irecv_close(recovery);
+		return -1;
+	}
+
+	recovery_error = irecv_send_command(recovery, "saveenv");
+	if (recovery_error != IRECV_E_SUCCESS) {
+		error("ERROR: Unable to save auto-boot variable\n");
+		irecv_close(recovery);
+		return -1;
+	}
+
+	idevicerestore_mode = RECOVERY_MODE;
+	irecv_close(recovery);
+	recovery = NULL;
 	return 0;
 }
 
@@ -192,4 +219,5 @@ int normal_get_ecid(const char* uuid, uint64_t* ecid) {
 	idevice_free(device);
 	lockdown = NULL;
 	device = NULL;
+	return 0;
 }
diff --git a/src/recovery.c b/src/recovery.c
index 9885982..3bfb97e 100644
--- a/src/recovery.c
+++ b/src/recovery.c
@@ -48,6 +48,43 @@ int recovery_check_mode() {
 	return 0;
 }
 
+int recovery_enter_restore(const char* ipsw, plist_t tss) {
+	// upload data to make device boot restore mode
+	if (recovery_send_ibec(ipsw, tss) < 0) {
+		error("ERROR: Unable to send iBEC\n");
+		return -1;
+	}
+	sleep(1);
+
+	if (recovery_send_applelogo(ipsw, tss) < 0) {
+		error("ERROR: Unable to send AppleLogo\n");
+		return -1;
+	}
+
+	if (recovery_send_devicetree(ipsw, tss) < 0) {
+		error("ERROR: Unable to send DeviceTree\n");
+		return -1;
+	}
+
+	if (recovery_send_ramdisk(ipsw, tss) < 0) {
+		error("ERROR: Unable to send Ramdisk\n");
+		return -1;
+	}
+
+	// for some reason iboot requires a hard reset after ramdisk
+	//   or things start getting wacky
+	printf("Please unplug your device, then plug it back in\n");
+	printf("Hit any key to continue...");
+	getchar();
+
+	if (recovery_send_kernelcache(ipsw, tss) < 0) {
+		error("ERROR: Unable to send KernelCache\n");
+		return -1;
+	}
+
+	return 0;
+}
+
 int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plist_t tss, char* component) {
 	int size = 0;
 	char* data = NULL;
@@ -306,7 +343,7 @@ int recovery_get_cpid(uint32_t* cpid) {
 		return -1;
 	}
 
-	irecv_error_t error = irecv_get_ecid(recovery, cpid);
+	irecv_error_t error = irecv_get_cpid(recovery, cpid);
 	if (error != IRECV_E_SUCCESS) {
 		irecv_close(recovery);
 		return -1;
@@ -323,7 +360,7 @@ int recovery_get_bdid(uint32_t* bdid) {
 		return -1;
 	}
 
-	irecv_error_t error = irecv_get_ecid(recovery, bdid);
+	irecv_error_t error = irecv_get_bdid(recovery, bdid);
 	if (error != IRECV_E_SUCCESS) {
 		irecv_close(recovery);
 		return -1;
diff --git a/src/recovery.h b/src/recovery.h
index 86e3af2..b191aa5 100644
--- a/src/recovery.h
+++ b/src/recovery.h
@@ -26,6 +26,7 @@
 #include <plist/plist.h>
 
 int recovery_check_mode();
+int recovery_enter_restore(const char* ipsw, plist_t tss);
 int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plist_t tss, char* component);
 irecv_error_t recovery_open_with_timeout(irecv_client_t* client);
 int recovery_send_ibec(const char* ipsw, plist_t tss);
diff --git a/src/tss.c b/src/tss.c
index f36bc5f..a9e9456 100644
--- a/src/tss.c
+++ b/src/tss.c
@@ -124,7 +124,6 @@ plist_t tss_create_request(plist_t build_identity, uint64_t ecid) {
 		plist_dict_insert_item(tss_request, key, tss_entry);
 		free(key);
 	}
-	plist_free(manifest_node);
 
 	int sz = 0;
 	char* xml = NULL;
-- 
cgit v1.1-32-gdbae