From 4d74cd31751165b671eba9a1b0936718b7f39b52 Mon Sep 17 00:00:00 2001
From: Joshua Hill
Date: Tue, 1 Jun 2010 16:13:25 -0400
Subject: Began major refactoring, not quite finished yet, this branch is
 probably broke

---
 src/dfu.c            |  28 +++++
 src/dfu.h            |   7 +-
 src/idevicerestore.c | 339 ++++++++++++++++++++++++++++++++-------------------
 src/idevicerestore.h |  55 ++++++++-
 src/img3.h           |   4 +-
 src/ipsw.h           |   4 +-
 src/normal.c         | 169 ++++++++++++++++++++++++-
 src/normal.h         |  11 +-
 src/recovery.c       |  78 +++++++++++-
 src/recovery.h       |  19 +--
 src/restore.c        |  43 ++++++-
 src/restore.h        |   9 +-
 src/tss.h            |   4 +-
 13 files changed, 609 insertions(+), 161 deletions(-)

(limited to 'src')

diff --git a/src/dfu.c b/src/dfu.c
index 5e13f38..1da895d 100644
--- a/src/dfu.c
+++ b/src/dfu.c
@@ -20,9 +20,37 @@
  */
 
 #include <stdint.h>
+#include <libirecovery.h>
 
 #include "dfu.h"
 
+int dfu_check_mode() {
+	irecv_client_t dfu = NULL;
+	irecv_error_t dfu_error = IRECV_E_SUCCESS;
+
+	dfu_error = irecv_open(&dfu);
+	if (dfu_error != IRECV_E_SUCCESS) {
+		return -1;
+	}
+
+	if(dfu->mode != kDfuMode) {
+		irecv_close(dfu);
+		return -1;
+	}
+
+	irecv_close(dfu);
+	dfu = NULL;
+	return 0;
+}
+
+int dfu_get_cpid(uint32_t* cpid) {
+	return 0;
+}
+
+int dfu_get_bdid(uint32_t* bdid) {
+	return 0;
+}
+
 int dfu_get_ecid(uint64_t* ecid) {
 	return 0;
 }
diff --git a/src/dfu.h b/src/dfu.h
index ef9d911..f8f34fc 100644
--- a/src/dfu.h
+++ b/src/dfu.h
@@ -19,11 +19,14 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#ifndef DFU_H
-#define DFU_H
+#ifndef IDEVICERESTORE_DFU_H
+#define IDEVICERESTORE_DFU_H
 
 #include <stdint.h>
 
+int dfu_check_mode();
+int dfu_get_cpid(uint32_t* cpid);
+int dfu_get_bdid(uint32_t* bdid);
 int dfu_get_ecid(uint64_t* ecid);
 
 #endif
diff --git a/src/idevicerestore.c b/src/idevicerestore.c
index aaff4d6..f03e30e 100644
--- a/src/idevicerestore.c
+++ b/src/idevicerestore.c
@@ -38,25 +38,203 @@
 #include "recovery.h"
 #include "idevicerestore.h"
 
-#define UNKNOWN_MODE   0
-#define DFU_MODE       1
-#define NORMAL_MODE    2
-#define RECOVERY_MODE  3
-#define RESTORE_MODE   4
-
+int idevicerestore_quit = 0;
 int idevicerestore_debug = 0;
-static int idevicerestore_mode = 0;
-static int idevicerestore_quit = 0;
-static int idevicerestore_custom = 0;
+int idevicerestore_custom = 0;
+int idevicerestore_verbose = 0;
+idevicerestore_mode_t idevicerestore_mode = UNKNOWN_MODE;
+idevicerestore_device_t idevicerestore_device = UNKNOWN_DEVICE;
 
 void usage(int argc, char* argv[]);
+int get_device(const char* uuid);
+idevicerestore_mode_t check_mode(const char* uuid);
+int get_ecid(const char* uuid, uint64_t* ecid);
+int get_bdid(const char* uuid, uint32_t* bdid);
+int get_cpid(const char* uuid, uint32_t* cpid);
 int write_file(const char* filename, char* data, int size);
+int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest);
 int get_tss_data_by_name(plist_t tss, const char* entry, char** path, char** blob);
 int get_tss_data_by_path(plist_t tss, const char* path, char** name, char** blob);
 void device_callback(const idevice_event_t* event, void *user_data);
 int get_signed_component_by_name(char* ipsw, plist_t tss, char* component, char** pdata, int* psize);
 int get_signed_component_by_path(char* ipsw, plist_t tss, char* path, char** pdata, int* psize);
 
+idevicerestore_mode_t check_mode(const char* uuid) {
+	if(normal_check_mode(uuid) == 0) {
+		info("Found device in normal mode\n");
+		idevicerestore_mode = NORMAL_MODE;
+	}
+
+	else if(recovery_check_mode() == 0) {
+		info("Found device in recovery mode\n");
+		idevicerestore_mode = RECOVERY_MODE;
+	}
+
+	else if(dfu_check_mode() == 0) {
+		info("Found device in DFU mode\n");
+		idevicerestore_mode = DFU_MODE;
+	}
+
+	else if(restore_check_mode(uuid) == 0) {
+		info("Found device in restore mode\n");
+		idevicerestore_mode = RESTORE_MODE;
+	}
+
+	return idevicerestore_mode;
+}
+
+int get_device(const char* uuid) {
+	uint32_t bdid = 0;
+	uint32_t cpid = 0;
+
+	if(get_cpid(uuid, &cpid) < 0) {
+		error("ERROR: Unable to get device CPID\n");
+		return -1;
+	}
+
+	switch(cpid) {
+	case IPHONE2G_CPID:
+		// iPhone1,1 iPhone1,2 and iPod1,1 all share the same ChipID
+		//   so we need to check the BoardID
+		if(get_bdid(uuid, &bdid) < 0) {
+			error("ERROR: Unable to get device BDID\n");
+			return -1;
+		}
+
+		switch(bdid) {
+		case IPHONE2G_BDID:
+			idevicerestore_device = IPHONE2G_DEVICE;
+			break;
+
+		case IPHONE3G_BDID:
+			idevicerestore_device = IPHONE3G_DEVICE;
+			break;
+
+		case IPOD1G_BDID:
+			idevicerestore_device = IPOD1G_DEVICE;
+			break;
+
+		default:
+			idevicerestore_device = UNKNOWN_DEVICE;
+			break;
+		}
+		break;
+
+	case IPHONE3GS_CPID:
+		idevicerestore_device = IPHONE3GS_DEVICE;
+		break;
+
+	case IPOD2G_CPID:
+		idevicerestore_device = IPOD2G_DEVICE;
+		break;
+
+	case IPOD3G_CPID:
+		idevicerestore_device = IPOD3G_DEVICE;
+		break;
+
+	case IPAD1G_CPID:
+		idevicerestore_device = IPAD1G_DEVICE;
+		break;
+
+	default:
+		idevicerestore_device = UNKNOWN_DEVICE;
+		break;
+	}
+
+	return idevicerestore_device;
+}
+
+int get_bdid(const char* uuid, uint32_t* bdid) {
+	switch(idevicerestore_mode) {
+	case NORMAL_MODE:
+		if(normal_get_bdid(uuid, bdid) < 0) {
+			*bdid = -1;
+			return -1;
+		}
+		break;
+
+	case RECOVERY_MODE:
+		if(recovery_get_bdid(bdid) < 0) {
+			*bdid = -1;
+			return -1;
+		}
+		break;
+
+	case DFU_MODE:
+		if(dfu_get_bdid(bdid) < 0) {
+			*bdid = -1;
+			return -1;
+		}
+		break;
+
+	default:
+		error("ERROR: Device is in an invalid state\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int get_cpid(const char* uuid, uint32_t* cpid) {
+	switch(idevicerestore_mode) {
+	case NORMAL_MODE:
+		if(normal_get_cpid(uuid, cpid) < 0) {
+			*cpid = -1;
+			return -1;
+		}
+		break;
+
+	case RECOVERY_MODE:
+		if(recovery_get_cpid(cpid) < 0) {
+			*cpid = -1;
+			return -1;
+		}
+		break;
+
+	case DFU_MODE:
+		if(dfu_get_cpid(cpid) < 0) {
+			*cpid = -1;
+			return -1;
+		}
+		break;
+
+	default:
+		error("ERROR: Device is in an invalid state\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int get_ecid(const char* uuid, uint64_t* ecid) {
+	if(normal_get_ecid(uuid, ecid) == 0) {
+		info("Found device in normal mode\n");
+		idevicerestore_mode = NORMAL_MODE;
+	}
+
+	else if(recovery_get_ecid(ecid) == 0) {
+		info("Found device in recovery mode\n");
+		idevicerestore_mode = RECOVERY_MODE;
+	}
+
+	else if(dfu_get_ecid(ecid) == 0) {
+		info("Found device in DFU mode\n");
+		idevicerestore_mode = DFU_MODE;
+	}
+
+	return idevicerestore_mode;
+}
+
+int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest) {
+	int size = 0;
+	char* data = NULL;
+	if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &data, &size) < 0) {
+		return -1;
+	}
+	plist_from_xml(data, size, buildmanifest);
+	return 0;
+}
+
 int main(int argc, char* argv[]) {
 	int opt = 0;
 	char* ipsw = NULL;
@@ -68,16 +246,16 @@ int main(int argc, char* argv[]) {
 			usage(argc, argv);
 			break;
 
-		case 'v':
-			idevicerestore_debug += 1;
+		case 'd':
+			idevicerestore_debug = 1;
 			break;
 
 		case 'c':
 			idevicerestore_custom = 1;
 			break;
 
-		case 'd':
-			idevicerestore_debug = 3;
+		case 'v':
+			idevicerestore_verbose = 1;
 			break;
 
 		case 'u':
@@ -86,7 +264,7 @@ int main(int argc, char* argv[]) {
 
 		default:
 			usage(argc, argv);
-			break;
+			return -1;
 		}
 	}
 
@@ -97,105 +275,40 @@ int main(int argc, char* argv[]) {
 		ipsw = argv[0];
 
 	if (ipsw == NULL) {
+		usage(argc, argv);
 		error("ERROR: Please supply an IPSW\n");
 		return -1;
 	}
 
-	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 = LOCKDOWN_E_SUCCESS;
-
-	/* determine recovery or normal mode */
-	info("Checking for device in normal mode...\n");
-	device_error = idevice_new(&device, uuid);
-	if (device_error != IDEVICE_E_SUCCESS) {
-		info("Checking for the device in recovery mode...\n");
-		recovery_error = irecv_open(&recovery);
-		if (recovery_error != IRECV_E_SUCCESS) {
-			error("ERROR: Unable to find device, is it plugged in?\n");
-			return -1;
-		}
-		info("Found device in recovery mode\n");
-		idevicerestore_mode = RECOVERY_MODE;
-
-	} else {
-		info("Found device in normal mode\n");
-		idevicerestore_mode = NORMAL_MODE;
-	}
-
-	/* retrieve ECID */
-	if (idevicerestore_mode == NORMAL_MODE) {
-		lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore");
-		if (lockdown_error != LOCKDOWN_E_SUCCESS) {
-			error("ERROR: Unable to connect to lockdownd\n");
-			idevice_free(device);
-			return -1;
-		}
-
-		plist_t unique_chip_node = NULL;
-		lockdown_error = lockdownd_get_value(lockdown, NULL, "UniqueChipID", &unique_chip_node);
-		if (lockdown_error != LOCKDOWN_E_SUCCESS) {
-			error("ERROR: Unable to get UniqueChipID from lockdownd\n");
-			lockdownd_client_free(lockdown);
-			idevice_free(device);
-			return -1;
-		}
-
-		if (!unique_chip_node || plist_get_node_type(unique_chip_node) != PLIST_UINT) {
-			error("ERROR: Unable to get ECID\n");
-			lockdownd_client_free(lockdown);
-			idevice_free(device);
-			return -1;
-		}
-
-		plist_get_uint_val(unique_chip_node, &ecid);
-		lockdownd_client_free(lockdown);
-		plist_free(unique_chip_node);
-		idevice_free(device);
-		lockdown = NULL;
-		device = NULL;
-
-	} else if (idevicerestore_mode == RECOVERY_MODE) {
-		recovery_error = irecv_get_ecid(recovery, &ecid);
-		if (recovery_error != IRECV_E_SUCCESS) {
-			error("ERROR: Unable to get device ECID\n");
-			irecv_close(recovery);
-			return -1;
-		}
-		irecv_close(recovery);
-		recovery = NULL;
+	/* discover the device type */
+	if(get_device(uuid) < 0) {
+		error("ERROR: Unable to find device type\n");
+		return -1;
 	}
 
-	if (ecid != 0) {
-		info("Found ECID %llu\n", ecid);
-	} else {
-		error("Unable to find device ECID\n");
+	/* get the device ECID and determine mode */
+	if(get_ecid(uuid, &ecid) < 0 || ecid == 0) {
+		error("ERROR: Unable to find device ECID\n");
 		return -1;
 	}
+	info("Found ECID %llu\n", ecid);
 
-	/* parse buildmanifest */
-	int buildmanifest_size = 0;
-	char* buildmanifest_data = NULL;
+	/* extract buildmanifest */
+	plist_t buildmanifest = NULL;
 	info("Extracting BuildManifest.plist from IPSW\n");
-	if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &buildmanifest_data, &buildmanifest_size) < 0) {
-		error("ERROR: Unable to extract BuildManifest.plist IPSW\n");
+	if(extract_buildmanifest(ipsw, &buildmanifest) < 0) {
+		error("ERROR: Unable to extract BuildManifest from %s\n", ipsw);
 		return -1;
 	}
 
-	plist_t manifest = NULL;
-	plist_from_xml(buildmanifest_data, buildmanifest_size, &manifest);
-
 	info("Creating TSS request\n");
-	plist_t tss_request = tss_create_request(manifest, ecid);
+	plist_t tss_request = tss_create_request(buildmanifest, ecid);
 	if (tss_request == NULL) {
 		error("ERROR: Unable to create TSS request\n");
-		plist_free(manifest);
+		plist_free(buildmanifest);
 		return -1;
 	}
-	plist_free(manifest);
+	plist_free(buildmanifest);
 
 	info("Sending TSS request\n");
 	plist_t tss_response = tss_send_request(tss_request);
@@ -240,34 +353,12 @@ int main(int argc, char* argv[]) {
 	/* place device into recovery mode if required */
 	if (idevicerestore_mode == NORMAL_MODE) {
 		info("Entering recovery mode...\n");
-		device_error = idevice_new(&device, uuid);
-		if (device_error != IDEVICE_E_SUCCESS) {
-			error("ERROR: Unable to find device\n");
-			plist_free(tss_response);
-			return -1;
-		}
-
-		lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore");
-		if (lockdown_error != LOCKDOWN_E_SUCCESS) {
-			error("ERROR: Unable to connect to lockdownd service\n");
-			plist_free(tss_response);
-			idevice_free(device);
-			return -1;
-		}
-
-		lockdown_error = lockdownd_enter_recovery(lockdown);
-		if (lockdown_error != LOCKDOWN_E_SUCCESS) {
-			error("ERROR: Unable to place device in recovery mode\n");
-			lockdownd_client_free(lockdown);
+		if(normal_enter_recovery(uuid) < 0) {
+			error("ERROR: Unable to place device into recovery mode\n");
 			plist_free(tss_response);
-			idevice_free(device);
 			return -1;
 		}
 
-		lockdownd_client_free(lockdown);
-		idevice_free(device);
-		lockdown = NULL;
-		device = NULL;
 	}
 
 	/* upload data to make device boot restore mode */
@@ -315,7 +406,8 @@ int main(int argc, char* argv[]) {
 		sleep(1);
 	}
 
-	device_error = idevice_new(&device, uuid);
+	idevice_t device = NULL;
+	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);
@@ -364,7 +456,7 @@ int main(int argc, char* argv[]) {
 						char *datatype = NULL;
 						plist_get_string_val(datatype_node, &datatype);
 						if (!strcmp(datatype, "SystemImageData")) {
-							asr_send_system_image_data_from_file(device, restore, filesystem);
+							restore_send_filesystem(device, restore, filesystem);
 
 						} else if (!strcmp(datatype, "KernelCache")) {
 							int kernelcache_size = 0;
@@ -377,7 +469,7 @@ int main(int argc, char* argv[]) {
 							free(kernelcache_data);
 
 						} else if (!strcmp(datatype, "NORData")) {
-							restore_send_nor_data(restore, ipsw, tss_response);
+							restore_send_nor(restore, ipsw, tss_response);
 
 						} else {
 							// Unknown DataType!!
@@ -428,9 +520,8 @@ void usage(int argc, char* argv[]) {
 	printf("  -u, \t\ttarget specific device by its 40-digit device UUID\n");
 	printf("  -h, \t\tprints usage information\n");
 	printf("  -c, \t\trestore with a custom firmware\n");
-	printf("  -v, \t\tenable incremental levels of verboseness\n");
+	printf("  -v, \t\tenable verbose output\n");
 	printf("\n");
-	exit(1);
 }
 
 int write_file(const char* filename, char* data, int size) {
diff --git a/src/idevicerestore.h b/src/idevicerestore.h
index 3dcf1d5..f1861e9 100644
--- a/src/idevicerestore.h
+++ b/src/idevicerestore.h
@@ -22,10 +22,61 @@
 #ifndef IDEVICERESTORE_H
 #define IDEVICERESTORE_H
 
+#define info(...) printf(__VA_ARGS__)
 #define error(...) fprintf(stderr, __VA_ARGS__)
-#define info(...) if(idevicerestore_debug >= 1) fprintf(stderr, __VA_ARGS__)
-#define debug(...) if(idevicerestore_debug >= 2) fprintf(stderr, __VA_ARGS__)
+#define debug(...) if(idevicerestore_debug >= 1) fprintf(stderr, __VA_ARGS__)
 
+#define IPHONE2G_CPID    8900
+#define IPHONE3G_CPID    8900
+#define IPHONE3GS_CPID   8920
+#define IPOD1G_CPID      8900
+#define IPOD2G_CPID      8720
+#define IPOD3G_CPID      8922
+#define IPAD1G_CPID      8930
+
+#define IPHONE2G_BDID       0
+#define IPHONE3G_BDID       4
+#define IPHONE3GS_BDID      0
+#define IPOD1G_BDID         2
+#define IPOD2G_BDID         0
+#define IPOD3G_BDID         2
+#define IPAD1G_BDID         2
+
+typedef enum {
+	UNKNOWN_MODE =       -1,
+	DFU_MODE =            0,
+	NORMAL_MODE =         1,
+	RECOVERY_MODE =       2,
+	RESTORE_MODE =        3
+} idevicerestore_mode_t;
+
+typedef enum {
+	UNKNOWN_DEVICE =     -1,
+	IPHONE2G_DEVICE =     0,
+	IPHONE3G_DEVICE =     1,
+	IPHONE3GS_DEVICE =    2,
+	IPOD1G_DEVICE =       3,
+	IPOD2G_DEVICE =       4,
+	IPOD3G_DEVICE =       5,
+	IPAD1G_DEVICE =       6
+} idevicerestore_device_t;
+
+static char* idevicerestore_products[] = {
+	"iPhone1,1",
+	"iPhone1,2",
+	"iPhone2,1",
+	"iPod1,1",
+	"iPod2,1",
+	"iPod3,1",
+	"iPad1,1",
+	NULL
+};
+
+extern int idevicerestore_quit;
 extern int idevicerestore_debug;
+extern int idevicerestore_custom;
+extern int idevicerestore_verbose;
+extern idevicerestore_mode_t idevicerestore_mode;
+extern idevicerestore_device_t idevicerestore_device;
 
 #endif
diff --git a/src/img3.h b/src/img3.h
index a19ae99..c172455 100644
--- a/src/img3.h
+++ b/src/img3.h
@@ -19,8 +19,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#ifndef IMG3_H
-#define IMG3_H
+#ifndef IDEVICERESTORE_IMG3_H
+#define IDEVICERESTORE_IMG3_H
 
 typedef enum {
     kNorContainer  = 0x696D6733, // img3
diff --git a/src/ipsw.h b/src/ipsw.h
index f764611..20f6bf5 100644
--- a/src/ipsw.h
+++ b/src/ipsw.h
@@ -19,8 +19,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#ifndef IPSW_H
-#define IPSW_H
+#ifndef IDEVICERESTORE_IPSW_H
+#define IDEVICERESTORE_IPSW_H
 
 #include <zip.h>
 
diff --git a/src/normal.c b/src/normal.c
index c7baefd..0420a82 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -19,10 +19,177 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#include <stdio.h>
 #include <stdint.h>
+#include <libimobiledevice/lockdown.h>
+#include <libimobiledevice/libimobiledevice.h>
 
 #include "normal.h"
+#include "idevicerestore.h"
 
-int normal_get_ecid(uint64_t* ecid) {
+int normal_check_mode(const char* uuid) {
+	char* type = NULL;
+	idevice_t device = NULL;
+	lockdownd_client_t lockdown = NULL;
+	idevice_error_t device_error = IDEVICE_E_SUCCESS;
+	lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS;
+
+	device_error = idevice_new(&device, uuid);
+	if (device_error != IDEVICE_E_SUCCESS) {
+		return -1;
+	}
+
+	lockdown_error = lockdownd_client_new(device, &lockdown, "idevicerestore");
+	if (lockdown_error != LOCKDOWN_E_SUCCESS) {
+		idevice_free(device);
+		return -1;
+	}
+
+	lockdown_error = lockdownd_query_type(lockdown, &type);
+	if (lockdown_error != LOCKDOWN_E_SUCCESS) {
+		lockdownd_client_free(lockdown);
+		idevice_free(device);
+		return -1;
+	}
+
+	lockdownd_client_free(lockdown);
+	idevice_free(device);
+	lockdown = NULL;
+	device = NULL;
 	return 0;
 }
+
+int normal_get_device(const char* uuid) {
+	idevice_t device = NULL;
+	char* product_type = NULL;
+	plist_t product_type_node = NULL;
+	lockdownd_client_t lockdown = NULL;
+	idevice_error_t device_error = IDEVICE_E_SUCCESS;
+	lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS;
+
+	device_error = idevice_new(&device, uuid);
+	if (device_error != IDEVICE_E_SUCCESS) {
+		return -1;
+	}
+
+	lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore");
+	if (lockdown_error != LOCKDOWN_E_SUCCESS) {
+		idevice_free(device);
+		return -1;
+	}
+
+	lockdown_error = lockdownd_get_value(lockdown, NULL, "ProductType", &product_type_node);
+	if (lockdown_error != LOCKDOWN_E_SUCCESS) {
+		lockdownd_client_free(lockdown);
+		idevice_free(device);
+		return -1;
+	}
+
+	if (!product_type_node || plist_get_node_type(product_type_node) != PLIST_STRING) {
+		if(product_type_node) plist_free(product_type_node);
+		lockdownd_client_free(lockdown);
+		idevice_free(device);
+		return -1;
+	}
+	plist_get_string_val(product_type_node, &product_type);
+	plist_free(product_type_node);
+
+	lockdownd_client_free(lockdown);
+	idevice_free(device);
+	lockdown = NULL;
+	device = NULL;
+
+	int i = 0;
+	for(i = 0; idevicerestore_products[i] != NULL; i++) {
+		if(!strcmp(product_type, idevicerestore_products[i])) {
+			idevicerestore_device = i;
+			break;
+		}
+	}
+
+	return idevicerestore_device;
+}
+
+int normal_enter_recovery(const char* uuid) {
+	idevice_t device = NULL;
+	lockdownd_client_t lockdown = NULL;
+	idevice_error_t device_error = IDEVICE_E_SUCCESS;
+	lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS;
+
+	device_error = idevice_new(&device, uuid);
+	if (device_error != IDEVICE_E_SUCCESS) {
+		error("ERROR: Unable to find device\n");
+		return -1;
+	}
+
+	lockdown_error = lockdownd_client_new(device, &lockdown, "idevicerestore");
+	if (lockdown_error != LOCKDOWN_E_SUCCESS) {
+		error("ERROR: Unable to connect to lockdownd service\n");
+		idevice_free(device);
+		return -1;
+	}
+
+	lockdown_error = lockdownd_enter_recovery(lockdown);
+	if (lockdown_error != LOCKDOWN_E_SUCCESS) {
+		error("ERROR: Unable to place device in recovery mode\n");
+		lockdownd_client_free(lockdown);
+		idevice_free(device);
+		return -1;
+	}
+
+	lockdownd_client_free(lockdown);
+	idevice_free(device);
+	lockdown = NULL;
+	device = NULL;
+	return 0;
+}
+
+int normal_get_cpid(const char* uuid, uint32_t* cpid) {
+	return 0;
+}
+
+int normal_get_bdid(const char* uuid, uint32_t* bdid) {
+	return 0;
+}
+
+int normal_get_ecid(const char* uuid, uint64_t* ecid) {
+	idevice_t device = NULL;
+	plist_t unique_chip_node = NULL;
+	lockdownd_client_t lockdown = NULL;
+	idevice_error_t device_error = IDEVICE_E_SUCCESS;
+	lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS;
+
+	device_error = idevice_new(&device, uuid);
+	if(device_error != IDEVICE_E_SUCCESS) {
+		return -1;
+	}
+
+	lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore");
+	if (lockdown_error != LOCKDOWN_E_SUCCESS) {
+		error("ERROR: Unable to connect to lockdownd\n");
+		idevice_free(device);
+		return -1;
+	}
+
+	lockdown_error = lockdownd_get_value(lockdown, NULL, "UniqueChipID", &unique_chip_node);
+	if (lockdown_error != LOCKDOWN_E_SUCCESS) {
+		error("ERROR: Unable to get UniqueChipID from lockdownd\n");
+		lockdownd_client_free(lockdown);
+		idevice_free(device);
+		return -1;
+	}
+
+	if (!unique_chip_node || plist_get_node_type(unique_chip_node) != PLIST_UINT) {
+		error("ERROR: Unable to get ECID\n");
+		lockdownd_client_free(lockdown);
+		idevice_free(device);
+		return -1;
+	}
+	plist_get_uint_val(unique_chip_node, ecid);
+	plist_free(unique_chip_node);
+
+	lockdownd_client_free(lockdown);
+	idevice_free(device);
+	lockdown = NULL;
+	device = NULL;
+}
diff --git a/src/normal.h b/src/normal.h
index 3e2868d..bde1de0 100644
--- a/src/normal.h
+++ b/src/normal.h
@@ -19,11 +19,16 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#ifndef NORMAL_H
-#define NORMAL_H
+#ifndef IDEVICERESTORE_NORMAL_H
+#define IDEVICERESTORE_NORMAL_H
 
 #include <stdint.h>
 
-int normal_get_ecid(uint64_t* ecid);
+int normal_check_mode(const char* uuid);
+int normal_get_device(const char* uuid);
+int normal_enter_recovery(const char* uuid);
+int normal_get_cpid(const char* uuid, uint32_t* cpid);
+int normal_get_bdid(const char* uuid, uint32_t* cpid);
+int normal_get_ecid(const char* uuid, uint64_t* ecid);
 
 #endif
diff --git a/src/recovery.c b/src/recovery.c
index 4e2e7ad..9885982 100644
--- a/src/recovery.c
+++ b/src/recovery.c
@@ -29,7 +29,26 @@
 #include "recovery.h"
 #include "idevicerestore.h"
 
-int recovery_send_signed_component(irecv_client_t client, char* ipsw, plist_t tss, char* component) {
+int recovery_check_mode() {
+	irecv_client_t recovery = NULL;
+	irecv_error_t recovery_error = IRECV_E_SUCCESS;
+
+	recovery_error = irecv_open(&recovery);
+	if (recovery_error != IRECV_E_SUCCESS) {
+		return -1;
+	}
+
+	if(recovery->mode == kDfuMode) {
+		irecv_close(recovery);
+		return -1;
+	}
+
+	irecv_close(recovery);
+	recovery = NULL;
+	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;
 	char* path = NULL;
@@ -77,7 +96,7 @@ irecv_error_t recovery_open_with_timeout(irecv_client_t* client) {
 	return error;
 }
 
-int recovery_send_ibec(char* ipsw, plist_t tss) {
+int recovery_send_ibec(const char* ipsw, plist_t tss) {
 	irecv_error_t error = 0;
 	irecv_client_t client = NULL;
 	char* component = "iBEC";
@@ -125,7 +144,7 @@ int recovery_send_ibec(char* ipsw, plist_t tss) {
 	return 0;
 }
 
-int recovery_send_applelogo(char* ipsw, plist_t tss) {
+int recovery_send_applelogo(const char* ipsw, plist_t tss) {
 	irecv_error_t error = 0;
 	irecv_client_t client = NULL;
 	char* component = "AppleLogo";
@@ -167,7 +186,7 @@ int recovery_send_applelogo(char* ipsw, plist_t tss) {
 	return 0;
 }
 
-int recovery_send_devicetree(char* ipsw, plist_t tss) {
+int recovery_send_devicetree(const char* ipsw, plist_t tss) {
 	irecv_error_t error = 0;
 	irecv_client_t client = NULL;
 	char *component = "RestoreDeviceTree";
@@ -199,7 +218,7 @@ int recovery_send_devicetree(char* ipsw, plist_t tss) {
 	return 0;
 }
 
-int recovery_send_ramdisk(char* ipsw, plist_t tss) {
+int recovery_send_ramdisk(const char* ipsw, plist_t tss) {
 	irecv_error_t error = 0;
 	irecv_client_t client = NULL;
 	char *component = "RestoreRamDisk";
@@ -231,7 +250,7 @@ int recovery_send_ramdisk(char* ipsw, plist_t tss) {
 	return 0;
 }
 
-int recovery_send_kernelcache(char* ipsw, plist_t tss) {
+int recovery_send_kernelcache(const char* ipsw, plist_t tss) {
 	irecv_error_t error = 0;
 	irecv_client_t client = NULL;
 	char *component = "RestoreKernelCache";
@@ -265,5 +284,52 @@ int recovery_send_kernelcache(char* ipsw, plist_t tss) {
 
 
 int recovery_get_ecid(uint64_t* ecid) {
+	irecv_client_t recovery = NULL;
+	if(recovery_open_with_timeout(&recovery) < 0) {
+		return -1;
+	}
+
+	irecv_error_t error = irecv_get_ecid(recovery, ecid);
+	if (error != IRECV_E_SUCCESS) {
+		irecv_close(recovery);
+		return -1;
+	}
+
+	irecv_close(recovery);
+	recovery = NULL;
+	return 0;
+}
+
+int recovery_get_cpid(uint32_t* cpid) {
+	irecv_client_t recovery = NULL;
+	if(recovery_open_with_timeout(&recovery) < 0) {
+		return -1;
+	}
+
+	irecv_error_t error = irecv_get_ecid(recovery, cpid);
+	if (error != IRECV_E_SUCCESS) {
+		irecv_close(recovery);
+		return -1;
+	}
+
+	irecv_close(recovery);
+	recovery = NULL;
+	return 0;
+}
+
+int recovery_get_bdid(uint32_t* bdid) {
+	irecv_client_t recovery = NULL;
+	if(recovery_open_with_timeout(&recovery) < 0) {
+		return -1;
+	}
+
+	irecv_error_t error = irecv_get_ecid(recovery, bdid);
+	if (error != IRECV_E_SUCCESS) {
+		irecv_close(recovery);
+		return -1;
+	}
+
+	irecv_close(recovery);
+	recovery = NULL;
 	return 0;
 }
diff --git a/src/recovery.h b/src/recovery.h
index 5495638..86e3af2 100644
--- a/src/recovery.h
+++ b/src/recovery.h
@@ -19,19 +19,22 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#ifndef RECOVERY_H
-#define RECOVERY_H
+#ifndef IDEVICERESTORE_RECOVERY_H
+#define IDEVICERESTORE_RECOVERY_H
 
 #include <stdint.h>
 #include <plist/plist.h>
 
-int recovery_send_signed_component(irecv_client_t client, char* ipsw, plist_t tss, char* component);
+int recovery_check_mode();
+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(char* ipsw, plist_t tss);
-int recovery_send_applelogo(char* ipsw, plist_t tss);
-int recovery_send_devicetree(char* ipsw, plist_t tss);
-int recovery_send_ramdisk(char* ipsw, plist_t tss);
-int recovery_send_kernelcache(char* ipsw, plist_t tss);
+int recovery_send_ibec(const char* ipsw, plist_t tss);
+int recovery_send_applelogo(const char* ipsw, plist_t tss);
+int recovery_send_devicetree(const char* ipsw, plist_t tss);
+int recovery_send_ramdisk(const char* ipsw, plist_t tss);
+int recovery_send_kernelcache(const char* ipsw, plist_t tss);
 int recovery_get_ecid(uint64_t* ecid);
+int recovery_get_cpid(uint32_t* cpid);
+int recovery_get_bdid(uint32_t* bdid);
 
 #endif
diff --git a/src/restore.c b/src/restore.c
index 485df9b..90d8c0e 100644
--- a/src/restore.c
+++ b/src/restore.c
@@ -44,6 +44,39 @@
 #define WAIT_FOR_DEVICE        33
 #define LOAD_NOR               36
 
+int restore_check_mode(const char* uuid) {
+	char* type = NULL;
+	uint64_t version = 0;
+	idevice_t device = NULL;
+	restored_client_t restore = NULL;
+	idevice_error_t device_error = IDEVICE_E_SUCCESS;
+	restored_error_t restore_error = RESTORE_E_SUCCESS;
+
+	device_error = idevice_new(&device, uuid);
+	if (device_error != IDEVICE_E_SUCCESS) {
+		return -1;
+	}
+
+	restore_error = restored_client_new(device, &restore, "idevicerestore");
+	if (restore_error != RESTORE_E_SUCCESS) {
+		idevice_free(device);
+		return -1;
+	}
+
+	restore_error = restored_query_type(restore, &type, &version);
+	if (restore_error != RESTORE_E_SUCCESS) {
+		restored_client_free(restore);
+		idevice_free(device);
+		return -1;
+	}
+
+	restored_client_free(restore);
+	idevice_free(device);
+	restore = NULL;
+	device = NULL;
+	return 0;
+}
+
 const char* restore_progress_string(unsigned int operation) {
 	switch(operation) {
 	case CREATE_PARTITION_MAP:
@@ -98,7 +131,7 @@ int restore_handle_progress_msg(restored_client_t client, plist_t msg) {
 	plist_t node = NULL;
 	uint64_t operation = 0;
 	uint64_t uprogress = 0;
-	uint32_t progress = 0;
+	uint64_t progress = 0;
 
 	node = plist_dict_get_item(msg, "Operation");
 	if (node && PLIST_UINT == plist_get_node_type(node)) {
@@ -111,14 +144,14 @@ int restore_handle_progress_msg(restored_client_t client, plist_t msg) {
 	node = plist_dict_get_item(msg, "Progress");
 	if (node && PLIST_UINT == plist_get_node_type(node)) {
 		plist_get_uint_val(node, &uprogress);
-		progress = (uint32_t) uprogress;
+		progress = uprogress;
 	} else {
 		debug("Failed to parse progress from ProgressMsg plist \n");
 		return 0;
 	}
 
 	if ((progress > 0) && (progress < 100))
-		info("%s - Progress: %ul%%\n", restore_progress_string(operation), progress);
+		info("%s - Progress: %02ull%%\n", restore_progress_string(operation), progress);
 	else
 		info("%s\n", restore_progress_string(operation));
 
@@ -130,7 +163,7 @@ int restore_handle_status_msg(restored_client_t client, plist_t msg) {
 	return 0;
 }
 
-int asr_send_system_image_data_from_file(idevice_t device, restored_client_t client, const char *filesystem) {
+int restore_send_filesystem(idevice_t device, restored_client_t client, const char *filesystem) {
 	int i = 0;
 	char buffer[0x1000];
 	uint32_t recv_bytes = 0;
@@ -314,7 +347,7 @@ int restore_send_kernelcache(restored_client_t client, char *kernel_data, int le
 	return 0;
 }
 
-int restore_send_nor_data(restored_client_t client, char* ipsw, plist_t tss) {
+int restore_send_nor(restored_client_t client, char* ipsw, plist_t tss) {
 	char* llb_path = NULL;
 	char* llb_blob = NULL;
 	if (get_tss_data_by_name(tss, "LLB", &llb_path, &llb_blob) < 0) {
diff --git a/src/restore.h b/src/restore.h
index 644658a..f344b5d 100644
--- a/src/restore.h
+++ b/src/restore.h
@@ -19,18 +19,19 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#ifndef RESTORED_H
-#define RESTORED_H
+#ifndef IDEVICERESTORE_RESTORE_H
+#define IDEVICERESTORE_RESTORE_H
 
 #include <libimobiledevice/restore.h>
 
 #include "restore.h"
 
+int restore_check_mode(const char* uuid);
 int restore_handle_progress_msg(restored_client_t client, plist_t msg);
 int restore_handle_status_msg(restored_client_t client, plist_t msg);
-int asr_send_system_image_data_from_file(idevice_t device, restored_client_t client, const char *filesystem);
+int restore_send_filesystem(idevice_t device, restored_client_t client, const char *filesystem);
 int restore_send_kernelcache(restored_client_t client, char *kernel_data, int len);
-int restore_send_nor_data(restored_client_t client, char* ipsw, plist_t tss);
+int restore_send_nor(restored_client_t client, char* ipsw, plist_t tss);
 const char* restore_progress_string(unsigned int operation);
 
 #endif
diff --git a/src/tss.h b/src/tss.h
index c1ff4b4..c264ee3 100644
--- a/src/tss.h
+++ b/src/tss.h
@@ -19,8 +19,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#ifndef TSS_H
-#define TSS_H
+#ifndef IDEVICERESTORE_TSS_H
+#define IDEVICERESTORE_TSS_H
 
 #include <plist/plist.h>
 
-- 
cgit v1.1-32-gdbae