/** @file * X11 guest client - host version check. */ /* * Copyright (C) 2009 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ #include #include #include #include #include #include #ifdef VBOX_WITH_DBUS #include #endif #include #include #include "VBoxClient.h" class HostVersionService : public VBoxClient::Service { public: virtual const char *getPidFilePath() { return ".vboxclient-hostversion.pid"; } virtual int showNotify(const char *pcHeader, const char *pcBody) { int rc; # ifdef VBOX_WITH_DBUS DBusConnection *conn; DBusMessage* msg; conn = dbus_bus_get (DBUS_BUS_SESSON, NULL); if (conn == NULL) { LogRelFlowFunc(("Could not retrieve D-BUS session bus!\n")); rc = VERR_INVALID_HANDLE; } else { msg = dbus_message_new_method_call("org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications", "Notify"); if (msg == NULL) { LogRel(("Could not create D-BUS message!\n")); rc = VERR_INVALID_HANDLE; } else rc = VINF_SUCCESS; } if (RT_SUCCESS(rc)) { uint32_t msg_replace_id = 0; const char *msg_app = "VBoxClient"; const char *msg_icon = ""; const char *msg_summary = pcHeader; const char *msg_body = pcBody; int32_t msg_timeout = -1; /* Let the notification server decide */ DBusMessageIter iter; DBusMessageIter array; DBusMessageIter dict; DBusMessageIter value; DBusMessageIter variant; DBusMessageIter data; /* Format: UINT32 org.freedesktop.Notifications.Notify * (STRING app_name, UINT32 replaces_id, STRING app_icon, STRING summary, STRING body, * ARRAY actions, DICT hints, INT32 expire_timeout) */ dbus_message_iter_init_append(msg,&iter); dbus_message_iter_append_basic(&iter,DBUS_TYPE_STRING,&msg_app); dbus_message_iter_append_basic(&iter,DBUS_TYPE_UINT32,&msg_replace_id); dbus_message_iter_append_basic(&iter,DBUS_TYPE_STRING,&msg_icon); dbus_message_iter_append_basic(&iter,DBUS_TYPE_STRING,&msg_summary); dbus_message_iter_append_basic(&iter,DBUS_TYPE_STRING,&msg_body); dbus_message_iter_open_container(&iter,DBUS_TYPE_ARRAY,DBUS_TYPE_STRING_AS_STRING,&array); dbus_message_iter_close_container(&iter,&array); dbus_message_iter_open_container(&iter,DBUS_TYPE_ARRAY,"{sv}",&array); dbus_message_iter_close_container(&iter,&array); dbus_message_iter_append_basic(&iter,DBUS_TYPE_INT32,&msg_timeout); DBusError err; dbus_error_init(&err); DBusMessage *reply; reply = dbus_connection_send_with_reply_and_block(conn, msg, 30 * 1000 /* 30 seconds timeout */, &err); if (dbus_error_is_set(&err)) { LogRel(("D-BUS returned an error while sending the notification: %s", err.message)); } else if (reply) { dbus_connection_flush(conn); dbus_message_unref(reply); } if (dbus_error_is_set(&err)) dbus_error_free(&err); } if (msg != NULL) dbus_message_unref(msg); # else /* TODO: Implement me */ rc = VINF_SUCCESS; # endif /* VBOX_WITH_DBUS */ return rc; } /** @todo Move this part in VbglR3 and just provide a callback for the platform-specific notification stuff, since this is very similar to the VBoxTray code. */ virtual int run(bool fDaemonised /* = false */) { int rc; LogRelFlowFunc(("\n")); /* Because we need desktop notifications to be displayed, wait * some time to make the desktop environment load (as a work around). */ if (fDaemonised) RTThreadSleep(30 * 1000 /* Wait 30 seconds */); # ifdef VBOX_WITH_DBUS rc = RTDBusLoadLib(); if (RT_FAILURE(rc)) LogRel(("VBoxClient: D-Bus seems not to be installed; no host version check/notification done.\n")); # else rc = VERR_NOT_IMPLEMENTED; # endif /* VBOX_WITH_DBUS */ # ifdef VBOX_WITH_GUEST_PROPS uint32_t uGuestPropSvcClientID; if (RT_SUCCESS(rc)) { rc = VbglR3GuestPropConnect(&uGuestPropSvcClientID); if (RT_FAILURE(rc)) LogRel(("Cannot connect to guest property service! rc = %Rrc\n", rc)); } if (RT_SUCCESS(rc)) { char *pszHostVersion; char *pszGuestVersion; bool bUpdate; rc = VbglR3HostVersionCheckForUpdate(uGuestPropSvcClientID, &bUpdate, &pszHostVersion, &pszGuestVersion); if (RT_SUCCESS(rc)) { if (bUpdate) { char szMsg[256]; char szTitle[64]; /** @todo add some translation macros here */ RTStrPrintf(szTitle, sizeof(szTitle), "VirtualBox Guest Additions update available!"); RTStrPrintf(szMsg, sizeof(szMsg), "Your guest is currently running the Guest Additions version %s. " "We recommend updating to the latest version (%s) by choosing the " "install option from the Devices menu.", pszGuestVersion, pszHostVersion); rc = showNotify(szTitle, szMsg); LogRel(("VBoxClient: VirtualBox Guest Additions update available!")); if (RT_FAILURE(rc)) LogRel(("VBoxClient: Could not show version notifier tooltip! rc = %d\n", rc)); } /* Store host version to not notify again */ rc = VbglR3HostVersionLastCheckedStore(uGuestPropSvcClientID, pszHostVersion); VbglR3GuestPropReadValueFree(pszHostVersion); VbglR3GuestPropReadValueFree(pszGuestVersion); } VbglR3GuestPropDisconnect(uGuestPropSvcClientID); } # endif /* VBOX_WITH_GUEST_PROPS */ LogRelFlowFunc(("returning %Rrc\n", rc)); return rc; } virtual void cleanup() { } }; /* Static factory */ VBoxClient::Service *VBoxClient::GetHostVersionService() { return new HostVersionService; }