2018-06-26 14:09:39 +02:00
|
|
|
#include "NativeMessagingManager.hpp"
|
2018-04-09 22:59:19 +02:00
|
|
|
|
2018-06-26 14:09:39 +02:00
|
|
|
#include "Application.hpp"
|
|
|
|
#include "providers/twitch/TwitchServer.hpp"
|
|
|
|
#include "singletons/PathManager.hpp"
|
|
|
|
#include "util/PostToThread.hpp"
|
2018-04-09 22:59:19 +02:00
|
|
|
|
|
|
|
#include <QCoreApplication>
|
|
|
|
#include <QFile>
|
2018-06-13 13:27:10 +02:00
|
|
|
#include <QJsonArray>
|
2018-04-09 22:59:19 +02:00
|
|
|
#include <QJsonDocument>
|
|
|
|
#include <QJsonObject>
|
|
|
|
#include <QJsonValue>
|
|
|
|
|
|
|
|
#include <boost/interprocess/ipc/message_queue.hpp>
|
2018-04-12 00:40:18 +02:00
|
|
|
|
|
|
|
namespace ipc = boost::interprocess;
|
2018-04-09 22:59:19 +02:00
|
|
|
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
#include <QProcess>
|
2018-04-25 14:49:30 +02:00
|
|
|
|
2018-04-27 22:11:19 +02:00
|
|
|
#include <Windows.h>
|
2018-06-26 14:09:39 +02:00
|
|
|
#include "singletons/WindowManager.hpp"
|
|
|
|
#include "widgets/AttachedWindow.hpp"
|
2018-04-09 22:59:19 +02:00
|
|
|
#endif
|
|
|
|
|
2018-04-12 00:09:16 +02:00
|
|
|
#include <iostream>
|
|
|
|
|
2018-06-23 22:17:57 +02:00
|
|
|
#define EXTENSION_ID "glknmaideaikkmemifbfkhnomoknepka"
|
2018-04-09 22:59:19 +02:00
|
|
|
#define MESSAGE_SIZE 1024
|
|
|
|
|
|
|
|
namespace chatterino {
|
|
|
|
|
2018-06-01 14:20:46 +02:00
|
|
|
// fourtf: don't add this class to the application class
|
2018-04-09 22:59:19 +02:00
|
|
|
NativeMessagingManager::NativeMessagingManager()
|
|
|
|
{
|
2018-04-26 18:10:26 +02:00
|
|
|
qDebug() << "init NativeMessagingManager";
|
2018-04-09 22:59:19 +02:00
|
|
|
}
|
|
|
|
|
2018-04-12 00:09:16 +02:00
|
|
|
void NativeMessagingManager::writeByteArray(QByteArray a)
|
|
|
|
{
|
|
|
|
char *data = a.data();
|
|
|
|
uint32_t size;
|
|
|
|
size = a.size();
|
|
|
|
std::cout.write(reinterpret_cast<char *>(&size), 4);
|
|
|
|
std::cout.write(data, a.size());
|
|
|
|
std::cout.flush();
|
|
|
|
}
|
|
|
|
|
2018-04-09 22:59:19 +02:00
|
|
|
void NativeMessagingManager::registerHost()
|
|
|
|
{
|
2018-04-27 22:11:19 +02:00
|
|
|
auto app = getApp();
|
|
|
|
|
2018-05-28 18:25:19 +02:00
|
|
|
if (app->paths->isPortable()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-13 13:27:10 +02:00
|
|
|
auto getBaseDocument = [&] {
|
|
|
|
QJsonObject obj;
|
|
|
|
obj.insert("name", "com.chatterino.chatterino");
|
|
|
|
obj.insert("description", "Browser interaction with chatterino.");
|
|
|
|
obj.insert("path", QCoreApplication::applicationFilePath());
|
|
|
|
obj.insert("type", "stdio");
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
};
|
|
|
|
|
|
|
|
auto registerManifest = [&](const QString &manifestFilename, const QString ®istryKeyName,
|
|
|
|
const QJsonDocument &document) {
|
|
|
|
// save the manifest
|
2018-06-21 13:02:34 +02:00
|
|
|
QString manifestPath = app->paths->miscDirectory + manifestFilename;
|
2018-06-13 13:27:10 +02:00
|
|
|
QFile file(manifestPath);
|
|
|
|
file.open(QIODevice::WriteOnly | QIODevice::Truncate);
|
|
|
|
file.write(document.toJson());
|
|
|
|
file.flush();
|
|
|
|
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
// clang-format off
|
|
|
|
QProcess::execute("REG ADD \"" + registryKeyName + "\" /ve /t REG_SZ /d \"" + manifestPath + "\" /f");
|
|
|
|
// clang-format on
|
|
|
|
#endif
|
|
|
|
};
|
2018-04-09 22:59:19 +02:00
|
|
|
|
2018-04-25 14:49:30 +02:00
|
|
|
// chrome
|
2018-06-13 13:27:10 +02:00
|
|
|
{
|
|
|
|
QJsonDocument document;
|
|
|
|
|
|
|
|
auto obj = getBaseDocument();
|
2018-06-23 22:17:57 +02:00
|
|
|
QJsonArray allowed_origins_arr = {"chrome-extension://" EXTENSION_ID "/"};
|
2018-06-13 13:27:10 +02:00
|
|
|
obj.insert("allowed_origins", allowed_origins_arr);
|
|
|
|
document.setObject(obj);
|
|
|
|
|
|
|
|
registerManifest(
|
|
|
|
"/native-messaging-manifest-chrome.json",
|
|
|
|
"HKCU\\Software\\Google\\Chrome\\NativeMessagingHosts\\com.chatterino.chatterino",
|
|
|
|
document);
|
|
|
|
}
|
2018-04-09 22:59:19 +02:00
|
|
|
|
2018-04-25 14:49:30 +02:00
|
|
|
// firefox
|
2018-06-13 13:27:10 +02:00
|
|
|
{
|
|
|
|
QJsonDocument document;
|
2018-04-25 14:49:30 +02:00
|
|
|
|
2018-06-13 13:27:10 +02:00
|
|
|
auto obj = getBaseDocument();
|
|
|
|
QJsonArray allowed_extensions = {"chatterino_native@chatterino.com"};
|
|
|
|
obj.insert("allowed_extensions", allowed_extensions);
|
|
|
|
document.setObject(obj);
|
2018-04-09 22:59:19 +02:00
|
|
|
|
2018-06-13 13:27:10 +02:00
|
|
|
registerManifest("/native-messaging-manifest-firefox.json",
|
|
|
|
"HKCU\\Software\\Mozilla\\NativeMessagingHosts\\com.chatterino.chatterino",
|
|
|
|
document);
|
|
|
|
}
|
2018-04-09 22:59:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void NativeMessagingManager::openGuiMessageQueue()
|
|
|
|
{
|
|
|
|
static ReceiverThread thread;
|
|
|
|
|
|
|
|
if (thread.isRunning()) {
|
|
|
|
thread.exit();
|
|
|
|
}
|
|
|
|
|
|
|
|
thread.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
void NativeMessagingManager::sendToGuiProcess(const QByteArray &array)
|
|
|
|
{
|
2018-06-27 22:56:56 +02:00
|
|
|
ipc::message_queue messageQueue(ipc::open_only, "chatterino_gui");
|
2018-04-09 22:59:19 +02:00
|
|
|
|
|
|
|
try {
|
|
|
|
messageQueue.try_send(array.data(), array.size(), 1);
|
|
|
|
} catch (ipc::interprocess_exception &ex) {
|
2018-04-12 00:09:16 +02:00
|
|
|
qDebug() << "send to gui process:" << ex.what();
|
2018-04-09 22:59:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NativeMessagingManager::ReceiverThread::run()
|
|
|
|
{
|
|
|
|
ipc::message_queue::remove("chatterino_gui");
|
|
|
|
|
2018-04-12 00:33:55 +02:00
|
|
|
ipc::message_queue messageQueue(ipc::open_or_create, "chatterino_gui", 100, MESSAGE_SIZE);
|
2018-04-09 22:59:19 +02:00
|
|
|
|
|
|
|
while (true) {
|
|
|
|
try {
|
2018-05-28 08:34:54 +02:00
|
|
|
std::unique_ptr<char> buf(static_cast<char *>(malloc(MESSAGE_SIZE)));
|
2018-04-09 22:59:19 +02:00
|
|
|
ipc::message_queue::size_type retSize;
|
|
|
|
unsigned int priority;
|
|
|
|
|
2018-05-28 08:34:54 +02:00
|
|
|
messageQueue.receive(buf.get(), MESSAGE_SIZE, retSize, priority);
|
2018-04-09 22:59:19 +02:00
|
|
|
|
2018-05-28 08:34:54 +02:00
|
|
|
QJsonDocument document =
|
|
|
|
QJsonDocument::fromJson(QByteArray::fromRawData(buf.get(), retSize));
|
2018-04-12 01:17:25 +02:00
|
|
|
|
|
|
|
this->handleMessage(document.object());
|
2018-04-09 22:59:19 +02:00
|
|
|
} catch (ipc::interprocess_exception &ex) {
|
2018-04-12 00:09:16 +02:00
|
|
|
qDebug() << "received from gui process:" << ex.what();
|
2018-04-09 22:59:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-04-12 01:17:25 +02:00
|
|
|
|
|
|
|
void NativeMessagingManager::ReceiverThread::handleMessage(const QJsonObject &root)
|
|
|
|
{
|
2018-04-28 15:20:18 +02:00
|
|
|
auto app = getApp();
|
|
|
|
|
2018-04-20 19:54:45 +02:00
|
|
|
QString action = root.value("action").toString();
|
|
|
|
|
|
|
|
if (action.isNull()) {
|
|
|
|
qDebug() << "NM action was null";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (action == "select") {
|
|
|
|
QString _type = root.value("type").toString();
|
2018-04-25 14:49:30 +02:00
|
|
|
bool attach = root.value("attach").toBool();
|
2018-04-20 19:54:45 +02:00
|
|
|
QString name = root.value("name").toString();
|
|
|
|
|
2018-06-13 13:27:10 +02:00
|
|
|
qDebug() << attach;
|
|
|
|
|
2018-05-28 19:49:37 +02:00
|
|
|
#ifdef USEWINSDK
|
2018-06-26 17:06:17 +02:00
|
|
|
AttachedWindow::GetArgs args;
|
2018-05-28 18:25:19 +02:00
|
|
|
args.winId = root.value("winId").toString();
|
|
|
|
args.yOffset = root.value("yOffset").toInt(-1);
|
|
|
|
args.width = root.value("size").toObject().value("width").toInt(-1);
|
|
|
|
args.height = root.value("size").toObject().value("height").toInt(-1);
|
|
|
|
|
|
|
|
if (_type.isNull() || args.winId.isNull()) {
|
2018-04-25 14:49:30 +02:00
|
|
|
qDebug() << "NM type, name or winId missing";
|
|
|
|
attach = false;
|
2018-04-20 19:54:45 +02:00
|
|
|
return;
|
|
|
|
}
|
2018-05-28 19:49:37 +02:00
|
|
|
#endif
|
2018-04-20 19:54:45 +02:00
|
|
|
|
|
|
|
if (_type == "twitch") {
|
2018-06-26 17:06:17 +02:00
|
|
|
postToThread([=] {
|
2018-05-28 18:25:19 +02:00
|
|
|
if (!name.isEmpty()) {
|
|
|
|
app->twitch.server->watchingChannel.update(
|
|
|
|
app->twitch.server->getOrAddChannel(name));
|
|
|
|
}
|
2018-04-25 14:49:30 +02:00
|
|
|
|
|
|
|
if (attach) {
|
2018-04-26 20:58:32 +02:00
|
|
|
#ifdef USEWINSDK
|
2018-06-13 13:27:10 +02:00
|
|
|
// if (args.height != -1) {
|
2018-06-26 17:06:17 +02:00
|
|
|
auto *window = AttachedWindow::get(::GetForegroundWindow(), args);
|
2018-06-13 13:27:10 +02:00
|
|
|
if (!name.isEmpty()) {
|
|
|
|
window->setChannel(app->twitch.server->getOrAddChannel(name));
|
2018-05-28 18:25:19 +02:00
|
|
|
}
|
2018-06-13 13:27:10 +02:00
|
|
|
// }
|
2018-05-28 18:25:19 +02:00
|
|
|
// window->show();
|
2018-04-26 20:58:32 +02:00
|
|
|
#endif
|
2018-04-25 14:49:30 +02:00
|
|
|
}
|
2018-04-20 19:54:45 +02:00
|
|
|
});
|
2018-04-25 14:49:30 +02:00
|
|
|
|
2018-04-20 19:54:45 +02:00
|
|
|
} else {
|
|
|
|
qDebug() << "NM unknown channel type";
|
|
|
|
}
|
2018-04-25 14:49:30 +02:00
|
|
|
} else if (action == "detach") {
|
|
|
|
QString winId = root.value("winId").toString();
|
|
|
|
|
|
|
|
if (winId.isNull()) {
|
|
|
|
qDebug() << "NM winId missing";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-04-26 20:58:32 +02:00
|
|
|
#ifdef USEWINSDK
|
2018-06-26 17:06:17 +02:00
|
|
|
postToThread([winId] {
|
2018-05-30 17:17:27 +02:00
|
|
|
qDebug() << "NW detach";
|
2018-06-26 17:06:17 +02:00
|
|
|
AttachedWindow::detach(winId);
|
2018-05-30 17:17:27 +02:00
|
|
|
});
|
2018-04-26 20:58:32 +02:00
|
|
|
#endif
|
2018-04-25 14:49:30 +02:00
|
|
|
} else {
|
|
|
|
qDebug() << "NM unknown action " + action;
|
2018-04-20 19:54:45 +02:00
|
|
|
}
|
2018-06-13 13:27:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string &NativeMessagingManager::getGuiMessageQueueName()
|
|
|
|
{
|
|
|
|
static std::string name =
|
2018-06-27 22:56:56 +02:00
|
|
|
"chatterino_gui" + PathManager::getInstance()->applicationFilePathHash.toStdString();
|
2018-06-13 13:27:10 +02:00
|
|
|
return name;
|
|
|
|
}
|
2018-04-12 01:17:25 +02:00
|
|
|
|
2018-04-09 22:59:19 +02:00
|
|
|
} // namespace chatterino
|