From 0f7af902dc07f3487f0d540923f0956fbcd30ebd Mon Sep 17 00:00:00 2001
From: Nikias Bassen
Date: Sun, 29 Jul 2012 05:56:00 +0200
Subject: move main() code after option parsing to separate function

---
 src/common.h         |   4 +-
 src/idevicerestore.c | 324 ++++++++++++++++++++++++++++++++++-----------------
 src/idevicerestore.h |  12 ++
 3 files changed, 233 insertions(+), 107 deletions(-)

diff --git a/src/common.h b/src/common.h
index 3f7d20e..d6be6bb 100644
--- a/src/common.h
+++ b/src/common.h
@@ -80,7 +80,7 @@ struct idevicerestore_client_t {
 	int nonce_size;
 	char* udid;
 	char* srnm;
-	const char* ipsw;
+	char* ipsw;
 	const char* filesystem;
 	struct dfu_client_t* dfu;
 	struct normal_client_t* normal;
@@ -127,8 +127,6 @@ char *generate_guid();
 
 int mkdir_with_parents(const char *dir, int mode);
 
-extern struct idevicerestore_client_t* idevicerestore;
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/idevicerestore.c b/src/idevicerestore.c
index 059ae08..02c1bc1 100644
--- a/src/idevicerestore.c
+++ b/src/idevicerestore.c
@@ -153,108 +153,23 @@ static int load_version_data(struct idevicerestore_client_t* client)
 	return 0;
 }
 
-int main(int argc, char* argv[]) {
-	int opt = 0;
-	int optindex = 0;
-	char* ipsw = NULL;
-	char* udid = NULL;
+int idevicerestore_start(struct idevicerestore_client_t* client)
+{
 	int tss_enabled = 0;
 	int result = 0;
 
-	// create an instance of our context
-	struct idevicerestore_client_t* client = (struct idevicerestore_client_t*) malloc(sizeof(struct idevicerestore_client_t));
-	if (client == NULL) {
-		error("ERROR: Out of memory\n");
+	if (!client) {
 		return -1;
 	}
-	memset(client, '\0', sizeof(struct idevicerestore_client_t));
 
-	while ((opt = getopt_long(argc, argv, "dhcesxtpli:u:nC:", longopts, &optindex)) > 0) {
-		switch (opt) {
-		case 'h':
-			usage(argc, argv);
-			return 0;
-
-		case 'd':
-			client->flags |= FLAG_DEBUG;
-			idevicerestore_debug = 1;
-			break;
-
-		case 'e':
-			client->flags |= FLAG_ERASE;
-			break;
-
-		case 'c':
-			client->flags |= FLAG_CUSTOM;
-			break;
-
-		case 's':
-			client->tss_url = strdup("http://cydia.saurik.com/TSS/controller?action=2");
-			break;
-
-		case 'x':
-			client->flags |= FLAG_EXCLUDE;
-			break;
-
-		case 'l':
-			client->flags |= FLAG_LATEST;
-			break;
-
-		case 'i':
-			if (optarg) {
-				char* tail = NULL;
-				client->ecid = strtoull(optarg, &tail, 16);
-				if (tail && (tail[0] != '\0')) {
-					client->ecid = 0;
-				}
-				if (client->ecid == 0) {
-					error("ERROR: Could not parse ECID from '%s'\n", optarg);
-					return -1;
-				}
-			}
-			break;
-
-		case 'u':
-			udid = optarg;
-			break;
-
-		case 't':
-			client->flags |= FLAG_SHSHONLY;
-			break;
-
-		case 'p':
-			client->flags |= FLAG_PWN;
-			break;
-
-		case 'n':
-			client->flags |= FLAG_NOACTION;
-			break;
-
-		case 'C':
-			client->cache_dir = strdup(optarg);
-			break;
-
-		default:
-			usage(argc, argv);
-			return -1;
-		}
-	}
-
-	if (((argc-optind) == 1) || (client->flags & FLAG_PWN) || (client->flags & FLAG_LATEST)) {
-		argc -= optind;
-		argv += optind;
-
-		ipsw = argv[0];
-	} else {
-		usage(argc, argv);
+	if ((client->flags & FLAG_LATEST) && (client->flags & FLAG_CUSTOM)) {
+		error("ERROR: FLAG_LATEST cannot be used with FLAG_CUSTOM.\n");
 		return -1;
 	}
 
-	if (client->flags & FLAG_LATEST) {
-		if (client->flags & FLAG_CUSTOM) {
-			error("ERROR: You can't use --custom and --latest options at the same time.\n");
-			return -1;
-		}
+	if (!client->ipsw && !(client->flags & FLAG_PWN) && !(client->flags & FLAG_LATEST)) {
+		error("ERROR: no ipsw file given\n");
+		return -1;
 	}
 
 	if (client->flags & FLAG_DEBUG) {
@@ -262,9 +177,6 @@ int main(int argc, char* argv[]) {
 		irecv_set_debug_level(1);
 	}
 
-	client->udid = udid;
-	client->ipsw = ipsw;
-
 	// update version data (from cache, or apple if too old)
 	load_version_data(client);
 
@@ -374,8 +286,12 @@ int main(int argc, char* argv[]) {
 	}
 
 	if (client->flags & FLAG_LATEST) {
+		char* ipsw = NULL;
 		int res = ipsw_download_latest_fw(client->version_data, client->device->product, "cache", &ipsw);
 		if (res != 0) {
+			if (ipsw) {
+				free(ipsw);
+			}
 			return res;
 		} else {
 			client->ipsw = ipsw;
@@ -398,8 +314,8 @@ int main(int argc, char* argv[]) {
 	}
 
 	// verify if ipsw file exists
-	if (access(ipsw, F_OK) < 0) {
-		error("ERROR: Firmware file %s does not exist.\n", ipsw);
+	if (access(client->ipsw, F_OK) < 0) {
+		error("ERROR: Firmware file %s does not exist.\n", client->ipsw);
 		return -1;
 	}
 
@@ -407,14 +323,14 @@ int main(int argc, char* argv[]) {
 	plist_t buildmanifest = NULL;
 	if (client->flags & FLAG_CUSTOM) {
 		info("Extracting Restore.plist from IPSW\n");
-		if (ipsw_extract_restore_plist(ipsw, &buildmanifest) < 0) {
-			error("ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", ipsw);
+		if (ipsw_extract_restore_plist(client->ipsw, &buildmanifest) < 0) {
+			error("ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw);
 			return -1;
 		}
 	} else {
 		info("Extracting BuildManifest from IPSW\n");
-		if (ipsw_extract_build_manifest(ipsw, &buildmanifest, &tss_enabled) < 0) {
-			error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", ipsw);
+		if (ipsw_extract_build_manifest(client->ipsw, &buildmanifest, &tss_enabled) < 0) {
+			error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw);
 			return -1;
 		}
 	}
@@ -473,7 +389,7 @@ int main(int argc, char* argv[]) {
 			char *files[16];
 			char *fmanifest = NULL;
 			uint32_t msize = 0;
-			if (ipsw_extract_to_memory(ipsw, tmpstr, &fmanifest, &msize) < 0) {
+			if (ipsw_extract_to_memory(client->ipsw, tmpstr, &fmanifest, &msize) < 0) {
 				error("ERROR: could not extract %s from IPSW\n", tmpstr);
 				return -1;
 			}
@@ -707,7 +623,7 @@ int main(int argc, char* argv[]) {
 		strcat(tmpf, basename(ipswtmp));
 		free(ipswtmp);
 	} else {
-		strcpy(tmpf, ipsw);
+		strcpy(tmpf, client->ipsw);
 	}
 	char* p = strrchr((const char*)tmpf, '.');
 	if (p) {
@@ -918,6 +834,206 @@ int main(int argc, char* argv[]) {
 	return result;
 }
 
+struct idevicerestore_client_t* idevicerestore_client_new()
+{
+	struct idevicerestore_client_t* client = (struct idevicerestore_client_t*) malloc(sizeof(struct idevicerestore_client_t));
+	if (client == NULL) {
+		error("ERROR: Out of memory\n");
+		return NULL;
+	}
+	memset(client, '\0', sizeof(struct idevicerestore_client_t));
+	return client;
+}
+
+void idevicerestore_client_free(struct idevicerestore_client_t* client)
+{
+	if (!client) {
+		return;
+	}
+
+	if (client->tss_url) {
+		free(client->tss_url);
+	}
+	if (client->version_data) {
+		plist_free(client->version_data);
+	}
+	if (client->nonce) {
+		free(client->nonce);
+	}
+	if (client->udid) {
+		free(client->udid);
+	}
+	if (client->srnm) {
+		free(client->srnm);
+	}
+	if (client->ipsw) {
+		free(client->ipsw);
+	}
+	if (client->version) {
+		free(client->version);
+	}
+	if (client->build) {
+		free(client->build);
+	}
+	if (client->restore_boot_args) {
+		free(client->restore_boot_args);
+	}
+	if (client->cache_dir) {
+		free(client->cache_dir);
+	}
+	free(client);
+}
+
+void idevicerestore_set_ecid(struct idevicerestore_client_t* client, unsigned long long ecid)
+{
+	if (!client)
+		return;
+	client->ecid = ecid;
+}
+
+void idevicerestore_set_udid(struct idevicerestore_client_t* client, const char* udid)
+{
+	if (!client)
+		return;
+	if (client->udid) {
+		free(client->udid);
+		client->udid = NULL;
+	}
+	if (udid) {
+		client->udid = strdup(udid);
+	}
+}
+
+void idevicerestore_set_flags(struct idevicerestore_client_t* client, int flags)
+{
+	if (!client)
+		return;
+	client->flags = flags;
+}
+
+void idevicerestore_set_ipsw(struct idevicerestore_client_t* client, const char* path)
+{
+	if (!client)
+		return;
+	if (client->ipsw) {
+		free(client->ipsw);
+		client->ipsw = NULL;
+	}
+	if (path) {
+		client->ipsw = strdup(path);
+	}
+}
+
+#ifndef IDEVICERESTORE_NOMAIN
+int main(int argc, char* argv[]) {
+	int opt = 0;
+	int optindex = 0;
+	char* ipsw = NULL;
+	char* udid = NULL;
+	int result = 0;
+
+	struct idevicerestore_client_t* client = idevicerestore_client_new();
+	if (client == NULL) {
+		error("ERROR: could not create idevicerestore client\n");
+		return -1;
+	}
+
+	while ((opt = getopt_long(argc, argv, "dhcesxtpli:u:nC:", longopts, &optindex)) > 0) {
+		switch (opt) {
+		case 'h':
+			usage(argc, argv);
+			return 0;
+
+		case 'd':
+			client->flags |= FLAG_DEBUG;
+			idevicerestore_debug = 1;
+			break;
+
+		case 'e':
+			client->flags |= FLAG_ERASE;
+			break;
+
+		case 'c':
+			client->flags |= FLAG_CUSTOM;
+			break;
+
+		case 's':
+			client->tss_url = strdup("http://cydia.saurik.com/TSS/controller?action=2");
+			break;
+
+		case 'x':
+			client->flags |= FLAG_EXCLUDE;
+			break;
+
+		case 'l':
+			client->flags |= FLAG_LATEST;
+			break;
+
+		case 'i':
+			if (optarg) {
+				char* tail = NULL;
+				client->ecid = strtoull(optarg, &tail, 16);
+				if (tail && (tail[0] != '\0')) {
+					client->ecid = 0;
+				}
+				if (client->ecid == 0) {
+					error("ERROR: Could not parse ECID from '%s'\n", optarg);
+					return -1;
+				}
+			}
+			break;
+
+		case 'u':
+			client->udid = strdup(optarg);
+			break;
+
+		case 't':
+			client->flags |= FLAG_SHSHONLY;
+			break;
+
+		case 'p':
+			client->flags |= FLAG_PWN;
+			break;
+
+		case 'n':
+			client->flags |= FLAG_NOACTION;
+			break;
+
+		case 'C':
+			client->cache_dir = strdup(optarg);
+			break;
+
+		default:
+			usage(argc, argv);
+			return -1;
+		}
+	}
+
+	if (((argc-optind) == 1) || (client->flags & FLAG_PWN) || (client->flags & FLAG_LATEST)) {
+		argc -= optind;
+		argv += optind;
+
+		ipsw = argv[0];
+	} else {
+		usage(argc, argv);
+		return -1;
+	}
+
+	if ((client->flags & FLAG_LATEST) && (client->flags & FLAG_CUSTOM)) {
+		error("ERROR: You can't use --custom and --latest options at the same time.\n");
+		return -1;
+	}
+
+	client->ipsw = strdup(ipsw);
+
+	result = idevicerestore_start(client);
+
+	idevicerestore_client_free(client);
+
+	return result;
+}
+#endif
+
 int check_mode(struct idevicerestore_client_t* client) {
 	int mode = MODE_UNKNOWN;
 	int dfumode = MODE_UNKNOWN;
diff --git a/src/idevicerestore.h b/src/idevicerestore.h
index 4d25428..446edf4 100644
--- a/src/idevicerestore.h
+++ b/src/idevicerestore.h
@@ -31,6 +31,18 @@ extern "C" {
 
 #include "common.h"
 
+struct idevicerestore_client_t;
+
+struct idevicerestore_client_t* idevicerestore_client_new();
+void idevicerestore_client_free(struct idevicerestore_client_t* client);
+
+void idevicerestore_set_ecid(struct idevicerestore_client_t* client, unsigned long long ecid);
+void idevicerestore_set_udid(struct idevicerestore_client_t* client, const char* udid);
+void idevicerestore_set_flags(struct idevicerestore_client_t* client, int flags);
+void idevicerestore_set_ipsw(struct idevicerestore_client_t* client, const char* path);
+
+int idevicerestore_start(struct idevicerestore_client_t* client);
+
 void usage(int argc, char* argv[]);
 int check_mode(struct idevicerestore_client_t* client);
 int check_device(struct idevicerestore_client_t* client);
-- 
cgit v1.1-32-gdbae