diff --git a/CMakeLists.txt b/CMakeLists.txt
index 723b0de75adc14f027ddbbb8bfb3c68c5fbe44ea..d0f53f1aea2577d5f0e54a59a478d972a8cb68e8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -54,6 +54,7 @@ option(ENABLE_TOOLS "Turn on or off compilation of tools." YES)
 option(ENABLE_TUNNEL "Turn on compilation of tunnel support." NO)
 option(ENABLE_TUTORIALS "Enable compilation of tutorials." YES)
 option(ENABLE_UNIT_TESTS "Enable compilation of unit tests." YES)
+option(ENABLE_UPDATE_CHECK "Enable update check." NO)
 option(ENABLE_VIDEO "Build with video support." YES)
 cmake_dependent_option(ENABLE_ASSISTANT "Turn on assistant compiling." YES "ENABLE_GTK_UI" NO)
 option(ENABLE_DEBUG_LOGS "Turn on or off debug level logs." NO)
diff --git a/config.h.cmake b/config.h.cmake
index fe8fd97690c10f16c4f21d629bff52772c86cb55..5de3f36a30207dc3d2992889eba08d95cef5d853 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -47,3 +47,4 @@
 #cmakedefine HAVE_LIBUDEV_H 0
 #cmakedefine HAVE_LIME
 #cmakedefine ENABLE_NLS 1
+#cmakedefine ENABLE_UPDATE_CHECK 1
diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c
index 0f6ce1e5771e2f45f708244bee3be1ccacdfedc6..f4671904afba50c5209d9eba00ae680638e0fa1a 100644
--- a/coreapi/linphonecore.c
+++ b/coreapi/linphonecore.c
@@ -401,6 +401,15 @@ void linphone_core_cbs_set_call_created(LinphoneCoreCbs *cbs, LinphoneCoreCbsCal
 	cbs->vtable->call_created = cb;
 }
 
+LinphoneCoreCbsVersionUpdateCheckResultReceivedCb linphone_core_cbs_get_version_update_check_result_received(LinphoneCoreCbs *cbs) {
+	return cbs->vtable->version_update_check_result_received;
+}
+
+void linphone_core_cbs_set_version_update_check_result_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsVersionUpdateCheckResultReceivedCb cb) {
+	cbs->vtable->version_update_check_result_received = cb;
+}
+
+
 typedef belle_sip_object_t_vptr_t LinphoneCore_vptr_t;
 BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCore);
 BELLE_SIP_INSTANCIATE_VPTR(LinphoneCore, belle_sip_object_t,
@@ -7245,3 +7254,143 @@ bool_t linphone_core_is_content_type_supported(const LinphoneCore *lc, const cha
 void linphone_core_add_content_type_support(LinphoneCore *lc, const char *content_type) {
 	sal_add_content_type_support(lc->sal, content_type);
 }
+
+#ifdef ENABLE_UPDATE_CHECK
+static void update_check_process_terminated(LinphoneCore *lc, LinphoneVersionUpdateCheckResult result, const char *version, const char *url) {
+	linphone_core_notify_version_update_check_result_received(lc, result, version, url);
+	if (lc->update_check_http_listener) {
+		belle_sip_object_unref(lc->update_check_http_listener);
+		lc->update_check_http_listener = NULL;
+	}
+	bctbx_free(lc->update_check_current_version);
+	lc->update_check_current_version = NULL;
+}
+
+typedef struct _parsed_version_st {
+	int major;
+	int minor;
+	int patch;
+} parsed_version_t;
+
+static int compare_parsed_versions(parsed_version_t current_version, parsed_version_t last_version) {
+	if (last_version.major > current_version.major) return 1;
+	if (last_version.minor > current_version.minor) return 1;
+	if (last_version.patch > current_version.patch) return 1;
+	return -1;
+}
+
+static void parse_version(const char *version, parsed_version_t *parsed_version) {
+	char *copy = bctbx_strdup(version);
+	char *ptr = copy;
+	char *next;
+	memset(parsed_version, 0, sizeof(parsed_version_t));
+	next = strchr(ptr, '.');
+	parsed_version->major = atoi(ptr);
+	ptr = next + 1;
+	next = strchr(ptr, '.');
+	parsed_version->minor = atoi(ptr);
+	if (next != NULL) {
+		ptr = next + 1;
+		parsed_version->patch = atoi(ptr);
+	}
+	bctbx_free(copy);
+}
+
+static bool_t update_is_available(const char *current_version, const char *last_version) {
+	parsed_version_t current_parsed_version;
+	parsed_version_t last_parsed_version;
+	parse_version(current_version, &current_parsed_version);
+	parse_version(last_version, &last_parsed_version);
+	return (compare_parsed_versions(current_parsed_version, last_parsed_version) > 0) ? TRUE : FALSE;
+}
+
+static void update_check_process_response_event(void *ctx, const belle_http_response_event_t *event) {
+	LinphoneCore *lc = (LinphoneCore *)ctx;
+
+	if (belle_http_response_get_status_code(event->response) == 200) {
+		belle_sip_message_t *message = BELLE_SIP_MESSAGE(event->response);
+		char *body = bctbx_strdup(belle_sip_message_get_body(message));
+		char *last_version = body;
+		char *url = strchr(body, '\t');
+		char *ptr;
+		if (url == NULL) {
+			update_check_process_terminated(lc, LinphoneVersionUpdateCheckError, NULL, NULL);
+			bctbx_free(body);
+			return;
+		}
+		*url = '\0';
+		url++;
+		ptr = strrchr(url, '\r');
+		if (ptr != NULL) *ptr = '\0';
+		ptr = strrchr(url, '\n');
+		if (ptr != NULL) *ptr = '\0';
+		if (update_is_available(lc->update_check_current_version, last_version)) {
+			update_check_process_terminated(lc, LinphoneVersionUpdateCheckNewVersionAvailable, last_version, url);
+		} else {
+			update_check_process_terminated(lc, LinphoneVersionUpdateCheckUpToDate, NULL, NULL);
+		}
+		bctbx_free(body);
+	} else {
+		update_check_process_terminated(lc, LinphoneVersionUpdateCheckError, NULL, NULL);
+	}
+}
+
+static void update_check_process_io_error(void *ctx, const belle_sip_io_error_event_t *event) {
+	LinphoneCore *lc = (LinphoneCore *)ctx;
+	update_check_process_terminated(lc, LinphoneVersionUpdateCheckError, NULL, NULL);
+}
+
+static void update_check_process_timeout(void *ctx, const belle_sip_timeout_event_t *event) {
+	LinphoneCore *lc = (LinphoneCore *)ctx;
+	update_check_process_terminated(lc, LinphoneVersionUpdateCheckError, NULL, NULL);
+}
+
+static void update_check_process_auth_requested(void *ctx, belle_sip_auth_event_t *event) {
+	LinphoneCore *lc = (LinphoneCore *)ctx;
+	update_check_process_terminated(lc, LinphoneVersionUpdateCheckError, NULL, NULL);
+}
+#endif /* ENABLE_UPDATE_CHECK */
+
+void linphone_core_check_for_update(LinphoneCore *lc, const char *current_version) {
+#ifdef ENABLE_UPDATE_CHECK
+	int err;
+	bool_t is_desktop = FALSE;
+	const char *platform = NULL;
+	const char *version_check_url_root = lp_config_get_string(lc->config, "misc", "version_check_url_root", NULL);
+
+	if (version_check_url_root != NULL) {
+		belle_http_request_listener_callbacks_t belle_request_listener = { 0 };
+		belle_http_request_t *request;
+		belle_generic_uri_t *uri;
+		char *version_check_url;
+		MSList *item;
+		MSList *platform_tags = ms_factory_get_platform_tags(linphone_core_get_ms_factory(lc));
+
+		for (item = platform_tags; item != NULL; item = ms_list_next(item)) {
+			const char *tag = (const char *)item->data;
+			if (strcmp(tag, "win32") == 0) platform = "windows";
+			else if (strcmp(tag, "apple") == 0) platform = "macosx";
+			else if (strcmp(tag, "linux") == 0) platform = "linux";
+			else if (strcmp(tag, "desktop") == 0) is_desktop = TRUE;
+		}
+		if ((is_desktop == FALSE) || (platform == NULL)) {
+			ms_warning("Update checking is not supported on this platform");
+			return;
+		}
+		version_check_url = bctbx_strdup_printf("%s/%s/RELEASE", version_check_url_root, platform);
+		uri = belle_generic_uri_parse(version_check_url);
+		ms_message("Checking for new version at: %s", version_check_url);
+		bctbx_free(version_check_url);
+
+		belle_request_listener.process_response = update_check_process_response_event;
+		belle_request_listener.process_auth_requested = update_check_process_auth_requested;
+		belle_request_listener.process_io_error = update_check_process_io_error;
+		belle_request_listener.process_timeout = update_check_process_timeout;
+
+		lc->update_check_current_version = bctbx_strdup(current_version);
+		lc->update_check_http_listener = belle_http_request_listener_create_from_callbacks(&belle_request_listener, lc);
+		request = belle_http_request_create("GET", uri, belle_sip_header_create("User-Agent", linphone_core_get_user_agent(lc)), NULL);
+		err = belle_http_provider_send_request(lc->http_provider, request, lc->update_check_http_listener);
+	}
+#endif
+}
diff --git a/coreapi/private.h b/coreapi/private.h
index 4d0c38caf8ff60e91b3997aed71b9a0a0d238e9f..6a29177e3fddd22edee086fb65cd9cd30094f106 100644
--- a/coreapi/private.h
+++ b/coreapi/private.h
@@ -1110,6 +1110,10 @@ struct _LinphoneCore
 	belle_http_provider_t *http_provider;
 	belle_tls_crypto_config_t *http_crypto_config;
 	belle_http_request_listener_t *provisioning_http_listener;
+#ifdef ENABLE_UPDATE_CHECK
+	belle_http_request_listener_t *update_check_http_listener;
+	char *update_check_current_version;
+#endif
 	MSList *tones;
 	LinphoneReason chat_deny_code;
 	char *file_transfer_server;
@@ -1922,6 +1926,7 @@ void linphone_core_notify_log_collection_upload_progress_indication(LinphoneCore
 void linphone_core_notify_friend_list_created(LinphoneCore *lc, LinphoneFriendList *list);
 void linphone_core_notify_friend_list_removed(LinphoneCore *lc, LinphoneFriendList *list);
 void linphone_core_notify_call_created(LinphoneCore *lc, LinphoneCall *call);
+void linphone_core_notify_version_update_check_result_received(LinphoneCore *lc, LinphoneVersionUpdateCheckResult result, const char *version, const char *url);
 
 void set_mic_gain_db(AudioStream *st, float gain);
 void set_playback_gain_db(AudioStream *st, float gain);
diff --git a/coreapi/vtables.c b/coreapi/vtables.c
index d48342b36d7944b462eb0f0e6f639e0f7d1291fb..ca9960ef9092aa3759add56b61920abf9123bb90 100644
--- a/coreapi/vtables.c
+++ b/coreapi/vtables.c
@@ -316,6 +316,11 @@ void linphone_core_notify_call_created(LinphoneCore *lc, LinphoneCall *call) {
 	cleanup_dead_vtable_refs(lc);
 }
 
+void linphone_core_notify_version_update_check_result_received(LinphoneCore *lc, LinphoneVersionUpdateCheckResult result, const char *version, const char *url) {
+	NOTIFY_IF_EXIST(version_update_check_result_received, lc, result, version, url);
+	cleanup_dead_vtable_refs(lc);
+}
+
 static VTableReference * v_table_reference_new(LinphoneCoreCbs *cbs, bool_t internal){
 	VTableReference *ref=ms_new0(VTableReference,1);
 	ref->valid=TRUE;
diff --git a/include/linphone/callbacks.h b/include/linphone/callbacks.h
index b9dd4b7a10ef2031df635ffd48ff2ae85fbef2d4..067d6ca11c0224ab10b4f72abed714560a892b2c 100644
--- a/include/linphone/callbacks.h
+++ b/include/linphone/callbacks.h
@@ -486,6 +486,14 @@ typedef void (*LinphoneCoreCbsFriendListRemovedCb) (LinphoneCore *lc, LinphoneFr
  */
 typedef LinphoneCoreCbsFriendListRemovedCb LinphoneCoreFriendListRemovedCb;
 
+/**
+ * Callback prototype for reporting the result of a version update check.
+ * @param[in] lc LinphoneCore object
+ * @param[in] result The result of the version update check
+ * @param[in] url The url where to download the new version if the result is LinphoneVersionUpdateCheckNewVersionAvailable
+ */
+typedef void (*LinphoneCoreCbsVersionUpdateCheckResultReceivedCb) (LinphoneCore *lc, LinphoneVersionUpdateCheckResult result, const char *version, const char *url);
+
 /**
  * @}
 **/
diff --git a/include/linphone/core.h b/include/linphone/core.h
index 434993a1d6ea1c0131ee9f2fa54cfcfa01104707..eec6369ccbf7bb65d22d5f213b467f53e06edf2e 100644
--- a/include/linphone/core.h
+++ b/include/linphone/core.h
@@ -113,6 +113,13 @@ LINPHONE_PUBLIC LinphonePlayer *linphone_core_create_local_player(LinphoneCore *
 **/
 LINPHONE_PUBLIC LinphoneInfoMessage *linphone_core_create_info_message(LinphoneCore*lc);
 
+/**
+ * Checks if a new version of the application is available.
+ * @param lc LinphoneCore object
+ * @param current_version The current version of the application
+ */
+LINPHONE_PUBLIC void linphone_core_check_for_update(LinphoneCore *lc, const char *current_version);
+
 /**
  * @}
  */
@@ -208,6 +215,7 @@ typedef struct _LinphoneCoreVTable{
 	LinphoneCoreFriendListCreatedCb friend_list_created;
 	LinphoneCoreFriendListRemovedCb friend_list_removed;
 	LinphoneCoreCbsCallCreatedCb call_created;
+	LinphoneCoreCbsVersionUpdateCheckResultReceivedCb version_update_check_result_received;
 	void *user_data; /**<User data associated with the above callbacks */
 } LinphoneCoreVTable;
 
@@ -652,6 +660,20 @@ LINPHONE_PUBLIC void linphone_core_cbs_set_call_created(LinphoneCoreCbs *cbs, Li
  */
 LINPHONE_PUBLIC LinphoneCoreCbsCallCreatedCb linphone_core_cbs_get_call_created(LinphoneCoreCbs *cbs);
 
+/**
+ * Set the version update check result callback.
+ * @param[in] cbs LinphoneCoreCbs object
+ * @param[in] cb The callback to use
+ */
+LINPHONE_PUBLIC void linphone_core_cbs_set_version_update_check_result_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsVersionUpdateCheckResultReceivedCb cb);
+
+/**
+ * Get the version update check result callback.
+ * @param[in] cbs LinphoneCoreCbs object
+ * @return The current callback
+ */
+LINPHONE_PUBLIC LinphoneCoreCbsVersionUpdateCheckResultReceivedCb linphone_core_cbs_get_version_update_check_result_received(LinphoneCoreCbs *cbs);
+
 /**
  * @}
 **/
diff --git a/include/linphone/types.h b/include/linphone/types.h
index dbfcf8ef9bda62be5bd854f0ff39d018aaeaf850..1a99dc630f5f0fb5515eccdf2ff7970fa5c08d54 100644
--- a/include/linphone/types.h
+++ b/include/linphone/types.h
@@ -1148,6 +1148,16 @@ typedef enum _LinphoneUpnpState {
  */
 typedef struct _LinphoneVcard LinphoneVcard;
 
+/**
+ * Enum describing the result of a version update check.
+ * @ingroup misc
+ */
+typedef enum _LinphoneVersionUpdateCheckResult {
+	LinphoneVersionUpdateCheckUpToDate,
+	LinphoneVersionUpdateCheckNewVersionAvailable,
+	LinphoneVersionUpdateCheckError
+} LinphoneVersionUpdateCheckResult;
+
 /**
  * The LinphoneVideoDefinition object represents a video definition, eg. its width and its height.
  * @ingroup media_parameters