diff --git a/data/icons/protocols/Matrix.png b/data/icons/protocols/Matrix.png new file mode 100644 index 0000000..48793de Binary files /dev/null and b/data/icons/protocols/Matrix.png differ diff --git a/protocols/matrix/Makefile b/protocols/matrix/Makefile new file mode 100644 index 0000000..b71620b --- /dev/null +++ b/protocols/matrix/Makefile @@ -0,0 +1,142 @@ +## Haiku Generic Makefile v2.6 ## + +## Fill in this file to specify the project being created, and the referenced +## Makefile-Engine will do all of the hard work for you. This handles any +## architecture of Haiku. +## +## For more information, see: +## file:///system/develop/documentation/makefile-engine.html + +# The name of the binary. +NAME = chat-o-matic/matrix + +# The type of binary, must be one of: +# APP: Application +# SHARED: Shared library or add-on +# STATIC: Static library archive +# DRIVER: Kernel driver +TYPE = APP + +# If you plan to use localization, specify the application's MIME signature. +APP_MIME_SIG = application/x-vnd.chat-o-matic.matrix + + +# The following lines tell Pe and Eddie where the SRCS, RDEFS, and RSRCS are +# so that Pe and Eddie can fill them in for you. +#%{ +# @src->@ + +# Specify the source files to use. Full paths or paths relative to the +# Makefile can be included. All files, regardless of directory, will have +# their object files created in the common object directory. Note that this +# means this Makefile will not work correctly if two source files with the +# same name (source.c or source.cpp) are included from different directories. +# Also note that spaces in folder names do not work well with this Makefile. +SRCS = \ + protocols/matrix/MatrixApp.cpp \ + protocols/matrix/MatrixMain.cpp \ + protocols/matrix/MatrixProtocol.cpp \ + +# Specify the resource definition files to use. Full or relative paths can be +# used. +RDEFS = \ + data/icons/protocols/IRC.rdef \ + protocols/matrix/matrix.rdef \ + +# Specify the resource files to use. Full or relative paths can be used. +# Both RDEFS and RSRCS can be utilized in the same Makefile. +RSRCS = + +# End Pe/Eddie support. +# @<-src@ +#%} + +# Specify libraries to link against. +# There are two acceptable forms of library specifications: +# - if your library follows the naming pattern of libXXX.so or libXXX.a, +# you can simply specify XXX for the library. (e.g. the entry for +# "libtracker.so" would be "tracker") +# +# - for GCC-independent linking of standard C++ libraries, you can use +# $(STDCPPLIBS) instead of the raw "stdc++[.r4] [supc++]" library names. +# +# - if your library does not follow the standard library naming scheme, +# you need to specify the path to the library and it's name. +# (e.g. for mylib.a, specify "mylib.a" or "path/mylib.a") +LIBS = be bnetapi localestub matrix_client network $(STDCPPLIBS) + + +# Specify additional paths to directories following the standard libXXX.so +# or libXXX.a naming scheme. You can specify full paths or paths relative +# to the Makefile. The paths included are not parsed recursively, so +# include all of the paths where libraries must be found. Directories where +# source files were specified are automatically included. +LIBPATHS = + +# Additional paths to look for system headers. These use the form +# "#include
". Directories that contain the files in SRCS are +# NOT auto-included here. +SYSTEM_INCLUDE_PATHS = application/ libs/ + +# Additional paths paths to look for local headers. These use the form +# #include "header". Directories that contain the files in SRCS are +# automatically included. +LOCAL_INCLUDE_PATHS = + +# Specify the level of optimization that you want. Specify either NONE (O0), +# SOME (O1), FULL (O3), or leave blank (for the default optimization level). +OPTIMIZE := + +# Specify the codes for languages you are going to support in this +# application. The default "en" one must be provided too. "make catkeys" +# will recreate only the "locales/en.catkeys" file. Use it as a template +# for creating catkeys for other languages. All localization files must be +# placed in the "locales" subdirectory. +LOCALES = + +# Specify all the preprocessor symbols to be defined. The symbols will not +# have their values set automatically; you must supply the value (if any) to +# use. For example, setting DEFINES to "DEBUG=1" will cause the compiler +# option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" would pass +# "-DDEBUG" on the compiler's command line. +DEFINES = + +# Specify the warning level. Either NONE (suppress all warnings), +# ALL (enable all warnings), or leave blank (enable default warnings). +WARNINGS = + +# With image symbols, stack crawls in the debugger are meaningful. +# If set to "TRUE", symbols will be created. +SYMBOLS := + +# Includes debug information, which allows the binary to be debugged easily. +# If set to "TRUE", debug info will be created. +DEBUGGER := + +# Specify any additional compiler flags to be used. +COMPILER_FLAGS = -std=c++17 + +# Specify any additional linker flags to be used. +LINKER_FLAGS = + +# Specify the version of this binary. Example: +# -app 3 4 0 d 0 -short 340 -long "340 "`echo -n -e '\302\251'`"1999 GNU GPL" +# This may also be specified in a resource. +APP_VERSION := + +# (Only used when "TYPE" is "DRIVER"). Specify the desired driver install +# location in the /dev hierarchy. Example: +# DRIVER_PATH = video/usb +# will instruct the "driverinstall" rule to place a symlink to your driver's +# binary in ~/add-ons/kernel/drivers/dev/video/usb, so that your driver will +# appear at /dev/video/usb when loaded. The default is "misc". +DRIVER_PATH = + +## Include the Makefile-Engine +DEVEL_DIRECTORY := /boot/system/develop/ +include $(DEVEL_DIRECTORY)/etc/makefile-engine + +include Makefile.common +include protocols/Makefile.common + +CATKEYS_DIR = locales/matrix diff --git a/protocols/matrix/Matrix.h b/protocols/matrix/Matrix.h new file mode 100644 index 0000000..429fe97 --- /dev/null +++ b/protocols/matrix/Matrix.h @@ -0,0 +1,12 @@ +/* + * Copyright 2021, Jaidyn Levesque + * All rights reserved. Distributed under the terms of the MIT license. + */ + +#ifndef _MATRIX_H +#define _MATRIX_H + +#define MATRIX_SIGNATURE "application/x-vnd.chat-o-matic.matrix" +#define MATRIX_ADDON "matrix" + +#endif // _MATRIX_H diff --git a/protocols/matrix/MatrixApp.cpp b/protocols/matrix/MatrixApp.cpp new file mode 100644 index 0000000..17210cf --- /dev/null +++ b/protocols/matrix/MatrixApp.cpp @@ -0,0 +1,299 @@ +/* + * Copyright 2021, Jaidyn Levesque + * All rights reserved. Distributed under the terms of the MIT license. + */ + +#include "MatrixApp.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "Matrix.h" +#include "MatrixMessages.h" + + +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "MatrixApp" + + +std::shared_ptr client = nullptr; +MatrixApp* m_app = NULL; + + +int +main(int arc, char** argv) +{ + MatrixApp app; + app.Run(); + return 0; +} + + +MatrixApp::MatrixApp() + : + BApplication(MATRIX_SIGNATURE), + fUser(NULL), + fPassword(NULL), + fInitStatus(B_NOT_INITIALIZED), + fProtoThread(-1) +{ + new BMessageRunner(this, new BMessage(CHECK_APP), 10000000, -1); +} + + +void +MatrixApp::MessageReceived(BMessage* msg) +{ + switch (msg->what) { + case MATRIX_REGISTER_ACCOUNT: + { + int64 thread_id; + if (msg->FindInt64("thread_id", &thread_id) != B_OK) + break; + + fProtoThread = thread_id; + fUser = msg->FindString("username"); + fSession = msg->GetString("session", "Chat-O-Matic [Haiku]"); + fServer = msg->FindString("server"); + fPassword = msg->FindString("password"); + + app_info info; + GetAppInfo(&info); + BMessage registerApp(MATRIX_ACCOUNT_REGISTERED); + registerApp.AddInt64("team_id", info.team); + SendMessage(registerApp); + + Connect(); + break; + } + case CHECK_APP: + { + BRoster roster; + if (roster.IsRunning(APP_SIGNATURE) == false) + Quit(); + break; + } + default: + BApplication::MessageReceived(msg); + } +} + + +void +MatrixApp::ImMessage(BMessage* msg) +{ + int32 im_what = msg->GetInt32("im_what", -1); + switch (im_what) { + case IM_SET_OWN_STATUS: + { + } + default: { + std::cout << "Unhandled message for Matrix:\n"; + msg->PrintToStream(); + } + } +} + + +void +MatrixApp::Connect() +{ + client = std::make_shared(fServer.String()); + client->set_device_id(fSession.String()); + client->login(fUser.String(), fPassword.String(), + [this](const mtx::responses::Login &res, mtx::http::RequestErr err) + { + if (err) { + SendError("Error occured during login, please try again.", err, + true); + fInitStatus = B_ERROR; + } + else { + client->set_access_token(res.access_token); + fInitStatus = B_OK; + StartLoop(); + } + }); +} + + +void +MatrixApp::StartLoop() +{ + BMessage ready(IM_MESSAGE); + ready.AddInt32("im_what", IM_PROTOCOL_READY); + SendMessage(ready); + + BString mxId("@"); + mxId << fUser << ":" << fServer; + BMessage init(IM_MESSAGE); + init.AddInt32("im_what", IM_OWN_CONTACT_INFO); + init.AddString("user_id", mxId); + SendMessage(init); + + BMessage status(IM_MESSAGE); + status.AddInt32("im_what", IM_OWN_STATUS_SET); + status.AddInt32("status", (int32)STATUS_ONLINE); + SendMessage(status); + + mtx::http::SyncOpts opts; + opts.timeout = 0; + client->sync(opts, &initial_sync_handler); + client->close(); +} + + +void +MatrixApp::SendMessage(BMessage msg) +{ + if (fProtoThread <= 0) + return; + + ssize_t size = msg.FlattenedSize(); + char buffer[size]; + + send_data(fProtoThread, size, NULL, 0); + msg.Flatten(buffer, size); + send_data(fProtoThread, 0, buffer, size); +} + + +void +MatrixApp::SendError(const char* message, mtx::http::RequestErr err, + bool fatal) +{ + print_error(err); + + BString detail; + if (!err->matrix_error.error.empty()) + detail << err->matrix_error.error.c_str(); + + BMessage error(IM_ERROR); + error.AddString("error", message); + error.AddString("detail", detail); + SendMessage(error); + + if (fatal == true) { + BMessage disable(IM_MESSAGE); + disable.AddInt32("im_what", IM_PROTOCOL_DISABLE); + SendMessage(disable); + } +} + + +void +print_error(mtx::http::RequestErr err, const char* message) +{ + if (message != NULL) + std::cerr << message << " ― "; + std::cerr << err->status_code << " : " << err->error_code; + if (!err->matrix_error.error.empty()) + std::cerr << " : " << err->matrix_error.error; + std::cerr << std::endl; +} + + +void +initial_sync_handler(const mtx::responses::Sync &res, mtx::http::RequestErr err) +{ + mtx::http::SyncOpts opts; + + if (err) { + print_error(err, "Error occured during initial sync. Retrying…"); + if ((int)err->status_code != 200) { + opts.timeout = 0; + client->sync(opts, &initial_sync_handler); + } + return; + } + + room_sync(res.rooms); + + opts.since = res.next_batch; + client->set_next_batch_token(res.next_batch); + client->sync(opts, &sync_handler); +} + + +// Callback to executed after a /sync request completes. +void +sync_handler(const mtx::responses::Sync &res, mtx::http::RequestErr err) +{ + mtx::http::SyncOpts opts; + + if (err) { + print_error(err, "Error occured during sync. Retrying…"); + opts.since = client->next_batch_token(); + client->sync(opts, &sync_handler); + return; + } + + room_sync(res.rooms); + + opts.since = res.next_batch; + client->set_next_batch_token(res.next_batch); + client->sync(opts, &sync_handler); +} + + +void +room_sync(mtx::responses::Rooms rooms) +{ + MatrixApp* app = (MatrixApp*)be_app; + + std::map joined = rooms.join; + for (std::map::iterator iter + = joined.begin(); + iter != joined.end(); + ++iter) + { + const char* chat_id = iter->first.c_str(); + mtx::responses::JoinedRoom room = iter->second; + + if (app->fRoomList.HasString(BString(chat_id)) == false) { + BMessage joinedMsg(IM_MESSAGE); + joinedMsg.AddInt32("im_what", IM_ROOM_JOINED); + joinedMsg.AddString("chat_id", chat_id); + ((MatrixApp*)be_app)->SendMessage(joinedMsg); + + app->fRoomList.Add(BString(chat_id)); + } + + for (mtx::events::collections::TimelineEvents &ev : room.timeline.events) + if (auto event = std::get_if>(&ev); + event != nullptr) + { + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", IM_MESSAGE_RECEIVED); + msg.AddString("body", event->content.body.c_str()); + msg.AddString("chat_id", chat_id); + msg.AddString("user_id", event->sender.c_str()); + app->SendMessage(msg); + } + } + + std::map left = rooms.leave; + for (std::map::iterator iter + = left.begin(); + iter != left.end(); + ++iter) + { + const char* chat_id = iter->first.c_str(); + if (app->fRoomList.HasString(BString(chat_id)) == true) + app->fRoomList.Remove(BString(chat_id)); + + BMessage leftMsg(IM_MESSAGE); + leftMsg.AddInt32("im_what", IM_ROOM_LEFT); + leftMsg.AddString("chat_id", ((std::string)iter->first).c_str()); + ((MatrixApp*)be_app)->SendMessage(leftMsg); + } +} diff --git a/protocols/matrix/MatrixApp.h b/protocols/matrix/MatrixApp.h new file mode 100644 index 0000000..48ad365 --- /dev/null +++ b/protocols/matrix/MatrixApp.h @@ -0,0 +1,58 @@ +/* + * Copyright 2021, Jaidyn Levesque + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef _MATRIX_APP_H +#define _MATRIX_APP_H + +#include +#include +#include + +#include +#include +#include + + +const uint32 CHECK_APP = 'Paca'; + + +class MatrixApp : public BApplication { +public: + MatrixApp(); + + virtual void MessageReceived(BMessage* msg); + void ImMessage(BMessage* msg); + + void Connect(); + void StartLoop(); + + void SendMessage(BMessage msg); + void SendError(const char* message, + mtx::http::RequestErr err, bool fatal = false); + + BMessage* fSettings; + status_t fInitStatus; + BStringList fRoomList; + +private: + // Settings + BString fUser; + BString fPassword; + BString fServer; + BString fSession; + + thread_id fProtoThread; +}; + + +void print_error(mtx::http::RequestErr err, const char* message = NULL); + +void login_handler(const mtx::responses::Login &res, mtx::http::RequestErr err); + +void initial_sync_handler(const mtx::responses::Sync &res, mtx::http::RequestErr err); +void sync_handler(const mtx::responses::Sync &res, mtx::http::RequestErr err); + +void room_sync(mtx::responses::Rooms rooms); + +#endif // _MATRIX_APP_H diff --git a/protocols/matrix/MatrixMain.cpp b/protocols/matrix/MatrixMain.cpp new file mode 100644 index 0000000..415cad1 --- /dev/null +++ b/protocols/matrix/MatrixMain.cpp @@ -0,0 +1,50 @@ +/* + * Copyright 2021, Jaidyn Levesque + * All rights reserved. Distributed under the terms of the MIT license. + */ + +#include "MatrixProtocol.h" + + +extern "C" _EXPORT ChatProtocol* protocol_at(int32 i); +extern "C" _EXPORT int32 protocol_count(); +extern "C" _EXPORT const char* signature(); +extern "C" _EXPORT const char* friendly_signature(); +extern "C" _EXPORT uint32 version(); + + +ChatProtocol* +protocol_at(int32 i) +{ + if (i == 0) + return (ChatProtocol*)new MatrixProtocol(); + return NULL; +} + + +int32 +protocol_count() +{ + return 1; +} + + +const char* +signature() +{ + return "matrix"; +} + + +const char* +friendly_signature() +{ + return "Matrix"; +} + + +uint32 +version() +{ + return APP_VERSION_1_ALPHA_1; +} diff --git a/protocols/matrix/MatrixMessages.h b/protocols/matrix/MatrixMessages.h new file mode 100644 index 0000000..ceb4027 --- /dev/null +++ b/protocols/matrix/MatrixMessages.h @@ -0,0 +1,23 @@ +/* + * Copyright 2021, Jaidyn Levesque + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef _MATRIX_MESSAGES_H +#define _MATRIX_MESSAGES_H + +enum matrix_message { + /* + * Messages between the Matrix add-on and server + */ + + /*! Register account & thread with app →Server + Requires: Account template, int64 thread_id */ + MATRIX_REGISTER_ACCOUNT = 'MXra', + + + /*! Inform the protocol of app team id →Protocol + Requires: int64 team_id */ + MATRIX_ACCOUNT_REGISTERED = 'MXar' +}; + +#endif // _MATRIX_MESSAGES_H diff --git a/protocols/matrix/MatrixProtocol.cpp b/protocols/matrix/MatrixProtocol.cpp new file mode 100644 index 0000000..eb88d4f --- /dev/null +++ b/protocols/matrix/MatrixProtocol.cpp @@ -0,0 +1,271 @@ +/* + * Copyright 2021, Jaidyn Levesque + * All rights reserved. Distributed under the terms of the MIT license. + */ + +#include "MatrixProtocol.h" + +#include +#include +#include + +#include + +#include +#include + +#include "Matrix.h" +#include "MatrixMessages.h" + + +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "MatrixProtocol" + + +status_t +connect_thread(void* data) +{ + MatrixProtocol* protocol = (MatrixProtocol*)data; + while (true) { + BMessage* msg = new BMessage(receive_message()); + switch (msg->what) { + case MATRIX_ACCOUNT_REGISTERED: + protocol->RegisterApp((team_id)msg->GetInt64("team_id", -1)); + break; + default: + protocol->SendMessage(msg); + } + } +} + + +BMessage +receive_message() +{ + thread_id sender; + int32 size = receive_data(&sender, NULL, 0); + char buffer[size]; + receive_data(&sender, buffer, size); + BMessage temp; + temp.Unflatten(buffer); + return temp; +} + + +MatrixProtocol::MatrixProtocol() + : + fAppMessenger(NULL), + fAppTeam(-1) +{ +} + + +MatrixProtocol::~MatrixProtocol() +{ + Shutdown(); +} + + +status_t +MatrixProtocol::Init(ChatProtocolMessengerInterface* interface) +{ + fMessenger = interface; + return B_OK; +} + + +status_t +MatrixProtocol::Shutdown() +{ + _SendMatrixMessage(new BMessage(B_QUIT_REQUESTED)); + kill_thread(fRecvThread); + return B_OK; +} + + +status_t +MatrixProtocol::UpdateSettings(BMessage* settings) +{ + fRecvThread = spawn_thread(connect_thread, "moon_w_blackjack_and_hookers", + B_NORMAL_PRIORITY, (void*)this); + + if (fRecvThread < B_OK) + return B_ERROR; + + settings->AddInt64("thread_id", fRecvThread); + fSettings = new BMessage(*settings); + return B_OK; +} + + +status_t +MatrixProtocol::Process(BMessage* msg) +{ + int32 im_what = msg->GetInt32("im_what", -1); + + switch (im_what) { + case IM_SET_OWN_STATUS: + { + int32 status = msg->GetInt32("status", -1); + switch (status) { + case STATUS_ONLINE: + resume_thread(fRecvThread); + if (fAppMessenger == NULL || fAppMessenger->IsValid() == false) + _StartApp(); + break; + case STATUS_OFFLINE: + { + _SendMatrixMessage(new BMessage(B_QUIT_REQUESTED)); + kill_thread(fRecvThread); + + delete fAppMessenger; + fAppMessenger = NULL; + fAppTeam = -1; + break; + } + default: + _SendMatrixMessage(msg); + } + } + default: + _SendMatrixMessage(msg); + } + return B_OK; +} + + +BMessage +MatrixProtocol::SettingsTemplate(const char* name) +{ + BMessage settings; + if (strcmp(name, "account") == 0) + settings = _AccountTemplate(); + else if (strcmp(name, "join_room") == 0 || strcmp(name, "create_room") == 0) + settings = _RoomTemplate(); + else if (strcmp(name, "roster") == 0) + settings = _RosterTemplate(); + return settings; +} + + +BObjectList +MatrixProtocol::Commands() +{ + return BObjectList(); +} + + +BBitmap* +MatrixProtocol::Icon() const +{ + return NULL; +// return ReadNodeIcon(fAddOnPath.Path(), B_LARGE_ICON, true); +} + + +void +MatrixProtocol::SendMessage(BMessage* msg) +{ + msg->AddString("protocol", Signature()); + fMessenger->SendMessage(msg); +} + + +void +MatrixProtocol::RegisterApp(team_id team) +{ + if (team < 0) + return; + fAppTeam = team; + fAppMessenger = new BMessenger(NULL, team); +} + + +void +MatrixProtocol::_SendMatrixMessage(BMessage* msg) +{ + msg->AddString("protocol", MATRIX_ADDON); + if (fAppMessenger != NULL && fAppMessenger->IsValid()) + fAppMessenger->SendMessage(msg); +} + + +void +MatrixProtocol::_StartApp() +{ + BMessage* start = new BMessage(*fSettings); + start->what = MATRIX_REGISTER_ACCOUNT; + + BRoster roster; + if (roster.Launch(MATRIX_SIGNATURE, start) == B_OK) + snooze(100000); +} + + +BMessage +MatrixProtocol::_AccountTemplate() +{ + BMessage settings; + + BMessage server; + server.AddString("name", "server"); + server.AddString("description", B_TRANSLATE("Homeserver:")); + server.AddString("default", "matrix.org"); + server.AddString("error", B_TRANSLATE("Please enter a valid server address.")); + server.AddInt32("type", B_STRING_TYPE); + settings.AddMessage("setting", &server); + + BMessage user; + user.AddString("name", "username"); + user.AddString("description", B_TRANSLATE("Username:")); + user.AddString("error", B_TRANSLATE("You need a username in order to connect!")); + user.AddInt32("type", B_STRING_TYPE); + settings.AddMessage("setting", &user); + + BMessage password; + password.AddString("name", "password"); password.AddString("description", B_TRANSLATE("Password:")); + password.AddString("error", B_TRANSLATE("Without a password, how will love survive?")); + password.AddInt32("type", B_STRING_TYPE); + settings.AddMessage("setting", &password); + + BMessage session; + session.AddString("name", "session"); + session.AddString("description", B_TRANSLATE("Session name:")); + session.AddInt32("type", B_STRING_TYPE); + session.AddString("default", "Chat-O-Matic [Haiku]"); + settings.AddMessage("setting", &session); + + return settings; +} + + +BMessage +MatrixProtocol::_RoomTemplate() +{ + BMessage settings; + + BMessage id; + id.AddString("name", "chat_id"); + id.AddString("description", B_TRANSLATE("Channel:")); + id.AddString("error", B_TRANSLATE("Please enter a channel― skipping it doesn't make sense!")); + id.AddInt32("type", B_STRING_TYPE); + settings.AddMessage("setting", &id); + + return settings; +} + + +BMessage +MatrixProtocol::_RosterTemplate() +{ + BMessage settings; + + BMessage nick; + nick.AddString("name", "user_id"); + nick.AddString("description", B_TRANSLATE("User ID:")); + nick.AddString("error", B_TRANSLATE("How can someone be your friend if you don't know their ID?")); + nick.AddInt32("type", B_STRING_TYPE); + settings.AddMessage("setting", &nick); + + return settings; +} diff --git a/protocols/matrix/MatrixProtocol.h b/protocols/matrix/MatrixProtocol.h new file mode 100644 index 0000000..eca91ce --- /dev/null +++ b/protocols/matrix/MatrixProtocol.h @@ -0,0 +1,75 @@ +/* + * Copyright 2021, Jaidyn Levesque + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef _MATRIX_PROTOCOL_H +#define _MATRIX_PROTOCOL_H + +#include + +#include + +#include "Matrix.h" + + +status_t connect_thread(void* data); +BMessage receive_message(); + + +class MatrixProtocol : public ChatProtocol { +public: + MatrixProtocol(); + ~MatrixProtocol(); + + // ChatProtocol inheritance + virtual status_t Init(ChatProtocolMessengerInterface* interface); + virtual status_t Shutdown(); + + virtual status_t UpdateSettings(BMessage* settings); + + virtual status_t Process(BMessage* msg); + + virtual BMessage SettingsTemplate(const char* name); + virtual BObjectList + Commands(); + + virtual const char* Signature() const { return MATRIX_ADDON; } + virtual const char* FriendlySignature() const { return "Matrix"; } + + virtual BBitmap* Icon() const; + + virtual void SetAddOnPath(BPath path) { fAddOnPath = path; } + virtual BPath AddOnPath() { return fAddOnPath; } + + virtual const char* GetName() { return fName; } + virtual void SetName(const char* name) { fName = name; } + + virtual ChatProtocolMessengerInterface* + MessengerInterface() const { return fMessenger; } + + // Matrix + void SendMessage(BMessage* msg); + void RegisterApp(team_id team); + +private: + void _SendMatrixMessage(BMessage* msg); + void _StartApp(); + + // GUI templates + BMessage _AccountTemplate(); + BMessage _RoomTemplate(); + BMessage _RosterTemplate(); + + // Settings + BMessage* fSettings; + + BPath fAddOnPath; + BString fName; + ChatProtocolMessengerInterface* fMessenger; + + team_id fAppTeam; + thread_id fRecvThread; + BMessenger* fAppMessenger; +}; + +#endif // _MATRIX_PROTOCOL_H diff --git a/protocols/matrix/matrix.rdef b/protocols/matrix/matrix.rdef new file mode 100644 index 0000000..0792ac2 --- /dev/null +++ b/protocols/matrix/matrix.rdef @@ -0,0 +1,16 @@ +#include "Matrix.h" + +resource app_signature MATRIX_SIGNATURE; +resource app_flags B_BACKGROUND_APP | B_MULTIPLE_LAUNCH; + +resource app_version { + major = 0, + middle = 0, + minor = 1, + + variety = B_APPV_ALPHA, + internal = 0, + + short_info = "Chat-O-Matic Matrix add-on", + long_info = "©2021 Jaidyn Levesque" +};