summaryrefslogtreecommitdiffstats
path: root/browser/components/shell/nsGNOMEShellDBusHelper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/shell/nsGNOMEShellDBusHelper.cpp')
-rw-r--r--browser/components/shell/nsGNOMEShellDBusHelper.cpp397
1 files changed, 397 insertions, 0 deletions
diff --git a/browser/components/shell/nsGNOMEShellDBusHelper.cpp b/browser/components/shell/nsGNOMEShellDBusHelper.cpp
new file mode 100644
index 0000000000..2349cf8cc2
--- /dev/null
+++ b/browser/components/shell/nsGNOMEShellDBusHelper.cpp
@@ -0,0 +1,397 @@
+/* -*- 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 "nsGNOMEShellSearchProvider.h"
+
+#include "RemoteUtils.h"
+#include "nsIStringBundle.h"
+#include "nsServiceManagerUtils.h"
+#include "nsPrintfCString.h"
+#include "mozilla/XREAppData.h"
+#include "nsAppRunner.h"
+
+#define DBUS_BUS_NAME_TEMPLATE "org.mozilla.%s.SearchProvider"
+#define DBUS_OBJECT_PATH_TEMPLATE "/org/mozilla/%s/SearchProvider"
+
+const char* GetDBusBusName() {
+ static const char* name = []() {
+ nsAutoCString appName;
+ gAppData->GetDBusAppName(appName);
+ return ToNewCString(nsPrintfCString(DBUS_BUS_NAME_TEMPLATE,
+ appName.get())); // Intentionally leak
+ }();
+ return name;
+}
+
+const char* GetDBusObjectPath() {
+ static const char* path = []() {
+ nsAutoCString appName;
+ gAppData->GetDBusAppName(appName);
+ return ToNewCString(nsPrintfCString(DBUS_OBJECT_PATH_TEMPLATE,
+ appName.get())); // Intentionally leak
+ }();
+ return path;
+}
+
+static bool GetGnomeSearchTitle(const char* aSearchedTerm,
+ nsAutoCString& aGnomeSearchTitle) {
+ static nsCOMPtr<nsIStringBundle> bundle;
+ if (!bundle) {
+ nsCOMPtr<nsIStringBundleService> sbs =
+ do_GetService(NS_STRINGBUNDLE_CONTRACTID);
+ if (NS_WARN_IF(!sbs)) {
+ return false;
+ }
+
+ sbs->CreateBundle("chrome://browser/locale/browser.properties",
+ getter_AddRefs(bundle));
+ if (NS_WARN_IF(!bundle)) {
+ return false;
+ }
+ }
+
+ AutoTArray<nsString, 1> formatStrings;
+ CopyUTF8toUTF16(nsCString(aSearchedTerm), *formatStrings.AppendElement());
+
+ nsAutoString gnomeSearchTitle;
+ bundle->FormatStringFromName("gnomeSearchProviderSearchWeb", formatStrings,
+ gnomeSearchTitle);
+ AppendUTF16toUTF8(gnomeSearchTitle, aGnomeSearchTitle);
+ return true;
+}
+
+int DBusGetIndexFromIDKey(const char* aIDKey) {
+ // ID is NN:URL where NN is index to our current history
+ // result container.
+ char tmp[] = {aIDKey[0], aIDKey[1], '\0'};
+ return atoi(tmp);
+}
+
+static void ConcatArray(nsACString& aOutputStr, const char** aStringArray) {
+ for (const char** term = aStringArray; *term; term++) {
+ aOutputStr.Append(*term);
+ if (*(term + 1)) {
+ aOutputStr.Append(" ");
+ }
+ }
+}
+
+// GetInitialResultSet :: (as) → (as)
+// GetSubsearchResultSet :: (as,as) → (as)
+void DBusHandleResultSet(RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult,
+ GVariant* aParameters, bool aInitialSearch,
+ GDBusMethodInvocation* aReply) {
+ // Inital search has params (as), any following one has (as,as) and we want
+ // the second string array.
+ fprintf(stderr, "%s\n", g_variant_get_type_string(aParameters));
+ RefPtr<GVariant> variant = dont_AddRef(
+ g_variant_get_child_value(aParameters, aInitialSearch ? 0 : 1));
+ const char** stringArray = g_variant_get_strv(variant, nullptr);
+ if (!stringArray) {
+ g_dbus_method_invocation_return_error(
+ aReply, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Wrong params!");
+ return;
+ }
+
+ aSearchResult->SetReply(aReply);
+ nsAutoCString searchTerm;
+ ConcatArray(searchTerm, stringArray);
+ aSearchResult->SetSearchTerm(searchTerm.get());
+ GetGNOMEShellHistoryService()->QueryHistory(aSearchResult);
+ // DBus reply will be send asynchronously by
+ // nsGNOMEShellHistorySearchResult::SendDBusSearchResultReply()
+ // when GetGNOMEShellHistoryService() has the results.
+
+ g_free(stringArray);
+}
+
+/*
+ "icon-data": a tuple of type (iiibiiay) describing a pixbuf with width,
+ height, rowstride, has-alpha,
+ bits-per-sample, channels,
+ image data
+*/
+static void DBusAppendIcon(GVariantBuilder* aBuilder, GnomeHistoryIcon* aIcon) {
+ GVariantBuilder b;
+ g_variant_builder_init(&b, G_VARIANT_TYPE("(iiibiiay)"));
+ g_variant_builder_add_value(&b, g_variant_new_int32(aIcon->GetWidth()));
+ g_variant_builder_add_value(&b, g_variant_new_int32(aIcon->GetHeight()));
+ g_variant_builder_add_value(&b, g_variant_new_int32(aIcon->GetWidth() * 4));
+ g_variant_builder_add_value(&b, g_variant_new_boolean(true));
+ g_variant_builder_add_value(&b, g_variant_new_int32(8));
+ g_variant_builder_add_value(&b, g_variant_new_int32(4));
+ g_variant_builder_add_value(
+ &b, g_variant_new_fixed_array(G_VARIANT_TYPE("y"), aIcon->GetData(),
+ aIcon->GetWidth() * aIcon->GetHeight() * 4,
+ sizeof(char)));
+ g_variant_builder_add(aBuilder, "{sv}", "icon-data",
+ g_variant_builder_end(&b));
+}
+
+/* Appends history search results to the DBUS reply.
+
+ We can return those fields at GetResultMetas:
+
+ "id": the result ID
+ "name": the display name for the result
+ "icon": a serialized GIcon (see g_icon_serialize()), or alternatively,
+ "gicon": a textual representation of a GIcon (see g_icon_to_string()),
+ or alternativly,
+ "icon-data": a tuple of type (iiibiiay) describing a pixbuf with width,
+ height, rowstride, has-alpha, bits-per-sample, and image data
+ "description": an optional short description (1-2 lines)
+*/
+static already_AddRefed<GVariant> DBusAppendResultID(
+ nsGNOMEShellHistorySearchResult* aSearchResult, const char* aID) {
+ nsCOMPtr<nsINavHistoryContainerResultNode> container =
+ aSearchResult->GetSearchResultContainer();
+
+ int index = DBusGetIndexFromIDKey(aID);
+ nsCOMPtr<nsINavHistoryResultNode> child;
+ container->GetChild(index, getter_AddRefs(child));
+ nsAutoCString title;
+ if (!child || NS_FAILED(child->GetTitle(title))) {
+ return nullptr;
+ }
+
+ if (title.IsEmpty()) {
+ if (NS_FAILED(child->GetUri(title)) || title.IsEmpty()) {
+ return nullptr;
+ }
+ }
+
+ GVariantBuilder b;
+ g_variant_builder_init(&b, G_VARIANT_TYPE("a{sv}"));
+
+ const char* titleStr = title.get();
+ g_variant_builder_add(&b, "{sv}", "id", g_variant_new_string(aID));
+ g_variant_builder_add(&b, "{sv}", "name", g_variant_new_string(titleStr));
+
+ GnomeHistoryIcon* icon = aSearchResult->GetHistoryIcon(index);
+ if (icon) {
+ DBusAppendIcon(&b, icon);
+ } else {
+ g_variant_builder_add(&b, "{sv}", "gicon",
+ g_variant_new_string("text-html"));
+ }
+ return dont_AddRef(g_variant_ref_sink(g_variant_builder_end(&b)));
+}
+
+// Search the web for: "searchTerm" to the DBUS reply.
+static already_AddRefed<GVariant> DBusAppendSearchID(const char* aID) {
+ /* aID contains:
+
+ KEYWORD_SEARCH_STRING:ssssss
+
+ KEYWORD_SEARCH_STRING is a 'special:search' keyword
+ ssssss is a searched term, must be at least one character long
+ */
+
+ // aID contains only 'KEYWORD_SEARCH_STRING:' so we're missing searched
+ // string.
+ if (strlen(aID) <= KEYWORD_SEARCH_STRING_LEN + 1) {
+ return nullptr;
+ }
+
+ GVariantBuilder b;
+ g_variant_builder_init(&b, G_VARIANT_TYPE("a{sv}"));
+ g_variant_builder_add(&b, "{sv}", "id",
+ g_variant_new_string(KEYWORD_SEARCH_STRING));
+
+ // Extract ssssss part from aID
+ nsAutoCString searchTerm(aID + KEYWORD_SEARCH_STRING_LEN + 1);
+ nsAutoCString gnomeSearchTitle;
+ if (GetGnomeSearchTitle(searchTerm.get(), gnomeSearchTitle)) {
+ g_variant_builder_add(&b, "{sv}", "name",
+ g_variant_new_string(gnomeSearchTitle.get()));
+ // TODO: When running on flatpak/snap we may need to use
+ // icon like org.mozilla.Firefox or so.
+ g_variant_builder_add(&b, "{sv}", "gicon", g_variant_new_string("firefox"));
+ }
+
+ return dont_AddRef(g_variant_ref_sink(g_variant_builder_end(&b)));
+}
+
+// GetResultMetas :: (as) → (aa{sv})
+void DBusHandleResultMetas(
+ RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult,
+ GVariant* aParameters, GDBusMethodInvocation* aReply) {
+ RefPtr<GVariant> variant =
+ dont_AddRef(g_variant_get_child_value(aParameters, 0));
+ gsize elements;
+ const char** stringArray = g_variant_get_strv(variant, &elements);
+ if (!stringArray) {
+ g_dbus_method_invocation_return_error(
+ aReply, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Wrong params!");
+ return;
+ }
+
+ GVariantBuilder b;
+ g_variant_builder_init(&b, G_VARIANT_TYPE("aa{sv}"));
+ for (gsize i = 0; i < elements; i++) {
+ RefPtr<GVariant> value;
+ if (strncmp(stringArray[i], KEYWORD_SEARCH_STRING,
+ KEYWORD_SEARCH_STRING_LEN) == 0) {
+ value = DBusAppendSearchID(stringArray[i]);
+ } else {
+ value = DBusAppendResultID(aSearchResult, stringArray[i]);
+ }
+ if (value) {
+ g_variant_builder_add_value(&b, value);
+ }
+ }
+
+ GVariant* v = g_variant_builder_end(&b);
+ g_dbus_method_invocation_return_value(aReply, g_variant_new_tuple(&v, 1));
+
+ g_free(stringArray);
+} // namespace mozilla
+
+static void ActivateResultID(
+ RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult,
+ const char* aResultID, uint32_t aTimeStamp) {
+ char* commandLine = nullptr;
+ int tmp;
+
+ if (strncmp(aResultID, KEYWORD_SEARCH_STRING, KEYWORD_SEARCH_STRING_LEN) ==
+ 0) {
+ const char* urlList[3] = {"unused", "--search",
+ aSearchResult->GetSearchTerm().get()};
+ commandLine = ConstructCommandLine(std::size(urlList), (char**)urlList,
+ nullptr, &tmp);
+ } else {
+ int keyIndex = atoi(aResultID);
+ nsCOMPtr<nsINavHistoryResultNode> child;
+ aSearchResult->GetSearchResultContainer()->GetChild(keyIndex,
+ getter_AddRefs(child));
+ if (!child) {
+ return;
+ }
+
+ nsAutoCString uri;
+ nsresult rv = child->GetUri(uri);
+ if (NS_FAILED(rv)) {
+ return;
+ }
+
+ const char* urlList[2] = {"unused", uri.get()};
+ commandLine = ConstructCommandLine(std::size(urlList), (char**)urlList,
+ nullptr, &tmp);
+ }
+
+ if (commandLine) {
+ aSearchResult->HandleCommandLine(commandLine, aTimeStamp);
+ free(commandLine);
+ }
+}
+
+static void DBusLaunchWithAllResults(
+ RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult,
+ uint32_t aTimeStamp) {
+ uint32_t childCount = 0;
+ nsresult rv =
+ aSearchResult->GetSearchResultContainer()->GetChildCount(&childCount);
+ if (NS_FAILED(rv) || childCount == 0) {
+ return;
+ }
+
+ if (childCount > MAX_SEARCH_RESULTS_NUM) {
+ childCount = MAX_SEARCH_RESULTS_NUM;
+ }
+
+ // Allocate space for all found results, "unused", "--search" and
+ // potential search request.
+ char** urlList = (char**)moz_xmalloc(sizeof(char*) * (childCount + 3));
+ int urlListElements = 0;
+
+ urlList[urlListElements++] = strdup("unused");
+
+ for (uint32_t i = 0; i < childCount; i++) {
+ nsCOMPtr<nsINavHistoryResultNode> child;
+ aSearchResult->GetSearchResultContainer()->GetChild(i,
+ getter_AddRefs(child));
+
+ if (!IsHistoryResultNodeURI(child)) {
+ continue;
+ }
+
+ nsAutoCString uri;
+ nsresult rv = child->GetUri(uri);
+ if (NS_FAILED(rv)) {
+ continue;
+ }
+ urlList[urlListElements++] = strdup(uri.get());
+ }
+
+ // When there isn't any uri to open pass search at least.
+ if (!childCount) {
+ urlList[urlListElements++] = strdup("--search");
+ urlList[urlListElements++] = strdup(aSearchResult->GetSearchTerm().get());
+ }
+
+ int tmp;
+ char* commandLine =
+ ConstructCommandLine(urlListElements, urlList, nullptr, &tmp);
+ if (commandLine) {
+ aSearchResult->HandleCommandLine(commandLine, aTimeStamp);
+ free(commandLine);
+ }
+
+ for (int i = 0; i < urlListElements; i++) {
+ free(urlList[i]);
+ }
+ free(urlList);
+}
+
+// ActivateResult :: (s,as,u) → ()
+void DBusActivateResult(RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult,
+ GVariant* aParameters, GDBusMethodInvocation* aReply) {
+ const char* resultID;
+
+ // aParameters is "(s,as,u)" type
+ RefPtr<GVariant> r = dont_AddRef(g_variant_get_child_value(aParameters, 0));
+ if (!(resultID = g_variant_get_string(r, nullptr))) {
+ g_dbus_method_invocation_return_error(
+ aReply, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Wrong params!");
+ return;
+ }
+ RefPtr<GVariant> t = dont_AddRef(g_variant_get_child_value(aParameters, 2));
+ uint32_t timestamp = g_variant_get_uint32(t);
+
+ ActivateResultID(aSearchResult, resultID, timestamp);
+ g_dbus_method_invocation_return_value(aReply, nullptr);
+}
+
+// LaunchSearch :: (as,u) → ()
+void DBusLaunchSearch(RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult,
+ GVariant* aParameters, GDBusMethodInvocation* aReply) {
+ RefPtr<GVariant> variant =
+ dont_AddRef(g_variant_get_child_value(aParameters, 1));
+ if (!variant) {
+ g_dbus_method_invocation_return_error(
+ aReply, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Wrong params!");
+ return;
+ }
+ DBusLaunchWithAllResults(aSearchResult, g_variant_get_uint32(variant));
+ g_dbus_method_invocation_return_value(aReply, nullptr);
+}
+
+bool IsHistoryResultNodeURI(nsINavHistoryResultNode* aHistoryNode) {
+ uint32_t type;
+ nsresult rv = aHistoryNode->GetType(&type);
+ if (NS_FAILED(rv) || type != nsINavHistoryResultNode::RESULT_TYPE_URI)
+ return false;
+
+ nsAutoCString title;
+ rv = aHistoryNode->GetTitle(title);
+ if (NS_SUCCEEDED(rv) && !title.IsEmpty()) {
+ return true;
+ }
+
+ rv = aHistoryNode->GetUri(title);
+ return NS_SUCCEEDED(rv) && !title.IsEmpty();
+}