Add new idevice_get_device_version() to interface

This allows getting a numerical representation of the device's
ProductVersion string for easier version range checks
diff --git a/include/libimobiledevice/libimobiledevice.h b/include/libimobiledevice/libimobiledevice.h
index 8df3fed..bc57778 100644
--- a/include/libimobiledevice/libimobiledevice.h
+++ b/include/libimobiledevice/libimobiledevice.h
@@ -404,6 +404,19 @@
 LIBIMOBILEDEVICE_API idevice_error_t idevice_get_udid(idevice_t device, char **udid);
 
 /**
+ * Returns the device ProductVersion in numerical form, where "X.Y.Z"
+ * will be returned as (X << 16) | (Y << 8) | Z .
+ * Use IDEVICE_DEVICE_VERSION macro for easy version comparison.
+ * @see IDEVICE_DEVICE_VERSION
+ *
+ * @param client Initialized device client
+ *
+ * @return A numerical representation of the X.Y.Z ProductVersion string
+ *         or 0 if the version cannot be retrieved.
+ */
+LIBIMOBILEDEVICE_API unsigned int idevice_get_device_version(idevice_t device);
+
+/**
  * Gets a readable error string for a given idevice error code.
  *
  * @param err An idevice error code
@@ -419,6 +432,10 @@
  */
 LIBIMOBILEDEVICE_API const char* libimobiledevice_version();
 
+/* macros */
+/** Helper macro to get a numerical representation of a product version tuple */
+#define IDEVICE_DEVICE_VERSION(maj, min, patch) ((((maj) & 0xFF) << 16) | (((min) & 0xFF) << 8) | ((patch) & 0xFF))
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/idevice.c b/src/idevice.c
index e9c909f..1cdfef2 100644
--- a/src/idevice.c
+++ b/src/idevice.c
@@ -946,6 +946,20 @@
 	return IDEVICE_E_SUCCESS;
 }
 
+unsigned int idevice_get_device_version(idevice_t device)
+{
+	if (!device) {
+		return 0;
+	}
+	if (!device->version) {
+		lockdownd_client_t lockdown = NULL;
+		lockdownd_client_new(device, &lockdown, NULL);
+		// we don't handle any errors here. We should have the product version cached now.
+		lockdownd_client_free(lockdown);
+	}
+	return device->version;
+}
+
 #if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS)
 typedef ssize_t ssl_cb_ret_type_t;
 #elif defined(HAVE_MBEDTLS)
@@ -1229,7 +1243,7 @@
 #if OPENSSL_VERSION_NUMBER < 0x10100002L || \
 	(defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x2060000fL))
 	/* force use of TLSv1 for older devices */
-	if (connection->device->version < DEVICE_VERSION(10,0,0)) {
+	if (connection->device->version < IDEVICE_DEVICE_VERSION(10,0,0)) {
 #ifdef SSL_OP_NO_TLSv1_1
 		SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_1);
 #endif
diff --git a/src/idevice.h b/src/idevice.h
index dd72f9d..e05338e 100644
--- a/src/idevice.h
+++ b/src/idevice.h
@@ -52,8 +52,6 @@
 #include "common/userpref.h"
 #include "libimobiledevice/libimobiledevice.h"
 
-#define DEVICE_VERSION(maj, min, patch) (((maj & 0xFF) << 16) | ((min & 0xFF) << 8) | (patch & 0xFF))
-
 #define DEVICE_CLASS_IPHONE  1
 #define DEVICE_CLASS_IPAD    2
 #define DEVICE_CLASS_IPOD    3
diff --git a/src/lockdown-cu.c b/src/lockdown-cu.c
index 9fbd2c8..30eec99 100644
--- a/src/lockdown-cu.c
+++ b/src/lockdown-cu.c
@@ -509,7 +509,7 @@
 			char *s_version = NULL;
 			plist_get_string_val(p_version, &s_version);
 			if (s_version && sscanf(s_version, "%d.%d.%d", &vers[0], &vers[1], &vers[2]) >= 2) {
-				client->device->version = DEVICE_VERSION(vers[0], vers[1], vers[2]);
+				client->device->version = IDEVICE_DEVICE_VERSION(vers[0], vers[1], vers[2]);
 			}
 			free(s_version);
 		}
@@ -962,7 +962,7 @@
 
 	// Starting with iOS/tvOS 11.2 and WatchOS 4.2, this nonce is random and sent along with the request. Before, the request doesn't have a nonce and it uses hardcoded nonce "sendone01234".
 	unsigned char cu_nonce[12] = "sendone01234"; // guaranteed to be random by fair dice troll
-        if (client->device->version >= DEVICE_VERSION(11,2,0)) {
+        if (client->device->version >= IDEVICE_DEVICE_VERSION(11,2,0)) {
 #if defined(HAVE_OPENSSL)
 		RAND_bytes(cu_nonce, sizeof(cu_nonce));
 #elif defined(HAVE_GCRYPT)
diff --git a/src/lockdown.c b/src/lockdown.c
index 411136c..a1ad67b 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -659,7 +659,7 @@
 			char *s_version = NULL;
 			plist_get_string_val(p_version, &s_version);
 			if (s_version && sscanf(s_version, "%d.%d.%d", &vers[0], &vers[1], &vers[2]) >= 2) {
-				device->version = DEVICE_VERSION(vers[0], vers[1], vers[2]);
+				device->version = IDEVICE_DEVICE_VERSION(vers[0], vers[1], vers[2]);
 			}
 			free(s_version);
 		}
@@ -733,7 +733,7 @@
 	plist_free(pair_record);
 	pair_record = NULL;
 
-	if (device->version < DEVICE_VERSION(7,0,0) && device->device_class != DEVICE_CLASS_WATCH) {
+	if (device->version < IDEVICE_DEVICE_VERSION(7,0,0) && device->device_class != DEVICE_CLASS_WATCH) {
 		/* for older devices, we need to validate pairing to receive trusted host status */
 		ret = lockdownd_validate_pair(client_loc, NULL);