mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-11-13 06:38:48 +02:00
Currently the windows client sends the current process command line which is potentially an issue since some of those arguments may have been consumed already. It will also not support sending custom command lines after startup. This also switches to sending the UTF-8 command line we already have since that matches other platforms better and makes some arguments const. Differential Revision: https://phabricator.services.mozilla.com/D216031
398 lines
13 KiB
C++
398 lines
13 KiB
C++
/* -*- 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), 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), 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.
|
|
const char** urlList =
|
|
(const 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((void*)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();
|
|
}
|