diff --git a/.gitignore b/.gitignore index 84c048a..5f81c1a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /build/ +*.zip diff --git a/CMakeLists.txt b/CMakeLists.txt index 24c7454..7b58694 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ project(remwharead set(WITH_MAN "YES" CACHE STRING "WITH_MAN defaults to \"YES\"") set(WITH_TESTS "NO" CACHE STRING "WITH_TESTS defaults to \"NO\"") +set(WITH_MOZILLA "NO" CACHE STRING "WITH_MOZILLA defaults to \"NO\"") include(GNUInstallDirs) find_package(PkgConfig REQUIRED) @@ -63,6 +64,10 @@ if (WITH_MAN) DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) endif() +if (WITH_MOZILLA) + add_subdirectory(browser-plugins/webextension/native-wrapper) +endif() + if(WITH_TESTS) add_library(${PROJECT_NAME}_testlib SHARED ${sources}) target_link_libraries(${PROJECT_NAME}_testlib ${COMMON_LIBRARIES}) diff --git a/README.adoc b/README.adoc index e24952a..88d1ab6 100644 --- a/README.adoc +++ b/README.adoc @@ -96,6 +96,7 @@ cmake --build . * `-DCMAKE_BUILD_TYPE=Debug` for a debug build. * `-DWITH_MAN=NO` to not compile the manpage. * `WITH_TESTS=YES` to compile the tests. +* `WITH_MOZILLA=YES` to install the helper script for the Mozilla extension. * One of: ** `-DWITH_DEB=YES` if you want to be able to generate a deb-package. ** `-DWITH_RPM=YES` if you want to be able to generate an rpm-package. @@ -105,6 +106,10 @@ You can run the tests with `ctest` inside the build directory. Install with == Copyright +The icons of the plugins are from the +https://github.com/PapirusDevelopmentTeam/papirus-icon-theme[Papirus icon +theme] with the license GPLv3. + ---- Copyright © 2019 tastytea . License GPLv3: GNU GPL version 3 . diff --git a/browser-plugins/webextension/add_uri.html b/browser-plugins/webextension/add_uri.html new file mode 100644 index 0000000..76a56d5 --- /dev/null +++ b/browser-plugins/webextension/add_uri.html @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/browser-plugins/webextension/build_package.sh b/browser-plugins/webextension/build_package.sh new file mode 100755 index 0000000..df5a37c --- /dev/null +++ b/browser-plugins/webextension/build_package.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +zip -r -FS ../remwharead.zip * --exclude 'native-wrapper/*' --exclude build_package.sh diff --git a/browser-plugins/webextension/icon_dark.svg b/browser-plugins/webextension/icon_dark.svg new file mode 100644 index 0000000..99621e3 --- /dev/null +++ b/browser-plugins/webextension/icon_dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/browser-plugins/webextension/icon_light.svg b/browser-plugins/webextension/icon_light.svg new file mode 100644 index 0000000..e8d7cfb --- /dev/null +++ b/browser-plugins/webextension/icon_light.svg @@ -0,0 +1,3 @@ + + + diff --git a/browser-plugins/webextension/launch.js b/browser-plugins/webextension/launch.js new file mode 100644 index 0000000..b807b99 --- /dev/null +++ b/browser-plugins/webextension/launch.js @@ -0,0 +1,61 @@ +var taburl; +var port; + +function set_taburl(tabs) // Set taburl to URL of current tab. +{ + let tab = tabs[0]; + taburl = tab.url; +} + +function get_tags() // get tags from text input. +{ + let tags = document.getElementById("tags").value; + if (tags != "") + { + return "-t " + tags + " "; + } + return ""; +} + +function onResponse(response) { + console.log("Received: " + response); + if (response == "Command successful.") + { + window.close(); + } + else + { + document.getElementById("error").textContent = response; + } + +} + +function onError(error) { + console.log(`Error: ${error}`); +} + +function launch() // Launch wrapper and send tags + URL to stdin. +{ + var arguments = get_tags() + taburl; + console.log("Sending: " + arguments + " to remwharead"); + var sending = browser.runtime.sendNativeMessage("remwharead", arguments); + sending.then(onResponse, onError); +} + + +// Call set_taburl() with current tab. +browser.tabs.query({currentWindow: true, active: true}).then(set_taburl); + +button.addEventListener("click", launch); // Call send() if submit is clicked. + +// Click button if enter is hit in text input. +document.querySelector("#tags").addEventListener( + "keyup", event => + { + if(event.key !== "Enter") + { + return; + } + document.querySelector("#button").click(); + event.preventDefault(); + }); diff --git a/browser-plugins/webextension/manifest.json b/browser-plugins/webextension/manifest.json new file mode 100644 index 0000000..7f238fe --- /dev/null +++ b/browser-plugins/webextension/manifest.json @@ -0,0 +1,54 @@ +{ + "manifest_version": 2, + "name": "remwharead", + "version": "0.2.0", + + "description": "Integrates remwharead into your Browser.", + "homepage_url": "https://schlomp.space/tastytea/remwharead", + + "icons": + { + "16": "icon_dark.svg" + }, + + "applications": + { + "gecko": + { + "id": "remwharead@tastytea.de", + "strict_min_version": "57.0" + } + }, + + "permissions": + [ + "activeTab", + "nativeMessaging" + ], + + "browser_action": + { + "default_title": "remwharead", + "default_popup": "add_uri.html", + "browser_style": true, + "default_icon": "icon_dark.svg", + "theme_icons": + [{ // Dark means dark text in Firefox. 🙄 + "dark": "icon_light.svg", + "light": "icon_dark.svg", + "size": 16 + }] + }, + + "commands": + { + "open_popup": + { + "suggested_key": + { + "default": "Ctrl+Shift+S" + }, + "description": "Add URI to remwharead." + } + } +} diff --git a/browser-plugins/webextension/native-wrapper/CMakeLists.txt b/browser-plugins/webextension/native-wrapper/CMakeLists.txt new file mode 100644 index 0000000..f8e49b9 --- /dev/null +++ b/browser-plugins/webextension/native-wrapper/CMakeLists.txt @@ -0,0 +1,7 @@ +set(MOZILLA_NMH_DIR "${CMAKE_INSTALL_LIBDIR}/mozilla/native-messaging-hosts") + +add_executable(${PROJECT_NAME}_wrapper ${PROJECT_NAME}_wrapper.cpp) + +install(TARGETS ${PROJECT_NAME}_wrapper DESTINATION ${MOZILLA_NMH_DIR}) +install(FILES remwharead.json remwharead_wrapper.sh + DESTINATION ${MOZILLA_NMH_DIR}) diff --git a/browser-plugins/webextension/native-wrapper/remwharead.json b/browser-plugins/webextension/native-wrapper/remwharead.json new file mode 100644 index 0000000..21cc13b --- /dev/null +++ b/browser-plugins/webextension/native-wrapper/remwharead.json @@ -0,0 +1,7 @@ +{ + "name": "remwharead", + "description": "Saves URIs of things you want to remember in a database.", + "path": "/usr/lib/mozilla/native-messaging-hosts/remwharead_wrapper", + "type": "stdio", + "allowed_extensions": [ "remwharead@tastytea.de" ] +} diff --git a/browser-plugins/webextension/native-wrapper/remwharead_wrapper.cpp b/browser-plugins/webextension/native-wrapper/remwharead_wrapper.cpp new file mode 100644 index 0000000..4a04478 --- /dev/null +++ b/browser-plugins/webextension/native-wrapper/remwharead_wrapper.cpp @@ -0,0 +1,91 @@ +/* This file is part of remwharead. + * Copyright © 2019 tastytea + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +using std::string; +using std::cin; +using std::cout; +using std::uint32_t; +using std::system; + +const string read_input() +{ + string input; + char c; + + bool start = false; + while (cin.read(&c, 1).good()) + { + if (!start) + { + if (c == '"') + { + start = true; + } + continue; + } + if (c != '"') + { + input += c; + } + else + { + break; + } + } + return input; +} + +void send_message(const string &message) +{ + uint32_t length = message.length() + 2; + cout.write(reinterpret_cast(&length), sizeof(length)); + cout << '"' << message << '"'; +} + +int launch(const string &args) +{ + const string cmd = "remwharead " + args + " 2>/dev/null"; + int ret = system(cmd.c_str()); + if (WIFEXITED(ret)) + { + ret = WEXITSTATUS(ret); + } + + return ret; +} + +int main() +{ + const string args = read_input(); + int ret = launch(args); + + if (ret == 0) + { + send_message("Command successful."); + } + else + { + send_message("Command failed with status: " + std::to_string(ret) + '.'); + } + + return ret; +}