summaryrefslogtreecommitdiffstats
path: root/toolkit/components/remote/nsDBusRemoteServer.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /toolkit/components/remote/nsDBusRemoteServer.cpp
parentInitial commit. (diff)
downloadthunderbird-upstream.tar.xz
thunderbird-upstream.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/remote/nsDBusRemoteServer.cpp')
-rw-r--r--toolkit/components/remote/nsDBusRemoteServer.cpp214
1 files changed, 214 insertions, 0 deletions
diff --git a/toolkit/components/remote/nsDBusRemoteServer.cpp b/toolkit/components/remote/nsDBusRemoteServer.cpp
new file mode 100644
index 0000000000..34167177d9
--- /dev/null
+++ b/toolkit/components/remote/nsDBusRemoteServer.cpp
@@ -0,0 +1,214 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsDBusRemoteServer.h"
+
+#include "nsCOMPtr.h"
+#include "mozilla/XREAppData.h"
+#include "mozilla/Base64.h"
+#include "mozilla/ScopeExit.h"
+#include "nsPrintfCString.h"
+
+#include "nsGTKToolkit.h"
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include <dlfcn.h>
+
+static const char* introspect_template =
+ "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection "
+ "1.0//EN\"\n"
+ "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
+ "<node>\n"
+ " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
+ " <method name=\"Introspect\">\n"
+ " <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
+ " </method>\n"
+ " </interface>\n"
+ " <interface name=\"org.mozilla.%s\">\n"
+ " <method name=\"OpenURL\">\n"
+ " <arg name=\"url\" direction=\"in\" type=\"ay\"/>\n"
+ " </method>\n"
+ " </interface>\n"
+ "</node>\n";
+
+DBusHandlerResult nsDBusRemoteServer::Introspect(DBusMessage* msg) {
+ DBusMessage* reply = dbus_message_new_method_return(msg);
+ if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ nsAutoCString introspect_xml;
+ introspect_xml = nsPrintfCString(introspect_template, mAppName.get());
+
+ const char* message = introspect_xml.get();
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &message,
+ DBUS_TYPE_INVALID);
+
+ dbus_connection_send(mConnection, reply, nullptr);
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+DBusHandlerResult nsDBusRemoteServer::OpenURL(DBusMessage* msg) {
+ DBusMessage* reply = nullptr;
+ const char* commandLine;
+ int length;
+
+ if (!dbus_message_get_args(msg, nullptr, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ &commandLine, &length, DBUS_TYPE_INVALID) ||
+ length == 0) {
+ nsAutoCString errorMsg;
+ errorMsg = nsPrintfCString("org.mozilla.%s.Error", mAppName.get());
+ reply = dbus_message_new_error(msg, errorMsg.get(), "Wrong argument");
+ } else {
+ guint32 timestamp = gtk_get_current_event_time();
+ if (timestamp == GDK_CURRENT_TIME) {
+ timestamp = guint32(g_get_monotonic_time() / 1000);
+ }
+ HandleCommandLine(commandLine, timestamp);
+ reply = dbus_message_new_method_return(msg);
+ }
+
+ dbus_connection_send(mConnection, reply, nullptr);
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+DBusHandlerResult nsDBusRemoteServer::HandleDBusMessage(
+ DBusConnection* aConnection, DBusMessage* msg) {
+ NS_ASSERTION(mConnection == aConnection, "Wrong D-Bus connection.");
+
+ const char* method = dbus_message_get_member(msg);
+ const char* iface = dbus_message_get_interface(msg);
+
+ if ((strcmp("Introspect", method) == 0) &&
+ (strcmp("org.freedesktop.DBus.Introspectable", iface) == 0)) {
+ return Introspect(msg);
+ }
+
+ nsAutoCString ourInterfaceName;
+ ourInterfaceName = nsPrintfCString("org.mozilla.%s", mAppName.get());
+
+ if ((strcmp("OpenURL", method) == 0) &&
+ (strcmp(ourInterfaceName.get(), iface) == 0)) {
+ return OpenURL(msg);
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+void nsDBusRemoteServer::UnregisterDBusInterface(DBusConnection* aConnection) {
+ NS_ASSERTION(mConnection == aConnection, "Wrong D-Bus connection.");
+ // Not implemented
+}
+
+static DBusHandlerResult message_handler(DBusConnection* conn, DBusMessage* msg,
+ void* user_data) {
+ auto interface = static_cast<nsDBusRemoteServer*>(user_data);
+ return interface->HandleDBusMessage(conn, msg);
+}
+
+static void unregister(DBusConnection* conn, void* user_data) {
+ auto interface = static_cast<nsDBusRemoteServer*>(user_data);
+ interface->UnregisterDBusInterface(conn);
+}
+
+static DBusObjectPathVTable remoteHandlersTable = {
+ .unregister_function = unregister,
+ .message_function = message_handler,
+};
+
+nsresult nsDBusRemoteServer::Startup(const char* aAppName,
+ const char* aProfileName) {
+ if (mConnection && dbus_connection_get_is_connected(mConnection)) {
+ // We're already connected so we don't need to reconnect
+ return NS_ERROR_ALREADY_INITIALIZED;
+ }
+
+ // Don't even try to start without any application/profile name
+ if (!aAppName || aAppName[0] == '\0' || !aProfileName ||
+ aProfileName[0] == '\0')
+ return NS_ERROR_INVALID_ARG;
+
+ mConnection = dont_AddRef(dbus_bus_get(DBUS_BUS_SESSION, nullptr));
+ if (!mConnection) {
+ return NS_ERROR_FAILURE;
+ }
+ auto releaseDBusConnection =
+ mozilla::MakeScopeExit([&] { mConnection = nullptr; });
+ dbus_connection_set_exit_on_disconnect(mConnection, false);
+ dbus_connection_setup_with_g_main(mConnection, nullptr);
+
+ mAppName = aAppName;
+ mozilla::XREAppData::SanitizeNameForDBus(mAppName);
+
+ nsAutoCString profileName;
+ MOZ_TRY(
+ mozilla::Base64Encode(aProfileName, strlen(aProfileName), profileName));
+
+ mozilla::XREAppData::SanitizeNameForDBus(profileName);
+
+ nsPrintfCString busName("org.mozilla.%s.%s", mAppName.get(),
+ profileName.get());
+ if (busName.Length() > DBUS_MAXIMUM_NAME_LENGTH)
+ busName.Truncate(DBUS_MAXIMUM_NAME_LENGTH);
+
+ static auto sDBusValidateBusName = (bool (*)(const char*, DBusError*))dlsym(
+ RTLD_DEFAULT, "dbus_validate_bus_name");
+ if (!sDBusValidateBusName) {
+ return NS_ERROR_FAILURE;
+ }
+
+ // We don't have a valid busName yet - try to create a default one.
+ if (!sDBusValidateBusName(busName.get(), nullptr)) {
+ busName = nsPrintfCString("org.mozilla.%s.%s", mAppName.get(), "default");
+ if (!sDBusValidateBusName(busName.get(), nullptr)) {
+ // We failed completelly to get a valid bus name - just quit
+ // to prevent crash at dbus_bus_request_name().
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ DBusError err;
+ dbus_error_init(&err);
+ dbus_bus_request_name(mConnection, busName.get(), DBUS_NAME_FLAG_DO_NOT_QUEUE,
+ &err);
+ // The interface is already owned - there is another application/profile
+ // instance already running.
+ if (dbus_error_is_set(&err)) {
+ dbus_error_free(&err);
+ return NS_ERROR_FAILURE;
+ }
+
+ mPathName = nsPrintfCString("/org/mozilla/%s/Remote", mAppName.get());
+ static auto sDBusValidatePathName = (bool (*)(const char*, DBusError*))dlsym(
+ RTLD_DEFAULT, "dbus_validate_path");
+ if (!sDBusValidatePathName ||
+ !sDBusValidatePathName(mPathName.get(), nullptr)) {
+ return NS_ERROR_FAILURE;
+ }
+ if (!dbus_connection_register_object_path(mConnection, mPathName.get(),
+ &remoteHandlersTable, this)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ releaseDBusConnection.release();
+ return NS_OK;
+}
+
+void nsDBusRemoteServer::Shutdown() {
+ if (!mConnection) {
+ return;
+ }
+
+ dbus_connection_unregister_object_path(mConnection, mPathName.get());
+
+ // dbus_connection_unref() will be called by RefPtr here.
+ mConnection = nullptr;
+}