Proof of concept native messaging

This commit is contained in:
Ximi1970
2020-01-13 22:50:50 +01:00
parent 3e37699677
commit 7a00657c6d
20 changed files with 653 additions and 23 deletions

1
app/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
build-*

View File

@@ -1,10 +1,11 @@
# SysTray-X App
Please be aware that the JSON file needs to be installed in the:
Please be aware that the JSON file needs to be installed in the
.mozilla/native-messaging-hosts (Firefox) config directory
and NOT in the .thunderbird/native-messaging-hosts (Thunderbird) config dir.
and NOT in the .thunderbird/native-messaging-hosts (Thunderbird) config dir.

View File

@@ -0,0 +1,3 @@
Native messaging
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging

2
app/SysTray-X/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
SysTray-X.pro.user
*.autosave

195
app/SysTray-X/SysTray-X.pro Normal file
View File

@@ -0,0 +1,195 @@
#-------------------------------------------------
#
# Project created by QtCreator 2020-01-12T19:19:44
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = SysTray-X
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
CONFIG += c++11
#CONFIG += staticlib
#
# System dependency
#
unix:!macx: {
# QMAKE_LFLAGS += -lX11 -static-libgcc -static-libstdc++
}
win32: {
# QMAKE_LFLAGS += -static -lwinpthread -static-libgcc -static-libstdc++ $$(QMAKE_LFLAGS_WINDOWS)
#
# Windows host (not used in cross compiling with mingw on Linux)
#
contains(QMAKE_HOST.os, Windows): {
contains(QMAKE_HOST.version, 192): {
#
# Windows 10 Universal CRT
#
UCRT_INCLUDE = "C:/Program Files (x86)/Windows Kits/10/include/10.0.10240.0/ucrt"
UCRT_LIBS = "C:/Program Files (x86)/Windows Kits/10/Lib/10.0.10240.0/ucrt"
INCLUDEPATH += $$UCRT_INCLUDE
contains(QMAKE_TARGET.arch, x86_64) {
CONFIG(debug, debug|release) {
LIBS += $$UCRT_LIBS"/x64/ucrtd.lib"
} else {
LIBS += $$UCRT_LIBS"/x64/ucrt.lib"
}
} else {
CONFIG(debug, debug|release) {
LIBS += $$UCRT_LIBS"/x86/ucrtd.lib"
} else {
LIBS += $$UCRT_LIBS"/x86/ucrt.lib"
}
}
}
}
}
unix:macx: {
QMAKE_LFLAGS += -framework IOKit -framework Foundation
QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.7
LIBS += -dead_strip
}
#
# Git version getters
#
win32: {
contains(QMAKE_HOST.os, Windows): {
#
# Host is Windows
#
GIT = ""C:\\Progra~1\\Git\\bin\\git.exe""
}
else {
#
# Host is Linux, cross compiling with mingw
#
GIT = git
}
}
unix:GIT = git
#
# Define the app version strings
#
BUILD_NUMBER = $$system($$GIT rev-list --count HEAD)
GIT_HASH = $$system($$GIT rev-parse HEAD)
GIT_BRANCH = $$system($$GIT rev-parse --abbrev-ref HEAD)
GIT_VERSION_LONG = $$system($$GIT describe --long)
GIT_VERSION = $$section(GIT_VERSION_LONG, -, 0, 0)
VERSION_MAJOR = $$section(GIT_VERSION, ., 0, 0)
VERSION_MINOR = $$section(GIT_VERSION, ., 1, 1)
VERSION_PATCH = $$section(GIT_VERSION, ., 2, 2)
DEFINES += APP_VERSION_MAJOR=\\\"$$VERSION_MAJOR\\\"
DEFINES += APP_VERSION_MINOR=\\\"$$VERSION_MINOR\\\"
DEFINES += APP_VERSION_PATCH=\\\"$$VERSION_PATCH\\\"
DEFINES += APP_BUILD=\\\"$$BUILD_NUMBER\\\"
DEFINES += APP_GITHASH=\\\"$$GIT_HASH\\\"
DEFINES += APP_GITBRANCH=\\\"$$GIT_BRANCH\\\"
message("Buildnumber: "$$BUILD_NUMBER)
message("Git hash: "$$GIT_HASH)
message("Git branch: "$$GIT_BRANCH)
message("Version: "$$VERSION_MAJOR"."$$VERSION_MINOR"."$$VERSION_PATCH)
#message($$QMAKESPEC)
#
# DO NOT COMPRESS THE RESOURCES. QFile.map() cannot handle it...
#
#QMAKE_RESOURCE_FLAGS += -no-compress
SOURCES += \
main.cpp \
mainwindow.cpp \
systrayxlink.cpp
HEADERS += \
mainwindow.h \
systrayxlink.h
FORMS += \
mainwindow.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
RESOURCES += \
SysTray-X.qrc
win32:RC_FILE += \
SysTray-X.rc
#
# Needs to be at the end of the .pro file (bug in qmake?)
#
unix:macx: {
#
# Use custom plist
#
QMAKE_INFO_PLIST = files/mac/SysTrayXInfo.plist
#
# Set company name
#
QMAKE_TARGET_BUNDLE_PREFIX = Ximi1970.
#
# Set icon
#
ICON = files/mac/SysTray-X.icns
#
# Set version
#
VERSION = "$$VERSION_MAJOR"."$$VERSION_MINOR"."$$VERSION_PATCH"
VERSION_LONG = "$$VERSION_MAJOR"."$$VERSION_MINOR"."$$VERSION_PATCH" "$$LITERAL_HASH$$BUILD_NUMBER" - "$$GIT_HASH" - "$$GIT_BRANCH"
QMAKE_POST_LINK = /usr/libexec/PlistBuddy -c \"Set :CFBundleShortVersionString $${VERSION}\" $${OUT_PWD}/$${TARGET}.app/Contents/Info.plist ;
QMAKE_POST_LINK += /usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $${VERSION_LONG}\" $${OUT_PWD}/$${TARGET}.app/Contents/Info.plist ;
#
# Add license file
#
APP_LICENSE_FILES.files = files/mac/LICENSE
APP_LICENSE_FILES.path = Contents/SharedSupport
QMAKE_BUNDLE_DATA += APP_LICENSE_FILES
#
# Create and use internal frameworks
#
QMAKE_LFLAGS += '-Wl,-rpath,\'@executable_path/../Frameworks\''
QMAKE_POST_LINK += rm -rf $${OUT_PWD}/$${TARGET}.app/Contents/Frameworks ;
QMAKE_POST_LINK += mkdir -p $${OUT_PWD}/$${TARGET}.app/Contents/Frameworks ;
QMAKE_POST_LINK += cp -R $$[QT_INSTALL_LIBS]/QtCore.framework $${OUT_PWD}/$${TARGET}.app/Contents/Frameworks ;
QMAKE_POST_LINK += cp -R $$[QT_INSTALL_LIBS]/QtGui.framework $${OUT_PWD}/$${TARGET}.app/Contents/Frameworks ;
}

View File

@@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/">
<file>files/icons/SysTray-X.png</file>
</qresource>
</RCC>

View File

@@ -0,0 +1 @@
IDI_ICON1 ICON DISCARDABLE "files/icons/SysTray-X.ico"

View File

@@ -0,0 +1 @@
The icon used here is taken from the "Miscellany Web icons" set by Maria & Guillem (https://www.iconfinder.com/andromina), and is used under the Creative Commons (Attribution 3.0 Unported) license.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

11
app/SysTray-X/main.cpp Normal file
View File

@@ -0,0 +1,11 @@
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

View File

@@ -0,0 +1,38 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect( &m_systray_x_link, &SysTrayXLink::signalReceivedMessageLength, this, &MainWindow::slotReceivedMessageLength );
connect( &m_systray_x_link, &SysTrayXLink::signalReceivedMessage, this, &MainWindow::slotReceivedMessage );
connect( this, &MainWindow::signalWriteMessage, &m_systray_x_link, &SysTrayXLink::slotLinkWrite );
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::slotReceivedMessageLength( qint32 msglen )
{
ui->label_length->setText(QString::number( msglen ) );
}
void MainWindow::slotReceivedMessage( QByteArray message )
{
ui->label_message->setText( QString::fromStdString( message.toStdString() ) );
/*
* Reply
*/
QByteArray reply = QString( "\"Hallo other world!\"" ).toUtf8();
emit signalWriteMessage( reply );
}

View File

@@ -0,0 +1,60 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
/*
* Local includes
*/
#include "systrayxlink.h"
/*
* Qt includes
*/
#include <QObject>
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
/**
* @brief slotReceivedMessageLength
*
* @param msglen
*/
void slotReceivedMessageLength( qint32 msglen );
/**
* @brief slotReceivedMessage
*
* @param message
*/
void slotReceivedMessage( QByteArray message );
signals:
/**
* @brief signalWriteMessage
*
* @param message
*/
void signalWriteMessage( QByteArray message );
private:
Ui::MainWindow *ui;
SysTrayXLink m_systray_x_link;
};
#endif // MAINWINDOW_H

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QLabel" name="label_length">
<property name="geometry">
<rect>
<x>50</x>
<y>10</y>
<width>271</width>
<height>51</height>
</rect>
</property>
<property name="text">
<string>Data here</string>
</property>
</widget>
<widget class="QLabel" name="label_message">
<property name="geometry">
<rect>
<x>50</x>
<y>80</y>
<width>271</width>
<height>51</height>
</rect>
</property>
<property name="text">
<string>Data here</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>30</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,142 @@
#include "systrayxlink.h"
/*
* Local includes
*/
#include <unistd.h>
/*
* Qt includes
*/
#include <QFile>
#include <QDataStream>
#include <QSocketNotifier>
/*
* Constructor
*/
SysTrayXLink::SysTrayXLink()
{
/*
* Open stdin
*/
m_stdin = new QFile( this );
m_stdin->open( stdin, QIODevice::ReadOnly );
/*
* Open stdout
*/
m_stdout = new QFile( this );
m_stdout->open( stdout, QIODevice::WriteOnly );
/*
* Setup the notifiers
*/
m_notifierLinkRead = new QSocketNotifier( STDIN_FILENO, QSocketNotifier::Read, this );
connect( m_notifierLinkRead, &QSocketNotifier::activated, this, &SysTrayXLink::slotLinkRead );
m_notifierLinkReadException = new QSocketNotifier( STDIN_FILENO, QSocketNotifier::Exception, this );
connect( m_notifierLinkReadException, &QSocketNotifier::activated, this, &SysTrayXLink::slotLinkReadException );
QDataStream out( m_stdout );
char reply[] = "\"Hallo other World!\"";
qint32 replylen = sizeof( reply ) - 1;
out.writeRawData( reinterpret_cast< char* >( &replylen ), sizeof( qint32 ) );
out.writeRawData( reply, replylen );
}
/*
* Destructor
*/
SysTrayXLink::~SysTrayXLink()
{
/*
* Cleanup
*/
m_stdin->close();
delete m_stdin;
m_stdout->close();
delete m_stdout;
delete m_notifierLinkRead;
delete m_notifierLinkReadException;
}
/*
* Read the input
*/
void SysTrayXLink::slotLinkRead()
{
QDataStream in( m_stdin );
qint32 msglen;
int status1 = in.readRawData( reinterpret_cast< char* >( &msglen ), sizeof( qint32 ) );
emit signalReceivedMessageLength(msglen);
QByteArray message(msglen + 1, 0 );
int status2 = in.readRawData( message.data(), msglen );
emit signalReceivedMessage( message );
if( ( status1 == 4 ) && ( status2 == msglen ) )
{
//dummy
}
/*
QDataStream out( m_stdout );
char reply[] = "\"Hallo other World!\"";
qint32 replylen = sizeof( reply ) - 1;
int status3 = out.writeRawData( reinterpret_cast< char* >( &replylen ), sizeof( qint32 ) );
int status4 = out.writeRawData( reply, replylen );
m_stdout->flush();
if( status3 && status4 )
{
//dummy
}
*/
}
/*
* Handle notifier exception
*/
void SysTrayXLink::slotLinkReadException()
{
// Something went wrong
}
/*
* Read the input
*/
void SysTrayXLink::slotLinkWrite( QByteArray message )
{
QDataStream out( m_stdout );
qint32 msglen = message.length();
int status1 = out.writeRawData( reinterpret_cast< char* >( &msglen ), sizeof( qint32 ) );
int status2 = out.writeRawData( message.data(), msglen );
m_stdout->flush();
if( status1 && status2 )
{
//dummy
}
}

View File

@@ -0,0 +1,92 @@
#ifndef SYSTRAYXLINK_H
#define SYSTRAYXLINK_H
/*
* Local includes
*/
/*
* Qt includes
*/
#include <QObject>
/*
* Predefines
*/
class QFile;
class QSocketNotifier;
/**
* @brief The SysTrayXLink class. Handles the communications link.
*/
class SysTrayXLink : public QObject
{
Q_OBJECT
public:
/**
* @brief SysTrayXLink. Constructor, destructor.
*/
SysTrayXLink();
~SysTrayXLink();
public slots:
/**
* @brief slotLinkWrite. Write the link.
*/
void slotLinkWrite( QByteArray message );
private slots:
/**
* @brief slotLinkRead. Read the link.
*/
void slotLinkRead();
/**
* @brief slotLinkReadException. Handle a read link exception.
*/
void slotLinkReadException();
signals:
/**
* @brief signalReceivedMessageLength
*
* @param msglen
*/
void signalReceivedMessageLength(qint32 msglen);
/**
* @brief signalReceivedMessage
*
* @param message
*/
void signalReceivedMessage(QByteArray message);
private:
/**
* @brief m_stdin. Pointer to stdin file.
*/
QFile *m_stdin;
/**
* @brief m_stdin. Pointer to stdout file.
*/
QFile *m_stdout;
/**
* @brief m_notifierLinkRead. Pointers to the link read data notifier.
*/
QSocketNotifier *m_notifierLinkRead;
/**
* @brief m_notifierLinkReadException. Pointers to the link read exception notifier.
*/
QSocketNotifier *m_notifierLinkReadException;
};
#endif // SYSTRAYXLINK_H

7
app/SysTray_X.json Normal file
View File

@@ -0,0 +1,7 @@
{
"name": "SysTray_X",
"description": "SysTray-X System Tray App",
"path": "/path/to/native-messaging/app/SysTray-X",
"type": "stdio",
"allowed_extensions": [ "systray-x@Ximi1970" ]
}

View File

@@ -1,14 +0,0 @@
#!/bin/bash
if [ -z $1 ] ; then
echo "Usage: $0 <tb-config-path>"
exit 1
fi
mkdir .mozilla/native-messaging-hosts
#mkdir .mozilla/managed-storage
#mkdir .mozilla/pkcs11-modules
cp ping_pong.json .mozilla/native-messaging-hosts/ping_pong.json
#cp ping_pong.json .mozilla/managed-storage/ping_pong.json
#cp ping_pong.json .mozilla/pkcs11-modules/ping_pong.json

View File

@@ -1,7 +1,7 @@
{
"name": "ping_pong",
"description": "Example host for native messaging",
"path": "/home/maxime/Diskstation/github/Ximi1970/systray-x/app/ping_pong.py",
"path": "/path/to/native-messaging/app/ping_pong.py",
"type": "stdio",
"allowed_extensions": [ "systray-x@Ximi1970" ]
}

View File

@@ -57,6 +57,7 @@ except AttributeError:
sys.stdout.flush()
while True:
sendMessage(encodeMessage("pong2"))
receivedMessage = getMessage()
if receivedMessage == "ping":
sendMessage(encodeMessage("pong2"))

View File

@@ -73,7 +73,7 @@ SysTrayX.Messaging = {
filtersDiv.setAttribute("data-filters", JSON.stringify(filters));
},
onGetAccountsStoageError: function(error) {
onGetAccountsStorageError: function(error) {
console.log(`GetAccounts Error: ${error}`);
},
@@ -81,7 +81,7 @@ SysTrayX.Messaging = {
console.debug("Get accounts");
let getter = browser.storage.sync.get(["accounts", "filters"]);
getter.then(this.getAccountsStorage, this.onGetAccountsStoageError);
getter.then(this.getAccountsStorage, this.onGetAccountsStorageError);
if (SysTrayX.debugAccounts) {
let accountsDiv = document.getElementById("accounts");
@@ -92,21 +92,20 @@ SysTrayX.Messaging = {
let accounts = JSON.parse(accountsAttr);
console.debug("Accounts poll: " + accounts.length);
}
},
}
};
console.log("Starting SysTray-X");
SysTrayX.Messaging.init();
/*
* Start native messaging
* Start native messaging ping pong
*/
var port = browser.runtime.connectNative("ping_pong");
// Listen for messages from the app.
port.onMessage.addListener((response) => {
port.onMessage.addListener(response => {
console.log("Received: " + response);
});
@@ -118,6 +117,24 @@ function ping() {
window.setInterval(ping, 1000);
/*
* Start native messaging SysTray-X
*/
var portSysTrayX = browser.runtime.connectNative("SysTray_X");
// Listen for messages from the app.
portSysTrayX.onMessage.addListener(response => {
console.log("Received: " + response);
});
// Every second, send the app a message.
function postSysTrayXMessage() {
console.log("Sending: Hallo World!");
portSysTrayX.postMessage("Hallo World!");
// portSysTrayX.postMessage({ key: "Hallo", value: "World!" });
}
window.setInterval(postSysTrayXMessage, 1000);
/*
* Poll the accounts