Properly set ProgName (and BundleID if available) in plist messages to usbmuxd
diff --git a/configure.ac b/configure.ac
index f44e26c..13d6b20 100644
--- a/configure.ac
+++ b/configure.ac
@@ -24,6 +24,8 @@
 AC_SUBST(LIBUSBMUXD_SO_VERSION)
 AC_SUBST(LIBPLIST_VERSION)
 
+AC_GNU_SOURCE
+
 # Checks for programs.
 AC_PROG_CC
 AC_PROG_CXX
diff --git a/src/libusbmuxd.c b/src/libusbmuxd.c
index f7508c5..20f7aa1 100644
--- a/src/libusbmuxd.c
+++ b/src/libusbmuxd.c
@@ -20,16 +20,15 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
 #include <stdint.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
 #ifdef WIN32
   #define USBMUXD_API __declspec( dllexport )
 #else
@@ -60,6 +59,13 @@
 #include <sys/socket.h>
 #include <arpa/inet.h>
 #include <pthread.h>
+#ifdef _GNU_SOURCE
+extern char *program_invocation_short_name;
+#endif
+#ifdef __APPLE__
+extern int _NSGetExecutablePath(char* buf, uint32_t* bufsize);
+#include <sys/stat.h>
+#endif
 #endif
 
 #ifdef HAVE_INOTIFY
@@ -71,11 +77,12 @@
 #endif /* HAVE_INOTIFY */
 
 #include <plist/plist.h>
-#define PLIST_BUNDLE_ID "org.libimobiledevice.usbmuxd"
 #define PLIST_CLIENT_VERSION_STRING "usbmuxd built for freedom"
-#define PLIST_PROGNAME "libusbmuxd"
 #define PLIST_LIBUSBMUX_VERSION 3
 
+static char *bundle_id = NULL;
+static char *prog_name = NULL;
+
 // usbmuxd public interface
 #include "usbmuxd.h"
 // usbmuxd protocol
@@ -406,13 +413,163 @@
 	return res;
 }
 
+static void get_bundle_id()
+{
+#if defined (__APPLE__)
+	char CONTENTS_INFO_PLIST[] = "Contents/Info.plist";
+	char* execpath = malloc(1024);
+	uint32_t size = 1024;
+	if (_NSGetExecutablePath(execpath, &size) != 0) {
+		free(execpath);
+		return;
+	}
+	// strip off executable name
+	char *p = execpath + strlen(execpath) - 1;
+	while (p > execpath && *p != '/') p--;
+	if (*p == '/') *p = '\0';
+	// now walk back trying to find "/Contents/MacOS", and strip it off
+	int macos_found = 0;
+	while (p > execpath) {
+		p--;
+		if (*p != '/') continue;
+		if (strcmp(p, "/.") == 0) {
+			*p = '\0';
+		} else if (!macos_found && strcmp(p, "/MacOS") == 0) {
+			*p = '\0';
+			macos_found++;
+		} else if (macos_found && strcmp(p, "/Contents") == 0) {
+			*p = '\0';
+			break;
+		} else {
+			break;
+		}
+	}
+	// now just append "/Contents/Info.plist"
+	size_t len = strlen(execpath) + sizeof(CONTENTS_INFO_PLIST) + 1;
+	char *infopl = malloc(len);
+	snprintf(infopl, len, "%s/%s", execpath, CONTENTS_INFO_PLIST);
+	free(execpath);
+	struct stat fst;
+	fst.st_size = 0;
+	if (stat(infopl, &fst) != 0) {
+		free(infopl);
+		return;
+	}
+	size_t fsize = fst.st_size;
+	if (fsize < 8) {
+		free(infopl);
+		return;
+	}
+	FILE *f = fopen(infopl, "r");
+	free(infopl);
+	if (!f)
+		return;
+	char *buf = malloc(fsize);
+	if (!buf)
+		return;
+	if (fread(buf, 1, fsize, f) == fsize) {
+		plist_t pl = NULL;
+		if (memcmp(buf, "bplist00", 8) == 0) {
+			plist_from_bin(buf, fst.st_size, &pl);
+		} else {
+			plist_from_xml(buf, fst.st_size, &pl);
+		}
+		if (pl) {
+			plist_t bid = plist_dict_get_item(pl, "CFBundleIdentifier");
+			if (plist_get_node_type(bid) == PLIST_STRING) {
+				plist_get_string_val(bid, &bundle_id);
+			}
+			plist_free(pl);
+		}
+	}
+	free(buf);
+	fclose(f);
+#endif
+}
+
+static void get_prog_name()
+{
+#if defined(__APPLE__) || defined(__FreeBSD__)
+	const char *pname = getprogname();
+	if (pname) {
+		prog_name = strdup(pname);
+	}
+#elif defined (WIN32)
+	TCHAR *_pname = malloc((MAX_PATH+1) * sizeof(TCHAR));
+	if (GetModuleFileName(NULL, _pname, MAX_PATH+1) > 0) {
+		char* pname = NULL;
+	#if defined(UNICODE) || defined(_UNICODE)
+		char* __pname = NULL;
+		int l = WideCharToMultiByte(CP_UTF8, 0, _pname, -1, NULL, 0, NULL, NULL);
+		if (l > 0) {
+			__pname = malloc(l);
+			if (WideCharToMultiByte(CP_UTF8, 0, _pname, -1, __pname, l, NULL, NULL) > 0) {
+				pname = __pname;
+			}
+		}
+	#else
+		pname = _pname;
+	#endif
+		if (pname) {
+			char *p = pname+strlen(pname)-1;
+			while (p > pname && *p != '\\' && *p != '/') p--;
+			if (*p == '\\' || *p == '/') p++;
+			prog_name = strdup(p);
+		}
+	#if defined(UNICODE) || defined(_UNICODE)
+		free(__pname);
+	#endif
+	}
+	free(_pname);
+#elif defined (_GNU_SOURCE)
+	char *pname = program_invocation_short_name;
+	if (pname) {
+		prog_name = strdup(pname);
+	}
+#elif defined (__linux__)
+	FILE *f = fopen("/proc/self/stat", "r");
+	if (!f) {
+		return;
+	}
+	char *tmpbuf = malloc(512);
+	size_t r = fread(tmpbuf, 1, 512, f);
+	if (r > 0) {
+		char *p = tmpbuf;
+		while ((p-tmpbuf < r) && (*p != '(') && (*p != '\0')) p++;
+		if (*p == '(') {
+			p++;
+			char *pname = p;
+			while ((p-tmpbuf < r) && (*p != ')') && (*p != '\0')) p++;
+			if (*p == ')') {
+				*p = '\0';
+				prog_name = strdup(pname);
+			}
+		}
+	}
+	free(tmpbuf);
+	fclose(f);
+#else
+	#warning FIXME: no method to determine program name
+#endif
+}
+
 static plist_t create_plist_message(const char* message_type)
 {
+	if (!bundle_id) {
+		get_bundle_id();
+	}
+	if (!prog_name) {
+		get_prog_name();
+	}
 	plist_t plist = plist_new_dict();
-	plist_dict_set_item(plist, "BundleID", plist_new_string(PLIST_BUNDLE_ID));
+	if (bundle_id) {
+		plist_dict_set_item(plist, "BundleID", plist_new_string(bundle_id));
+	}
 	plist_dict_set_item(plist, "ClientVersionString", plist_new_string(PLIST_CLIENT_VERSION_STRING));
 	plist_dict_set_item(plist, "MessageType", plist_new_string(message_type));
-	plist_dict_set_item(plist, "ProgName", plist_new_string(PLIST_PROGNAME));	
+	if (prog_name) {
+		plist_dict_set_item(plist, "ProgName", plist_new_string(prog_name));
+	}
 	plist_dict_set_item(plist, "kLibUSBMuxVersion", plist_new_uint(PLIST_LIBUSBMUX_VERSION));
 	return plist;
 }