mirror of
https://github.com/weechat/weechat.git
synced 2026-07-09 03:03:12 +02:00
relay: add "api" protocol (HTTP REST API) (issue #2066)
This commit is contained in:
@@ -5,7 +5,41 @@ on:
|
||||
- pull_request
|
||||
|
||||
env:
|
||||
WEECHAT_DEPENDENCIES: devscripts equivs python3-pip cmake ninja-build lcov pkg-config libncurses-dev gem2deb libperl-dev python3-dev libaspell-dev liblua5.3-dev tcl8.6-dev guile-3.0-dev libv8-dev libcurl4-gnutls-dev libgcrypt20-dev libgnutls28-dev libzstd-dev zlib1g-dev curl libcpputest-dev php-dev libphp-embed libargon2-dev libsodium-dev flake8 pylint python3-bandit asciidoctor ruby-pygments.rb shellcheck
|
||||
WEECHAT_DEPENDENCIES: >-
|
||||
asciidoctor
|
||||
cmake
|
||||
curl
|
||||
devscripts
|
||||
equivs
|
||||
flake8
|
||||
gem2deb
|
||||
guile-3.0-dev
|
||||
lcov
|
||||
libargon2-dev
|
||||
libaspell-dev
|
||||
libcjson-dev
|
||||
libcpputest-dev
|
||||
libcurl4-gnutls-dev
|
||||
libgcrypt20-dev
|
||||
libgnutls28-dev
|
||||
liblua5.3-dev
|
||||
libncurses-dev
|
||||
libperl-dev
|
||||
libphp-embed
|
||||
libsodium-dev
|
||||
libv8-dev
|
||||
libzstd-dev
|
||||
ninja-build
|
||||
php-dev
|
||||
pkg-config
|
||||
pylint
|
||||
python3-bandit
|
||||
python3-dev
|
||||
python3-pip
|
||||
ruby-pygments.rb
|
||||
shellcheck
|
||||
tcl8.6-dev
|
||||
zlib1g-dev
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -20,6 +54,7 @@ jobs:
|
||||
- { name: "gcc_ninja", cc: "gcc", cxx: "g++", buildargs: "-G Ninja" }
|
||||
- { name: "gcc_no_nls", cc: "gcc", cxx: "g++", buildargs: "-DENABLE_NLS=OFF -DENABLE_DOC=OFF" }
|
||||
- { name: "gcc_no_zstd", cc: "gcc", cxx: "g++", buildargs: "-DENABLE_ZSTD=OFF -DENABLE_DOC=OFF" }
|
||||
- { name: "gcc_no_cjson", cc: "gcc", cxx: "g++", buildargs: "-DENABLE_CJSON=OFF -DENABLE_DOC=OFF" }
|
||||
- { name: "gcc_coverage", cc: "gcc", cxx: "g++", buildargs: "-DENABLE_CODE_COVERAGE=ON" }
|
||||
- { name: "clang", cc: "clang", cxx: "clang++", buildargs: "" }
|
||||
|
||||
@@ -115,7 +150,7 @@ jobs:
|
||||
/usr/local/bin/python3.11 \
|
||||
/usr/local/bin/python3.11-config \
|
||||
;
|
||||
brew install asciidoctor guile lua pkg-config ruby
|
||||
brew install asciidoctor cjson guile lua pkg-config ruby
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
|
||||
@@ -100,6 +100,7 @@ option(ENABLE_HEADLESS "Compile the headless binary" ON)
|
||||
option(ENABLE_NLS "Enable Native Language Support" ON)
|
||||
option(ENABLE_LARGEFILE "Enable Large File Support" ON)
|
||||
option(ENABLE_ZSTD "Enable Zstandard compression" ON)
|
||||
option(ENABLE_CJSON "Enable cJSON support" ON)
|
||||
option(ENABLE_ALIAS "Enable Alias plugin" ON)
|
||||
option(ENABLE_BUFLIST "Enable Buflist plugin" ON)
|
||||
option(ENABLE_CHARSET "Enable Charset plugin" ON)
|
||||
@@ -222,6 +223,12 @@ if(ENABLE_ZSTD)
|
||||
add_definitions(-DHAVE_ZSTD)
|
||||
endif()
|
||||
|
||||
# Check for cJSON
|
||||
if(ENABLE_CJSON)
|
||||
pkg_check_modules(LIBCJSON REQUIRED libcjson)
|
||||
add_definitions(-DHAVE_CJSON)
|
||||
endif()
|
||||
|
||||
# Check for iconv
|
||||
find_package(Iconv)
|
||||
if(ICONV_FOUND)
|
||||
|
||||
@@ -18,6 +18,7 @@ New features::
|
||||
* core: allow case insensitive search of partial buffer name with `(?i)name` in command `/buffer`
|
||||
* core: use function util_strftimeval in evaluation of expression `date:xxx`
|
||||
* api: add support of specifier `%!` for timestamp in function util_strftimeval
|
||||
* relay: add "api" protocol (HTTP REST API), add option relay.look.display_clients, change option type relay.look.auto_open_buffer to string (issue #2066)
|
||||
|
||||
Bug fixes::
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@ Build-Depends:
|
||||
libgcrypt20-dev,
|
||||
libgnutls28-dev,
|
||||
libzstd-dev,
|
||||
zlib1g-dev
|
||||
zlib1g-dev,
|
||||
libcjson-dev
|
||||
Standards-Version: 4.6.2
|
||||
Homepage: https://weechat.org/
|
||||
Vcs-Git: https://salsa.debian.org/kolter/weechat.git
|
||||
|
||||
@@ -21,7 +21,8 @@ Build-Depends:
|
||||
libgcrypt20-dev,
|
||||
libgnutls28-dev,
|
||||
libzstd-dev,
|
||||
zlib1g-dev
|
||||
zlib1g-dev,
|
||||
libcjson-dev
|
||||
Standards-Version: 4.6.2
|
||||
Homepage: https://weechat.org/
|
||||
Vcs-Git: https://salsa.debian.org/kolter/weechat.git
|
||||
|
||||
@@ -159,6 +159,10 @@ WeeChat optional sind:
|
||||
| ca-certificates |
|
||||
| Zertifikate für TLS Verbindungen.
|
||||
|
||||
// TRANSLATION MISSING
|
||||
| libcjson-dev |
|
||||
| Relay plugin: protocol "api" (HTTP REST API).
|
||||
|
||||
| libzstd-dev | ≥ 0.8.1
|
||||
| Logger-Erweiterung: Kompression von rotierenden Protokolldateien (zstandard). +
|
||||
Relay-Erweiterung: Kompression von Nachrichten (WeeChat -> client) with https://facebook.github.io/zstd/[Zstandard ^↗^^] (weechat protocol).
|
||||
@@ -279,6 +283,10 @@ Liste der verfügbaren Optionen:
|
||||
| ENABLE_CHARSET | `ON`, `OFF` | ON
|
||||
| kompiliert <<charset,Charset Erweiterung>>.
|
||||
|
||||
// TRANSLATION MISSING
|
||||
| ENABLE_CJSON | `ON`, `OFF` | ON
|
||||
| Support of JSON with https://github.com/DaveGamble/cJSON[cJSON ^↗^^] library.
|
||||
|
||||
| ENABLE_MAN | `ON`, `OFF` | OFF
|
||||
| erstellt die man page.
|
||||
|
||||
|
||||
@@ -331,15 +331,20 @@ WeeChat "core" is located in following directories:
|
||||
| relay-command.c | Relay commands.
|
||||
| relay-completion.c | Relay completions.
|
||||
| relay-config.c | Relay config options (file relay.conf).
|
||||
| relay-http.c | HTTP functions.
|
||||
| relay-info.c | Relay info/infolists/hdata.
|
||||
| relay-network.c | Network functions for relay.
|
||||
| relay-raw.c | Relay raw buffer.
|
||||
| relay-server.c | Relay server.
|
||||
| relay-upgrade.c | Save/restore of relay data when upgrading WeeChat.
|
||||
| relay-websocket.c | WebSocket server functions (RFC 6455).
|
||||
| api/ | Relay for remote interfaces (using HTTP REST API).
|
||||
| relay-api.c | Main API functions for HTTP REST API.
|
||||
| relay-api-msg.c | Send JSON messages to clients.
|
||||
| relay-api-protocol.c | HTTP REST API protocol.
|
||||
| irc/ | IRC proxy.
|
||||
| relay-irc.c | Main IRC proxy functions.
|
||||
| weechat/ | Relay for remote interfaces.
|
||||
| weechat/ | Relay for remote interfaces (using "weechat" binary protocol).
|
||||
| relay-weechat.c | Relay for remote interfaces (main functions).
|
||||
| relay-weechat-msg.c | Send binary messages to clients.
|
||||
| relay-weechat-nicklist.c | Nicklist functions.
|
||||
@@ -469,6 +474,7 @@ WeeChat "core" is located in following directories:
|
||||
| test-typing-status.cpp | Tests: typing status.
|
||||
| relay/ | Root of unit tests for Relay plugin.
|
||||
| test-relay-auth.cpp | Tests: clients authentication.
|
||||
| test-relay-http.cpp | Tests: HTTP functions for Relay plugin.
|
||||
| irc/ | Root of unit tests for Relay "irc" protocol.
|
||||
| test-relay-irc.cpp | Tests: Relay "irc" protocol.
|
||||
| xfer/ | Root of unit tests for Xfer plugin.
|
||||
|
||||
@@ -154,6 +154,9 @@ WeeChat:
|
||||
| ca-certificates |
|
||||
| Certificates for TLS connections.
|
||||
|
||||
| libcjson-dev |
|
||||
| Relay plugin: protocol "api" (HTTP REST API).
|
||||
|
||||
| libzstd-dev | ≥ 0.8.1
|
||||
| Logger plugin: compression of rotated log files (zstandard). +
|
||||
Relay plugin: compression of messages (WeeChat -> client) with https://facebook.github.io/zstd/[Zstandard ^↗^^] (weechat protocol).
|
||||
@@ -273,6 +276,9 @@ List of available options:
|
||||
| ENABLE_CHARSET | `ON`, `OFF` | ON
|
||||
| Compile <<charset,Charset plugin>>.
|
||||
|
||||
| ENABLE_CJSON | `ON`, `OFF` | ON
|
||||
| Support of JSON with https://github.com/DaveGamble/cJSON[cJSON ^↗^^] library.
|
||||
|
||||
| ENABLE_MAN | `ON`, `OFF` | OFF
|
||||
| Build man page.
|
||||
|
||||
|
||||
@@ -333,15 +333,20 @@ Le cœur de WeeChat est situé dans les répertoires suivants :
|
||||
| relay-command.c | Commandes de Relay.
|
||||
| relay-completion.c | Complétions de Relay.
|
||||
| relay-config.c | Options de configuration pour Relay (fichier relay.conf).
|
||||
| relay-http.c | Fonctions HTTP.
|
||||
| relay-info.c | Info/infolists/hdata pour Relay.
|
||||
| relay-network.c | Fonctions de réseau pour Relay.
|
||||
| relay-raw.c | Tampon des données brutes de Relay.
|
||||
| relay-server.c | Serveur Relay.
|
||||
| relay-upgrade.c | Sauvegarde/restauration des données Relay lors de la mise à jour de WeeChat.
|
||||
| relay-websocket.c | Fonctions pour le serveur WebSocket (RFC 6455).
|
||||
| api/ | Relai pour les interfaces distantes (en utilisant une API REST HTTP).
|
||||
| relay-api.c | Fonctions principales pour l'API REST HTTP.
|
||||
| relay-api-msg.c | Envoi de messages JSON aux clients.
|
||||
| relay-api-protocol.c | Protocole HTTP REST API.
|
||||
| irc/ | Proxy IRC.
|
||||
| relay-irc.c | Fonctions principales pour le proxy IRC.
|
||||
| weechat/ | Relai pour les interfaces distantes.
|
||||
| weechat/ | Relai pour les interfaces distantes (en utilisant le protocole binaire "weechat").
|
||||
| relay-weechat.c | Relai pour les interfaces distantes (fonctions principales).
|
||||
| relay-weechat-msg.c | Envoi de messages binaires aux clients.
|
||||
| relay-weechat-nicklist.c | Fonctions pour la liste de pseudos.
|
||||
@@ -471,6 +476,7 @@ Le cœur de WeeChat est situé dans les répertoires suivants :
|
||||
| test-typing-status.cpp | Tests : statut d'écriture.
|
||||
| relay/ | Racine des tests unitaires pour l'extension Relay.
|
||||
| test-relay-auth.cpp | Tests : authentification des clients.
|
||||
| test-relay-http.cpp | Tests : fonctions HTTP pour l'extension Relay.
|
||||
| irc/ | Racine des tests unitaires pour le protocole relay "irc".
|
||||
| test-relay-irc.cpp | Tests : Protocole relay "irc".
|
||||
| xfer/ | Racine des tests unitaires pour l'extension Xfer.
|
||||
|
||||
@@ -153,6 +153,9 @@ Le tableau suivant liste les paquets optionnels pour compiler WeeChat :
|
||||
| ca-certificates |
|
||||
| Certificats pour les connexions TLS.
|
||||
|
||||
| libcjson-dev |
|
||||
| Extension Relay : protocole "api" (API REST HTTP).
|
||||
|
||||
| libzstd-dev | ≥ 0.8.1
|
||||
| Extension Logger : compression des fichiers de log qui tournent (zstandard). +
|
||||
Extension Relay : compression des messages (WeeChat -> client) avec https://facebook.github.io/zstd/[Zstandard ^↗^^] (protocole weechat).
|
||||
@@ -272,6 +275,9 @@ Liste des options disponibles :
|
||||
| ENABLE_CHARSET | `ON`, `OFF` | ON
|
||||
| Compiler <<charset,l'extension Charset>>.
|
||||
|
||||
| ENABLE_CJSON | `ON`, `OFF` | ON
|
||||
| Support du JSON avec la bibliothèque https://github.com/DaveGamble/cJSON[cJSON ^↗^^].
|
||||
|
||||
| ENABLE_MAN | `ON`, `OFF` | OFF
|
||||
| Construire la page man.
|
||||
|
||||
|
||||
@@ -188,6 +188,10 @@ WeeChat:
|
||||
| ca-certificates |
|
||||
| Certificati per le connessioni TLS.
|
||||
|
||||
// TRANSLATION MISSING
|
||||
| libcjson-dev |
|
||||
| Relay plugin: protocol "api" (HTTP REST API).
|
||||
|
||||
// TRANSLATION MISSING
|
||||
| libzstd-dev | ≥ 0.8.1
|
||||
| Logger plugin: compression of rotated log files (zstandard). +
|
||||
@@ -320,6 +324,10 @@ List of available options:
|
||||
| ENABLE_CHARSET | `ON`, `OFF` | ON
|
||||
| Compile <<charset,Charset plugin>>.
|
||||
|
||||
// TRANSLATION MISSING
|
||||
| ENABLE_CJSON | `ON`, `OFF` | ON
|
||||
| Support of JSON with https://github.com/DaveGamble/cJSON[cJSON ^↗^^] library.
|
||||
|
||||
| ENABLE_MAN | `ON`, `OFF` | OFF
|
||||
| Build man page.
|
||||
|
||||
|
||||
@@ -352,15 +352,26 @@ WeeChat "core" は以下のディレクトリに配置されています:
|
||||
| relay-command.c | relay コマンド
|
||||
| relay-completion.c | relay 補完
|
||||
| relay-config.c | relay 設定オプション (relay.conf ファイル)
|
||||
// TRANSLATION MISSING
|
||||
| relay-http.c | HTTP functions.
|
||||
| relay-info.c | relay の情報/インフォリスト/hdata
|
||||
| relay-network.c | relay 用のネットワーク関数
|
||||
| relay-raw.c | relay 生バッファ
|
||||
| relay-server.c | relay サーバ
|
||||
| relay-upgrade.c | WeeChat をアップグレードする際にデータを保存/回復
|
||||
| relay-websocket.c | リレー用の websocket サーバ関数 (RFC 6455)
|
||||
// TRANSLATION MISSING
|
||||
| api/ | Relay for remote interfaces (using HTTP REST API).
|
||||
// TRANSLATION MISSING
|
||||
| relay-api.c | Main API functions for HTTP REST API.
|
||||
// TRANSLATION MISSING
|
||||
| relay-api-msg.c | Send JSON messages to clients.
|
||||
// TRANSLATION MISSING
|
||||
| relay-api-protocol.c | HTTP REST API protocol.
|
||||
| irc/ | IRC プロキシ
|
||||
| relay-irc.c | IRC プロキシの主要関数
|
||||
| weechat/ | リモートインターフェースへの中継
|
||||
// TRANSLATION MISSING
|
||||
| weechat/ | Relay for remote interfaces (using "weechat" binary protocol).
|
||||
| relay-weechat.c | リモートインターフェースへの中継 (主要関数)
|
||||
| relay-weechat-msg.c | クライアントにバイナリメッセージを送信
|
||||
| relay-weechat-nicklist.c | ニックネームリスト関数
|
||||
@@ -543,6 +554,8 @@ WeeChat "core" は以下のディレクトリに配置されています:
|
||||
// TRANSLATION MISSING
|
||||
| test-relay-auth.cpp | Tests: clients authentication.
|
||||
// TRANSLATION MISSING
|
||||
| test-relay-http.cpp | Tests: HTTP functions for Relay plugin.
|
||||
// TRANSLATION MISSING
|
||||
| irc/ | Root of unit tests for Relay "irc" protocol.
|
||||
// TRANSLATION MISSING
|
||||
| test-relay-irc.cpp | Tests: Relay "irc" protocol.
|
||||
|
||||
@@ -173,6 +173,10 @@ WeeChat:
|
||||
| ca-certificates |
|
||||
| TLS 接続に必要な証明書、relay プラグインで TLS サポート
|
||||
|
||||
// TRANSLATION MISSING
|
||||
| libcjson-dev |
|
||||
| Relay plugin: protocol "api" (HTTP REST API).
|
||||
|
||||
// TRANSLATION MISSING
|
||||
| libzstd-dev | ≥ 0.8.1
|
||||
| Logger plugin: compression of rotated log files (zstandard). +
|
||||
@@ -298,6 +302,10 @@ List of available options:
|
||||
| ENABLE_CHARSET | `ON`, `OFF` | ON
|
||||
| <<charset,Charset プラグイン>>のコンパイル。
|
||||
|
||||
// TRANSLATION MISSING
|
||||
| ENABLE_CJSON | `ON`, `OFF` | ON
|
||||
| Support of JSON with https://github.com/DaveGamble/cJSON[cJSON ^↗^^] library.
|
||||
|
||||
| ENABLE_MAN | `ON`, `OFF` | OFF
|
||||
| man ページのコンパイル。
|
||||
|
||||
|
||||
@@ -158,6 +158,10 @@ WeeChat:
|
||||
| ca-certificates |
|
||||
| Certyfikaty dla połączeń TLS.
|
||||
|
||||
// TRANSLATION MISSING
|
||||
| libcjson-dev |
|
||||
| Relay plugin: protocol "api" (HTTP REST API).
|
||||
|
||||
| libzstd-dev | ≥ 0.8.1
|
||||
| Wtyczka logger: kompresja rotowanych plików z logami (zstandard). +
|
||||
Wtyczka Relay: kompresja wiadomości (WeeChat -> klient) za pomocą https://facebook.github.io/zstd/[Zstandard ^↗^^] (protokół weechat).
|
||||
@@ -277,6 +281,10 @@ Lista dostępnych opcji:
|
||||
| ENABLE_CHARSET | `ON`, `OFF` | ON
|
||||
| Kompilacja <<charset,wtyczki charset>>.
|
||||
|
||||
// TRANSLATION MISSING
|
||||
| ENABLE_CJSON | `ON`, `OFF` | ON
|
||||
| Support of JSON with https://github.com/DaveGamble/cJSON[cJSON ^↗^^] library.
|
||||
|
||||
| ENABLE_MAN | `ON`, `OFF` | OFF
|
||||
| Generowanie strony manuala.
|
||||
|
||||
|
||||
@@ -333,15 +333,26 @@ WeeChat „језгро” се налази у следећим директо
|
||||
| relay-command.c | Релеј команде.
|
||||
| relay-completion.c | Релеј довршавања.
|
||||
| relay-config.c | Релеј опције конфиг (фајл relay.conf).
|
||||
// TRANSLATION MISSING
|
||||
| relay-http.c | HTTP functions.
|
||||
| relay-info.c | Релеј info/infolists/hdata.
|
||||
| relay-network.c | Мрежне функције за релеј.
|
||||
| relay-raw.c | Релеј сирови бафер.
|
||||
| relay-server.c | Релеј сервер.
|
||||
| relay-upgrade.c | Save/restore of relay data when upgrading WeeChat.
|
||||
| relay-websocket.c | WebSocket сервер функције (RFC 6455).
|
||||
// TRANSLATION MISSING
|
||||
| api/ | Relay for remote interfaces (using HTTP REST API).
|
||||
// TRANSLATION MISSING
|
||||
| relay-api.c | Main API functions for HTTP REST API.
|
||||
// TRANSLATION MISSING
|
||||
| relay-api-msg.c | Send JSON messages to clients.
|
||||
// TRANSLATION MISSING
|
||||
| relay-api-protocol.c | HTTP REST API protocol.
|
||||
| irc/ | IRC прокси.
|
||||
| relay-irc.c | Главне IRC прокси функције.
|
||||
| weechat/ | Релеј за удаљене интерфејсе.
|
||||
// TRANSLATION MISSING
|
||||
| weechat/ | Relay for remote interfaces (using "weechat" binary protocol).
|
||||
| relay-weechat.c | Релеј за удаљене интерфејсе (главне функције).
|
||||
| relay-weechat-msg.c | Слање бинарних порука клијентима.
|
||||
| relay-weechat-nicklist.c | Функције листе надимака.
|
||||
@@ -471,6 +482,8 @@ WeeChat „језгро” се налази у следећим директо
|
||||
| test-typing-status.cpp | Тестови: typing статус.
|
||||
| relay/ | Корен unit тестова за Релеј додатак.
|
||||
| test-relay-auth.cpp | Тестови: аутентификација клијената.
|
||||
// TRANSLATION MISSING
|
||||
| test-relay-http.cpp | Tests: HTTP functions for Relay plugin.
|
||||
| irc/ | Корен unit тестова за Релеј „irc” протокол.
|
||||
| test-relay-irc.cpp | Тестови: РЕлеј „irc” протокол.
|
||||
| xfer/ | Корен unit тестова за Xfer додатак.
|
||||
|
||||
@@ -151,6 +151,10 @@ WeeChat мора да се изгради са CMake.
|
||||
| ca-certificates |
|
||||
| Сертификати за TLS везе.
|
||||
|
||||
// TRANSLATION MISSING
|
||||
| libcjson-dev |
|
||||
| Relay plugin: protocol "api" (HTTP REST API).
|
||||
|
||||
| libzstd-dev | ≥ 0.8.1
|
||||
| Logger додатак: компресија ротирајућих лог фајлова (zstandard). +
|
||||
Relay додатак: компресија порука (WeeChat -> клијент) са https://facebook.github.io/zstd/[Zstandard ^↗^^] (weechat протокол).
|
||||
@@ -268,6 +272,10 @@ $ make install
|
||||
| ENABLE_CHARSET | `ON`, `OFF` | ON
|
||||
| Компајлира <<charset,Charset додатак>>.
|
||||
|
||||
// TRANSLATION MISSING
|
||||
| ENABLE_CJSON | `ON`, `OFF` | ON
|
||||
| Support of JSON with https://github.com/DaveGamble/cJSON[cJSON ^↗^^] library.
|
||||
|
||||
| ENABLE_MAN | `ON`, `OFF` | OFF
|
||||
| Изграђује man страницу.
|
||||
|
||||
|
||||
@@ -344,6 +344,12 @@ SET(WEECHAT_SOURCES
|
||||
./src/plugins/python/weechat-python-api.h
|
||||
./src/plugins/python/weechat-python.c
|
||||
./src/plugins/python/weechat-python.h
|
||||
./src/plugins/relay/api/relay-api.c
|
||||
./src/plugins/relay/api/relay-api.h
|
||||
./src/plugins/relay/api/relay-api-msg.c
|
||||
./src/plugins/relay/api/relay-api-msg.h
|
||||
./src/plugins/relay/api/relay-api-protocol.c
|
||||
./src/plugins/relay/api/relay-api-protocol.h
|
||||
./src/plugins/relay/irc/relay-irc.c
|
||||
./src/plugins/relay/irc/relay-irc.h
|
||||
./src/plugins/relay/relay-auth.c
|
||||
@@ -360,6 +366,8 @@ SET(WEECHAT_SOURCES
|
||||
./src/plugins/relay/relay-config.c
|
||||
./src/plugins/relay/relay-config.h
|
||||
./src/plugins/relay/relay.h
|
||||
./src/plugins/relay/relay-http.c
|
||||
./src/plugins/relay/relay-http.h
|
||||
./src/plugins/relay/relay-info.c
|
||||
./src/plugins/relay/relay-info.h
|
||||
./src/plugins/relay/relay-network.c
|
||||
|
||||
@@ -95,6 +95,10 @@ if(ENABLE_ZSTD)
|
||||
include_directories(${ZSTD_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
if(ENABLE_CJSON)
|
||||
include_directories(${CJSON_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
include_directories("${CMAKE_BINARY_DIR}")
|
||||
add_library(weechat_core STATIC ${LIB_CORE_SRC})
|
||||
target_link_libraries(weechat_core coverage_config)
|
||||
|
||||
@@ -36,6 +36,9 @@
|
||||
#ifdef HAVE_ZSTD
|
||||
#include <zstd.h>
|
||||
#endif
|
||||
#ifdef HAVE_CJSON
|
||||
#include <cjson/cJSON.h>
|
||||
#endif
|
||||
|
||||
#include <gnutls/gnutls.h>
|
||||
|
||||
@@ -702,6 +705,16 @@ debug_libs_cb (const void *pointer, void *data,
|
||||
gui_chat_printf (NULL, " zstd: %s", _("not available"));
|
||||
#endif /* HAVE_ZSTD */
|
||||
|
||||
/* display cJSON version */
|
||||
#ifdef HAVE_CJSON
|
||||
gui_chat_printf (NULL, " cJSON: %d.%d.%d",
|
||||
CJSON_VERSION_MAJOR,
|
||||
CJSON_VERSION_MINOR,
|
||||
CJSON_VERSION_PATCH);
|
||||
#else
|
||||
gui_chat_printf (NULL, " cJSON: %s", _("not available"));
|
||||
#endif /* HAVE_CJSON */
|
||||
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# along with WeeChat. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
add_library(relay MODULE
|
||||
set(RELAY_SRC
|
||||
relay.c relay.h
|
||||
relay-auth.c relay-auth.h
|
||||
relay-buffer.c relay-buffer.h
|
||||
@@ -25,6 +25,7 @@ add_library(relay MODULE
|
||||
relay-command.c relay-command.h
|
||||
relay-completion.c relay-completion.h
|
||||
relay-config.c relay-config.h
|
||||
relay-http.c relay-http.h
|
||||
relay-info.c relay-info.h
|
||||
relay-network.c relay-network.h
|
||||
relay-raw.c relay-raw.h
|
||||
@@ -38,7 +39,19 @@ add_library(relay MODULE
|
||||
weechat/relay-weechat-msg.c weechat/relay-weechat-msg.h
|
||||
weechat/relay-weechat-nicklist.c weechat/relay-weechat-nicklist.h
|
||||
weechat/relay-weechat-protocol.c weechat/relay-weechat-protocol.h
|
||||
|
||||
)
|
||||
|
||||
if(ENABLE_CJSON)
|
||||
list(APPEND RELAY_SRC
|
||||
# API relay
|
||||
api/relay-api.c api/relay-api.h
|
||||
api/relay-api-msg.c api/relay-api-msg.h
|
||||
api/relay-api-protocol.c api/relay-api-protocol.h
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(relay MODULE ${RELAY_SRC})
|
||||
set_target_properties(relay PROPERTIES PREFIX "")
|
||||
|
||||
set(LINK_LIBS)
|
||||
@@ -55,6 +68,11 @@ if(ENABLE_ZSTD)
|
||||
list(APPEND LINK_LIBS ${LIBZSTD_LDFLAGS})
|
||||
endif()
|
||||
|
||||
if(ENABLE_CJSON)
|
||||
include_directories(${CJSON_INCLUDE_DIRS})
|
||||
list(APPEND LINK_LIBS ${LIBCJSON_LDFLAGS})
|
||||
endif()
|
||||
|
||||
target_link_libraries(relay ${LINK_LIBS} coverage_config)
|
||||
|
||||
install(TARGETS relay LIBRARY DESTINATION "${WEECHAT_LIBDIR}/plugins")
|
||||
|
||||
@@ -0,0 +1,601 @@
|
||||
/*
|
||||
* relay-api-msg.c - build JSON messages for "api" protocol
|
||||
*
|
||||
* Copyright (C) 2023-2024 Sébastien Helleu <flashcode@flashtux.org>
|
||||
*
|
||||
* This file is part of WeeChat, the extensible chat client.
|
||||
*
|
||||
* WeeChat 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; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* WeeChat 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 WeeChat. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <cjson/cJSON.h>
|
||||
|
||||
#include "../../weechat-plugin.h"
|
||||
#include "../relay.h"
|
||||
#include "../relay-client.h"
|
||||
#include "../relay-http.h"
|
||||
#include "relay-api.h"
|
||||
#include "relay-api-msg.h"
|
||||
#include "relay-api-protocol.h"
|
||||
|
||||
#define MSG_ADD_STR_BUF(__json_name, __string) \
|
||||
cJSON_AddItemToObject( \
|
||||
json, __json_name, \
|
||||
cJSON_CreateString (__string));
|
||||
|
||||
#define MSG_ADD_STR_PTR(__json_name, __string) \
|
||||
cJSON_AddItemToObject( \
|
||||
json, __json_name, \
|
||||
cJSON_CreateString ((__string) ? __string : ""));
|
||||
|
||||
#define MSG_ADD_HDATA_VAR(__json_type, __json_name, \
|
||||
__var_type, __var_name) \
|
||||
cJSON_AddItemToObject( \
|
||||
json, __json_name, \
|
||||
cJSON_Create##__json_type ( \
|
||||
weechat_hdata_##__var_type (hdata, pointer, __var_name)));
|
||||
|
||||
#define MSG_ADD_HDATA_TIME(__json_name, __var_name) \
|
||||
date = weechat_hdata_time (hdata, pointer, __var_name); \
|
||||
strftime (str_time, sizeof (str_time), "%FT%TZ", gmtime (&date)); \
|
||||
MSG_ADD_STR_BUF(__json_name, str_time);
|
||||
|
||||
#define MSG_ADD_HDATA_TIME_USEC(__json_name, \
|
||||
__var_name, __var_name_usec) \
|
||||
time_value = weechat_hdata_time (hdata, pointer, __var_name); \
|
||||
gmtime_r (&time_value, &gm_time); \
|
||||
tv.tv_sec = mktime (&gm_time); \
|
||||
tv.tv_usec = weechat_hdata_integer (hdata, pointer, \
|
||||
__var_name_usec); \
|
||||
weechat_util_strftimeval (str_time, sizeof (str_time), \
|
||||
"%FT%T.%fZ", &tv); \
|
||||
MSG_ADD_STR_BUF(__json_name, str_time);
|
||||
|
||||
#define MSG_ADD_HDATA_STR(__json_name, __var_name) \
|
||||
ptr_string = weechat_hdata_string (hdata, pointer, __var_name); \
|
||||
MSG_ADD_STR_PTR(__json_name, ptr_string);
|
||||
|
||||
#define MSG_ADD_HDATA_STR_COLORS(__json_name, __var_name) \
|
||||
ptr_string = weechat_hdata_string (hdata, pointer, __var_name); \
|
||||
switch (colors) \
|
||||
{ \
|
||||
case RELAY_API_COLORS_ANSI: \
|
||||
string = weechat_hook_modifier_exec ( \
|
||||
"color_encode_ansi", NULL, \
|
||||
(ptr_string) ? ptr_string : ""); \
|
||||
if (string) \
|
||||
{ \
|
||||
MSG_ADD_STR_PTR(__json_name, string); \
|
||||
free (string); \
|
||||
} \
|
||||
break; \
|
||||
case RELAY_API_COLORS_WEECHAT: \
|
||||
MSG_ADD_STR_PTR(__json_name, ptr_string); \
|
||||
break; \
|
||||
case RELAY_API_COLORS_STRIP: \
|
||||
string = weechat_string_remove_color ( \
|
||||
(ptr_string) ? ptr_string : "", NULL); \
|
||||
if (string) \
|
||||
{ \
|
||||
MSG_ADD_STR_PTR(__json_name, string); \
|
||||
free (string); \
|
||||
} \
|
||||
case RELAY_API_NUM_COLORS: \
|
||||
break; \
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sends JSON response to client (internal use).
|
||||
*
|
||||
* Returns number of bytes sent to client, -1 if error.
|
||||
*/
|
||||
|
||||
int
|
||||
relay_api_msg_send_json_internal (struct t_relay_client *client,
|
||||
int return_code,
|
||||
const char *message,
|
||||
const char *event_name,
|
||||
const char *event_type,
|
||||
const char *event_context,
|
||||
const char *headers,
|
||||
cJSON *json_body)
|
||||
{
|
||||
cJSON *json, *json_event;
|
||||
int num_bytes;
|
||||
char *string;
|
||||
|
||||
if (!client || !message)
|
||||
return -1;
|
||||
|
||||
num_bytes = -1;
|
||||
|
||||
if (client->websocket == RELAY_CLIENT_WEBSOCKET_READY)
|
||||
{
|
||||
/*
|
||||
* with established websocket, we return JSON string instead of
|
||||
* an HTTP response
|
||||
*/
|
||||
json = cJSON_CreateObject ();
|
||||
if (json)
|
||||
{
|
||||
cJSON_AddItemToObject (json, "code", cJSON_CreateNumber (return_code));
|
||||
cJSON_AddItemToObject (json, "message", cJSON_CreateString (message));
|
||||
if (event_name)
|
||||
{
|
||||
json_event = cJSON_CreateObject ();
|
||||
if (json_event)
|
||||
{
|
||||
cJSON_AddItemToObject (
|
||||
json_event, "name",
|
||||
cJSON_CreateString ((event_name) ? event_name : ""));
|
||||
cJSON_AddItemToObject (
|
||||
json_event, "type",
|
||||
cJSON_CreateString ((event_type) ? event_type : ""));
|
||||
cJSON_AddItemToObject (
|
||||
json_event, "context",
|
||||
cJSON_CreateString ((event_context) ? event_context : ""));
|
||||
cJSON_AddItemToObject (json, "event", json_event);
|
||||
}
|
||||
}
|
||||
cJSON_AddItemToObject (json, "body", json_body);
|
||||
string = cJSON_PrintUnformatted (json);
|
||||
num_bytes = relay_client_send (
|
||||
client,
|
||||
RELAY_CLIENT_MSG_STANDARD,
|
||||
string,
|
||||
(string) ? strlen (string) : 0,
|
||||
NULL); /* raw_message */
|
||||
if (string)
|
||||
free (string);
|
||||
cJSON_DetachItemFromObject (json, "body");
|
||||
cJSON_Delete (json);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string = (json_body) ? cJSON_PrintUnformatted (json_body) : NULL;
|
||||
num_bytes = relay_http_send_json (client, return_code, message, headers,
|
||||
string);
|
||||
if (string)
|
||||
free (string);
|
||||
}
|
||||
|
||||
return num_bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends JSON response to client (internal use).
|
||||
*
|
||||
* Returns number of bytes sent to client, -1 if error.
|
||||
*/
|
||||
|
||||
int
|
||||
relay_api_msg_send_json (struct t_relay_client *client,
|
||||
int return_code,
|
||||
const char *message,
|
||||
cJSON *json_body)
|
||||
{
|
||||
return relay_api_msg_send_json_internal (client,
|
||||
return_code,
|
||||
message,
|
||||
NULL, /* event_name */
|
||||
NULL, /* event_type */
|
||||
NULL, /* event_context */
|
||||
NULL, /* headers */
|
||||
json_body);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends JSON error to client.
|
||||
*
|
||||
* Returns number of bytes sent to client, -1 if error.
|
||||
*/
|
||||
|
||||
int
|
||||
relay_api_msg_send_error_json (struct t_relay_client *client,
|
||||
int return_code,
|
||||
const char *message,
|
||||
const char *headers,
|
||||
const char *format, ...)
|
||||
{
|
||||
cJSON *json;
|
||||
int num_bytes, length;
|
||||
char *error_msg, *str_json;
|
||||
|
||||
if (!client || !message || !format)
|
||||
return -1;
|
||||
|
||||
weechat_va_format (format);
|
||||
if (!vbuffer)
|
||||
return -1;
|
||||
|
||||
num_bytes = -1;
|
||||
|
||||
if (client->websocket == RELAY_CLIENT_WEBSOCKET_READY)
|
||||
{
|
||||
/*
|
||||
* with established websocket, we return JSON string instead of
|
||||
* an HTTP response
|
||||
*/
|
||||
json = cJSON_CreateObject ();
|
||||
if (json)
|
||||
{
|
||||
cJSON_AddItemToObject (json, "error", cJSON_CreateString (vbuffer));
|
||||
num_bytes = relay_api_msg_send_json_internal (
|
||||
client,
|
||||
return_code,
|
||||
message,
|
||||
NULL, /* event_name */
|
||||
NULL, /* event_type */
|
||||
NULL, /* event_context */
|
||||
headers,
|
||||
json);
|
||||
cJSON_Delete (json);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error_msg = weechat_string_replace (vbuffer, "\"", "\\\"");
|
||||
if (error_msg)
|
||||
{
|
||||
length = strlen (error_msg) + 64;
|
||||
str_json = malloc (length);
|
||||
if (str_json)
|
||||
{
|
||||
snprintf (str_json, length, "{\"error\": \"%s\"}", error_msg);
|
||||
num_bytes = relay_http_send_json (client, return_code, message,
|
||||
headers, str_json);
|
||||
free (str_json);
|
||||
}
|
||||
free (error_msg);
|
||||
}
|
||||
}
|
||||
|
||||
free (vbuffer);
|
||||
return num_bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends event to the client.
|
||||
*
|
||||
* Returns number of bytes sent to client, -1 if error.
|
||||
*/
|
||||
|
||||
int
|
||||
relay_api_msg_send_event (struct t_relay_client *client,
|
||||
const char *name,
|
||||
const char *type,
|
||||
const char *context,
|
||||
cJSON *json_body)
|
||||
{
|
||||
return relay_api_msg_send_json_internal (client,
|
||||
RELAY_API_HTTP_0_EVENT,
|
||||
name,
|
||||
type,
|
||||
context,
|
||||
NULL, /* headers */
|
||||
json_body);
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds a buffer local variable into a JSON object.
|
||||
*/
|
||||
|
||||
void
|
||||
relay_api_msg_buffer_add_local_vars_cb (void *data,
|
||||
struct t_hashtable *hashtable,
|
||||
const void *key,
|
||||
const void *value)
|
||||
{
|
||||
cJSON *json;
|
||||
|
||||
/* make C compiler happy */
|
||||
(void) hashtable;
|
||||
|
||||
json = (cJSON *)data;
|
||||
|
||||
cJSON_AddItemToObject (
|
||||
json,
|
||||
(const char *)key,
|
||||
cJSON_CreateString ((value) ? (const char *)value : ""));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a JSON object with a buffer.
|
||||
*/
|
||||
|
||||
cJSON *
|
||||
relay_api_msg_buffer_to_json (struct t_gui_buffer *buffer,
|
||||
long lines,
|
||||
int nicks,
|
||||
enum t_relay_api_colors colors)
|
||||
{
|
||||
struct t_hdata *hdata;
|
||||
struct t_gui_buffer *pointer;
|
||||
cJSON *json, *json_local_vars, *json_lines, *json_nicks;
|
||||
const char *ptr_string;
|
||||
char *string;
|
||||
|
||||
hdata = relay_hdata_buffer;
|
||||
pointer = buffer;
|
||||
|
||||
json = cJSON_CreateObject ();
|
||||
if (!json)
|
||||
return NULL;
|
||||
|
||||
if (!buffer)
|
||||
return json;
|
||||
|
||||
MSG_ADD_HDATA_STR("name", "full_name");
|
||||
MSG_ADD_HDATA_STR("short_name", "short_name");
|
||||
MSG_ADD_HDATA_VAR(Number, "number", integer, "number");
|
||||
ptr_string = weechat_buffer_get_string (buffer, "type");
|
||||
MSG_ADD_STR_PTR("type", ptr_string);
|
||||
MSG_ADD_HDATA_STR_COLORS("title", "title");
|
||||
|
||||
/* local_variables */
|
||||
json_local_vars = cJSON_CreateObject ();
|
||||
if (json_local_vars)
|
||||
{
|
||||
weechat_hashtable_map (
|
||||
weechat_hdata_pointer (hdata, buffer, "local_variables"),
|
||||
&relay_api_msg_buffer_add_local_vars_cb,
|
||||
json_local_vars);
|
||||
cJSON_AddItemToObject (json, "local_variables", json_local_vars);
|
||||
}
|
||||
|
||||
/* lines */
|
||||
if (lines != 0)
|
||||
{
|
||||
json_lines = relay_api_msg_lines_to_json (buffer, lines, colors);
|
||||
if (json_lines)
|
||||
cJSON_AddItemToObject (json, "lines", json_lines);
|
||||
}
|
||||
|
||||
/* nicks */
|
||||
if (nicks)
|
||||
{
|
||||
json_nicks = relay_api_msg_nick_group_to_json (
|
||||
weechat_hdata_pointer (hdata, buffer, "nicklist_root"));
|
||||
if (json_nicks)
|
||||
cJSON_AddItemToObject (json, "nicks", json_nicks);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a JSON object with a buffer line data.
|
||||
*/
|
||||
|
||||
cJSON *
|
||||
relay_api_msg_line_data_to_json (struct t_gui_line_data *line_data,
|
||||
enum t_relay_api_colors colors)
|
||||
{
|
||||
struct t_hdata *hdata;
|
||||
struct t_gui_line_data *pointer;
|
||||
cJSON *json, *json_tags;
|
||||
const char *ptr_string;
|
||||
char *string, str_time[256], str_var[64];
|
||||
int i, tags_count;
|
||||
time_t time_value;
|
||||
struct timeval tv;
|
||||
struct tm gm_time;
|
||||
|
||||
hdata = relay_hdata_line_data;
|
||||
pointer = line_data;
|
||||
|
||||
json = cJSON_CreateObject ();
|
||||
if (!json)
|
||||
return NULL;
|
||||
|
||||
if (!line_data)
|
||||
return json;
|
||||
|
||||
MSG_ADD_HDATA_VAR(Number, "id", integer, "id");
|
||||
MSG_ADD_HDATA_VAR(Number, "index", integer, "y");
|
||||
MSG_ADD_HDATA_TIME_USEC("date", "date", "date_usec");
|
||||
MSG_ADD_HDATA_TIME_USEC("date_printed", "date_printed", "date_usec_printed");
|
||||
MSG_ADD_HDATA_VAR(Bool, "highlight", char, "highlight");
|
||||
MSG_ADD_HDATA_STR_COLORS("prefix", "prefix");
|
||||
MSG_ADD_HDATA_STR_COLORS("message", "message");
|
||||
|
||||
/* tags */
|
||||
json_tags = cJSON_CreateArray ();
|
||||
if (json_tags)
|
||||
{
|
||||
tags_count = weechat_hdata_integer (hdata, line_data, "tags_count");
|
||||
for (i = 0; i < tags_count; i++)
|
||||
{
|
||||
snprintf (str_var, sizeof (str_var), "%d|tags_array", i);
|
||||
cJSON_AddItemToArray (
|
||||
json_tags,
|
||||
cJSON_CreateString (weechat_hdata_string (hdata, line_data, str_var)));
|
||||
}
|
||||
}
|
||||
cJSON_AddItemToObject(json, "tags", json_tags);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a JSON object with an array of buffer lines.
|
||||
*/
|
||||
|
||||
cJSON *
|
||||
relay_api_msg_lines_to_json (struct t_gui_buffer *buffer,
|
||||
long lines,
|
||||
enum t_relay_api_colors colors)
|
||||
{
|
||||
cJSON *json;
|
||||
struct t_gui_lines *ptr_lines;
|
||||
struct t_gui_line *ptr_line;
|
||||
struct t_gui_line_data *ptr_line_data;
|
||||
long i, count;
|
||||
|
||||
json = cJSON_CreateArray ();
|
||||
if (!json)
|
||||
return NULL;
|
||||
|
||||
if (lines == 0)
|
||||
return json;
|
||||
|
||||
ptr_lines = weechat_hdata_pointer (relay_hdata_buffer, buffer, "own_lines");
|
||||
if (!ptr_lines)
|
||||
return json;
|
||||
|
||||
if (lines < 0)
|
||||
{
|
||||
/* search start line from the last line */
|
||||
ptr_line = weechat_hdata_pointer (relay_hdata_lines, ptr_lines, "last_line");
|
||||
if (ptr_line)
|
||||
{
|
||||
for (i = 1; i < lines * -1; i++)
|
||||
{
|
||||
ptr_line = weechat_hdata_move (relay_hdata_line, ptr_line, -1);
|
||||
if (!ptr_line)
|
||||
break;
|
||||
}
|
||||
if (!ptr_line)
|
||||
ptr_line = weechat_hdata_pointer (relay_hdata_lines, ptr_lines, "first_line");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr_line = weechat_hdata_pointer (relay_hdata_lines, ptr_lines, "first_line");
|
||||
}
|
||||
|
||||
if (!ptr_line)
|
||||
return json;
|
||||
|
||||
count = 0;
|
||||
while (ptr_line)
|
||||
{
|
||||
ptr_line_data = weechat_hdata_pointer (relay_hdata_line, ptr_line, "data");
|
||||
if (ptr_line_data)
|
||||
{
|
||||
cJSON_AddItemToArray (
|
||||
json,
|
||||
relay_api_msg_line_data_to_json (ptr_line_data, colors));
|
||||
}
|
||||
count++;
|
||||
if ((lines > 0) && (count >= lines))
|
||||
break;
|
||||
ptr_line = weechat_hdata_move (relay_hdata_line, ptr_line, 1);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a nick JSON object.
|
||||
*/
|
||||
|
||||
cJSON *
|
||||
relay_api_msg_nick_to_json (struct t_gui_nick *nick)
|
||||
{
|
||||
struct t_hdata *hdata;
|
||||
struct t_gui_nick *pointer;
|
||||
cJSON *json;
|
||||
const char *ptr_string;
|
||||
|
||||
hdata = relay_hdata_nick;
|
||||
pointer = nick;
|
||||
|
||||
json = cJSON_CreateObject ();
|
||||
if (!json)
|
||||
return NULL;
|
||||
|
||||
if (!nick)
|
||||
return json;
|
||||
|
||||
MSG_ADD_HDATA_STR("prefix", "prefix");
|
||||
MSG_ADD_HDATA_STR("prefix_color", "prefix_color");
|
||||
MSG_ADD_HDATA_STR("name", "name");
|
||||
MSG_ADD_HDATA_STR("color", "color");
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a nick group JSON object.
|
||||
*/
|
||||
|
||||
cJSON *
|
||||
relay_api_msg_nick_group_to_json (struct t_gui_nick_group *nick_group)
|
||||
{
|
||||
struct t_hdata *hdata;
|
||||
struct t_gui_nick_group *pointer;
|
||||
cJSON *json, *json_groups, *json_nicks;
|
||||
const char *ptr_string;
|
||||
struct t_gui_nick_group *ptr_group;
|
||||
struct t_gui_nick *ptr_nick;
|
||||
|
||||
hdata = relay_hdata_nick_group;
|
||||
pointer = nick_group;
|
||||
|
||||
json = cJSON_CreateObject ();
|
||||
if (!json)
|
||||
return NULL;
|
||||
|
||||
if (!nick_group)
|
||||
return json;
|
||||
|
||||
MSG_ADD_HDATA_STR("name", "name");
|
||||
MSG_ADD_HDATA_STR("color", "color");
|
||||
|
||||
json_groups = cJSON_CreateArray ();
|
||||
if (json_groups)
|
||||
{
|
||||
ptr_group = weechat_hdata_pointer (relay_hdata_nick_group, nick_group, "children");
|
||||
if (ptr_group)
|
||||
{
|
||||
while (ptr_group)
|
||||
{
|
||||
cJSON_AddItemToArray (
|
||||
json_groups,
|
||||
relay_api_msg_nick_group_to_json (ptr_group));
|
||||
ptr_group = weechat_hdata_move (relay_hdata_nick_group, ptr_group, 1);
|
||||
}
|
||||
}
|
||||
cJSON_AddItemToObject (json, "groups", json_groups);
|
||||
}
|
||||
|
||||
json_nicks = cJSON_CreateArray ();
|
||||
if (json_nicks)
|
||||
{
|
||||
ptr_nick = weechat_hdata_pointer (relay_hdata_nick_group, nick_group, "nicks");
|
||||
if (ptr_nick)
|
||||
{
|
||||
while (ptr_nick)
|
||||
{
|
||||
cJSON_AddItemToArray (
|
||||
json_nicks,
|
||||
relay_api_msg_nick_to_json (ptr_nick));
|
||||
ptr_nick = weechat_hdata_move (relay_hdata_nick, ptr_nick, 1);
|
||||
}
|
||||
}
|
||||
cJSON_AddItemToObject (json, "nicks", json_nicks);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2024 Sébastien Helleu <flashcode@flashtux.org>
|
||||
*
|
||||
* This file is part of WeeChat, the extensible chat client.
|
||||
*
|
||||
* WeeChat 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; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* WeeChat 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 WeeChat. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef WEECHAT_PLUGIN_RELAY_API_MSG_H
|
||||
#define WEECHAT_PLUGIN_RELAY_API_MSG_H
|
||||
|
||||
enum t_relay_api_colors;
|
||||
|
||||
extern int relay_api_msg_send_json (struct t_relay_client *client,
|
||||
int return_code,
|
||||
const char *message,
|
||||
cJSON *json_body);
|
||||
extern int relay_api_msg_send_error_json (struct t_relay_client *client,
|
||||
int return_code,
|
||||
const char *message,
|
||||
const char *headers,
|
||||
const char *format, ...);
|
||||
extern int relay_api_msg_send_event (struct t_relay_client *client,
|
||||
const char *name,
|
||||
const char *type,
|
||||
const char *context,
|
||||
cJSON *json_body);
|
||||
extern cJSON *relay_api_msg_buffer_to_json (struct t_gui_buffer *buffer,
|
||||
long lines,
|
||||
int nicks,
|
||||
enum t_relay_api_colors colors);
|
||||
extern cJSON *relay_api_msg_lines_to_json (struct t_gui_buffer *pointer,
|
||||
long lines,
|
||||
enum t_relay_api_colors colors);
|
||||
extern cJSON *relay_api_msg_line_data_to_json (struct t_gui_line_data *line_data,
|
||||
enum t_relay_api_colors colors);
|
||||
extern cJSON *relay_api_msg_nick_to_json (struct t_gui_nick *nick);
|
||||
extern cJSON *relay_api_msg_nick_group_to_json (struct t_gui_nick_group *nick_group);
|
||||
|
||||
#endif /* WEECHAT_PLUGIN_RELAY_API_MSG_H */
|
||||
@@ -0,0 +1,878 @@
|
||||
/*
|
||||
* relay-api-protocol.c - API protocol for relay to client
|
||||
*
|
||||
* Copyright (C) 2023-2024 Sébastien Helleu <flashcode@flashtux.org>
|
||||
*
|
||||
* This file is part of WeeChat, the extensible chat client.
|
||||
*
|
||||
* WeeChat 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; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* WeeChat 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 WeeChat. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <cjson/cJSON.h>
|
||||
|
||||
#include "../../weechat-plugin.h"
|
||||
#include "../relay.h"
|
||||
#include "../relay-buffer.h"
|
||||
#include "../relay-client.h"
|
||||
#include "../relay-config.h"
|
||||
#include "../relay-http.h"
|
||||
#include "relay-api.h"
|
||||
#include "relay-api-msg.h"
|
||||
#include "relay-api-protocol.h"
|
||||
|
||||
|
||||
/*
|
||||
* Checks authentication from client.
|
||||
*
|
||||
* Returns:
|
||||
* 1: OK, client authenticated
|
||||
* 0: client NOT authenticated
|
||||
*/
|
||||
|
||||
int
|
||||
relay_api_protocol_check_auth (struct t_relay_client *client,
|
||||
struct t_relay_http_request *request)
|
||||
{
|
||||
if (client->status == RELAY_STATUS_CONNECTED)
|
||||
return 1;
|
||||
|
||||
switch (relay_http_check_auth (request))
|
||||
{
|
||||
case 0: /* OK */
|
||||
return 1;
|
||||
case -1: /* missing password */
|
||||
relay_api_msg_send_error_json (client,
|
||||
RELAY_HTTP_401_UNAUTHORIZED,
|
||||
"WWW-Authenticate: Basic realm=Password",
|
||||
RELAY_HTTP_ERROR_MISSING_PASSWORD);
|
||||
break;
|
||||
case -2: /* invalid password */
|
||||
relay_api_msg_send_error_json (client,
|
||||
RELAY_HTTP_401_UNAUTHORIZED,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_INVALID_PASSWORD);
|
||||
break;
|
||||
case -3: /* missing TOTP */
|
||||
relay_api_msg_send_error_json (client,
|
||||
RELAY_HTTP_401_UNAUTHORIZED,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_MISSING_TOTP);
|
||||
break;
|
||||
case -4: /* invalid TOTP */
|
||||
relay_api_msg_send_error_json (client,
|
||||
RELAY_HTTP_401_UNAUTHORIZED,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_INVALID_TOTP);
|
||||
break;
|
||||
case -5: /* out of memory */
|
||||
relay_api_msg_send_error_json (client,
|
||||
RELAY_HTTP_503_SERVICE_UNAVAILABLE,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_OUT_OF_MEMORY);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns value of an URL parameter as boolean (0 or 1), using a default value
|
||||
* if the parameter is not set or if it's not a valid boolean.
|
||||
*/
|
||||
|
||||
int
|
||||
relay_api_protocol_get_param_boolean (struct t_relay_http_request *request,
|
||||
const char *name,
|
||||
int default_value)
|
||||
{
|
||||
const char *ptr_value;
|
||||
|
||||
ptr_value = weechat_hashtable_get (request->params, name);
|
||||
if (!ptr_value)
|
||||
return default_value;
|
||||
|
||||
return weechat_config_string_to_boolean (ptr_value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns value of an URL parameter as long, using a default value if the
|
||||
* parameter is not set or if it's not a valid long integer.
|
||||
*/
|
||||
|
||||
long
|
||||
relay_api_protocol_get_param_long (struct t_relay_http_request *request,
|
||||
const char *name,
|
||||
long default_value)
|
||||
{
|
||||
const char *ptr_value;
|
||||
char *error;
|
||||
long number;
|
||||
|
||||
ptr_value = weechat_hashtable_get (request->params, name);
|
||||
if (!ptr_value)
|
||||
return default_value;
|
||||
|
||||
number = strtol (ptr_value, &error, 10);
|
||||
if (error && !error[0])
|
||||
return number;
|
||||
|
||||
return default_value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for signals "buffer_*".
|
||||
*/
|
||||
|
||||
int
|
||||
relay_api_protocol_signal_buffer_cb (const void *pointer, void *data,
|
||||
const char *signal,
|
||||
const char *type_data,
|
||||
void *signal_data)
|
||||
{
|
||||
struct t_relay_client *ptr_client;
|
||||
struct t_gui_buffer *ptr_buffer;
|
||||
struct t_gui_line *ptr_line;
|
||||
struct t_gui_line_data *ptr_line_data;
|
||||
cJSON *json;
|
||||
long lines;
|
||||
|
||||
/* make C compiler happy */
|
||||
(void) data;
|
||||
(void) type_data;
|
||||
|
||||
ptr_client = (struct t_relay_client *)pointer;
|
||||
if (!ptr_client || !relay_client_valid (ptr_client))
|
||||
return WEECHAT_RC_OK;
|
||||
|
||||
if ((strcmp (signal, "buffer_opened") == 0)
|
||||
|| (strcmp (signal, "buffer_type_changed") == 0)
|
||||
|| (strcmp (signal, "buffer_moved") == 0)
|
||||
|| (strcmp (signal, "buffer_merged") == 0)
|
||||
|| (strcmp (signal, "buffer_unmerged") == 0)
|
||||
|| (strcmp (signal, "buffer_hidden") == 0)
|
||||
|| (strcmp (signal, "buffer_unhidden") == 0)
|
||||
|| (strcmp (signal, "buffer_renamed") == 0)
|
||||
|| (strcmp (signal, "buffer_title_changed") == 0)
|
||||
|| (strncmp (signal, "buffer_localvar_", 16) == 0)
|
||||
|| (strcmp (signal, "buffer_cleared") == 0)
|
||||
|| (strcmp (signal, "buffer_closing") == 0))
|
||||
{
|
||||
ptr_buffer = (struct t_gui_buffer *)signal_data;
|
||||
if (!ptr_buffer)
|
||||
return WEECHAT_RC_OK;
|
||||
|
||||
lines = (strcmp (signal, "buffer_opened") == 0) ? LONG_MIN : 0;
|
||||
json = relay_api_msg_buffer_to_json (
|
||||
ptr_buffer, lines, 0, RELAY_API_DATA(ptr_client, sync_colors));
|
||||
if (json)
|
||||
{
|
||||
relay_api_msg_send_event (ptr_client, signal, "buffer", "", json);
|
||||
cJSON_Delete (json);
|
||||
}
|
||||
}
|
||||
else if (strcmp (signal, "buffer_line_added") == 0)
|
||||
{
|
||||
ptr_line = (struct t_gui_line *)signal_data;
|
||||
if (!ptr_line)
|
||||
return WEECHAT_RC_OK;
|
||||
|
||||
ptr_line_data = weechat_hdata_pointer (relay_hdata_line,
|
||||
ptr_line, "data");
|
||||
if (!ptr_line_data)
|
||||
return WEECHAT_RC_OK;
|
||||
|
||||
ptr_buffer = weechat_hdata_pointer (relay_hdata_line_data,
|
||||
ptr_line_data, "buffer");
|
||||
if (!ptr_buffer || relay_buffer_is_relay (ptr_buffer))
|
||||
return WEECHAT_RC_OK;
|
||||
|
||||
json = relay_api_msg_line_data_to_json (
|
||||
ptr_line_data, RELAY_API_DATA(ptr_client, sync_colors));
|
||||
if (json)
|
||||
{
|
||||
relay_api_msg_send_event (
|
||||
ptr_client,
|
||||
signal,
|
||||
"line",
|
||||
weechat_buffer_get_string (ptr_buffer, "full_name"),
|
||||
json);
|
||||
cJSON_Delete (json);
|
||||
}
|
||||
}
|
||||
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for hsignals "nicklist_*".
|
||||
*/
|
||||
|
||||
int
|
||||
relay_api_protocol_hsignal_nicklist_cb (const void *pointer, void *data,
|
||||
const char *signal,
|
||||
struct t_hashtable *hashtable)
|
||||
{
|
||||
struct t_relay_client *ptr_client;
|
||||
struct t_gui_buffer *ptr_buffer;
|
||||
struct t_gui_nick_group *ptr_parent_group, *ptr_group;
|
||||
struct t_gui_nick *ptr_nick;
|
||||
cJSON *json;
|
||||
|
||||
/* make C compiler happy */
|
||||
(void) data;
|
||||
|
||||
ptr_client = (struct t_relay_client *)pointer;
|
||||
if (!ptr_client || !relay_client_valid (ptr_client))
|
||||
return WEECHAT_RC_OK;
|
||||
|
||||
ptr_buffer = weechat_hashtable_get (hashtable, "buffer");
|
||||
ptr_parent_group = weechat_hashtable_get (hashtable, "parent_group");
|
||||
ptr_group = weechat_hashtable_get (hashtable, "group");
|
||||
ptr_nick = weechat_hashtable_get (hashtable, "nick");
|
||||
|
||||
/* if there is no parent group (for example "root" group), ignore the signal */
|
||||
if (!ptr_parent_group)
|
||||
return WEECHAT_RC_OK;
|
||||
|
||||
if ((strcmp (signal, "nicklist_group_added") == 0)
|
||||
|| (strcmp (signal, "nicklist_group_changed") == 0)
|
||||
|| (strcmp (signal, "nicklist_group_removing") == 0))
|
||||
{
|
||||
json = relay_api_msg_nick_group_to_json (ptr_group);
|
||||
if (json)
|
||||
{
|
||||
relay_api_msg_send_event (
|
||||
ptr_client,
|
||||
signal,
|
||||
"nick_group",
|
||||
weechat_buffer_get_string (ptr_buffer, "full_name"),
|
||||
json);
|
||||
cJSON_Delete (json);
|
||||
}
|
||||
}
|
||||
else if ((strcmp (signal, "nicklist_nick_added") == 0)
|
||||
|| (strcmp (signal, "nicklist_nick_changed") == 0)
|
||||
|| (strcmp (signal, "nicklist_nick_removing") == 0))
|
||||
{
|
||||
json = relay_api_msg_nick_to_json (ptr_nick);
|
||||
if (json)
|
||||
{
|
||||
relay_api_msg_send_event (
|
||||
ptr_client,
|
||||
signal,
|
||||
"nick",
|
||||
weechat_buffer_get_string (ptr_buffer, "full_name"),
|
||||
json);
|
||||
cJSON_Delete (json);
|
||||
}
|
||||
}
|
||||
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for signals "upgrade*".
|
||||
*/
|
||||
|
||||
int
|
||||
relay_api_protocol_signal_upgrade_cb (const void *pointer, void *data,
|
||||
const char *signal,
|
||||
const char *type_data,
|
||||
void *signal_data)
|
||||
{
|
||||
struct t_relay_client *ptr_client;
|
||||
|
||||
/* make C compiler happy */
|
||||
(void) data;
|
||||
(void) type_data;
|
||||
(void) signal_data;
|
||||
|
||||
ptr_client = (struct t_relay_client *)pointer;
|
||||
if (!ptr_client || !relay_client_valid (ptr_client))
|
||||
return WEECHAT_RC_OK;
|
||||
|
||||
if ((strcmp (signal, "upgrade") == 0)
|
||||
|| (strcmp (signal, "upgrade_ended") == 0))
|
||||
{
|
||||
relay_api_msg_send_event (ptr_client, signal, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for resource "version".
|
||||
*
|
||||
* Routes:
|
||||
* GET /api/version
|
||||
*/
|
||||
|
||||
RELAY_API_PROTOCOL_CALLBACK(version)
|
||||
{
|
||||
cJSON *json;
|
||||
char *version, *error;
|
||||
long number;
|
||||
|
||||
/* make C compiler happy */
|
||||
(void) request;
|
||||
|
||||
json = cJSON_CreateObject ();
|
||||
if (!json)
|
||||
return WEECHAT_RC_ERROR;
|
||||
|
||||
version = weechat_info_get ("version", NULL);
|
||||
cJSON_AddItemToObject (json,
|
||||
"weechat_version", cJSON_CreateString (version));
|
||||
free (version);
|
||||
|
||||
version = weechat_info_get ("version_git", NULL);
|
||||
cJSON_AddItemToObject (json,
|
||||
"weechat_version_git", cJSON_CreateString (version));
|
||||
free (version);
|
||||
|
||||
version = weechat_info_get ("version_number", NULL);
|
||||
error = NULL;
|
||||
number = strtol (version, &error, 10);
|
||||
if (error && !error[0])
|
||||
{
|
||||
cJSON_AddItemToObject (json,
|
||||
"weechat_version_number",
|
||||
cJSON_CreateNumber (number));
|
||||
}
|
||||
free (version);
|
||||
|
||||
cJSON_AddItemToObject (json, "relay_api_version",
|
||||
cJSON_CreateString (RELAY_API_VERSION_STR));
|
||||
cJSON_AddItemToObject (json,
|
||||
"relay_api_version_number",
|
||||
cJSON_CreateNumber (RELAY_API_VERSION_NUMBER));
|
||||
|
||||
relay_api_msg_send_json (client, RELAY_HTTP_200_OK, json);
|
||||
|
||||
cJSON_Delete (json);
|
||||
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for resource "buffers".
|
||||
*
|
||||
* Routes:
|
||||
* GET /api/buffers
|
||||
* GET /api/buffers/{buffer_name}
|
||||
* GET /api/buffers/{buffer_name}/lines
|
||||
* GET /api/buffers/{buffer_name}/lines/{line_id}
|
||||
* GET /api/buffers/{buffer_name}/nicks
|
||||
*/
|
||||
|
||||
RELAY_API_PROTOCOL_CALLBACK(buffers)
|
||||
{
|
||||
cJSON *json;
|
||||
struct t_gui_buffer *ptr_buffer;
|
||||
long lines;
|
||||
int nicks;
|
||||
enum t_relay_api_colors colors;
|
||||
|
||||
ptr_buffer = NULL;
|
||||
if (request->num_path_items > 2)
|
||||
{
|
||||
ptr_buffer = weechat_buffer_search ("==", request->path_items[2]);
|
||||
if (!ptr_buffer)
|
||||
{
|
||||
relay_api_msg_send_error_json (client, RELAY_HTTP_404_NOT_FOUND, NULL,
|
||||
"Buffer \"%s\" not found",
|
||||
request->path_items[2]);
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
}
|
||||
|
||||
nicks = relay_api_protocol_get_param_boolean (request, "nicks", 0);
|
||||
colors = relay_api_search_colors (
|
||||
weechat_hashtable_get (request->params, "colors"));
|
||||
|
||||
if (request->num_path_items > 3)
|
||||
{
|
||||
/* sub-resource of buffers */
|
||||
if (strcmp (request->path_items[3], "lines") == 0)
|
||||
{
|
||||
lines = relay_api_protocol_get_param_long (request, "lines", -100L);
|
||||
json = relay_api_msg_lines_to_json (ptr_buffer, lines, colors);
|
||||
}
|
||||
else if (strcmp (request->path_items[3], "nicks") == 0)
|
||||
{
|
||||
json = relay_api_msg_nick_group_to_json (
|
||||
weechat_hdata_pointer (relay_hdata_buffer,
|
||||
ptr_buffer, "nicklist_root"));
|
||||
}
|
||||
else
|
||||
{
|
||||
relay_api_msg_send_error_json (
|
||||
client, RELAY_HTTP_404_NOT_FOUND, NULL,
|
||||
"Sub-resource of buffers not found: \"%s\"",
|
||||
request->path_items[3]);
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lines = relay_api_protocol_get_param_long (request, "lines", 0L);
|
||||
if (ptr_buffer)
|
||||
{
|
||||
json = relay_api_msg_buffer_to_json (ptr_buffer, lines, nicks, colors);
|
||||
}
|
||||
else
|
||||
{
|
||||
json = cJSON_CreateArray ();
|
||||
if (!json)
|
||||
return WEECHAT_RC_ERROR;
|
||||
ptr_buffer = weechat_hdata_get_list (relay_hdata_buffer,
|
||||
"gui_buffers");
|
||||
while (ptr_buffer)
|
||||
{
|
||||
cJSON_AddItemToArray (
|
||||
json,
|
||||
relay_api_msg_buffer_to_json (ptr_buffer,
|
||||
lines, nicks, colors));
|
||||
ptr_buffer = weechat_hdata_move (relay_hdata_buffer, ptr_buffer, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!json)
|
||||
goto error;
|
||||
|
||||
relay_api_msg_send_json (client, RELAY_HTTP_200_OK, json);
|
||||
cJSON_Delete (json);
|
||||
return WEECHAT_RC_OK;
|
||||
|
||||
error:
|
||||
relay_api_msg_send_error_json (client,
|
||||
RELAY_HTTP_503_SERVICE_UNAVAILABLE,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_OUT_OF_MEMORY);
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for resource "input".
|
||||
*
|
||||
* Routes:
|
||||
* POST /api/input/{buffer_name}
|
||||
*/
|
||||
|
||||
RELAY_API_PROTOCOL_CALLBACK(input)
|
||||
{
|
||||
cJSON *json_body, *json_buffer, *json_command;
|
||||
const char *ptr_buffer_name, *ptr_command, *ptr_weechat_commands;
|
||||
struct t_gui_buffer *ptr_buffer;
|
||||
struct t_hashtable *options;
|
||||
|
||||
json_body = cJSON_Parse(request->body);
|
||||
if (!json_body)
|
||||
return WEECHAT_RC_ERROR;
|
||||
|
||||
json_buffer = cJSON_GetObjectItem (json_body, "buffer");
|
||||
if (json_buffer)
|
||||
{
|
||||
ptr_buffer_name = cJSON_GetStringValue (json_buffer);
|
||||
ptr_buffer = weechat_buffer_search ("==", ptr_buffer_name);
|
||||
if (!ptr_buffer)
|
||||
{
|
||||
cJSON_Delete (json_body);
|
||||
relay_api_msg_send_error_json (client,
|
||||
RELAY_HTTP_404_NOT_FOUND, NULL,
|
||||
"Buffer \"%s\" not found",
|
||||
ptr_buffer_name);
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr_buffer = weechat_buffer_search_main ();
|
||||
}
|
||||
if (!ptr_buffer)
|
||||
{
|
||||
cJSON_Delete (json_body);
|
||||
return WEECHAT_RC_ERROR;
|
||||
}
|
||||
|
||||
json_command = cJSON_GetObjectItem (json_body, "command");
|
||||
if (!json_command)
|
||||
{
|
||||
cJSON_Delete (json_body);
|
||||
return WEECHAT_RC_ERROR;
|
||||
}
|
||||
|
||||
ptr_command = cJSON_GetStringValue (json_command);
|
||||
if (!ptr_command)
|
||||
{
|
||||
cJSON_Delete (json_body);
|
||||
return WEECHAT_RC_ERROR;
|
||||
}
|
||||
|
||||
options = weechat_hashtable_new (8,
|
||||
WEECHAT_HASHTABLE_STRING,
|
||||
WEECHAT_HASHTABLE_STRING,
|
||||
NULL, NULL);
|
||||
if (!options)
|
||||
{
|
||||
relay_api_msg_send_error_json (client,
|
||||
RELAY_HTTP_503_SERVICE_UNAVAILABLE,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_OUT_OF_MEMORY);
|
||||
cJSON_Delete (json_body);
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
|
||||
ptr_weechat_commands = weechat_config_string (
|
||||
relay_config_weechat_commands);
|
||||
if (ptr_weechat_commands && ptr_weechat_commands[0])
|
||||
{
|
||||
weechat_hashtable_set (
|
||||
options,
|
||||
"commands",
|
||||
weechat_config_string (relay_config_weechat_commands));
|
||||
}
|
||||
|
||||
/*
|
||||
* delay the execution of command after we go back in the WeeChat
|
||||
* main loop (some commands like /upgrade executed now can cause
|
||||
* a crash)
|
||||
*/
|
||||
weechat_hashtable_set (options, "delay", "1");
|
||||
|
||||
/* execute the command, with the delay */
|
||||
weechat_command_options (ptr_buffer, ptr_command, options);
|
||||
|
||||
weechat_hashtable_free (options);
|
||||
cJSON_Delete (json_body);
|
||||
|
||||
relay_api_msg_send_json (client, RELAY_HTTP_204_NO_CONTENT, NULL);
|
||||
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for resource "ping".
|
||||
*
|
||||
* Routes:
|
||||
* POST /api/ping
|
||||
*/
|
||||
|
||||
RELAY_API_PROTOCOL_CALLBACK(ping)
|
||||
{
|
||||
cJSON *json, *json_body, *json_data;
|
||||
const char *ptr_data;
|
||||
|
||||
ptr_data = NULL;
|
||||
json_body = cJSON_Parse(request->body);
|
||||
if (json_body)
|
||||
{
|
||||
json_data = cJSON_GetObjectItem (json_body, "data");
|
||||
if (json_data && cJSON_IsString (json_data))
|
||||
ptr_data = cJSON_GetStringValue (json_data);
|
||||
}
|
||||
|
||||
if (ptr_data)
|
||||
{
|
||||
json = cJSON_CreateObject ();
|
||||
if (!json)
|
||||
{
|
||||
cJSON_Delete (json_body);
|
||||
return WEECHAT_RC_ERROR;
|
||||
}
|
||||
cJSON_AddItemToObject (json, "data",
|
||||
cJSON_CreateString ((ptr_data) ? ptr_data : ""));
|
||||
relay_api_msg_send_json (client, RELAY_HTTP_200_OK, json);
|
||||
cJSON_Delete (json);
|
||||
cJSON_Delete (json_body);
|
||||
}
|
||||
else
|
||||
{
|
||||
relay_api_msg_send_json (client, RELAY_HTTP_204_NO_CONTENT, NULL);
|
||||
}
|
||||
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for resource "sync".
|
||||
*
|
||||
* Routes:
|
||||
* POST /api/sync
|
||||
*/
|
||||
|
||||
RELAY_API_PROTOCOL_CALLBACK(sync)
|
||||
{
|
||||
cJSON *json_body, *json_sync, *json_nicks, *json_colors;
|
||||
|
||||
if (client->websocket != RELAY_CLIENT_WEBSOCKET_READY)
|
||||
{
|
||||
relay_api_msg_send_error_json (
|
||||
client,
|
||||
RELAY_HTTP_403_FORBIDDEN,
|
||||
NULL,
|
||||
"Sync resource is available only with a websocket connection");
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
|
||||
RELAY_API_DATA(client, sync_enabled) = 1;
|
||||
RELAY_API_DATA(client, sync_nicks) = 1;
|
||||
RELAY_API_DATA(client, sync_colors) = RELAY_API_COLORS_ANSI;
|
||||
|
||||
json_body = cJSON_Parse(request->body);
|
||||
if (json_body)
|
||||
{
|
||||
json_sync = cJSON_GetObjectItem (json_body, "sync");
|
||||
if (json_sync && cJSON_IsBool (json_sync))
|
||||
RELAY_API_DATA(client, sync_enabled) = (cJSON_IsTrue (json_sync)) ? 1 : 0;
|
||||
json_nicks = cJSON_GetObjectItem (json_body, "nicks");
|
||||
if (json_nicks && cJSON_IsBool (json_nicks))
|
||||
RELAY_API_DATA(client, sync_nicks) = (cJSON_IsTrue (json_nicks)) ? 1 : 0;
|
||||
json_colors = cJSON_GetObjectItem (json_body, "colors");
|
||||
if (json_colors && cJSON_IsString (json_colors))
|
||||
RELAY_API_DATA(client, sync_colors) = relay_api_search_colors (
|
||||
cJSON_GetStringValue (json_colors));
|
||||
}
|
||||
|
||||
if (RELAY_API_DATA(client, sync_enabled))
|
||||
relay_api_hook_signals (client);
|
||||
else
|
||||
relay_api_unhook_signals (client);
|
||||
|
||||
relay_api_msg_send_json (client, RELAY_HTTP_204_NO_CONTENT, NULL);
|
||||
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads a HTTP request from a client.
|
||||
*/
|
||||
|
||||
void
|
||||
relay_api_protocol_recv_http (struct t_relay_client *client,
|
||||
struct t_relay_http_request *request)
|
||||
{
|
||||
int i, return_code, num_args;
|
||||
struct t_relay_api_protocol_cb protocol_cb[] =
|
||||
{ { "GET", "version", 0, 0, &relay_api_protocol_cb_version },
|
||||
{ "GET", "buffers", 0, 3, &relay_api_protocol_cb_buffers },
|
||||
{ "POST", "input", 0, 0, &relay_api_protocol_cb_input },
|
||||
{ "POST", "ping", 0, 0, &relay_api_protocol_cb_ping },
|
||||
{ "POST", "sync", 0, 0, &relay_api_protocol_cb_sync },
|
||||
{ NULL, NULL, 0, 0, NULL },
|
||||
};
|
||||
|
||||
if (!request || RELAY_CLIENT_HAS_ENDED(client))
|
||||
return;
|
||||
|
||||
if (!relay_api_protocol_check_auth (client, request))
|
||||
{
|
||||
relay_client_set_status (client, RELAY_STATUS_AUTH_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
/* display debug message */
|
||||
if (weechat_relay_plugin->debug >= 2)
|
||||
{
|
||||
weechat_printf (NULL,
|
||||
"%s: recv from client %s%s%s: \"%s %s\", body: \"%s\"",
|
||||
RELAY_PLUGIN_NAME,
|
||||
RELAY_COLOR_CHAT_CLIENT,
|
||||
client->desc,
|
||||
RELAY_COLOR_CHAT,
|
||||
request->method,
|
||||
request->path,
|
||||
request->body);
|
||||
}
|
||||
|
||||
if ((request->num_path_items < 2) || !request->path_items
|
||||
|| !request->path_items[0] || !request->path_items[1])
|
||||
{
|
||||
goto error404;
|
||||
}
|
||||
|
||||
if (strcmp (request->path_items[0], "api") != 0)
|
||||
goto error404;
|
||||
|
||||
num_args = request->num_path_items - 2;
|
||||
|
||||
for (i = 0; protocol_cb[i].resource; i++)
|
||||
{
|
||||
if ((strcmp (protocol_cb[i].method, request->method) == 0)
|
||||
&& (strcmp (protocol_cb[i].resource, request->path_items[1]) == 0))
|
||||
{
|
||||
if (num_args < protocol_cb[i].min_args)
|
||||
{
|
||||
if (weechat_relay_plugin->debug >= 1)
|
||||
{
|
||||
weechat_printf (
|
||||
NULL,
|
||||
_("%s%s: too few arguments received from client "
|
||||
"%s%s%s for resource \"%s\" "
|
||||
"(received: %d arguments, expected: at least %d)"),
|
||||
weechat_prefix ("error"),
|
||||
RELAY_PLUGIN_NAME,
|
||||
RELAY_COLOR_CHAT_CLIENT,
|
||||
client->desc,
|
||||
RELAY_COLOR_CHAT,
|
||||
request->path_items[1],
|
||||
num_args,
|
||||
protocol_cb[i].min_args);
|
||||
}
|
||||
goto error404;
|
||||
}
|
||||
if (num_args > protocol_cb[i].max_args)
|
||||
{
|
||||
if (weechat_relay_plugin->debug >= 1)
|
||||
{
|
||||
weechat_printf (
|
||||
NULL,
|
||||
_("%s%s: too many arguments received from client "
|
||||
"%s%s%s for resource \"%s\" "
|
||||
"(received: %d arguments, expected: at most %d)"),
|
||||
weechat_prefix ("error"),
|
||||
RELAY_PLUGIN_NAME,
|
||||
RELAY_COLOR_CHAT_CLIENT,
|
||||
client->desc,
|
||||
RELAY_COLOR_CHAT,
|
||||
request->path_items[1],
|
||||
num_args,
|
||||
protocol_cb[i].max_args);
|
||||
}
|
||||
goto error404;
|
||||
}
|
||||
return_code = (int) (protocol_cb[i].cmd_function) (
|
||||
client, request);
|
||||
if (return_code == WEECHAT_RC_OK)
|
||||
return;
|
||||
else
|
||||
goto error400;
|
||||
}
|
||||
}
|
||||
|
||||
goto error404;
|
||||
|
||||
error400:
|
||||
relay_api_msg_send_json (client, RELAY_HTTP_400_BAD_REQUEST, NULL);
|
||||
goto error;
|
||||
|
||||
error404:
|
||||
relay_api_msg_send_json (client, RELAY_HTTP_404_NOT_FOUND, NULL);
|
||||
goto error;
|
||||
|
||||
error:
|
||||
if (weechat_relay_plugin->debug >= 1)
|
||||
{
|
||||
weechat_printf (NULL,
|
||||
_("%s%s: failed to execute route \"%s %s\" "
|
||||
"for client %s%s%s"),
|
||||
weechat_prefix ("error"),
|
||||
RELAY_PLUGIN_NAME,
|
||||
request->method,
|
||||
request->path,
|
||||
RELAY_COLOR_CHAT_CLIENT,
|
||||
client->desc,
|
||||
RELAY_COLOR_CHAT);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads JSON string from a client: when connected via websocket (persistent
|
||||
* connection), the client is sending JSON data as a request, which is
|
||||
* converted to HTTP request by this function, before calling the function
|
||||
* relay_api_protocol_recv_http.
|
||||
*
|
||||
* Example of JSON received:
|
||||
*
|
||||
* {
|
||||
* "request": "POST /api/input",
|
||||
* "body": {
|
||||
* "buffer": "irc.libera.#weechat",
|
||||
* "command": "hello!"
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* It is converted to an HTTP request which could have been:
|
||||
*
|
||||
* POST /api/input HTTP/1.1
|
||||
* Content-Length: 53
|
||||
* Content-Type: application/json
|
||||
*
|
||||
* {"buffer": "irc.libera.#weechat","command": "hello!"}
|
||||
*/
|
||||
|
||||
void
|
||||
relay_api_protocol_recv_json (struct t_relay_client *client, const char *json)
|
||||
{
|
||||
cJSON *json_obj, *json_request, *json_body;
|
||||
char *string_body;
|
||||
int length;
|
||||
struct t_relay_http_request *request;
|
||||
|
||||
request = NULL;
|
||||
|
||||
json_obj = cJSON_Parse(json);
|
||||
if (!json_obj)
|
||||
goto error;
|
||||
|
||||
json_request = cJSON_GetObjectItem (json_obj, "request");
|
||||
if (!json_request)
|
||||
goto error;
|
||||
|
||||
request = relay_http_request_alloc ();
|
||||
if (!request)
|
||||
goto error;
|
||||
|
||||
if (!relay_http_parse_method_path (request,
|
||||
cJSON_GetStringValue (json_request)))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
json_body = cJSON_GetObjectItem (json_obj, "body");
|
||||
if (json_body)
|
||||
{
|
||||
string_body = cJSON_PrintUnformatted (json_body);
|
||||
if (string_body)
|
||||
{
|
||||
length = strlen (string_body);
|
||||
request->body = malloc (length + 1);
|
||||
if (request->body)
|
||||
{
|
||||
memcpy (request->body, string_body, length + 1);
|
||||
request->content_length = length;
|
||||
request->body_size = length;
|
||||
}
|
||||
free (string_body);
|
||||
}
|
||||
}
|
||||
|
||||
relay_api_protocol_recv_http (client, request);
|
||||
goto end;
|
||||
|
||||
error:
|
||||
relay_api_msg_send_json (client, RELAY_HTTP_400_BAD_REQUEST, NULL);
|
||||
|
||||
end:
|
||||
if (json_obj)
|
||||
cJSON_Delete (json_obj);
|
||||
if (request)
|
||||
relay_http_request_free (request);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2024 Sébastien Helleu <flashcode@flashtux.org>
|
||||
*
|
||||
* This file is part of WeeChat, the extensible chat client.
|
||||
*
|
||||
* WeeChat 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; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* WeeChat 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 WeeChat. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef WEECHAT_PLUGIN_RELAY_API_PROTOCOL_H
|
||||
#define WEECHAT_PLUGIN_RELAY_API_PROTOCOL_H
|
||||
|
||||
#define RELAY_API_PROTOCOL_CALLBACK(__command) \
|
||||
int \
|
||||
relay_api_protocol_cb_##__command ( \
|
||||
struct t_relay_client *client, \
|
||||
struct t_relay_http_request *request)
|
||||
|
||||
struct t_relay_api_protocol_ctxt
|
||||
{
|
||||
struct t_relay_client *client;
|
||||
struct t_relay_http_request *request;
|
||||
char *resource;
|
||||
};
|
||||
|
||||
typedef int (t_relay_api_cmd_func)(struct t_relay_client *client,
|
||||
struct t_relay_http_request *request);
|
||||
|
||||
struct t_relay_api_protocol_cb
|
||||
{
|
||||
char *method; /* method (eg: "GET", "POST", etc.) */
|
||||
char *resource; /* resource (eg: "buffers") */
|
||||
int min_args; /* min number of items in path */
|
||||
int max_args; /* max number of items in path */
|
||||
t_relay_api_cmd_func *cmd_function; /* callback */
|
||||
};
|
||||
|
||||
extern int relay_api_protocol_signal_buffer_cb (const void *pointer,
|
||||
void *data,
|
||||
const char *signal,
|
||||
const char *type_data,
|
||||
void *signal_data);
|
||||
extern int relay_api_protocol_hsignal_nicklist_cb (const void *pointer,
|
||||
void *data,
|
||||
const char *signal,
|
||||
struct t_hashtable *hashtable);
|
||||
extern int relay_api_protocol_signal_upgrade_cb (const void *pointer,
|
||||
void *data,
|
||||
const char *signal,
|
||||
const char *type_data,
|
||||
void *signal_data);
|
||||
extern void relay_api_protocol_recv_http (struct t_relay_client *client,
|
||||
struct t_relay_http_request *request);
|
||||
extern void relay_api_protocol_recv_json (struct t_relay_client *client,
|
||||
const char *json);
|
||||
|
||||
#endif /* WEECHAT_PLUGIN_RELAY_API_PROTOCOL_H */
|
||||
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* relay-api.c - API protocol for relay to client
|
||||
*
|
||||
* Copyright (C) 2023-2024 Sébastien Helleu <flashcode@flashtux.org>
|
||||
*
|
||||
* This file is part of WeeChat, the extensible chat client.
|
||||
*
|
||||
* WeeChat 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; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* WeeChat 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 WeeChat. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "../../weechat-plugin.h"
|
||||
#include "../relay.h"
|
||||
#include "../relay-client.h"
|
||||
#include "../relay-config.h"
|
||||
#include "../relay-http.h"
|
||||
#include "../relay-raw.h"
|
||||
#include "../relay-raw.h"
|
||||
#include "relay-api.h"
|
||||
#include "relay-api-protocol.h"
|
||||
|
||||
|
||||
/*
|
||||
* Returns value of "colors" URL parameter, an enum with one of these values:
|
||||
* - RELAY_API_COLORS_ANSI (default)
|
||||
* - RELAY_API_COLORS_WEECHAT
|
||||
* - RELAY_API_COLORS_STRIP
|
||||
*/
|
||||
|
||||
enum t_relay_api_colors
|
||||
relay_api_search_colors (const char *colors)
|
||||
{
|
||||
if (!colors)
|
||||
return RELAY_API_COLORS_ANSI;
|
||||
|
||||
if (strcmp (colors, "weechat") == 0)
|
||||
return RELAY_API_COLORS_WEECHAT;
|
||||
|
||||
if (strcmp (colors, "strip") == 0)
|
||||
return RELAY_API_COLORS_STRIP;
|
||||
|
||||
return RELAY_API_COLORS_ANSI;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hooks signals for a client.
|
||||
*/
|
||||
|
||||
void
|
||||
relay_api_hook_signals (struct t_relay_client *client)
|
||||
{
|
||||
if (!RELAY_API_DATA(client, hook_signal_buffer))
|
||||
{
|
||||
RELAY_API_DATA(client, hook_signal_buffer) =
|
||||
weechat_hook_signal ("buffer_*",
|
||||
&relay_api_protocol_signal_buffer_cb,
|
||||
client, NULL);
|
||||
}
|
||||
if (RELAY_API_DATA(client, sync_nicks))
|
||||
{
|
||||
if (!RELAY_API_DATA(client, hook_hsignal_nicklist))
|
||||
{
|
||||
RELAY_API_DATA(client, hook_hsignal_nicklist) =
|
||||
weechat_hook_hsignal ("nicklist_*",
|
||||
&relay_api_protocol_hsignal_nicklist_cb,
|
||||
client, NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RELAY_API_DATA(client, hook_hsignal_nicklist))
|
||||
{
|
||||
weechat_unhook (RELAY_API_DATA(client, hook_hsignal_nicklist));
|
||||
RELAY_API_DATA(client, hook_hsignal_nicklist) = NULL;
|
||||
}
|
||||
}
|
||||
if (!RELAY_API_DATA(client, hook_signal_upgrade))
|
||||
{
|
||||
RELAY_API_DATA(client, hook_signal_upgrade) =
|
||||
weechat_hook_signal ("upgrade*",
|
||||
&relay_api_protocol_signal_upgrade_cb,
|
||||
client, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Unhooks signals for a client.
|
||||
*/
|
||||
|
||||
void
|
||||
relay_api_unhook_signals (struct t_relay_client *client)
|
||||
{
|
||||
if (RELAY_API_DATA(client, hook_signal_buffer))
|
||||
{
|
||||
weechat_unhook (RELAY_API_DATA(client, hook_signal_buffer));
|
||||
RELAY_API_DATA(client, hook_signal_buffer) = NULL;
|
||||
}
|
||||
if (RELAY_API_DATA(client, hook_hsignal_nicklist))
|
||||
{
|
||||
weechat_unhook (RELAY_API_DATA(client, hook_hsignal_nicklist));
|
||||
RELAY_API_DATA(client, hook_hsignal_nicklist) = NULL;
|
||||
}
|
||||
if (RELAY_API_DATA(client, hook_signal_upgrade))
|
||||
{
|
||||
weechat_unhook (RELAY_API_DATA(client, hook_signal_upgrade));
|
||||
RELAY_API_DATA(client, hook_signal_upgrade) = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads HTTP request from a client.
|
||||
*/
|
||||
|
||||
void
|
||||
relay_api_recv_http (struct t_relay_client *client,
|
||||
struct t_relay_http_request *request)
|
||||
{
|
||||
relay_api_protocol_recv_http (client, request);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads JSON string from a client.
|
||||
*/
|
||||
|
||||
void
|
||||
relay_api_recv_json (struct t_relay_client *client, const char *json)
|
||||
{
|
||||
relay_api_protocol_recv_json (client, json);
|
||||
}
|
||||
|
||||
/*
|
||||
* Closes connection with a client.
|
||||
*/
|
||||
|
||||
void
|
||||
relay_api_close_connection (struct t_relay_client *client)
|
||||
{
|
||||
/*
|
||||
* IMPORTANT: if changes are made in this function or sub-functions called,
|
||||
* please also update the function relay_api_add_to_infolist:
|
||||
* when the flag force_disconnected_state is set to 1 we simulate
|
||||
* a disconnected state for client in infolist (used on /upgrade -save)
|
||||
*/
|
||||
|
||||
relay_api_unhook_signals (client);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializes relay data specific to API protocol.
|
||||
*/
|
||||
|
||||
void
|
||||
relay_api_alloc (struct t_relay_client *client)
|
||||
{
|
||||
client->protocol_data = malloc (sizeof (struct t_relay_api_data));
|
||||
if (!client->protocol_data)
|
||||
return;
|
||||
|
||||
RELAY_API_DATA(client, hook_signal_buffer) = NULL;
|
||||
RELAY_API_DATA(client, hook_hsignal_nicklist) = NULL;
|
||||
RELAY_API_DATA(client, hook_signal_upgrade) = NULL;
|
||||
RELAY_API_DATA(client, sync_enabled) = 0;
|
||||
RELAY_API_DATA(client, sync_nicks) = 0;
|
||||
RELAY_API_DATA(client, sync_colors) = RELAY_API_COLORS_ANSI;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializes relay data specific to API protocol with an infolist.
|
||||
*
|
||||
* This is called after /upgrade.
|
||||
*/
|
||||
|
||||
void
|
||||
relay_api_alloc_with_infolist (struct t_relay_client *client,
|
||||
struct t_infolist *infolist)
|
||||
{
|
||||
client->protocol_data = malloc (sizeof (struct t_relay_api_data));
|
||||
if (!client->protocol_data)
|
||||
return;
|
||||
|
||||
RELAY_API_DATA(client, hook_signal_buffer) = NULL;
|
||||
RELAY_API_DATA(client, hook_hsignal_nicklist) = NULL;
|
||||
RELAY_API_DATA(client, hook_signal_upgrade) = NULL;
|
||||
RELAY_API_DATA(client, sync_enabled) = weechat_infolist_integer (
|
||||
infolist, "sync_enabled");
|
||||
RELAY_API_DATA(client, sync_nicks) = weechat_infolist_integer (
|
||||
infolist, "sync_nicks");
|
||||
RELAY_API_DATA(client, sync_colors) = weechat_infolist_integer (
|
||||
infolist, "sync_colors");
|
||||
|
||||
if (!RELAY_CLIENT_HAS_ENDED(client) && RELAY_API_DATA(client, sync_enabled))
|
||||
relay_api_hook_signals (client);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the client initial status: it is always "waiting_auth" for API
|
||||
* protocol because we always expect the "init" command, even without any
|
||||
* password.
|
||||
*/
|
||||
|
||||
enum t_relay_status
|
||||
relay_api_get_initial_status (struct t_relay_client *client)
|
||||
{
|
||||
/* make C compiler happy */
|
||||
(void) client;
|
||||
|
||||
return RELAY_STATUS_WAITING_AUTH;
|
||||
}
|
||||
|
||||
/*
|
||||
* Frees relay data specific to API protocol.
|
||||
*/
|
||||
|
||||
void
|
||||
relay_api_free (struct t_relay_client *client)
|
||||
{
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
if (client->protocol_data)
|
||||
{
|
||||
if (RELAY_API_DATA(client, hook_signal_buffer))
|
||||
weechat_unhook (RELAY_API_DATA(client, hook_signal_buffer));
|
||||
if (RELAY_API_DATA(client, hook_hsignal_nicklist))
|
||||
weechat_unhook (RELAY_API_DATA(client, hook_hsignal_nicklist));
|
||||
if (RELAY_API_DATA(client, hook_signal_upgrade))
|
||||
weechat_unhook (RELAY_API_DATA(client, hook_signal_upgrade));
|
||||
|
||||
free (client->protocol_data);
|
||||
|
||||
client->protocol_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds client API data in an infolist.
|
||||
*
|
||||
* If force_disconnected_state == 1, the infolist contains the client
|
||||
* in a disconnected state (but the client is unchanged, still connected if it
|
||||
* was).
|
||||
*
|
||||
* Returns:
|
||||
* 1: OK
|
||||
* 0: error
|
||||
*/
|
||||
|
||||
int
|
||||
relay_api_add_to_infolist (struct t_infolist_item *item,
|
||||
struct t_relay_client *client,
|
||||
int force_disconnected_state)
|
||||
{
|
||||
if (!item || !client)
|
||||
return 0;
|
||||
|
||||
/* parameter not used today, it may be in future */
|
||||
(void) force_disconnected_state;
|
||||
|
||||
if (!weechat_infolist_new_var_pointer (item, "hook_signal_buffer", RELAY_API_DATA(client, hook_signal_buffer)))
|
||||
return 0;
|
||||
if (!weechat_infolist_new_var_pointer (item, "hook_hsignal_nicklist", RELAY_API_DATA(client, hook_hsignal_nicklist)))
|
||||
return 0;
|
||||
if (!weechat_infolist_new_var_pointer (item, "hook_signal_upgrade", RELAY_API_DATA(client, hook_signal_upgrade)))
|
||||
return 0;
|
||||
if (!weechat_infolist_new_var_integer (item, "sync_enabled", RELAY_API_DATA(client, sync_enabled)))
|
||||
return 0;
|
||||
if (!weechat_infolist_new_var_integer (item, "sync_nicks", RELAY_API_DATA(client, sync_nicks)))
|
||||
return 0;
|
||||
if (!weechat_infolist_new_var_integer (item, "sync_colors", RELAY_API_DATA(client, sync_colors)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prints client API data in WeeChat log file (usually for crash dump).
|
||||
*/
|
||||
|
||||
void
|
||||
relay_api_print_log (struct t_relay_client *client)
|
||||
{
|
||||
if (client->protocol_data)
|
||||
{
|
||||
weechat_log_printf (" hook_signal_buffer. . . : 0x%lx", RELAY_API_DATA(client, hook_signal_buffer));
|
||||
weechat_log_printf (" hook_hsignal_nicklist . : 0x%lx", RELAY_API_DATA(client, hook_hsignal_nicklist));
|
||||
weechat_log_printf (" hook_signal_upgrade . . : 0x%lx", RELAY_API_DATA(client, hook_signal_upgrade));
|
||||
weechat_log_printf (" sync_enabled. . . . . . : %d", RELAY_API_DATA(client, sync_enabled));
|
||||
weechat_log_printf (" sync_nicks. . . . . . . : %d", RELAY_API_DATA(client, sync_nicks));
|
||||
weechat_log_printf (" sync_colors . . . . . . : %d", RELAY_API_DATA(client, sync_colors));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2024 Sébastien Helleu <flashcode@flashtux.org>
|
||||
*
|
||||
* This file is part of WeeChat, the extensible chat client.
|
||||
*
|
||||
* WeeChat 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; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* WeeChat 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 WeeChat. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef WEECHAT_PLUGIN_RELAY_API_H
|
||||
#define WEECHAT_PLUGIN_RELAY_API_H
|
||||
|
||||
struct t_relay_client;
|
||||
struct t_relay_http_request;
|
||||
enum t_relay_status;
|
||||
|
||||
#define RELAY_API_VERSION_MAJOR 0
|
||||
#define RELAY_API_VERSION_MINOR 0
|
||||
#define RELAY_API_VERSION_PATCH 1
|
||||
#define RELAY_API_VERSION_NUMBER \
|
||||
((RELAY_API_VERSION_MAJOR << 16) \
|
||||
+ (RELAY_API_VERSION_MINOR << 8) \
|
||||
+ RELAY_API_VERSION_PATCH)
|
||||
#define RELAY_API_VERSION_STR \
|
||||
(TO_STR(RELAY_API_VERSION_MAJOR) \
|
||||
"." \
|
||||
TO_STR(RELAY_API_VERSION_MINOR) \
|
||||
"." \
|
||||
TO_STR(RELAY_API_VERSION_PATCH))
|
||||
|
||||
#define RELAY_API_DATA(client, var) \
|
||||
(((struct t_relay_api_data *)client->protocol_data)->var)
|
||||
|
||||
#define RELAY_API_HTTP_0_EVENT 0, "Event"
|
||||
|
||||
enum t_relay_api_colors
|
||||
{
|
||||
RELAY_API_COLORS_ANSI = 0, /* convert colors to ANSI colors */
|
||||
RELAY_API_COLORS_WEECHAT, /* keep WeeChat internal color codes */
|
||||
RELAY_API_COLORS_STRIP, /* strip colors */
|
||||
/* number of data types */
|
||||
RELAY_API_NUM_COLORS,
|
||||
};
|
||||
|
||||
struct t_relay_api_data
|
||||
{
|
||||
struct t_hook *hook_signal_buffer; /* hook for signals "buffer_*" */
|
||||
struct t_hook *hook_hsignal_nicklist; /* hook for hsignals "nicklist_*" */
|
||||
struct t_hook *hook_signal_upgrade; /* hook for signals "upgrade*" */
|
||||
int sync_enabled; /* 1 if sync is enabled */
|
||||
int sync_nicks; /* 1 if nicks are synchronized */
|
||||
enum t_relay_api_colors sync_colors; /* colors to send with sync */
|
||||
};
|
||||
|
||||
extern enum t_relay_api_colors relay_api_search_colors (const char *colors);
|
||||
extern void relay_api_hook_signals (struct t_relay_client *client);
|
||||
extern void relay_api_unhook_signals (struct t_relay_client *client);
|
||||
extern void relay_api_recv_http (struct t_relay_client *client,
|
||||
struct t_relay_http_request *request);
|
||||
extern void relay_api_recv_json (struct t_relay_client *client,
|
||||
const char *json);
|
||||
extern void relay_api_close_connection (struct t_relay_client *client);
|
||||
extern void relay_api_alloc (struct t_relay_client *client);
|
||||
extern void relay_api_alloc_with_infolist (struct t_relay_client *client,
|
||||
struct t_infolist *infolist);
|
||||
extern enum t_relay_status relay_api_get_initial_status (struct t_relay_client *client);
|
||||
extern void relay_api_free (struct t_relay_client *client);
|
||||
extern int relay_api_add_to_infolist (struct t_infolist_item *item,
|
||||
struct t_relay_client *client,
|
||||
int force_disconnected_state);
|
||||
extern void relay_api_print_log (struct t_relay_client *client);
|
||||
|
||||
#endif /* WEECHAT_PLUGIN_RELAY_API_H */
|
||||
+281
-260
@@ -37,10 +37,14 @@
|
||||
#include "relay-auth.h"
|
||||
#include "relay-config.h"
|
||||
#include "relay-buffer.h"
|
||||
#include "relay-http.h"
|
||||
#include "relay-network.h"
|
||||
#include "relay-raw.h"
|
||||
#include "relay-server.h"
|
||||
#include "relay-websocket.h"
|
||||
#ifdef HAVE_CJSON
|
||||
#include "api/relay-api.h"
|
||||
#endif
|
||||
#include "irc/relay-irc.h"
|
||||
#include "weechat/relay-weechat.h"
|
||||
|
||||
@@ -55,7 +59,7 @@ char *relay_client_status_name[] = /* name of status (for signal/info) */
|
||||
};
|
||||
|
||||
char *relay_client_data_type_string[] = /* strings for data types */
|
||||
{ "text", "binary" };
|
||||
{ "text", "binary", "http" };
|
||||
|
||||
char *relay_client_msg_type_string[] = /* prefix in raw buffer for message */
|
||||
{ "", "[PING]\n", "[PONG]\n", "[CLOSE]\n" };
|
||||
@@ -266,6 +270,13 @@ relay_client_handshake_timer_cb (const void *pointer, void *data,
|
||||
client,
|
||||
relay_irc_get_initial_status (client));
|
||||
break;
|
||||
case RELAY_PROTOCOL_API:
|
||||
#ifdef HAVE_CJSON
|
||||
relay_client_set_status (
|
||||
client,
|
||||
relay_api_get_initial_status (client));
|
||||
#endif /* HAVE_CJSON */
|
||||
break;
|
||||
case RELAY_NUM_PROTOCOLS:
|
||||
break;
|
||||
}
|
||||
@@ -312,6 +323,124 @@ relay_client_handshake_timer_cb (const void *pointer, void *data,
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads text data from a client (messages on a single line): splits data on
|
||||
* '\n' and keeps a partial message if data does not end with '\n'.
|
||||
*/
|
||||
|
||||
void
|
||||
relay_client_recv_text_single_line (struct t_relay_client *client)
|
||||
{
|
||||
char *pos, *raw_msg, **lines, *tmp;
|
||||
int i, num_lines, length;
|
||||
|
||||
if (!client->partial_message)
|
||||
return;
|
||||
|
||||
pos = strrchr (client->partial_message, '\n');
|
||||
if (!pos)
|
||||
return;
|
||||
|
||||
/* print message in raw buffer */
|
||||
raw_msg = weechat_strndup (client->partial_message,
|
||||
pos - client->partial_message + 1);
|
||||
if (raw_msg)
|
||||
{
|
||||
relay_raw_print (client, RELAY_CLIENT_MSG_STANDARD,
|
||||
RELAY_RAW_FLAG_RECV,
|
||||
raw_msg, strlen (raw_msg) + 1);
|
||||
free (raw_msg);
|
||||
}
|
||||
|
||||
pos[0] = '\0';
|
||||
|
||||
lines = weechat_string_split (client->partial_message, "\n", NULL,
|
||||
WEECHAT_STRING_SPLIT_STRIP_LEFT
|
||||
| WEECHAT_STRING_SPLIT_STRIP_RIGHT
|
||||
| WEECHAT_STRING_SPLIT_COLLAPSE_SEPS,
|
||||
0, &num_lines);
|
||||
if (lines)
|
||||
{
|
||||
for (i = 0; i < num_lines; i++)
|
||||
{
|
||||
/* remove final '\r' */
|
||||
length = strlen (lines[i]);
|
||||
if ((length > 0) && (lines[i][length - 1] == '\r'))
|
||||
lines[i][length - 1] = '\0';
|
||||
|
||||
/*
|
||||
* interpret text from client, according to the relay
|
||||
* protocol used
|
||||
*/
|
||||
switch (client->protocol)
|
||||
{
|
||||
case RELAY_PROTOCOL_WEECHAT:
|
||||
relay_weechat_recv (client, lines[i]);
|
||||
break;
|
||||
case RELAY_PROTOCOL_IRC:
|
||||
relay_irc_recv (client, lines[i]);
|
||||
break;
|
||||
case RELAY_PROTOCOL_API:
|
||||
/* api is multi-line only (JSON) */
|
||||
break;
|
||||
case RELAY_NUM_PROTOCOLS:
|
||||
break;
|
||||
}
|
||||
}
|
||||
weechat_string_free_split (lines);
|
||||
}
|
||||
if (pos[1])
|
||||
{
|
||||
tmp = strdup (pos + 1);
|
||||
free (client->partial_message);
|
||||
client->partial_message = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
free (client->partial_message);
|
||||
client->partial_message = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads text data from a client (multi-line messages).
|
||||
*/
|
||||
|
||||
void
|
||||
relay_client_recv_text_multi_line (struct t_relay_client *client)
|
||||
{
|
||||
if (!client->partial_message)
|
||||
return;
|
||||
|
||||
/* print message in raw buffer */
|
||||
relay_raw_print (client, RELAY_CLIENT_MSG_STANDARD,
|
||||
RELAY_RAW_FLAG_RECV,
|
||||
client->partial_message,
|
||||
strlen (client->partial_message) + 1);
|
||||
|
||||
/*
|
||||
* interpret text from client, according to the relay
|
||||
* protocol used
|
||||
*/
|
||||
switch (client->protocol)
|
||||
{
|
||||
case RELAY_PROTOCOL_WEECHAT:
|
||||
/* weechat is single line only */
|
||||
break;
|
||||
case RELAY_PROTOCOL_IRC:
|
||||
/* irc is single line only */
|
||||
break;
|
||||
case RELAY_PROTOCOL_API:
|
||||
relay_api_recv_json (client, client->partial_message);
|
||||
break;
|
||||
case RELAY_NUM_PROTOCOLS:
|
||||
break;
|
||||
}
|
||||
|
||||
free (client->partial_message);
|
||||
client->partial_message = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads text data from a client: splits data on '\n' and keeps a partial
|
||||
* message if data does not end with '\n'.
|
||||
@@ -320,9 +449,7 @@ relay_client_handshake_timer_cb (const void *pointer, void *data,
|
||||
void
|
||||
relay_client_recv_text (struct t_relay_client *client, const char *data)
|
||||
{
|
||||
char *new_partial, *raw_msg, **lines, *pos, *tmp, *handshake;
|
||||
const char *ptr_real_ip;
|
||||
int i, num_lines, length, rc;
|
||||
char *new_partial;
|
||||
|
||||
if (client->partial_message)
|
||||
{
|
||||
@@ -337,172 +464,12 @@ relay_client_recv_text (struct t_relay_client *client, const char *data)
|
||||
else
|
||||
client->partial_message = strdup (data);
|
||||
|
||||
pos = strrchr (client->partial_message, '\n');
|
||||
if (pos)
|
||||
if (client->partial_message)
|
||||
{
|
||||
/* print message in raw buffer */
|
||||
raw_msg = weechat_strndup (client->partial_message,
|
||||
pos - client->partial_message + 1);
|
||||
if (raw_msg)
|
||||
{
|
||||
relay_raw_print (client, RELAY_CLIENT_MSG_STANDARD,
|
||||
RELAY_RAW_FLAG_RECV,
|
||||
raw_msg, strlen (raw_msg) + 1);
|
||||
free (raw_msg);
|
||||
}
|
||||
|
||||
pos[0] = '\0';
|
||||
|
||||
lines = weechat_string_split (client->partial_message, "\n", NULL,
|
||||
WEECHAT_STRING_SPLIT_STRIP_LEFT
|
||||
| WEECHAT_STRING_SPLIT_STRIP_RIGHT
|
||||
| WEECHAT_STRING_SPLIT_COLLAPSE_SEPS,
|
||||
0, &num_lines);
|
||||
if (lines)
|
||||
{
|
||||
for (i = 0; i < num_lines; i++)
|
||||
{
|
||||
/* remove final '\r' */
|
||||
length = strlen (lines[i]);
|
||||
if ((length > 0) && (lines[i][length - 1] == '\r'))
|
||||
lines[i][length - 1] = '\0';
|
||||
|
||||
/* if websocket is initializing */
|
||||
if (client->websocket == RELAY_CLIENT_WEBSOCKET_INITIALIZING)
|
||||
{
|
||||
if (lines[i][0])
|
||||
{
|
||||
/* web socket is initializing, read HTTP headers */
|
||||
relay_websocket_save_header (client, lines[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* empty line means that we have received all HTTP
|
||||
* headers: then we check the validity of websocket, and
|
||||
* if it is OK, we'll do the handshake and answer to the
|
||||
* client
|
||||
*/
|
||||
rc = relay_websocket_client_handshake_valid (client);
|
||||
if (rc == 0)
|
||||
{
|
||||
/* handshake from client is valid */
|
||||
handshake = relay_websocket_build_handshake (client);
|
||||
if (handshake)
|
||||
{
|
||||
relay_client_send (client,
|
||||
RELAY_CLIENT_MSG_STANDARD,
|
||||
handshake,
|
||||
strlen (handshake), NULL);
|
||||
free (handshake);
|
||||
client->websocket = RELAY_CLIENT_WEBSOCKET_READY;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (rc)
|
||||
{
|
||||
case -1:
|
||||
relay_websocket_send_http (client,
|
||||
"400 Bad Request");
|
||||
if (weechat_relay_plugin->debug >= 1)
|
||||
{
|
||||
weechat_printf_date_tags (
|
||||
NULL, 0, "relay_client",
|
||||
_("%s%s: invalid websocket "
|
||||
"handshake received for client "
|
||||
"%s%s%s"),
|
||||
weechat_prefix ("error"),
|
||||
RELAY_PLUGIN_NAME,
|
||||
RELAY_COLOR_CHAT_CLIENT,
|
||||
client->desc,
|
||||
RELAY_COLOR_CHAT);
|
||||
}
|
||||
break;
|
||||
case -2:
|
||||
relay_websocket_send_http (client,
|
||||
"403 Forbidden");
|
||||
if (weechat_relay_plugin->debug >= 1)
|
||||
{
|
||||
weechat_printf_date_tags (
|
||||
NULL, 0, "relay_client",
|
||||
_("%s%s: origin \"%s\" "
|
||||
"not allowed for websocket"),
|
||||
weechat_prefix ("error"),
|
||||
RELAY_PLUGIN_NAME,
|
||||
weechat_hashtable_get (client->http_headers,
|
||||
"origin"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
relay_client_set_status (client, RELAY_STATUS_DISCONNECTED);
|
||||
}
|
||||
|
||||
ptr_real_ip = weechat_hashtable_get (
|
||||
client->http_headers, "x-real-ip");
|
||||
if (ptr_real_ip)
|
||||
{
|
||||
if (client->real_ip)
|
||||
free (client->real_ip);
|
||||
client->real_ip = strdup (ptr_real_ip);
|
||||
relay_client_set_desc (client);
|
||||
weechat_printf_date_tags (
|
||||
NULL, 0, "relay_client",
|
||||
_("%s: websocket client %s%s%s has real IP "
|
||||
"address \"%s\""),
|
||||
RELAY_PLUGIN_NAME,
|
||||
RELAY_COLOR_CHAT_CLIENT,
|
||||
client->desc,
|
||||
RELAY_COLOR_CHAT,
|
||||
ptr_real_ip);
|
||||
}
|
||||
|
||||
/* remove HTTP headers */
|
||||
weechat_hashtable_free (client->http_headers);
|
||||
client->http_headers = NULL;
|
||||
|
||||
/*
|
||||
* discard all received data after the handshake
|
||||
* received from client, and return immediately
|
||||
*/
|
||||
free (client->partial_message);
|
||||
client->partial_message = NULL;
|
||||
weechat_string_free_split (lines);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* interpret text from client, according to the relay
|
||||
* protocol used
|
||||
*/
|
||||
switch (client->protocol)
|
||||
{
|
||||
case RELAY_PROTOCOL_WEECHAT:
|
||||
relay_weechat_recv (client, lines[i]);
|
||||
break;
|
||||
case RELAY_PROTOCOL_IRC:
|
||||
relay_irc_recv (client, lines[i]);
|
||||
break;
|
||||
case RELAY_NUM_PROTOCOLS:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
weechat_string_free_split (lines);
|
||||
}
|
||||
if (pos[1])
|
||||
{
|
||||
tmp = strdup (pos + 1);
|
||||
free (client->partial_message);
|
||||
client->partial_message = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
free (client->partial_message);
|
||||
client->partial_message = NULL;
|
||||
}
|
||||
if (client->recv_data_type == RELAY_CLIENT_DATA_TEXT_LINE)
|
||||
relay_client_recv_text_single_line (client);
|
||||
else if (client->recv_data_type == RELAY_CLIENT_DATA_TEXT_MULTILINE)
|
||||
relay_client_recv_text_multi_line (client);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,7 +533,17 @@ relay_client_recv_text_buffer (struct t_relay_client *client,
|
||||
}
|
||||
|
||||
if (msg_type == RELAY_CLIENT_MSG_STANDARD)
|
||||
relay_client_recv_text (client, buffer + index);
|
||||
{
|
||||
if ((client->websocket == RELAY_CLIENT_WEBSOCKET_INITIALIZING)
|
||||
|| (client->recv_data_type == RELAY_CLIENT_DATA_HTTP))
|
||||
{
|
||||
relay_http_recv (client, buffer + index);
|
||||
}
|
||||
else
|
||||
{
|
||||
relay_client_recv_text (client, buffer + index);
|
||||
}
|
||||
}
|
||||
|
||||
index += strlen (buffer + index) + 1;
|
||||
}
|
||||
@@ -622,7 +599,7 @@ relay_client_recv_cb (const void *pointer, void *data, int fd)
|
||||
*/
|
||||
if (client->bytes_recv == 0)
|
||||
{
|
||||
if (relay_websocket_is_http_get_weechat (buffer))
|
||||
if (relay_websocket_is_valid_http_get (client, buffer))
|
||||
{
|
||||
/*
|
||||
* web socket is just initializing for now, it's not accepted
|
||||
@@ -630,11 +607,6 @@ relay_client_recv_cb (const void *pointer, void *data, int fd)
|
||||
* valid or not)
|
||||
*/
|
||||
client->websocket = RELAY_CLIENT_WEBSOCKET_INITIALIZING;
|
||||
client->http_headers = weechat_hashtable_new (
|
||||
32,
|
||||
WEECHAT_HASHTABLE_STRING,
|
||||
WEECHAT_HASHTABLE_STRING,
|
||||
NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -679,9 +651,11 @@ relay_client_recv_cb (const void *pointer, void *data, int fd)
|
||||
}
|
||||
|
||||
if ((client->websocket == RELAY_CLIENT_WEBSOCKET_INITIALIZING)
|
||||
|| (client->recv_data_type == RELAY_CLIENT_DATA_TEXT))
|
||||
|| (client->recv_data_type == RELAY_CLIENT_DATA_TEXT_LINE)
|
||||
|| (client->recv_data_type == RELAY_CLIENT_DATA_TEXT_MULTILINE)
|
||||
|| (client->recv_data_type == RELAY_CLIENT_DATA_HTTP))
|
||||
{
|
||||
/* websocket initializing or text data for this client */
|
||||
/* websocket initializing or text/HTTP data for this client */
|
||||
relay_client_recv_text_buffer (client, ptr_buffer, length_buffer);
|
||||
}
|
||||
else
|
||||
@@ -698,17 +672,20 @@ relay_client_recv_cb (const void *pointer, void *data, int fd)
|
||||
if ((num_read == 0)
|
||||
|| ((num_read != GNUTLS_E_AGAIN) && (num_read != GNUTLS_E_INTERRUPTED)))
|
||||
{
|
||||
weechat_printf_date_tags (
|
||||
NULL, 0, "relay_client",
|
||||
_("%s%s: reading data on socket for client %s%s%s: "
|
||||
"error %d %s"),
|
||||
weechat_prefix ("error"), RELAY_PLUGIN_NAME,
|
||||
RELAY_COLOR_CHAT_CLIENT,
|
||||
client->desc,
|
||||
RELAY_COLOR_CHAT,
|
||||
num_read,
|
||||
(num_read == 0) ? _("(connection closed by peer)") :
|
||||
gnutls_strerror (num_read));
|
||||
if (relay_config_display_clients[client->protocol])
|
||||
{
|
||||
weechat_printf_date_tags (
|
||||
NULL, 0, "relay_client",
|
||||
_("%s%s: reading data on socket for client %s%s%s: "
|
||||
"error %d %s"),
|
||||
weechat_prefix ("error"), RELAY_PLUGIN_NAME,
|
||||
RELAY_COLOR_CHAT_CLIENT,
|
||||
client->desc,
|
||||
RELAY_COLOR_CHAT,
|
||||
num_read,
|
||||
(num_read == 0) ? _("(connection closed by peer)") :
|
||||
gnutls_strerror (num_read));
|
||||
}
|
||||
relay_client_set_status (client, RELAY_STATUS_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
@@ -717,17 +694,20 @@ relay_client_recv_cb (const void *pointer, void *data, int fd)
|
||||
if ((num_read == 0)
|
||||
|| ((errno != EAGAIN) && (errno != EWOULDBLOCK)))
|
||||
{
|
||||
weechat_printf_date_tags (
|
||||
NULL, 0, "relay_client",
|
||||
_("%s%s: reading data on socket for client %s%s%s: "
|
||||
"error %d %s"),
|
||||
weechat_prefix ("error"), RELAY_PLUGIN_NAME,
|
||||
RELAY_COLOR_CHAT_CLIENT,
|
||||
client->desc,
|
||||
RELAY_COLOR_CHAT,
|
||||
errno,
|
||||
(num_read == 0) ? _("(connection closed by peer)") :
|
||||
strerror (errno));
|
||||
if (relay_config_display_clients[client->protocol])
|
||||
{
|
||||
weechat_printf_date_tags (
|
||||
NULL, 0, "relay_client",
|
||||
_("%s%s: reading data on socket for client %s%s%s: "
|
||||
"error %d %s"),
|
||||
weechat_prefix ("error"), RELAY_PLUGIN_NAME,
|
||||
RELAY_COLOR_CHAT_CLIENT,
|
||||
client->desc,
|
||||
RELAY_COLOR_CHAT,
|
||||
errno,
|
||||
(num_read == 0) ? _("(connection closed by peer)") :
|
||||
strerror (errno));
|
||||
}
|
||||
relay_client_set_status (client, RELAY_STATUS_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
@@ -1067,7 +1047,8 @@ relay_client_send (struct t_relay_client *client,
|
||||
raw_size[1] = data_size;
|
||||
raw_flags[1] |= RELAY_RAW_FLAG_BINARY;
|
||||
if ((client->websocket == RELAY_CLIENT_WEBSOCKET_INITIALIZING)
|
||||
|| (client->send_data_type == RELAY_CLIENT_DATA_TEXT))
|
||||
|| (client->send_data_type == RELAY_CLIENT_DATA_TEXT_LINE)
|
||||
|| (client->send_data_type == RELAY_CLIENT_DATA_TEXT_MULTILINE))
|
||||
{
|
||||
raw_size[1]--;
|
||||
}
|
||||
@@ -1117,7 +1098,8 @@ relay_client_send (struct t_relay_client *client,
|
||||
opcode = WEBSOCKET_FRAME_OPCODE_CLOSE;
|
||||
break;
|
||||
default:
|
||||
opcode = (client->send_data_type == RELAY_CLIENT_DATA_TEXT) ?
|
||||
opcode = ((client->send_data_type == RELAY_CLIENT_DATA_TEXT_LINE)
|
||||
|| (client->send_data_type == RELAY_CLIENT_DATA_TEXT_MULTILINE)) ?
|
||||
WEBSOCKET_FRAME_OPCODE_TEXT : WEBSOCKET_FRAME_OPCODE_BINARY;
|
||||
break;
|
||||
}
|
||||
@@ -1325,7 +1307,7 @@ relay_client_new (int sock, const char *address, struct t_relay_server *server)
|
||||
new_client->hook_timer_handshake = NULL;
|
||||
new_client->gnutls_handshake_ok = 0;
|
||||
new_client->websocket = RELAY_CLIENT_WEBSOCKET_NOT_USED;
|
||||
new_client->http_headers = NULL;
|
||||
new_client->http_req = relay_http_request_alloc ();
|
||||
new_client->address = strdup ((address && address[0]) ?
|
||||
address : "local");
|
||||
new_client->real_ip = NULL;
|
||||
@@ -1353,16 +1335,20 @@ relay_client_new (int sock, const char *address, struct t_relay_server *server)
|
||||
switch (new_client->protocol)
|
||||
{
|
||||
case RELAY_PROTOCOL_WEECHAT:
|
||||
new_client->recv_data_type = RELAY_CLIENT_DATA_TEXT;
|
||||
new_client->recv_data_type = RELAY_CLIENT_DATA_TEXT_LINE;
|
||||
new_client->send_data_type = RELAY_CLIENT_DATA_BINARY;
|
||||
break;
|
||||
case RELAY_PROTOCOL_IRC:
|
||||
new_client->recv_data_type = RELAY_CLIENT_DATA_TEXT;
|
||||
new_client->send_data_type = RELAY_CLIENT_DATA_TEXT;
|
||||
new_client->recv_data_type = RELAY_CLIENT_DATA_TEXT_LINE;
|
||||
new_client->send_data_type = RELAY_CLIENT_DATA_TEXT_LINE;
|
||||
break;
|
||||
case RELAY_PROTOCOL_API:
|
||||
new_client->recv_data_type = RELAY_CLIENT_DATA_HTTP;
|
||||
new_client->send_data_type = RELAY_CLIENT_DATA_HTTP;
|
||||
break;
|
||||
default:
|
||||
new_client->recv_data_type = RELAY_CLIENT_DATA_TEXT;
|
||||
new_client->send_data_type = RELAY_CLIENT_DATA_TEXT;
|
||||
new_client->recv_data_type = RELAY_CLIENT_DATA_TEXT_MULTILINE;
|
||||
new_client->send_data_type = RELAY_CLIENT_DATA_TEXT_MULTILINE;
|
||||
break;
|
||||
}
|
||||
new_client->partial_message = NULL;
|
||||
@@ -1439,6 +1425,16 @@ relay_client_new (int sock, const char *address, struct t_relay_server *server)
|
||||
relay_irc_get_initial_status (new_client);
|
||||
}
|
||||
break;
|
||||
case RELAY_PROTOCOL_API:
|
||||
#ifdef HAVE_CJSON
|
||||
relay_api_alloc (new_client);
|
||||
if (!new_client->tls)
|
||||
{
|
||||
new_client->status =
|
||||
relay_api_get_initial_status (new_client);
|
||||
}
|
||||
#endif /* HAVE_CJSON */
|
||||
break;
|
||||
case RELAY_NUM_PROTOCOLS:
|
||||
break;
|
||||
}
|
||||
@@ -1454,29 +1450,32 @@ relay_client_new (int sock, const char *address, struct t_relay_server *server)
|
||||
last_relay_client = new_client;
|
||||
relay_clients = new_client;
|
||||
|
||||
if (server->unix_socket)
|
||||
if (relay_config_display_clients[new_client->protocol])
|
||||
{
|
||||
weechat_printf_date_tags (
|
||||
NULL, 0, "relay_client",
|
||||
_("%s: new client on path %s: %s%s%s (%s)"),
|
||||
RELAY_PLUGIN_NAME,
|
||||
server->path,
|
||||
RELAY_COLOR_CHAT_CLIENT,
|
||||
new_client->desc,
|
||||
RELAY_COLOR_CHAT,
|
||||
_(relay_client_status_string[new_client->status]));
|
||||
}
|
||||
else
|
||||
{
|
||||
weechat_printf_date_tags (
|
||||
NULL, 0, "relay_client",
|
||||
_("%s: new client on port %s: %s%s%s (%s)"),
|
||||
RELAY_PLUGIN_NAME,
|
||||
server->path,
|
||||
RELAY_COLOR_CHAT_CLIENT,
|
||||
new_client->desc,
|
||||
RELAY_COLOR_CHAT,
|
||||
_(relay_client_status_string[new_client->status]));
|
||||
if (server->unix_socket)
|
||||
{
|
||||
weechat_printf_date_tags (
|
||||
NULL, 0, "relay_client",
|
||||
_("%s: new client on path %s: %s%s%s (%s)"),
|
||||
RELAY_PLUGIN_NAME,
|
||||
server->path,
|
||||
RELAY_COLOR_CHAT_CLIENT,
|
||||
new_client->desc,
|
||||
RELAY_COLOR_CHAT,
|
||||
_(relay_client_status_string[new_client->status]));
|
||||
}
|
||||
else
|
||||
{
|
||||
weechat_printf_date_tags (
|
||||
NULL, 0, "relay_client",
|
||||
_("%s: new client on port %s: %s%s%s (%s)"),
|
||||
RELAY_PLUGIN_NAME,
|
||||
server->path,
|
||||
RELAY_COLOR_CHAT_CLIENT,
|
||||
new_client->desc,
|
||||
RELAY_COLOR_CHAT,
|
||||
_(relay_client_status_string[new_client->status]));
|
||||
}
|
||||
}
|
||||
|
||||
if (new_client->sock >= 0)
|
||||
@@ -1489,11 +1488,8 @@ relay_client_new (int sock, const char *address, struct t_relay_server *server)
|
||||
|
||||
relay_client_count++;
|
||||
|
||||
if (!relay_buffer
|
||||
&& weechat_config_boolean (relay_config_look_auto_open_buffer))
|
||||
{
|
||||
if (!relay_buffer && relay_config_auto_open_buffer[new_client->protocol])
|
||||
relay_buffer_open ();
|
||||
}
|
||||
|
||||
relay_client_send_signal (new_client);
|
||||
|
||||
@@ -1537,7 +1533,7 @@ relay_client_new_with_infolist (struct t_infolist *infolist)
|
||||
new_client->hook_timer_handshake = NULL;
|
||||
new_client->gnutls_handshake_ok = 0;
|
||||
new_client->websocket = weechat_infolist_integer (infolist, "websocket");
|
||||
new_client->http_headers = NULL;
|
||||
new_client->http_req = relay_http_request_alloc ();
|
||||
new_client->address = strdup (weechat_infolist_string (infolist, "address"));
|
||||
str = weechat_infolist_string (infolist, "real_ip");
|
||||
new_client->real_ip = (str) ? strdup (str) : NULL;
|
||||
@@ -1597,12 +1593,15 @@ relay_client_new_with_infolist (struct t_infolist *infolist)
|
||||
switch (new_client->protocol)
|
||||
{
|
||||
case RELAY_PROTOCOL_WEECHAT:
|
||||
relay_weechat_alloc_with_infolist (new_client,
|
||||
infolist);
|
||||
relay_weechat_alloc_with_infolist (new_client, infolist);
|
||||
break;
|
||||
case RELAY_PROTOCOL_IRC:
|
||||
relay_irc_alloc_with_infolist (new_client,
|
||||
infolist);
|
||||
relay_irc_alloc_with_infolist (new_client, infolist);
|
||||
break;
|
||||
case RELAY_PROTOCOL_API:
|
||||
#ifdef HAVE_CJSON
|
||||
relay_api_alloc_with_infolist (new_client, infolist);
|
||||
#endif /* HAVE_CJSON */
|
||||
break;
|
||||
case RELAY_NUM_PROTOCOLS:
|
||||
break;
|
||||
@@ -1644,7 +1643,8 @@ relay_client_set_status (struct t_relay_client *client,
|
||||
|
||||
client->status = status;
|
||||
|
||||
if (client->status == RELAY_STATUS_CONNECTED)
|
||||
if ((client->status == RELAY_STATUS_CONNECTED)
|
||||
&& relay_config_display_clients[client->protocol])
|
||||
{
|
||||
weechat_printf_date_tags (
|
||||
NULL, 0, "relay_client",
|
||||
@@ -1688,6 +1688,11 @@ relay_client_set_status (struct t_relay_client *client,
|
||||
case RELAY_PROTOCOL_IRC:
|
||||
relay_irc_close_connection (client);
|
||||
break;
|
||||
case RELAY_PROTOCOL_API:
|
||||
#ifdef HAVE_CJSON
|
||||
relay_api_close_connection (client);
|
||||
#endif /* HAVE_CJSON */
|
||||
break;
|
||||
case RELAY_NUM_PROTOCOLS:
|
||||
break;
|
||||
}
|
||||
@@ -1704,13 +1709,16 @@ relay_client_set_status (struct t_relay_client *client,
|
||||
RELAY_COLOR_CHAT);
|
||||
break;
|
||||
case RELAY_STATUS_DISCONNECTED:
|
||||
weechat_printf_date_tags (
|
||||
NULL, 0, "relay_client",
|
||||
_("%s: disconnected from client %s%s%s"),
|
||||
RELAY_PLUGIN_NAME,
|
||||
RELAY_COLOR_CHAT_CLIENT,
|
||||
client->desc,
|
||||
RELAY_COLOR_CHAT);
|
||||
if (relay_config_display_clients[client->protocol])
|
||||
{
|
||||
weechat_printf_date_tags (
|
||||
NULL, 0, "relay_client",
|
||||
_("%s: disconnected from client %s%s%s"),
|
||||
RELAY_PLUGIN_NAME,
|
||||
RELAY_COLOR_CHAT_CLIENT,
|
||||
client->desc,
|
||||
RELAY_COLOR_CHAT);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -1772,8 +1780,7 @@ relay_client_free (struct t_relay_client *client)
|
||||
free (client->nonce);
|
||||
if (client->hook_timer_handshake)
|
||||
weechat_unhook (client->hook_timer_handshake);
|
||||
if (client->http_headers)
|
||||
weechat_hashtable_free (client->http_headers);
|
||||
relay_http_request_free (client->http_req);
|
||||
if (client->hook_fd)
|
||||
weechat_unhook (client->hook_fd);
|
||||
if (client->hook_timer_send)
|
||||
@@ -1790,6 +1797,11 @@ relay_client_free (struct t_relay_client *client)
|
||||
case RELAY_PROTOCOL_IRC:
|
||||
relay_irc_free (client);
|
||||
break;
|
||||
case RELAY_PROTOCOL_API:
|
||||
#ifdef HAVE_CJSON
|
||||
relay_api_free (client);
|
||||
#endif /* HAVE_CJSON */
|
||||
break;
|
||||
case RELAY_NUM_PROTOCOLS:
|
||||
break;
|
||||
}
|
||||
@@ -1968,6 +1980,12 @@ relay_client_add_to_infolist (struct t_infolist *infolist,
|
||||
relay_irc_add_to_infolist (ptr_item, client,
|
||||
force_disconnected_state);
|
||||
break;
|
||||
case RELAY_PROTOCOL_API:
|
||||
#ifdef HAVE_CJSON
|
||||
relay_api_add_to_infolist (ptr_item, client,
|
||||
force_disconnected_state);
|
||||
#endif /* HAVE_CJSON */
|
||||
break;
|
||||
case RELAY_NUM_PROTOCOLS:
|
||||
break;
|
||||
}
|
||||
@@ -1989,20 +2007,18 @@ relay_client_print_log ()
|
||||
{
|
||||
weechat_log_printf ("");
|
||||
weechat_log_printf ("[relay client (addr:0x%lx)]", ptr_client);
|
||||
weechat_log_printf (" id. . . . . . . . . . . . : %d", ptr_client->id);
|
||||
weechat_log_printf (" desc. . . . . . . . . . . : '%s'", ptr_client->desc);
|
||||
weechat_log_printf (" sock. . . . . . . . . . . : %d", ptr_client->sock);
|
||||
weechat_log_printf (" server_port . . . . . . . : %d", ptr_client->server_port);
|
||||
weechat_log_printf (" tls . . . . . . . . . . . : %d", ptr_client->tls);
|
||||
weechat_log_printf (" id. . . . . . . . . . . . : %d", ptr_client->id);
|
||||
weechat_log_printf (" desc. . . . . . . . . . . : '%s'", ptr_client->desc);
|
||||
weechat_log_printf (" sock. . . . . . . . . . . : %d", ptr_client->sock);
|
||||
weechat_log_printf (" server_port . . . . . . . : %d", ptr_client->server_port);
|
||||
weechat_log_printf (" tls . . . . . . . . . . . : %d", ptr_client->tls);
|
||||
weechat_log_printf (" gnutls_sess . . . . . . . : 0x%lx", ptr_client->gnutls_sess);
|
||||
weechat_log_printf (" hook_timer_handshake. . . : 0x%lx", ptr_client->hook_timer_handshake);
|
||||
weechat_log_printf (" gnutls_handshake_ok . . . : 0x%lx", ptr_client->gnutls_handshake_ok);
|
||||
weechat_log_printf (" websocket . . . . . . . . : %d", ptr_client->websocket);
|
||||
weechat_log_printf (" http_headers. . . . . . . : 0x%lx (hashtable: '%s')",
|
||||
ptr_client->http_headers,
|
||||
weechat_hashtable_get_string (ptr_client->http_headers, "keys_values"));
|
||||
weechat_log_printf (" address . . . . . . . . . : '%s'", ptr_client->address);
|
||||
weechat_log_printf (" real_ip . . . . . . . . . : '%s'", ptr_client->real_ip);
|
||||
weechat_log_printf (" websocket . . . . . . . . : %d", ptr_client->websocket);
|
||||
relay_http_print_log (ptr_client->http_req);
|
||||
weechat_log_printf (" address . . . . . . . . . : '%s'", ptr_client->address);
|
||||
weechat_log_printf (" real_ip . . . . . . . . . : '%s'", ptr_client->real_ip);
|
||||
weechat_log_printf (" status. . . . . . . . . . : %d (%s)",
|
||||
ptr_client->status,
|
||||
relay_client_status_string[ptr_client->status]);
|
||||
@@ -2041,6 +2057,11 @@ relay_client_print_log ()
|
||||
case RELAY_PROTOCOL_IRC:
|
||||
relay_irc_print_log (ptr_client);
|
||||
break;
|
||||
case RELAY_PROTOCOL_API:
|
||||
#ifdef HAVE_CJSON
|
||||
relay_api_print_log (ptr_client);
|
||||
#endif /* HAVE_CJSON */
|
||||
break;
|
||||
case RELAY_NUM_PROTOCOLS:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <gnutls/gnutls.h>
|
||||
|
||||
struct t_relay_server;
|
||||
struct t_relay_http_request;
|
||||
|
||||
/* relay status */
|
||||
|
||||
@@ -43,8 +44,10 @@ enum t_relay_status
|
||||
|
||||
enum t_relay_client_data_type
|
||||
{
|
||||
RELAY_CLIENT_DATA_TEXT = 0, /* text messages */
|
||||
RELAY_CLIENT_DATA_TEXT_LINE = 0, /* text messages (on one line) */
|
||||
RELAY_CLIENT_DATA_BINARY, /* binary messages */
|
||||
RELAY_CLIENT_DATA_HTTP, /* HTTP messages (mostly text) */
|
||||
RELAY_CLIENT_DATA_TEXT_MULTILINE, /* multi-line text (eg: JSON) */
|
||||
/* number of data types */
|
||||
RELAY_NUM_CLIENT_DATA_TYPES,
|
||||
};
|
||||
@@ -53,7 +56,6 @@ enum t_relay_client_data_type
|
||||
|
||||
enum t_relay_client_websocket_status
|
||||
{
|
||||
/* 0=not a ws, 1=init ws, 2=ws ready */
|
||||
RELAY_CLIENT_WEBSOCKET_NOT_USED = 0, /* no webseocket or not yet init. */
|
||||
RELAY_CLIENT_WEBSOCKET_INITIALIZING, /* websocket used, initializing */
|
||||
RELAY_CLIENT_WEBSOCKET_READY, /* websocket used, ready */
|
||||
@@ -106,7 +108,7 @@ struct t_relay_client
|
||||
struct t_hook *hook_timer_handshake; /* timer for doing gnutls handshake*/
|
||||
int gnutls_handshake_ok; /* 1 if handshake was done and OK */
|
||||
enum t_relay_client_websocket_status websocket; /* websocket status */
|
||||
struct t_hashtable *http_headers; /* HTTP headers for websocket */
|
||||
struct t_relay_http_request *http_req; /* HTTP request */
|
||||
char *address; /* string with IP address */
|
||||
char *real_ip; /* real IP (X-Real-IP HTTP header) */
|
||||
enum t_relay_status status; /* status (connecting, active,..) */
|
||||
|
||||
@@ -54,6 +54,7 @@ struct t_config_section *relay_config_section_path = NULL;
|
||||
/* relay config, look section */
|
||||
|
||||
struct t_config_option *relay_config_look_auto_open_buffer = NULL;
|
||||
struct t_config_option *relay_config_look_display_clients = NULL;
|
||||
struct t_config_option *relay_config_look_raw_messages = NULL;
|
||||
|
||||
/* relay config, color section */
|
||||
@@ -101,12 +102,103 @@ struct t_config_option *relay_config_weechat_commands = NULL;
|
||||
|
||||
/* other */
|
||||
|
||||
int relay_config_auto_open_buffer[RELAY_NUM_PROTOCOLS];
|
||||
int relay_config_display_clients[RELAY_NUM_PROTOCOLS];
|
||||
regex_t *relay_config_regex_allowed_ips = NULL;
|
||||
regex_t *relay_config_regex_websocket_allowed_origins = NULL;
|
||||
struct t_hashtable *relay_config_hashtable_irc_backlog_tags = NULL;
|
||||
char **relay_config_network_password_hash_algo_list = NULL;
|
||||
|
||||
|
||||
/*
|
||||
* Callback for changes on option "relay.look.auto_open_buffer".
|
||||
*/
|
||||
|
||||
void
|
||||
relay_config_change_auto_open_buffer_cb (const void *pointer, void *data,
|
||||
struct t_config_option *option)
|
||||
{
|
||||
const char *auto_open_buffer;
|
||||
const char *value_on = "irc,weechat", *value_off = "";
|
||||
char **items;
|
||||
int i, num_items, protocol;
|
||||
|
||||
/* make C compiler happy */
|
||||
(void) pointer;
|
||||
(void) data;
|
||||
(void) option;
|
||||
|
||||
auto_open_buffer = weechat_config_string (relay_config_look_auto_open_buffer);
|
||||
|
||||
/* old option was a boolean, use these values for compatibility */
|
||||
if (strcmp (auto_open_buffer, "on") == 0)
|
||||
auto_open_buffer = value_on;
|
||||
else if (strcmp (auto_open_buffer, "off") == 0)
|
||||
auto_open_buffer = value_off;
|
||||
|
||||
for (i = 0; i < RELAY_NUM_PROTOCOLS; i++)
|
||||
{
|
||||
relay_config_auto_open_buffer[i] = 0;
|
||||
}
|
||||
|
||||
if (auto_open_buffer[0])
|
||||
{
|
||||
items = weechat_string_split (auto_open_buffer, ",", NULL, 0, 0,
|
||||
&num_items);
|
||||
if (items)
|
||||
{
|
||||
for (i = 0; i < num_items; i++)
|
||||
{
|
||||
protocol = relay_protocol_search (items[i]);
|
||||
if (protocol >= 0)
|
||||
relay_config_auto_open_buffer[protocol] = 1;
|
||||
}
|
||||
weechat_string_free_split (items);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for changes on option "relay.look.display_clients".
|
||||
*/
|
||||
|
||||
void
|
||||
relay_config_change_display_clients_cb (const void *pointer, void *data,
|
||||
struct t_config_option *option)
|
||||
{
|
||||
const char *display_clients;
|
||||
char **items;
|
||||
int i, num_items, protocol;
|
||||
|
||||
/* make C compiler happy */
|
||||
(void) pointer;
|
||||
(void) data;
|
||||
(void) option;
|
||||
|
||||
display_clients = weechat_config_string (relay_config_look_display_clients);
|
||||
|
||||
for (i = 0; i < RELAY_NUM_PROTOCOLS; i++)
|
||||
{
|
||||
relay_config_display_clients[i] = 0;
|
||||
}
|
||||
|
||||
if (display_clients[0])
|
||||
{
|
||||
items = weechat_string_split (display_clients, ",", NULL, 0, 0,
|
||||
&num_items);
|
||||
if (items)
|
||||
{
|
||||
for (i = 0; i < num_items; i++)
|
||||
{
|
||||
protocol = relay_protocol_search (items[i]);
|
||||
if (protocol >= 0)
|
||||
relay_config_display_clients[protocol] = 1;
|
||||
}
|
||||
weechat_string_free_split (items);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for changes on options that require a refresh of relay list.
|
||||
*/
|
||||
@@ -1030,10 +1122,24 @@ relay_config_init ()
|
||||
{
|
||||
relay_config_look_auto_open_buffer = weechat_config_new_option (
|
||||
relay_config_file, relay_config_section_look,
|
||||
"auto_open_buffer", "boolean",
|
||||
N_("auto open relay buffer when a new client is connecting"),
|
||||
NULL, 0, 0, "on", NULL, 0,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
"auto_open_buffer", "string",
|
||||
N_("auto open relay buffer when a new client is connecting "
|
||||
"using one of these protocols (comma-separated list); "
|
||||
"allowed protocols: \"irc\", \"weechat\", \"api\""),
|
||||
NULL, 0, 0, "irc,weechat", NULL, 0,
|
||||
NULL, NULL, NULL,
|
||||
&relay_config_change_auto_open_buffer_cb, NULL, NULL,
|
||||
NULL, NULL, NULL);
|
||||
relay_config_look_display_clients = weechat_config_new_option (
|
||||
relay_config_file, relay_config_section_look,
|
||||
"display_clients", "string",
|
||||
N_("display messages when clients connect/disconnect from relay "
|
||||
"using one of these protocols (comma-separated list); "
|
||||
"allowed protocols: \"irc\", \"weechat\", \"api\""),
|
||||
NULL, 0, 0, "irc,weechat", NULL, 0,
|
||||
NULL, NULL, NULL,
|
||||
&relay_config_change_display_clients_cb, NULL, NULL,
|
||||
NULL, NULL, NULL);
|
||||
relay_config_look_raw_messages = weechat_config_new_option (
|
||||
relay_config_file, relay_config_section_look,
|
||||
"raw_messages", "integer",
|
||||
@@ -1185,11 +1291,11 @@ relay_config_init ()
|
||||
relay_config_network_compression = weechat_config_new_option (
|
||||
relay_config_file, relay_config_section_network,
|
||||
"compression", "integer",
|
||||
N_("compression of messages sent to clients with \"weechat\" "
|
||||
"protocol: 0 = disable compression, 1 = low compression / fast "
|
||||
"... 100 = best compression / slow; the value is a percentage "
|
||||
"converted to 1-9 for zlib and 1-19 for zstd; "
|
||||
"the default value is recommended, it offers a good "
|
||||
N_("compression of messages sent to clients with weechat and "
|
||||
"api protocols: 0 = disable compression, "
|
||||
"1 = low compression / fast ... 100 = best compression / slow; "
|
||||
"the value is a percentage converted to 1-9 for zlib and 1-19 "
|
||||
"for zstd; the default value is recommended, it offers a good "
|
||||
"compromise between compression and speed"),
|
||||
NULL, 0, 100, "20", NULL, 0,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
@@ -1279,8 +1385,8 @@ relay_config_init ()
|
||||
"totp_secret", "string",
|
||||
N_("secret for the generation of the Time-based One-Time Password "
|
||||
"(TOTP), encoded in base32 (only letters and digits from 2 to 7); "
|
||||
"it is used as second factor in weechat protocol, in addition to "
|
||||
"the password, which must not be empty "
|
||||
"it is used as second factor in weechat and api protocols, "
|
||||
"in addition to the password, which must not be empty "
|
||||
"(empty value means no TOTP is required) "
|
||||
"(note: content is evaluated, see /help eval)"),
|
||||
NULL, 0, 0, "", NULL, 0,
|
||||
@@ -1435,6 +1541,8 @@ relay_config_read ()
|
||||
rc = weechat_config_read (relay_config_file);
|
||||
if (rc == WEECHAT_CONFIG_READ_OK)
|
||||
{
|
||||
relay_config_change_auto_open_buffer_cb (NULL, NULL, NULL);
|
||||
relay_config_change_display_clients_cb (NULL, NULL, NULL);
|
||||
relay_config_change_network_allowed_ips (NULL, NULL, NULL);
|
||||
relay_config_change_network_password_hash_algo (NULL, NULL, NULL);
|
||||
relay_config_change_irc_backlog_tags (NULL, NULL, NULL);
|
||||
|
||||
@@ -67,6 +67,8 @@ extern struct t_config_option *relay_config_irc_backlog_time_format;
|
||||
|
||||
extern struct t_config_option *relay_config_weechat_commands;
|
||||
|
||||
extern int relay_config_auto_open_buffer[];
|
||||
extern int relay_config_display_clients[];
|
||||
extern regex_t *relay_config_regex_allowed_ips;
|
||||
extern regex_t *relay_config_regex_websocket_allowed_origins;
|
||||
extern struct t_hashtable *relay_config_hashtable_irc_backlog_tags;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2024 Sébastien Helleu <flashcode@flashtux.org>
|
||||
*
|
||||
* This file is part of WeeChat, the extensible chat client.
|
||||
*
|
||||
* WeeChat 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; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* WeeChat 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 WeeChat. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef WEECHAT_PLUGIN_RELAY_HTTP_H
|
||||
#define WEECHAT_PLUGIN_RELAY_HTTP_H
|
||||
|
||||
struct t_relay_client;
|
||||
|
||||
enum t_relay_client_http_status
|
||||
{
|
||||
RELAY_HTTP_METHOD = 0, /* reading method (eg: GET, POST) */
|
||||
RELAY_HTTP_HEADERS, /* reading headers */
|
||||
RELAY_HTTP_BODY, /* reading body */
|
||||
RELAY_HTTP_END, /* end of HTTP request */
|
||||
/* number of HTTP status */
|
||||
RELAY_NUM_HTTP_STATUS,
|
||||
};
|
||||
|
||||
#define RELAY_HTTP_200_OK 200, "OK"
|
||||
#define RELAY_HTTP_204_NO_CONTENT 204, "No Content"
|
||||
#define RELAY_HTTP_400_BAD_REQUEST 400, "Bad Request"
|
||||
#define RELAY_HTTP_401_UNAUTHORIZED 401, "Unauthorized"
|
||||
#define RELAY_HTTP_403_FORBIDDEN 403, "Forbidden"
|
||||
#define RELAY_HTTP_404_NOT_FOUND 404, "Not Found"
|
||||
#define RELAY_HTTP_500_INTERNAL_SERVER_ERROR 500, "Internal Server Error"
|
||||
#define RELAY_HTTP_503_SERVICE_UNAVAILABLE 503, "Service Unvavailable"
|
||||
|
||||
#define RELAY_HTTP_ERROR_MISSING_PASSWORD "Missing password"
|
||||
#define RELAY_HTTP_ERROR_INVALID_PASSWORD "Invalid password"
|
||||
#define RELAY_HTTP_ERROR_MISSING_TOTP "Missing TOTP"
|
||||
#define RELAY_HTTP_ERROR_INVALID_TOTP "Invalid TOTP"
|
||||
#define RELAY_HTTP_ERROR_OUT_OF_MEMORY "Out of memory"
|
||||
|
||||
struct t_relay_http_request
|
||||
{
|
||||
enum t_relay_client_http_status status; /* HTTP status */
|
||||
char **raw; /* raw request */
|
||||
char *method; /* method (GET, POST, etc.) */
|
||||
char *path; /* path after method */
|
||||
char **path_items; /* list of items in path, eg: */
|
||||
/* "/api/a/b" => ["api", "a", "b"] */
|
||||
int num_path_items; /* number of path items */
|
||||
struct t_hashtable *params; /* optional parameters ("?p=a&q=b") */
|
||||
char *http_version; /* HTTP version (eg: "HTTP/1.1") */
|
||||
struct t_hashtable *headers; /* HTTP headers for websocket */
|
||||
/* and API protocol */
|
||||
struct t_hashtable *accept_encoding; /* allowed encoding for response */
|
||||
int content_length; /* value of header "Content-Length" */
|
||||
int body_size; /* size of HTTP body read so far */
|
||||
char *body; /* HTTP body (can be NULL) */
|
||||
};
|
||||
|
||||
extern void relay_http_request_reinit (struct t_relay_http_request *request);
|
||||
extern struct t_relay_http_request *relay_http_request_alloc ();
|
||||
extern int relay_http_parse_method_path (struct t_relay_http_request *request,
|
||||
const char *method_path);
|
||||
extern int relay_http_check_auth (struct t_relay_http_request *request);
|
||||
extern void relay_http_recv (struct t_relay_client *client, const char *data);
|
||||
extern int relay_http_send (struct t_relay_client *client,
|
||||
int return_code, const char *message,
|
||||
const char *headers,
|
||||
const char *body, int body_size);
|
||||
extern int relay_http_send_json (struct t_relay_client *client,
|
||||
int return_code,
|
||||
const char *message,
|
||||
const char *headers,
|
||||
const char *json_string);
|
||||
extern int relay_http_send_error_json (struct t_relay_client *client,
|
||||
int return_code,
|
||||
const char *message,
|
||||
const char *headers,
|
||||
const char *format, ...);
|
||||
extern void relay_http_request_free (struct t_relay_http_request *request);
|
||||
extern void relay_http_print_log (struct t_relay_http_request *request);
|
||||
|
||||
#endif /* WEECHAT_PLUGIN_RELAY_HTTP_H */
|
||||
@@ -52,7 +52,7 @@ struct t_relay_server *last_relay_server = NULL;
|
||||
* Examples:
|
||||
*
|
||||
* string ipv4 ipv6 tls unix protocol protocol_args
|
||||
* ---------------------------------------------------------------
|
||||
* -------------------------------------------------------------------
|
||||
* irc.libera 1 1 0 0 irc libera
|
||||
* tls.irc.libera 1 1 1 0 irc libera
|
||||
* ipv4.irc.libera 1 0 0 0 irc libera
|
||||
@@ -63,6 +63,9 @@ struct t_relay_server *last_relay_server = NULL;
|
||||
* tls.weechat 1 1 1 0 weechat
|
||||
* ipv6.tls.weechat 0 1 1 0 weechat
|
||||
* unix.weechat 0 0 0 1 weechat
|
||||
* tls.api 1 1 1 0 api
|
||||
* ipv6.tls.api 0 1 1 0 api
|
||||
* unix.api 0 0 0 1 api
|
||||
*
|
||||
* Note: *protocol and *protocol_args must be freed after use.
|
||||
*/
|
||||
@@ -801,6 +804,18 @@ relay_server_new (const char *protocol_string, enum t_relay_protocol protocol,
|
||||
if (!protocol_string)
|
||||
return NULL;
|
||||
|
||||
#ifndef HAVE_CJSON
|
||||
if (protocol == RELAY_PROTOCOL_API)
|
||||
{
|
||||
weechat_printf (NULL,
|
||||
_("%s%s: error: unable to add relay \"%s\" "
|
||||
"(cJSON support is not enabled)"),
|
||||
weechat_prefix ("error"), RELAY_PLUGIN_NAME,
|
||||
protocol_string);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* HAVE_CJSON */
|
||||
|
||||
/* look for duplicate ports/paths */
|
||||
dup_server = (unix_socket) ?
|
||||
relay_server_search_path (path) : relay_server_search_port (port);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "relay.h"
|
||||
#include "relay-client.h"
|
||||
#include "relay-config.h"
|
||||
#include "relay-http.h"
|
||||
#include "relay-websocket.h"
|
||||
|
||||
|
||||
@@ -39,81 +40,44 @@
|
||||
|
||||
|
||||
/*
|
||||
* Checks if a message is a HTTP GET with resource "/weechat".
|
||||
* Checks if a message is a HTTP GET with resource "/weechat" (for weechat
|
||||
* protocol) or "/api" (for api protocol).
|
||||
*
|
||||
* Returns:
|
||||
* 1: message is a HTTP GET with resource "/weechat"
|
||||
* 0: message is NOT a HTTP GET with resource "/weechat"
|
||||
* 1: message is a HTTP GET with appropriate resource
|
||||
* 0: message is NOT a HTTP GET with appropriate resource
|
||||
*/
|
||||
|
||||
int
|
||||
relay_websocket_is_http_get_weechat (const char *message)
|
||||
relay_websocket_is_valid_http_get (struct t_relay_client *client,
|
||||
const char *message)
|
||||
{
|
||||
/* the message must start with "GET /weechat" */
|
||||
if (strncmp (message, "GET /weechat", 12) != 0)
|
||||
char string[128];
|
||||
int length;
|
||||
|
||||
/* the message must start with "GET /weechat" or "GET /api" */
|
||||
snprintf (string, sizeof (string),
|
||||
"GET /%s", relay_protocol_string[client->protocol]);
|
||||
length = strlen (string);
|
||||
|
||||
if (strncmp (message, string, length) != 0)
|
||||
return 0;
|
||||
|
||||
/* after "GET /weechat", only a new line or " HTTP" is allowed */
|
||||
if ((message[12] != '\r') && (message[12] != '\n')
|
||||
&& (strncmp (message + 12, " HTTP", 5) != 0))
|
||||
/* after "GET /weechat" or "GET /api", only a new line or " HTTP" is allowed */
|
||||
if ((message[length] != '\r') && (message[length] != '\n')
|
||||
&& (strncmp (message + length, " HTTP", 5) != 0))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* valid HTTP GET for resource "/weechat" */
|
||||
/* valid HTTP GET */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Saves a HTTP header in hashtable "http_header" of client.
|
||||
*/
|
||||
|
||||
void
|
||||
relay_websocket_save_header (struct t_relay_client *client,
|
||||
const char *message)
|
||||
{
|
||||
char *pos, *name, *name_lower;
|
||||
const char *ptr_value;
|
||||
|
||||
/* ignore the "GET" request */
|
||||
if (strncmp (message, "GET ", 4) == 0)
|
||||
return;
|
||||
|
||||
pos = strchr (message, ':');
|
||||
|
||||
/* not a valid header */
|
||||
if (!pos || (pos == message))
|
||||
return;
|
||||
|
||||
/* get header name, which is case-insensitive */
|
||||
name = weechat_strndup (message, pos - message);
|
||||
if (!name)
|
||||
return;
|
||||
name_lower = weechat_string_tolower (name);
|
||||
if (!name_lower)
|
||||
{
|
||||
free (name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* get pointer on header value */
|
||||
ptr_value = pos + 1;
|
||||
while (ptr_value[0] == ' ')
|
||||
{
|
||||
ptr_value++;
|
||||
}
|
||||
|
||||
/* add header in the hashtable */
|
||||
weechat_hashtable_set (client->http_headers, name_lower, ptr_value);
|
||||
|
||||
free (name);
|
||||
free (name_lower);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if a client handshake is valid.
|
||||
*
|
||||
* A websocket query looks like:
|
||||
* A websocket query looks like (weechat protocol):
|
||||
* GET /weechat HTTP/1.1
|
||||
* Upgrade: websocket
|
||||
* Connection: Upgrade
|
||||
@@ -126,6 +90,20 @@ relay_websocket_save_header (struct t_relay_client *client,
|
||||
* Sec-WebSocket-Extensions: x-webkit-deflate-frame
|
||||
* Cookie: csrftoken=acb65377798f32dc377ebb50316a12b5
|
||||
*
|
||||
* A websocket query looks like (api protocol):
|
||||
* GET /api HTTP/1.1
|
||||
* Upgrade: websocket
|
||||
* Connection: Upgrade
|
||||
* Host: myhost:5000
|
||||
* Origin: https://example.org
|
||||
* Pragma: no-cache
|
||||
* Cache-Control: no-cache
|
||||
* Sec-WebSocket-Key: fo1J9uHSsrfDP3BkwUylzQ==
|
||||
* Sec-WebSocket-Version: 13
|
||||
* Sec-WebSocket-Extensions: x-webkit-deflate-frame
|
||||
* Cookie: csrftoken=acb65377798f32dc377ebb50316a12b5
|
||||
*
|
||||
*
|
||||
* Expected HTTP headers with values are:
|
||||
*
|
||||
* header | value
|
||||
@@ -149,20 +127,20 @@ relay_websocket_client_handshake_valid (struct t_relay_client *client)
|
||||
const char *value;
|
||||
|
||||
/* check if we have header "Upgrade" with value "websocket" */
|
||||
value = weechat_hashtable_get (client->http_headers, "upgrade");
|
||||
value = weechat_hashtable_get (client->http_req->headers, "upgrade");
|
||||
if (!value)
|
||||
return -1;
|
||||
if (weechat_strcasecmp (value, "websocket") != 0)
|
||||
return -1;
|
||||
|
||||
/* check if we have header "Sec-WebSocket-Key" with non-empty value */
|
||||
value = weechat_hashtable_get (client->http_headers, "sec-websocket-key");
|
||||
value = weechat_hashtable_get (client->http_req->headers, "sec-websocket-key");
|
||||
if (!value || !value[0])
|
||||
return -1;
|
||||
|
||||
if (relay_config_regex_websocket_allowed_origins)
|
||||
{
|
||||
value = weechat_hashtable_get (client->http_headers, "origin");
|
||||
value = weechat_hashtable_get (client->http_req->headers, "origin");
|
||||
if (!value || !value[0])
|
||||
return -2;
|
||||
if (regexec (relay_config_regex_websocket_allowed_origins, value, 0,
|
||||
@@ -196,7 +174,7 @@ relay_websocket_build_handshake (struct t_relay_client *client)
|
||||
char *key, sec_websocket_accept[128], handshake[1024], hash[160 / 8];
|
||||
int length, hash_size;
|
||||
|
||||
sec_websocket_key = weechat_hashtable_get (client->http_headers,
|
||||
sec_websocket_key = weechat_hashtable_get (client->http_req->headers,
|
||||
"sec-websocket-key");
|
||||
if (!sec_websocket_key || !sec_websocket_key[0])
|
||||
return NULL;
|
||||
@@ -238,31 +216,6 @@ relay_websocket_build_handshake (struct t_relay_client *client)
|
||||
return strdup (handshake);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends a HTTP message to client.
|
||||
*
|
||||
* Argument "http" is a HTTP code + message, for example:
|
||||
* "403 Forbidden".
|
||||
*/
|
||||
|
||||
void
|
||||
relay_websocket_send_http (struct t_relay_client *client,
|
||||
const char *http)
|
||||
{
|
||||
char *message;
|
||||
int length;
|
||||
|
||||
length = 32 + strlen (http) + 1;
|
||||
message = malloc (length);
|
||||
if (message)
|
||||
{
|
||||
snprintf (message, length, "HTTP/1.1 %s\r\n\r\n", http);
|
||||
relay_client_send (client, RELAY_CLIENT_MSG_STANDARD,
|
||||
message, strlen (message), NULL);
|
||||
free (message);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Decodes a websocket frame.
|
||||
*
|
||||
|
||||
@@ -27,13 +27,10 @@
|
||||
#define WEBSOCKET_FRAME_OPCODE_PING 0x09
|
||||
#define WEBSOCKET_FRAME_OPCODE_PONG 0x0A
|
||||
|
||||
extern int relay_websocket_is_http_get_weechat (const char *message);
|
||||
extern void relay_websocket_save_header (struct t_relay_client *client,
|
||||
const char *message);
|
||||
extern int relay_websocket_is_valid_http_get (struct t_relay_client *client,
|
||||
const char *message);
|
||||
extern int relay_websocket_client_handshake_valid (struct t_relay_client *client);
|
||||
extern char *relay_websocket_build_handshake (struct t_relay_client *client);
|
||||
extern void relay_websocket_send_http (struct t_relay_client *client,
|
||||
const char *http);
|
||||
extern int relay_websocket_decode_frame (const unsigned char *buffer,
|
||||
unsigned long long length,
|
||||
unsigned char *decoded,
|
||||
|
||||
@@ -47,7 +47,7 @@ WEECHAT_PLUGIN_PRIORITY(RELAY_PLUGIN_PRIORITY);
|
||||
struct t_weechat_plugin *weechat_relay_plugin = NULL;
|
||||
|
||||
char *relay_protocol_string[] = /* strings for protocols */
|
||||
{ "weechat", "irc" };
|
||||
{ "weechat", "irc", "api" };
|
||||
|
||||
struct t_hdata *relay_hdata_buffer = NULL;
|
||||
struct t_hdata *relay_hdata_lines = NULL;
|
||||
|
||||
@@ -43,6 +43,7 @@ enum t_relay_protocol
|
||||
{
|
||||
RELAY_PROTOCOL_WEECHAT = 0, /* WeeChat protocol */
|
||||
RELAY_PROTOCOL_IRC, /* IRC protocol (IRC proxy) */
|
||||
RELAY_PROTOCOL_API, /* HTTP REST API */
|
||||
/* number of relay protocols */
|
||||
RELAY_NUM_PROTOCOLS,
|
||||
};
|
||||
|
||||
@@ -107,6 +107,7 @@ endif()
|
||||
if (ENABLE_RELAY)
|
||||
list(APPEND LIB_WEECHAT_UNIT_TESTS_PLUGINS_SRC
|
||||
unit/plugins/relay/test-relay-auth.cpp
|
||||
unit/plugins/relay/test-relay-http.cpp
|
||||
unit/plugins/relay/irc/test-relay-irc.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,742 @@
|
||||
/*
|
||||
* test-relay-http.cpp - test HTTP functions
|
||||
*
|
||||
* Copyright (C) 2023-2024 Sébastien Helleu <flashcode@flashtux.org>
|
||||
*
|
||||
* This file is part of WeeChat, the extensible chat client.
|
||||
*
|
||||
* WeeChat 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; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CppUTest/TestHarness.h"
|
||||
|
||||
#include "tests/tests.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "src/core/wee-config-file.h"
|
||||
#include "src/core/wee-hashtable.h"
|
||||
#include "src/core/wee-hook.h"
|
||||
#include "src/core/wee-string.h"
|
||||
#include "src/plugins/relay/relay-config.h"
|
||||
#include "src/plugins/relay/relay-http.h"
|
||||
#include "src/plugins/weechat-plugin.h"
|
||||
|
||||
extern char *relay_http_url_decode (const char *url);
|
||||
extern void relay_http_parse_path (const char *url,
|
||||
char ***paths, int *num_paths,
|
||||
struct t_hashtable *params);
|
||||
extern int relay_http_parse_header (struct t_relay_http_request *request,
|
||||
const char *header);
|
||||
extern void relay_http_add_to_body (struct t_relay_http_request *request,
|
||||
char **partial_message);
|
||||
extern char *relay_http_compress (struct t_relay_http_request *request,
|
||||
const char *data, int data_size,
|
||||
int *compressed_size,
|
||||
char *http_content_encoding,
|
||||
int http_content_encoding_size);
|
||||
}
|
||||
|
||||
#define WEE_PARSE_PATH(__path) \
|
||||
paths = (char **)0x1; \
|
||||
num_paths = -1; \
|
||||
hashtable_remove_all (params); \
|
||||
relay_http_parse_path (__path, &paths, &num_paths, params);
|
||||
|
||||
TEST_GROUP(RelayHttp)
|
||||
{
|
||||
};
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_http_request_alloc
|
||||
* relay_http_request_reinit
|
||||
* relay_http_request_free
|
||||
*/
|
||||
|
||||
TEST(RelayHttp, AllocReinitFree)
|
||||
{
|
||||
struct t_relay_http_request *request;
|
||||
|
||||
request = relay_http_request_alloc ();
|
||||
CHECK(request);
|
||||
|
||||
LONGS_EQUAL(RELAY_HTTP_METHOD, request->status);
|
||||
CHECK(request->raw);
|
||||
STRCMP_EQUAL("", *(request->raw));
|
||||
POINTERS_EQUAL(NULL, request->method);
|
||||
POINTERS_EQUAL(NULL, request->path);
|
||||
POINTERS_EQUAL(NULL, request->path_items);
|
||||
LONGS_EQUAL(0, request->num_path_items);
|
||||
CHECK(request->params);
|
||||
LONGS_EQUAL(0, request->params->items_count);
|
||||
POINTERS_EQUAL(NULL, request->http_version);
|
||||
CHECK(request->headers);
|
||||
LONGS_EQUAL(0, request->headers->items_count);
|
||||
CHECK(request->accept_encoding);
|
||||
LONGS_EQUAL(0, request->accept_encoding->items_count);
|
||||
LONGS_EQUAL(0, request->content_length);
|
||||
LONGS_EQUAL(0, request->body_size);
|
||||
POINTERS_EQUAL(NULL, request->body);
|
||||
|
||||
request->status = RELAY_HTTP_HEADERS;
|
||||
string_dyn_concat (request->raw, "test", -1);
|
||||
request->method = strdup ("test");
|
||||
request->path = strdup ("test");
|
||||
request->path_items = string_split ("test,1,2,3", ",", NULL, 0, 0, &request->num_path_items);
|
||||
hashtable_set (request->params, "test", "value");
|
||||
request->http_version = strdup ("HTTP/1.1");
|
||||
hashtable_set (request->headers, "x-test", "value");
|
||||
hashtable_set (request->accept_encoding, "gzip", "");
|
||||
request->content_length = 100;
|
||||
request->body_size = 16;
|
||||
request->body = (char *)malloc (16);
|
||||
memset (request->body, 0, 16);
|
||||
|
||||
relay_http_request_reinit (request);
|
||||
|
||||
LONGS_EQUAL(RELAY_HTTP_METHOD, request->status);
|
||||
CHECK(request->raw);
|
||||
STRCMP_EQUAL("", *(request->raw));
|
||||
POINTERS_EQUAL(NULL, request->method);
|
||||
POINTERS_EQUAL(NULL, request->path);
|
||||
POINTERS_EQUAL(NULL, request->path_items);
|
||||
LONGS_EQUAL(0, request->num_path_items);
|
||||
CHECK(request->params);
|
||||
LONGS_EQUAL(0, request->params->items_count);
|
||||
POINTERS_EQUAL(NULL, request->http_version);
|
||||
CHECK(request->headers);
|
||||
LONGS_EQUAL(0, request->headers->items_count);
|
||||
CHECK(request->accept_encoding);
|
||||
LONGS_EQUAL(0, request->accept_encoding->items_count);
|
||||
LONGS_EQUAL(0, request->content_length);
|
||||
LONGS_EQUAL(0, request->body_size);
|
||||
POINTERS_EQUAL(NULL, request->body);
|
||||
|
||||
relay_http_request_free (request);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_http_url_decode
|
||||
*/
|
||||
|
||||
TEST(RelayHttp, UrlDecode)
|
||||
{
|
||||
char *str;
|
||||
|
||||
POINTERS_EQUAL(NULL, relay_http_url_decode (NULL));
|
||||
WEE_TEST_STR("", relay_http_url_decode (""));
|
||||
WEE_TEST_STR("test", relay_http_url_decode ("test"));
|
||||
WEE_TEST_STR("%", relay_http_url_decode ("%"));
|
||||
WEE_TEST_STR("%%", relay_http_url_decode ("%%"));
|
||||
WEE_TEST_STR("%test", relay_http_url_decode ("%test"));
|
||||
WEE_TEST_STR("#test", relay_http_url_decode ("#test"));
|
||||
WEE_TEST_STR("#test", relay_http_url_decode ("%23test"));
|
||||
WEE_TEST_STR("%#test", relay_http_url_decode ("%%23test"));
|
||||
WEE_TEST_STR("%#test hello", relay_http_url_decode ("%%23test%20hello"));
|
||||
WEE_TEST_STR("test+z", relay_http_url_decode ("test%2bz"));
|
||||
WEE_TEST_STR("test+z", relay_http_url_decode ("test%2Bz"));
|
||||
WEE_TEST_STR("test*", relay_http_url_decode ("test%2a"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_http_parse_path
|
||||
*/
|
||||
|
||||
TEST(RelayHttp, ParsePath)
|
||||
{
|
||||
char **paths;
|
||||
int num_paths;
|
||||
struct t_hashtable *params;
|
||||
|
||||
params = hashtable_new (
|
||||
32,
|
||||
WEECHAT_HASHTABLE_STRING,
|
||||
WEECHAT_HASHTABLE_STRING,
|
||||
NULL, NULL);
|
||||
|
||||
WEE_PARSE_PATH(NULL);
|
||||
POINTERS_EQUAL(NULL, paths);
|
||||
LONGS_EQUAL(0, num_paths);
|
||||
LONGS_EQUAL(0, params->items_count);
|
||||
|
||||
WEE_PARSE_PATH("");
|
||||
POINTERS_EQUAL(NULL, paths);
|
||||
LONGS_EQUAL(0, num_paths);
|
||||
LONGS_EQUAL(0, params->items_count);
|
||||
|
||||
WEE_PARSE_PATH("api");
|
||||
CHECK(paths);
|
||||
LONGS_EQUAL(1, num_paths);
|
||||
STRCMP_EQUAL("api", paths[0]);
|
||||
POINTERS_EQUAL(NULL, paths[1]);
|
||||
LONGS_EQUAL(0, params->items_count);
|
||||
|
||||
WEE_PARSE_PATH("/api");
|
||||
CHECK(paths);
|
||||
LONGS_EQUAL(1, num_paths);
|
||||
STRCMP_EQUAL("api", paths[0]);
|
||||
POINTERS_EQUAL(NULL, paths[1]);
|
||||
LONGS_EQUAL(0, params->items_count);
|
||||
|
||||
WEE_PARSE_PATH("/api/");
|
||||
CHECK(paths);
|
||||
LONGS_EQUAL(1, num_paths);
|
||||
STRCMP_EQUAL("api", paths[0]);
|
||||
POINTERS_EQUAL(NULL, paths[1]);
|
||||
LONGS_EQUAL(0, params->items_count);
|
||||
|
||||
WEE_PARSE_PATH("/api/buffers");
|
||||
CHECK(paths);
|
||||
LONGS_EQUAL(2, num_paths);
|
||||
STRCMP_EQUAL("api", paths[0]);
|
||||
STRCMP_EQUAL("buffers", paths[1]);
|
||||
POINTERS_EQUAL(NULL, paths[2]);
|
||||
LONGS_EQUAL(0, params->items_count);
|
||||
|
||||
WEE_PARSE_PATH("/api/buffers?");
|
||||
CHECK(paths);
|
||||
LONGS_EQUAL(2, num_paths);
|
||||
STRCMP_EQUAL("api", paths[0]);
|
||||
STRCMP_EQUAL("buffers", paths[1]);
|
||||
POINTERS_EQUAL(NULL, paths[2]);
|
||||
LONGS_EQUAL(0, params->items_count);
|
||||
|
||||
WEE_PARSE_PATH("/api/buffers?param");
|
||||
CHECK(paths);
|
||||
LONGS_EQUAL(2, num_paths);
|
||||
STRCMP_EQUAL("api", paths[0]);
|
||||
STRCMP_EQUAL("buffers", paths[1]);
|
||||
POINTERS_EQUAL(NULL, paths[2]);
|
||||
LONGS_EQUAL(1, params->items_count);
|
||||
STRCMP_EQUAL("", (const char *)hashtable_get (params, "param"));
|
||||
|
||||
WEE_PARSE_PATH("/api/buffers?param=");
|
||||
CHECK(paths);
|
||||
LONGS_EQUAL(2, num_paths);
|
||||
STRCMP_EQUAL("api", paths[0]);
|
||||
STRCMP_EQUAL("buffers", paths[1]);
|
||||
POINTERS_EQUAL(NULL, paths[2]);
|
||||
LONGS_EQUAL(1, params->items_count);
|
||||
STRCMP_EQUAL("", (const char *)hashtable_get (params, "param"));
|
||||
|
||||
WEE_PARSE_PATH("/api/buffers?param=off");
|
||||
CHECK(paths);
|
||||
LONGS_EQUAL(2, num_paths);
|
||||
STRCMP_EQUAL("api", paths[0]);
|
||||
STRCMP_EQUAL("buffers", paths[1]);
|
||||
POINTERS_EQUAL(NULL, paths[2]);
|
||||
LONGS_EQUAL(1, params->items_count);
|
||||
STRCMP_EQUAL("off", (const char *)hashtable_get (params, "param"));
|
||||
|
||||
WEE_PARSE_PATH("/api/buffers?param=off&test=value2");
|
||||
CHECK(paths);
|
||||
LONGS_EQUAL(2, num_paths);
|
||||
STRCMP_EQUAL("api", paths[0]);
|
||||
STRCMP_EQUAL("buffers", paths[1]);
|
||||
POINTERS_EQUAL(NULL, paths[2]);
|
||||
LONGS_EQUAL(2, params->items_count);
|
||||
STRCMP_EQUAL("off", (const char *)hashtable_get (params, "param"));
|
||||
STRCMP_EQUAL("value2", (const char *)hashtable_get (params, "test"));
|
||||
|
||||
WEE_PARSE_PATH("/api/buffers/irc.libera.%23weechat?param=off&test=value%202");
|
||||
CHECK(paths);
|
||||
LONGS_EQUAL(3, num_paths);
|
||||
STRCMP_EQUAL("api", paths[0]);
|
||||
STRCMP_EQUAL("buffers", paths[1]);
|
||||
STRCMP_EQUAL("irc.libera.#weechat", paths[2]);
|
||||
POINTERS_EQUAL(NULL, paths[3]);
|
||||
LONGS_EQUAL(2, params->items_count);
|
||||
STRCMP_EQUAL("off", (const char *)hashtable_get (params, "param"));
|
||||
STRCMP_EQUAL("value 2", (const char *)hashtable_get (params, "test"));
|
||||
|
||||
hashtable_free (params);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_http_parse_method_path
|
||||
*/
|
||||
|
||||
TEST(RelayHttp, ParseMethodPath)
|
||||
{
|
||||
struct t_relay_http_request *request;
|
||||
|
||||
request = relay_http_request_alloc ();
|
||||
CHECK(request);
|
||||
relay_http_parse_method_path (request, NULL);
|
||||
LONGS_EQUAL(RELAY_HTTP_METHOD, request->status);
|
||||
STRCMP_EQUAL("", *(request->raw));
|
||||
POINTERS_EQUAL(NULL, request->path);
|
||||
POINTERS_EQUAL(NULL, request->path_items);
|
||||
LONGS_EQUAL(0, request->num_path_items);
|
||||
LONGS_EQUAL(0, request->params->items_count);
|
||||
POINTERS_EQUAL(NULL, request->http_version);
|
||||
LONGS_EQUAL(0, request->headers->items_count);
|
||||
LONGS_EQUAL(0, request->accept_encoding->items_count);
|
||||
LONGS_EQUAL(0, request->content_length);
|
||||
LONGS_EQUAL(0, request->body_size);
|
||||
POINTERS_EQUAL(NULL, request->body);
|
||||
free (request);
|
||||
|
||||
request = relay_http_request_alloc ();
|
||||
CHECK(request);
|
||||
relay_http_parse_method_path (request, "");
|
||||
LONGS_EQUAL(RELAY_HTTP_METHOD, request->status);
|
||||
STRCMP_EQUAL("", *(request->raw));
|
||||
POINTERS_EQUAL(NULL, request->path);
|
||||
POINTERS_EQUAL(NULL, request->path_items);
|
||||
LONGS_EQUAL(0, request->num_path_items);
|
||||
LONGS_EQUAL(0, request->params->items_count);
|
||||
POINTERS_EQUAL(NULL, request->http_version);
|
||||
LONGS_EQUAL(0, request->headers->items_count);
|
||||
LONGS_EQUAL(0, request->accept_encoding->items_count);
|
||||
LONGS_EQUAL(0, request->content_length);
|
||||
LONGS_EQUAL(0, request->body_size);
|
||||
POINTERS_EQUAL(NULL, request->body);
|
||||
free (request);
|
||||
|
||||
request = relay_http_request_alloc ();
|
||||
CHECK(request);
|
||||
relay_http_parse_method_path (request, "GET");
|
||||
LONGS_EQUAL(RELAY_HTTP_END, request->status);
|
||||
STRCMP_EQUAL("GET\n", *(request->raw));
|
||||
POINTERS_EQUAL(NULL, request->path);
|
||||
POINTERS_EQUAL(NULL, request->path_items);
|
||||
LONGS_EQUAL(0, request->num_path_items);
|
||||
LONGS_EQUAL(0, request->params->items_count);
|
||||
POINTERS_EQUAL(NULL, request->http_version);
|
||||
LONGS_EQUAL(0, request->headers->items_count);
|
||||
LONGS_EQUAL(0, request->accept_encoding->items_count);
|
||||
LONGS_EQUAL(0, request->content_length);
|
||||
LONGS_EQUAL(0, request->body_size);
|
||||
POINTERS_EQUAL(NULL, request->body);
|
||||
free (request);
|
||||
|
||||
request = relay_http_request_alloc ();
|
||||
CHECK(request);
|
||||
relay_http_parse_method_path (request, "GET /api");
|
||||
LONGS_EQUAL(RELAY_HTTP_HEADERS, request->status);
|
||||
STRCMP_EQUAL("GET /api\n", *(request->raw));
|
||||
STRCMP_EQUAL("/api", request->path);
|
||||
CHECK(request->path_items);
|
||||
STRCMP_EQUAL("api", request->path_items[0]);
|
||||
POINTERS_EQUAL(NULL, request->path_items[1]);
|
||||
LONGS_EQUAL(1, request->num_path_items);
|
||||
LONGS_EQUAL(0, request->params->items_count);
|
||||
POINTERS_EQUAL(NULL, request->http_version);
|
||||
LONGS_EQUAL(0, request->headers->items_count);
|
||||
LONGS_EQUAL(0, request->accept_encoding->items_count);
|
||||
LONGS_EQUAL(0, request->content_length);
|
||||
LONGS_EQUAL(0, request->body_size);
|
||||
POINTERS_EQUAL(NULL, request->body);
|
||||
free (request);
|
||||
|
||||
request = relay_http_request_alloc ();
|
||||
CHECK(request);
|
||||
relay_http_parse_method_path (request, "GET /api/buffers HTTP/1.1");
|
||||
LONGS_EQUAL(RELAY_HTTP_HEADERS, request->status);
|
||||
STRCMP_EQUAL("GET /api/buffers HTTP/1.1\n", *(request->raw));
|
||||
STRCMP_EQUAL("/api/buffers", request->path);
|
||||
CHECK(request->path_items);
|
||||
STRCMP_EQUAL("api", request->path_items[0]);
|
||||
STRCMP_EQUAL("buffers", request->path_items[1]);
|
||||
POINTERS_EQUAL(NULL, request->path_items[2]);
|
||||
LONGS_EQUAL(2, request->num_path_items);
|
||||
LONGS_EQUAL(0, request->params->items_count);
|
||||
STRCMP_EQUAL("HTTP/1.1", request->http_version);
|
||||
LONGS_EQUAL(0, request->headers->items_count);
|
||||
LONGS_EQUAL(0, request->accept_encoding->items_count);
|
||||
LONGS_EQUAL(0, request->content_length);
|
||||
LONGS_EQUAL(0, request->body_size);
|
||||
POINTERS_EQUAL(NULL, request->body);
|
||||
free (request);
|
||||
|
||||
request = relay_http_request_alloc ();
|
||||
CHECK(request);
|
||||
relay_http_parse_method_path (request, "GET /api/buffers?test=1&var=abc HTTP/1.1");
|
||||
/* do it 2 times, to be sure it has no side effect */
|
||||
relay_http_parse_method_path (request, "GET /api/buffers?test=1&var=abc HTTP/1.1");
|
||||
LONGS_EQUAL(RELAY_HTTP_HEADERS, request->status);
|
||||
STRCMP_EQUAL("GET /api/buffers?test=1&var=abc HTTP/1.1\n"
|
||||
"GET /api/buffers?test=1&var=abc HTTP/1.1\n",
|
||||
*(request->raw));
|
||||
STRCMP_EQUAL("/api/buffers?test=1&var=abc", request->path);
|
||||
CHECK(request->path_items);
|
||||
STRCMP_EQUAL("api", request->path_items[0]);
|
||||
STRCMP_EQUAL("buffers", request->path_items[1]);
|
||||
POINTERS_EQUAL(NULL, request->path_items[2]);
|
||||
LONGS_EQUAL(2, request->num_path_items);
|
||||
LONGS_EQUAL(2, request->params->items_count);
|
||||
STRCMP_EQUAL("1", (const char *)hashtable_get (request->params, "test"));
|
||||
STRCMP_EQUAL("abc", (const char *)hashtable_get (request->params, "var"));
|
||||
STRCMP_EQUAL("HTTP/1.1", request->http_version);
|
||||
LONGS_EQUAL(0, request->headers->items_count);
|
||||
LONGS_EQUAL(0, request->accept_encoding->items_count);
|
||||
LONGS_EQUAL(0, request->content_length);
|
||||
LONGS_EQUAL(0, request->body_size);
|
||||
POINTERS_EQUAL(NULL, request->body);
|
||||
free (request);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_http_parse_header
|
||||
*/
|
||||
|
||||
TEST(RelayHttp, ParseHeader)
|
||||
{
|
||||
struct t_relay_http_request *request;
|
||||
|
||||
request = relay_http_request_alloc ();
|
||||
CHECK(request);
|
||||
relay_http_parse_method_path (request, "GET /api/version");
|
||||
relay_http_parse_header (request, NULL);
|
||||
LONGS_EQUAL(RELAY_HTTP_END, request->status);
|
||||
STRCMP_EQUAL("GET /api/version\n"
|
||||
"\n",
|
||||
*(request->raw));
|
||||
LONGS_EQUAL(0, request->headers->items_count);
|
||||
free (request);
|
||||
|
||||
request = relay_http_request_alloc ();
|
||||
CHECK(request);
|
||||
relay_http_parse_method_path (request, "GET /api/version");
|
||||
relay_http_parse_header (request, "");
|
||||
LONGS_EQUAL(RELAY_HTTP_END, request->status);
|
||||
STRCMP_EQUAL("GET /api/version\n"
|
||||
"\n",
|
||||
*(request->raw));
|
||||
LONGS_EQUAL(0, request->headers->items_count);
|
||||
free (request);
|
||||
|
||||
request = relay_http_request_alloc ();
|
||||
CHECK(request);
|
||||
relay_http_parse_method_path (request, "GET /api/version");
|
||||
relay_http_parse_header (request, "Test");
|
||||
LONGS_EQUAL(RELAY_HTTP_HEADERS, request->status);
|
||||
STRCMP_EQUAL("GET /api/version\n"
|
||||
"Test\n",
|
||||
*(request->raw));
|
||||
LONGS_EQUAL(0, request->headers->items_count);
|
||||
free (request);
|
||||
|
||||
request = relay_http_request_alloc ();
|
||||
CHECK(request);
|
||||
relay_http_parse_method_path (request, "GET /api/version");
|
||||
relay_http_parse_header (request, "X-Test: value");
|
||||
LONGS_EQUAL(RELAY_HTTP_HEADERS, request->status);
|
||||
STRCMP_EQUAL("GET /api/version\n"
|
||||
"X-Test: value\n",
|
||||
*(request->raw));
|
||||
LONGS_EQUAL(1, request->headers->items_count);
|
||||
STRCMP_EQUAL("value", (const char *)hashtable_get (request->headers, "x-test"));
|
||||
free (request);
|
||||
|
||||
request = relay_http_request_alloc ();
|
||||
CHECK(request);
|
||||
relay_http_parse_method_path (request, "GET /api/version");
|
||||
relay_http_parse_header (request, "Accept-Encoding: gzip, zstd, br");
|
||||
LONGS_EQUAL(RELAY_HTTP_HEADERS, request->status);
|
||||
STRCMP_EQUAL("GET /api/version\n"
|
||||
"Accept-Encoding: gzip, zstd, br\n",
|
||||
*(request->raw));
|
||||
LONGS_EQUAL(1, request->headers->items_count);
|
||||
STRCMP_EQUAL("gzip, zstd, br",
|
||||
(const char *)hashtable_get (request->headers, "accept-encoding"));
|
||||
LONGS_EQUAL(3, request->accept_encoding->items_count);
|
||||
CHECK(hashtable_has_key (request->accept_encoding, "gzip"));
|
||||
CHECK(hashtable_has_key (request->accept_encoding, "zstd"));
|
||||
CHECK(hashtable_has_key (request->accept_encoding, "br"));
|
||||
free (request);
|
||||
|
||||
request = relay_http_request_alloc ();
|
||||
CHECK(request);
|
||||
relay_http_parse_method_path (request, "GET /api/version");
|
||||
relay_http_parse_header (request, "Content-Length: 123");
|
||||
LONGS_EQUAL(RELAY_HTTP_HEADERS, request->status);
|
||||
STRCMP_EQUAL("GET /api/version\n"
|
||||
"Content-Length: 123\n",
|
||||
*(request->raw));
|
||||
LONGS_EQUAL(1, request->headers->items_count);
|
||||
LONGS_EQUAL(123, request->content_length);
|
||||
free (request);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_http_add_to_body
|
||||
*/
|
||||
|
||||
TEST(RelayHttp, AddToBody)
|
||||
{
|
||||
struct t_relay_http_request *request;
|
||||
const char *body_part1 = "abc", *body_part2 = "defghij";
|
||||
char *partial_message;
|
||||
|
||||
request = relay_http_request_alloc ();
|
||||
CHECK(request);
|
||||
LONGS_EQUAL(RELAY_HTTP_METHOD, request->status);
|
||||
relay_http_parse_method_path (request, "GET /api/version");
|
||||
LONGS_EQUAL(RELAY_HTTP_HEADERS, request->status);
|
||||
relay_http_parse_header (request, "Content-Length: 10");
|
||||
relay_http_parse_header (request, "");
|
||||
LONGS_EQUAL(RELAY_HTTP_BODY, request->status);
|
||||
LONGS_EQUAL(10, request->content_length);
|
||||
LONGS_EQUAL(0, request->body_size);
|
||||
|
||||
partial_message = strdup (body_part1);
|
||||
relay_http_add_to_body (request, &partial_message);
|
||||
LONGS_EQUAL(RELAY_HTTP_BODY, request->status);
|
||||
LONGS_EQUAL(3, request->body_size);
|
||||
MEMCMP_EQUAL("abc", request->body, 3);
|
||||
POINTERS_EQUAL(NULL, partial_message);
|
||||
|
||||
partial_message = strdup (body_part2);
|
||||
relay_http_add_to_body (request, &partial_message);
|
||||
LONGS_EQUAL(RELAY_HTTP_END, request->status);
|
||||
LONGS_EQUAL(10, request->body_size);
|
||||
MEMCMP_EQUAL("abcdefghij", request->body, 10);
|
||||
POINTERS_EQUAL(NULL, partial_message);
|
||||
|
||||
free (request);
|
||||
|
||||
request = relay_http_request_alloc ();
|
||||
CHECK(request);
|
||||
LONGS_EQUAL(RELAY_HTTP_METHOD, request->status);
|
||||
relay_http_parse_method_path (request, "GET /api/version");
|
||||
LONGS_EQUAL(RELAY_HTTP_HEADERS, request->status);
|
||||
relay_http_parse_header (request, "Content-Length: 5");
|
||||
relay_http_parse_header (request, "");
|
||||
LONGS_EQUAL(RELAY_HTTP_BODY, request->status);
|
||||
LONGS_EQUAL(5, request->content_length);
|
||||
LONGS_EQUAL(0, request->body_size);
|
||||
|
||||
partial_message = strdup (body_part1);
|
||||
relay_http_add_to_body (request, &partial_message);
|
||||
LONGS_EQUAL(RELAY_HTTP_BODY, request->status);
|
||||
LONGS_EQUAL(3, request->body_size);
|
||||
MEMCMP_EQUAL("abc", request->body, 3);
|
||||
POINTERS_EQUAL(NULL, partial_message);
|
||||
|
||||
partial_message = strdup (body_part2);
|
||||
relay_http_add_to_body (request, &partial_message);
|
||||
LONGS_EQUAL(RELAY_HTTP_END, request->status);
|
||||
LONGS_EQUAL(5, request->body_size);
|
||||
MEMCMP_EQUAL("abcde", request->body, 5);
|
||||
STRCMP_EQUAL("fghij", partial_message);
|
||||
free (partial_message);
|
||||
|
||||
free (request);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_http_check_auth
|
||||
*/
|
||||
|
||||
TEST(RelayHttp, CheckAuth)
|
||||
{
|
||||
struct t_relay_http_request *request;
|
||||
char *totp, *totp2;
|
||||
|
||||
config_file_option_set (relay_config_network_password, "secret_password", 1);
|
||||
|
||||
request = relay_http_request_alloc ();
|
||||
CHECK(request);
|
||||
|
||||
/* test password */
|
||||
LONGS_EQUAL(-1, relay_http_check_auth (request));
|
||||
hashtable_set (request->headers, "authorization", "Basic ");
|
||||
LONGS_EQUAL(-2, relay_http_check_auth (request));
|
||||
hashtable_set (request->headers, "authorization", "Basic \u26c4");
|
||||
LONGS_EQUAL(-2, relay_http_check_auth (request));
|
||||
/* set invalid user/password: "weechat:test" */
|
||||
hashtable_set (request->headers, "authorization", "Basic d2VlY2hhdDp0ZXN0");
|
||||
LONGS_EQUAL(-2, relay_http_check_auth (request));
|
||||
/* set valid user/password: "weechat:secret_password" */
|
||||
hashtable_set (request->headers,
|
||||
"authorization", "Basic d2VlY2hhdDpzZWNyZXRfcGFzc3dvcmQ");
|
||||
LONGS_EQUAL(0, relay_http_check_auth (request));
|
||||
|
||||
/* test missing/invalid TOTP */
|
||||
config_file_option_set (relay_config_network_totp_secret, "secretbase32", 1);
|
||||
config_file_option_set (relay_config_network_totp_window, "1", 1);
|
||||
LONGS_EQUAL(-3, relay_http_check_auth (request));
|
||||
totp = hook_info_get (NULL, "totp_generate", "secretbase32");
|
||||
CHECK(totp);
|
||||
totp2 = strdup (totp);
|
||||
totp2[0] = (totp2[0] == '1') ? '2' : '1';
|
||||
hashtable_set (request->headers, "x-weechat-totp", totp2);
|
||||
LONGS_EQUAL(-4, relay_http_check_auth (request));
|
||||
hashtable_set (request->headers, "x-weechat-totp", totp);
|
||||
LONGS_EQUAL(0, relay_http_check_auth (request));
|
||||
free (totp);
|
||||
free (totp2);
|
||||
config_file_option_reset (relay_config_network_totp_secret, 1);
|
||||
config_file_option_reset (relay_config_network_totp_window, 1);
|
||||
|
||||
config_file_option_reset (relay_config_network_password, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_http_process_websocket
|
||||
*/
|
||||
|
||||
TEST(RelayHttp, ProcessWebsocket)
|
||||
{
|
||||
/* TODO: write tests */
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_http_process_request
|
||||
*/
|
||||
|
||||
TEST(RelayHttp, ProcessRequest)
|
||||
{
|
||||
/* TODO: write tests */
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_http_recv
|
||||
*/
|
||||
|
||||
TEST(RelayHttp, Recv)
|
||||
{
|
||||
/* TODO: write tests */
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_http_compress
|
||||
*/
|
||||
|
||||
TEST(RelayHttp, Compress)
|
||||
{
|
||||
struct t_relay_http_request *request;
|
||||
char body[256], *buffer, encoding[256];
|
||||
int i, size;
|
||||
|
||||
request = relay_http_request_alloc ();
|
||||
|
||||
for (i = 0; i < (int)sizeof (body); i++)
|
||||
{
|
||||
body[i] = i % 64;
|
||||
}
|
||||
|
||||
hashtable_remove_all (request->accept_encoding);
|
||||
buffer = (char *)0x1;
|
||||
size = -1;
|
||||
buffer = relay_http_compress (request, NULL, 0, &size, NULL, 0);
|
||||
POINTERS_EQUAL(NULL, buffer);
|
||||
LONGS_EQUAL(0, size);
|
||||
|
||||
hashtable_remove_all (request->accept_encoding);
|
||||
buffer = (char *)0x1;
|
||||
size = -1;
|
||||
snprintf (encoding, sizeof (encoding), "test");
|
||||
buffer = relay_http_compress (request, NULL, 0, &size,
|
||||
encoding, sizeof (encoding));
|
||||
POINTERS_EQUAL(NULL, buffer);
|
||||
LONGS_EQUAL(0, size);
|
||||
STRCMP_EQUAL("", encoding);
|
||||
|
||||
/* no "Accept-Encoding" header was received => no compression */
|
||||
hashtable_remove_all (request->accept_encoding);
|
||||
buffer = (char *)0x1;
|
||||
size = -1;
|
||||
snprintf (encoding, sizeof (encoding), "test");
|
||||
buffer = relay_http_compress (request, body, sizeof (body), &size,
|
||||
encoding, sizeof (encoding));
|
||||
POINTERS_EQUAL(NULL, buffer);
|
||||
LONGS_EQUAL(0, size);
|
||||
STRCMP_EQUAL("", encoding);
|
||||
|
||||
/* "Accept-Encoding: gzip" => gzip compression */
|
||||
hashtable_remove_all (request->accept_encoding);
|
||||
hashtable_set (request->accept_encoding, "gzip", "");
|
||||
buffer = (char *)0x1;
|
||||
size = -1;
|
||||
snprintf (encoding, sizeof (encoding), "test");
|
||||
buffer = relay_http_compress (request, body, sizeof (body), &size,
|
||||
encoding, sizeof (encoding));
|
||||
CHECK(buffer);
|
||||
CHECK((size > 0) && (size < (int)sizeof (body)));
|
||||
STRCMP_EQUAL("Content-Encoding: gzip\r\n", encoding);
|
||||
free (buffer);
|
||||
|
||||
#ifdef HAVE_ZSTD
|
||||
/* "Accept-Encoding: gzip, zstd" => zstd compression */
|
||||
hashtable_remove_all (request->accept_encoding);
|
||||
hashtable_set (request->accept_encoding, "gzip", "");
|
||||
hashtable_set (request->accept_encoding, "zstd", "");
|
||||
buffer = (char *)0x1;
|
||||
size = -1;
|
||||
snprintf (encoding, sizeof (encoding), "test");
|
||||
buffer = relay_http_compress (request, body, sizeof (body), &size,
|
||||
encoding, sizeof (encoding));
|
||||
CHECK(buffer);
|
||||
CHECK((size > 0) && (size < (int)sizeof (body)));
|
||||
STRCMP_EQUAL("Content-Encoding: zstd\r\n", encoding);
|
||||
free (buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_http_send
|
||||
*/
|
||||
|
||||
TEST(RelayHttp, Send)
|
||||
{
|
||||
/* TODO: write tests */
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_http_send_json
|
||||
*/
|
||||
|
||||
TEST(RelayHttp, SendJson)
|
||||
{
|
||||
/* TODO: write tests */
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_http_send_error_json
|
||||
*/
|
||||
|
||||
TEST(RelayHttp, SendErrorJson)
|
||||
{
|
||||
/* TODO: write tests */
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_http_print_log
|
||||
*/
|
||||
|
||||
TEST(RelayHttp, PrintLog)
|
||||
{
|
||||
/* TODO: write tests */
|
||||
}
|
||||
@@ -6,10 +6,10 @@ index 48082f72f..b4de39476 100644
|
||||
-12
|
||||
+11
|
||||
diff --git a/debian-devel/control b/debian-devel/control
|
||||
index 4229b00f6..41addd80b 100644
|
||||
index a5d24b6a8..81ae98045 100644
|
||||
--- a/debian-devel/control
|
||||
+++ b/debian-devel/control
|
||||
@@ -5,17 +5,17 @@ Maintainer: Sébastien Helleu <flashcode@flashtux.org>
|
||||
@@ -5,24 +5,23 @@ Maintainer: Sébastien Helleu <flashcode@flashtux.org>
|
||||
Build-Depends:
|
||||
asciidoctor (>= 1.5.4),
|
||||
ruby-pygments.rb,
|
||||
@@ -31,6 +31,26 @@ index 4229b00f6..41addd80b 100644
|
||||
libxml2-dev,
|
||||
libcurl4-gnutls-dev,
|
||||
libgcrypt20-dev,
|
||||
libgnutls28-dev,
|
||||
libzstd-dev,
|
||||
- zlib1g-dev,
|
||||
- libcjson-dev
|
||||
+ zlib1g-dev
|
||||
Standards-Version: 4.6.2
|
||||
Homepage: https://weechat.org/
|
||||
Vcs-Git: https://salsa.debian.org/kolter/weechat.git
|
||||
diff --git a/debian-devel/rules b/debian-devel/rules
|
||||
index cab713c93..d2756333b 100755
|
||||
--- a/debian-devel/rules
|
||||
+++ b/debian-devel/rules
|
||||
@@ -8,6 +8,7 @@ override_dh_auto_configure:
|
||||
dh_auto_configure --buildsystem=cmake -- \
|
||||
-DCMAKE_INSTALL_PREFIX:FILEPATH=/usr \
|
||||
-DLIBDIR=/usr/lib/${DEB_HOST_MULTIARCH} \
|
||||
+ -DENABLE_CJSON:BOOL=OFF \
|
||||
-DENABLE_DOC:BOOL=ON \
|
||||
-DENABLE_MAN:BOOL=ON \
|
||||
-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo \
|
||||
diff --git a/debian-stable/compat b/debian-stable/compat
|
||||
index 48082f72f..b4de39476 100644
|
||||
--- a/debian-stable/compat
|
||||
@@ -39,10 +59,10 @@ index 48082f72f..b4de39476 100644
|
||||
-12
|
||||
+11
|
||||
diff --git a/debian-stable/control b/debian-stable/control
|
||||
index ad3f771b7..e88f167b8 100644
|
||||
index a75e6fee5..b39bf88dc 100644
|
||||
--- a/debian-stable/control
|
||||
+++ b/debian-stable/control
|
||||
@@ -5,17 +5,17 @@ Maintainer: Emmanuel Bouthenot <kolter@debian.org>
|
||||
@@ -5,24 +5,23 @@ Maintainer: Emmanuel Bouthenot <kolter@debian.org>
|
||||
Build-Depends:
|
||||
asciidoctor (>= 1.5.4),
|
||||
ruby-pygments.rb,
|
||||
@@ -64,3 +84,23 @@ index ad3f771b7..e88f167b8 100644
|
||||
libxml2-dev,
|
||||
libcurl4-gnutls-dev,
|
||||
libgcrypt20-dev,
|
||||
libgnutls28-dev,
|
||||
libzstd-dev,
|
||||
- zlib1g-dev,
|
||||
- libcjson-dev
|
||||
+ zlib1g-dev
|
||||
Standards-Version: 4.6.2
|
||||
Homepage: https://weechat.org/
|
||||
Vcs-Git: https://salsa.debian.org/kolter/weechat.git
|
||||
diff --git a/debian-stable/rules b/debian-stable/rules
|
||||
index cab713c93..d2756333b 100755
|
||||
--- a/debian-stable/rules
|
||||
+++ b/debian-stable/rules
|
||||
@@ -8,6 +8,7 @@ override_dh_auto_configure:
|
||||
dh_auto_configure --buildsystem=cmake -- \
|
||||
-DCMAKE_INSTALL_PREFIX:FILEPATH=/usr \
|
||||
-DLIBDIR=/usr/lib/${DEB_HOST_MULTIARCH} \
|
||||
+ -DENABLE_CJSON:BOOL=OFF \
|
||||
-DENABLE_DOC:BOOL=ON \
|
||||
-DENABLE_MAN:BOOL=ON \
|
||||
-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo \
|
||||
|
||||
+4
-1
@@ -61,7 +61,10 @@ zlib-devel"
|
||||
# 1. set prefix to /usr
|
||||
# 2. enable build of man pages and documentation
|
||||
#
|
||||
CYGCMAKE_ARGS="-DCMAKE_INSTALL_PREFIX=/usr -DENABLE_MAN=ON -DENABLE_DOC=ON"
|
||||
CYGCMAKE_ARGS="-DCMAKE_INSTALL_PREFIX=/usr \
|
||||
-DENABLE_CJSON=OFF \
|
||||
-DENABLE_MAN=ON \
|
||||
-DENABLE_DOC=ON"
|
||||
|
||||
PKG_IGNORE="
|
||||
etc/postinstall/weechat.sh
|
||||
|
||||
Reference in New Issue
Block a user