1
0
mirror of https://github.com/weechat/weechat.git synced 2026-06-26 04:46:37 +02:00

relay: add command /remote, add remote configuration in relay.conf (issue #2066)

This commit is contained in:
Sébastien Helleu
2024-02-10 22:30:03 +01:00
parent a89bc85dc0
commit 786f889251
25 changed files with 1487 additions and 99 deletions
+1
View File
@@ -41,6 +41,7 @@ New features::
* irc: add server option "autojoin_delay" (delay before autojoin), use option "command_delay" before execution of the command (issue #862)
* relay: add "api" protocol (HTTP REST API), add option relay.look.display_clients, change option type relay.look.auto_open_buffer to string, rename option relay.weechat.commands to relay.network.commands, add option relay.network.time_window (issue #2066)
* relay: add support of websocket extension "permessage-deflate" (issue #1549)
* relay: add command `/remote` to manage remote WeeChat relay servers and connect to them (issue #2066)
* script: add option `enable` in command `/script`
* script: add info "script_loaded"
+1
View File
@@ -335,6 +335,7 @@ WeeChat "core" is located in following directories:
|       relay-info.c | Relay info/infolists/hdata.
|       relay-network.c | Network functions for relay.
|       relay-raw.c | Relay raw buffer.
|       relay-remote.c | Relay remote.
|       relay-server.c | Relay server.
|       relay-upgrade.c | Save/restore of relay data when upgrading WeeChat.
|       relay-websocket.c | WebSocket server functions (RFC 6455).
+1
View File
@@ -337,6 +337,7 @@ Le cœur de WeeChat est situé dans les répertoires suivants :
|       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-remote.c | Relai distant.
|       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).
+2
View File
@@ -357,6 +357,8 @@ WeeChat "core" は以下のディレクトリに配置されています:
|       relay-info.c | relay の情報/インフォリスト/hdata
|       relay-network.c | relay 用のネットワーク関数
|       relay-raw.c | relay 生バッファ
// TRANSLATION MISSING
|       relay-remote.c | Relay remote.
|       relay-server.c | relay サーバ
|       relay-upgrade.c | WeeChat をアップグレードする際にデータを保存/回復
|       relay-websocket.c | リレー用の websocket サーバ関数 (RFC 6455)
+2
View File
@@ -337,6 +337,8 @@ WeeChat „језгро” се налази у следећим директо
|       relay-info.c | Релеј info/infolists/hdata.
|       relay-network.c | Мрежне функције за релеј.
|       relay-raw.c | Релеј сирови бафер.
// TRANSLATION MISSING
|       relay-remote.c | Relay remote.
|       relay-server.c | Релеј сервер.
|       relay-upgrade.c | Save/restore of relay data when upgrading WeeChat.
|       relay-websocket.c | WebSocket сервер функције (RFC 6455).
+2
View File
@@ -374,6 +374,8 @@ SET(WEECHAT_SOURCES
./src/plugins/relay/relay-network.h
./src/plugins/relay/relay-raw.c
./src/plugins/relay/relay-raw.h
./src/plugins/relay/relay-remote.c
./src/plugins/relay/relay-remote.h
./src/plugins/relay/relay-server.c
./src/plugins/relay/relay-server.h
./src/plugins/relay/relay-upgrade.c
+1
View File
@@ -29,6 +29,7 @@ set(RELAY_SRC
relay-info.c relay-info.h
relay-network.c relay-network.h
relay-raw.c relay-raw.h
relay-remote.c relay-remote.h
relay-server.c relay-server.h
relay-upgrade.c relay-upgrade.h
relay-websocket.c relay-websocket.h
+1 -1
View File
@@ -808,7 +808,7 @@ relay_api_protocol_recv_http (struct t_relay_client *client)
{ NULL, NULL, 0, 0, 0, NULL },
};
if (!client->http_req || RELAY_CLIENT_HAS_ENDED(client))
if (!client->http_req || RELAY_STATUS_HAS_ENDED(client->status))
return;
/* display debug message */
+7 -5
View File
@@ -208,14 +208,16 @@ relay_api_alloc_with_infolist (struct t_relay_client *client,
RELAY_API_DATA(client, sync_colors) = weechat_infolist_integer (
infolist, "sync_colors");
if (!RELAY_CLIENT_HAS_ENDED(client) && RELAY_API_DATA(client, sync_enabled))
if (!RELAY_STATUS_HAS_ENDED(client->status)
&& 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.
* Returns the client initial status: it is always "authenticating" for API
* protocol because we always expect the client to authenticate.
*/
enum t_relay_status
@@ -224,7 +226,7 @@ relay_api_get_initial_status (struct t_relay_client *client)
/* make C compiler happy */
(void) client;
return RELAY_STATUS_WAITING_AUTH;
return RELAY_STATUS_AUTHENTICATING;
}
/*
+3 -3
View File
@@ -2298,7 +2298,7 @@ relay_irc_alloc_with_infolist (struct t_relay_client *client,
}
/*
* Returns the client initial status: it can be "waiting_auth" or "connected",
* Returns the client initial status: it can be "authenticating" or "connected",
* depending if a password is expected or not.
*/
@@ -2306,7 +2306,7 @@ enum t_relay_status
relay_irc_get_initial_status (struct t_relay_client *client)
{
return (RELAY_IRC_DATA(client, password_ok)) ?
RELAY_STATUS_CONNECTED : RELAY_STATUS_WAITING_AUTH;
RELAY_STATUS_CONNECTED : RELAY_STATUS_AUTHENTICATING;
}
/*
@@ -2360,7 +2360,7 @@ relay_irc_add_to_infolist (struct t_infolist_item *item,
if (!item || !client)
return 0;
if (!RELAY_CLIENT_HAS_ENDED(client) && force_disconnected_state)
if (!RELAY_STATUS_HAS_ENDED(client->status) && force_disconnected_state)
{
if (!weechat_infolist_new_var_integer (item, "connected", 0))
return 0;
+6 -6
View File
@@ -77,11 +77,11 @@ relay_buffer_refresh (const char *hotlist)
weechat_color ("lightgreen"),
/* disconnect */
(client_selected
&& !RELAY_CLIENT_HAS_ENDED(client_selected)) ?
&& !RELAY_STATUS_HAS_ENDED(client_selected->status)) ?
_(" [D] Disconnect") : "",
/* remove */
(client_selected
&& RELAY_CLIENT_HAS_ENDED(client_selected)) ?
&& RELAY_STATUS_HAS_ENDED(client_selected->status)) ?
_(" [R] Remove") : "",
/* purge old */
_(" [P] Purge finished"),
@@ -98,7 +98,7 @@ relay_buffer_refresh (const char *hotlist)
weechat_config_string (relay_config_color_text_bg));
snprintf (str_status, sizeof (str_status),
"%s", _(relay_client_status_string[ptr_client->status]));
"%s", _(relay_status_string[ptr_client->status]));
length = weechat_utf8_strlen_screen (str_status);
if (length < 20)
{
@@ -191,7 +191,7 @@ relay_buffer_input_cb (const void *pointer, void *data,
/* disconnect client */
if (weechat_strcmp (input_data, "d") == 0)
{
if (client && !RELAY_CLIENT_HAS_ENDED(client))
if (client && !RELAY_STATUS_HAS_ENDED(client->status))
{
relay_client_disconnect (client);
relay_buffer_refresh (WEECHAT_HOTLIST_MESSAGE);
@@ -204,7 +204,7 @@ relay_buffer_input_cb (const void *pointer, void *data,
while (ptr_client)
{
next_client = ptr_client->next_client;
if (RELAY_CLIENT_HAS_ENDED(ptr_client))
if (RELAY_STATUS_HAS_ENDED(ptr_client->status))
relay_client_free (ptr_client);
ptr_client = next_client;
}
@@ -218,7 +218,7 @@ relay_buffer_input_cb (const void *pointer, void *data,
/* remove client */
else if (weechat_strcmp (input_data, "r") == 0)
{
if (client && RELAY_CLIENT_HAS_ENDED(client))
if (client && RELAY_STATUS_HAS_ENDED(client->status))
{
relay_client_free (client);
relay_buffer_refresh (WEECHAT_HOTLIST_MESSAGE);
+11 -44
View File
@@ -49,15 +49,6 @@
#include "weechat/relay-weechat.h"
char *relay_client_status_string[] = /* status strings for display */
{ N_("connecting"), N_("waiting auth"),
N_("connected"), N_("auth failed"), N_("disconnected")
};
char *relay_client_status_name[] = /* name of status (for signal/info) */
{ "connecting", "waiting_auth",
"connected", "auth_failed", "disconnected"
};
char *relay_client_data_type_string[] = /* strings for data types */
{ "text", "binary", "http" };
@@ -143,30 +134,6 @@ relay_client_search_by_id (int id)
return NULL;
}
/*
* Searches for a client status.
*
* Returns index of status in enum t_relay_status, -1 if status is not found.
*/
int
relay_client_status_search (const char *name)
{
int i;
if (!name)
return -1;
for (i = 0; i < RELAY_NUM_STATUS; i++)
{
if (strcmp (relay_client_status_name[i], name) == 0)
return i;
}
/* status not found */
return -1;
}
/*
* Returns the number of active clients (connecting or connected) on a given
* server port.
@@ -183,7 +150,7 @@ relay_client_count_active_by_port (int server_port)
ptr_client = ptr_client->next_client)
{
if ((ptr_client->server_port == server_port)
&& !RELAY_CLIENT_HAS_ENDED(ptr_client))
&& !RELAY_STATUS_HAS_ENDED(ptr_client->status))
{
count++;
}
@@ -203,7 +170,7 @@ relay_client_send_signal (struct t_relay_client *client)
snprintf (signal, sizeof (signal),
"relay_client_%s",
relay_client_status_name[client->status]);
relay_status_name[client->status]);
weechat_hook_signal_send (signal, WEECHAT_HOOK_SIGNAL_POINTER, client);
}
@@ -761,7 +728,7 @@ relay_client_recv_cb (const void *pointer, void *data, int fd)
* data can be received only during authentication
* or if connected (authentication was OK)
*/
if ((client->status != RELAY_STATUS_WAITING_AUTH)
if ((client->status != RELAY_STATUS_AUTHENTICATING)
&& (client->status != RELAY_STATUS_CONNECTED))
{
return WEECHAT_RC_OK;
@@ -1361,7 +1328,7 @@ relay_client_timer_cb (const void *pointer, void *data, int remaining_calls)
{
ptr_next_client = ptr_client->next_client;
if (RELAY_CLIENT_HAS_ENDED(ptr_client))
if (RELAY_STATUS_HAS_ENDED(ptr_client->status))
{
if ((purge_delay >= 0)
&& (current_time >= ptr_client->end_time + (purge_delay * 60)))
@@ -1377,7 +1344,7 @@ relay_client_timer_cb (const void *pointer, void *data, int remaining_calls)
/* disconnect clients not authenticated */
if ((auth_timeout > 0)
&& (ptr_client->status == RELAY_STATUS_WAITING_AUTH))
&& (ptr_client->status == RELAY_STATUS_AUTHENTICATING))
{
if (current_time - ptr_client->start_time > auth_timeout)
{
@@ -1576,7 +1543,7 @@ relay_client_new (int sock, const char *address, struct t_relay_server *server)
RELAY_COLOR_CHAT_CLIENT,
new_client->desc,
RELAY_COLOR_CHAT,
_(relay_client_status_string[new_client->status]));
_(relay_status_string[new_client->status]));
}
else
{
@@ -1588,7 +1555,7 @@ relay_client_new (int sock, const char *address, struct t_relay_server *server)
RELAY_COLOR_CHAT_CLIENT,
new_client->desc,
RELAY_COLOR_CHAT,
_(relay_client_status_string[new_client->status]));
_(relay_status_string[new_client->status]));
}
}
@@ -1818,7 +1785,7 @@ relay_client_set_status (struct t_relay_client *client,
client->desc,
RELAY_COLOR_CHAT);
}
else if (RELAY_CLIENT_HAS_ENDED(client))
else if (RELAY_STATUS_HAS_ENDED(client->status))
{
client->end_time = time (NULL);
@@ -2069,7 +2036,7 @@ relay_client_add_to_infolist (struct t_infolist *infolist,
return 0;
if (!weechat_infolist_new_var_string (ptr_item, "desc", client->desc))
return 0;
if (!RELAY_CLIENT_HAS_ENDED(client) && force_disconnected_state)
if (!RELAY_STATUS_HAS_ENDED(client->status) && force_disconnected_state)
{
if (!weechat_infolist_new_var_integer (ptr_item, "sock", -1))
return 0;
@@ -2156,7 +2123,7 @@ relay_client_add_to_infolist (struct t_infolist *infolist,
return 0;
if (!weechat_infolist_new_var_string (ptr_item, "real_ip", client->real_ip))
return 0;
if (!weechat_infolist_new_var_string (ptr_item, "status_string", relay_client_status_string[client->status]))
if (!weechat_infolist_new_var_string (ptr_item, "status_string", relay_status_string[client->status]))
return 0;
if (!weechat_infolist_new_var_integer (ptr_item, "protocol", client->protocol))
return 0;
@@ -2244,7 +2211,7 @@ relay_client_print_log ()
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]);
relay_status_string[ptr_client->status]);
weechat_log_printf (" protocol. . . . . . . . . : %d (%s)",
ptr_client->protocol,
relay_protocol_string[ptr_client->protocol]);
-22
View File
@@ -27,19 +27,6 @@
struct t_relay_server;
struct t_relay_http_request;
/* relay status */
enum t_relay_status
{
RELAY_STATUS_CONNECTING = 0, /* connecting to client */
RELAY_STATUS_WAITING_AUTH, /* waiting AUTH from client */
RELAY_STATUS_CONNECTED, /* connected to client */
RELAY_STATUS_AUTH_FAILED, /* AUTH failed with client */
RELAY_STATUS_DISCONNECTED, /* disconnected from client */
/* number of relay status */
RELAY_NUM_STATUS,
};
/* type of data exchanged with client */
enum t_relay_client_data_type
@@ -75,12 +62,6 @@ enum t_relay_client_msg_type
RELAY_NUM_CLIENT_MSG_TYPES,
};
/* macros for status */
#define RELAY_CLIENT_HAS_ENDED(client) \
((client->status == RELAY_STATUS_AUTH_FAILED) || \
(client->status == RELAY_STATUS_DISCONNECTED))
/* fake send function (for tests) */
typedef void (t_relay_fake_send_func)(void *client,
@@ -146,8 +127,6 @@ struct t_relay_client
struct t_relay_client *next_client;/* link to next client */
};
extern char *relay_client_status_string[];
extern char *relay_client_status_name[];
extern char *relay_client_msg_type_string[];
extern struct t_relay_client *relay_clients;
extern struct t_relay_client *last_relay_client;
@@ -156,7 +135,6 @@ extern int relay_client_count;
extern int relay_client_valid (struct t_relay_client *client);
extern struct t_relay_client *relay_client_search_by_number (int number);
extern struct t_relay_client *relay_client_search_by_id (int id);
extern int relay_client_status_search (const char *name);
extern int relay_client_count_active_by_port (int server_port);
extern void relay_client_set_desc (struct t_relay_client *client);
extern void relay_client_recv_buffer (struct t_relay_client *client,
+355 -6
View File
@@ -1,5 +1,5 @@
/*
* relay-command.c - relay command
* relay-command.c - relay commands
*
* Copyright (C) 2003-2024 Sébastien Helleu <flashcode@flashtux.org>
*
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <time.h>
#include "../weechat-plugin.h"
@@ -30,6 +31,7 @@
#include "relay-config.h"
#include "relay-network.h"
#include "relay-raw.h"
#include "relay-remote.h"
#include "relay-server.h"
@@ -49,7 +51,7 @@ relay_command_client_list (int full)
for (ptr_client = relay_clients; ptr_client;
ptr_client = ptr_client->next_client)
{
if (!full && RELAY_CLIENT_HAS_ENDED(ptr_client))
if (!full && RELAY_STATUS_HAS_ENDED(ptr_client->status))
continue;
if (num_found == 0)
@@ -89,7 +91,7 @@ relay_command_client_list (int full)
ptr_client->desc,
RELAY_COLOR_CHAT,
weechat_color (weechat_config_string (relay_config_color_status[ptr_client->status])),
relay_client_status_string[ptr_client->status],
relay_status_string[ptr_client->status],
RELAY_COLOR_CHAT,
date_start,
date_activity,
@@ -104,7 +106,7 @@ relay_command_client_list (int full)
ptr_client->desc,
RELAY_COLOR_CHAT,
weechat_color (weechat_config_string (relay_config_color_status[ptr_client->status])),
relay_client_status_string[ptr_client->status],
relay_status_string[ptr_client->status],
RELAY_COLOR_CHAT,
date_start);
}
@@ -386,6 +388,309 @@ relay_command_relay (const void *pointer, void *data,
return WEECHAT_RC_OK;
}
/*
* Displays a relay remote.
*/
void
relay_command_display_remote (struct t_relay_remote *remote, int with_detail)
{
if (with_detail)
{
weechat_printf (NULL, "");
weechat_printf (NULL, _("Remote: %s"), remote->name);
weechat_printf (NULL, " url. . . . . . . . . : '%s'",
weechat_config_string (remote->options[RELAY_REMOTE_OPTION_URL]));
weechat_printf (NULL, " password . . . . . . : '%s'",
weechat_config_string (remote->options[RELAY_REMOTE_OPTION_PASSWORD]));
weechat_printf (NULL, " totp_secret. . . . . : '%s'",
weechat_config_string (remote->options[RELAY_REMOTE_OPTION_TOTP_SECRET]));
}
else
{
weechat_printf (
NULL,
" %s: %s",
remote->name,
weechat_config_string (remote->options[RELAY_REMOTE_OPTION_URL]));
}
}
/*
* Callback for command "/remote".
*/
int
relay_command_remote (const void *pointer, void *data,
struct t_gui_buffer *buffer, int argc,
char **argv, char **argv_eol)
{
struct t_relay_remote *ptr_remote, *ptr_remote2;
int i, detailed_list, one_remote_found;
const char *ptr_password, *ptr_totp_secret;
char *remote_name;
/* make C compiler happy */
(void) pointer;
(void) data;
(void) buffer;
if ((argc == 1)
|| (weechat_strcmp (argv[1], "list") == 0)
|| (weechat_strcmp (argv[1], "listfull") == 0))
{
/* list remotes */
remote_name = NULL;
detailed_list = 0;
for (i = 1; i < argc; i++)
{
if (weechat_strcmp (argv[i], "list") == 0)
continue;
if (weechat_strcmp (argv[i], "listfull") == 0)
{
detailed_list = 1;
continue;
}
if (!remote_name)
remote_name = argv[i];
}
if (remote_name)
{
one_remote_found = 0;
for (ptr_remote = relay_remotes; ptr_remote;
ptr_remote = ptr_remote->next_remote)
{
if (strstr (ptr_remote->name, remote_name))
{
if (!one_remote_found)
{
weechat_printf (NULL, "");
weechat_printf (NULL,
_("Relay remotes with \"%s\":"),
remote_name);
}
one_remote_found = 1;
relay_command_display_remote (ptr_remote, detailed_list);
}
}
if (!one_remote_found)
{
weechat_printf (NULL,
_("No relay remote found with \"%s\""),
remote_name);
}
}
else
{
if (relay_remotes)
{
weechat_printf (NULL, "");
weechat_printf (NULL, _("All relay remotes:"));
for (ptr_remote = relay_remotes; ptr_remote;
ptr_remote = ptr_remote->next_remote)
{
relay_command_display_remote (ptr_remote, detailed_list);
}
}
else
weechat_printf (NULL, _("No relay remote"));
}
return WEECHAT_RC_OK;
}
if (weechat_strcmp (argv[1], "add") == 0)
{
WEECHAT_COMMAND_MIN_ARGS(4, "add");
ptr_remote = relay_remote_search (argv[2]);
if (ptr_remote)
{
weechat_printf (
NULL,
_("%s%s: remote \"%s\" already exists, can't add it!"),
weechat_prefix ("error"), RELAY_PLUGIN_NAME, ptr_remote->name);
return WEECHAT_RC_OK;
}
if (!relay_remote_name_valid (argv[2]))
{
weechat_printf (NULL,
_("%s%s: invalid remote name: \"%s\""),
weechat_prefix ("error"),
RELAY_PLUGIN_NAME,
argv[2]);
return WEECHAT_RC_OK;
}
if (!relay_remote_url_valid (argv[3]))
{
weechat_printf (NULL,
_("%s%s: invalid remote URL: \"%s\""),
weechat_prefix ("error"),
RELAY_PLUGIN_NAME,
argv[3]);
return WEECHAT_RC_OK;
}
ptr_password = NULL;
ptr_totp_secret = NULL;
for (i = 4; i < argc; i++)
{
if (strncmp (argv[i], "-password=", 10) == 0)
{
ptr_password = argv[i] + 10;
}
else if (strncmp (argv[i], "-totp_secret=", 13) == 0)
{
ptr_totp_secret = argv[i] + 13;
}
else
{
weechat_printf (NULL,
_("%s%s: invalid remote option: \"%s\""),
weechat_prefix ("error"),
RELAY_PLUGIN_NAME,
argv[i]);
return WEECHAT_RC_OK;
}
}
ptr_remote = relay_remote_new (
argv[2],
argv[3],
(ptr_password) ? ptr_password : "",
(ptr_totp_secret) ? ptr_totp_secret : "");
if (ptr_remote)
{
weechat_printf (NULL, _("Remote \"%s\" created"), argv[2]);
}
else
{
weechat_printf (
NULL,
_("%s%s: failed to create remote \"%s\""),
weechat_prefix ("error"), RELAY_PLUGIN_NAME,
argv[2]);
}
return WEECHAT_RC_OK;
}
if (weechat_strcmp (argv[1], "connect") == 0)
{
WEECHAT_COMMAND_MIN_ARGS(3, "connect");
ptr_remote = relay_remote_search (argv[2]);
if (!ptr_remote)
{
weechat_printf (
NULL,
_("%s%s: remote \"%s\" not found for \"%s\" command"),
weechat_prefix ("error"),
RELAY_PLUGIN_NAME,
argv[2],
"remote connect");
return WEECHAT_RC_OK;
}
WEECHAT_COMMAND_ERROR;
}
if (weechat_strcmp (argv[1], "rename") == 0)
{
WEECHAT_COMMAND_MIN_ARGS(4, "rename");
/* look for remote by name */
ptr_remote = relay_remote_search (argv[2]);
if (!ptr_remote)
{
weechat_printf (
NULL,
_("%s%s: remote \"%s\" not found for \"%s\" command"),
weechat_prefix ("error"),
RELAY_PLUGIN_NAME,
argv[2],
"remote rename");
return WEECHAT_RC_OK;
}
/* check if target name already exists */
ptr_remote2 = relay_remote_search (argv[3]);
if (ptr_remote2)
{
weechat_printf (
NULL,
_("%s%s: remote \"%s\" already exists for \"%s\" command"),
weechat_prefix ("error"),
RELAY_PLUGIN_NAME,
ptr_remote2->name,
"server rename");
return WEECHAT_RC_OK;
}
/* rename remote */
if (relay_remote_rename (ptr_remote, argv[3]))
{
weechat_printf (
NULL,
_("%s: remote \"%s\" has been renamed to \"%s\""),
RELAY_PLUGIN_NAME,
argv[2],
argv[3]);
return WEECHAT_RC_OK;
}
WEECHAT_COMMAND_ERROR;
}
if (weechat_strcmp (argv[1], "del") == 0)
{
WEECHAT_COMMAND_MIN_ARGS(3, "del");
/* look for remote by name */
ptr_remote = relay_remote_search (argv[2]);
if (!ptr_remote)
{
weechat_printf (
NULL,
_("%s%s: remote \"%s\" not found for \"%s\" command"),
weechat_prefix ("error"),
RELAY_PLUGIN_NAME,
argv[2],
"remote del");
return WEECHAT_RC_OK;
}
if (!RELAY_STATUS_HAS_ENDED(ptr_remote->status))
{
weechat_printf (
NULL,
_("%s%s: you can not delete remote \"%s\" because you are "
"connected to. Try \"/remote disconnect %s\" before."),
weechat_prefix ("error"),
RELAY_PLUGIN_NAME,
argv[2],
argv[2]);
return WEECHAT_RC_OK;
}
remote_name = strdup (ptr_remote->name);
relay_remote_free (ptr_remote);
weechat_printf (
NULL,
_("%s: remote \"%s\" has been deleted"),
RELAY_PLUGIN_NAME,
(remote_name) ? remote_name : "???");
if (remote_name)
free (remote_name);
return WEECHAT_RC_OK;
}
WEECHAT_COMMAND_ERROR;
}
/*
* Hooks command.
*/
@@ -435,8 +740,13 @@ relay_command_init ()
"",
N_("The \"irc\" protocol allows any IRC client (including WeeChat "
"itself) to connect on the port."),
N_("The \"weechat\" protocol allows a remote interface to connect on "
"the port, see the list here: https://weechat.org/about/interfaces/"),
N_("The \"api\" protocol allows a remote interface (including "
"WeeChat itself) to connect on the port."),
N_("The \"weechat\" protocol allows a remote interface "
"(but not WeeChat itself) to connect on the port."),
"",
N_("The list of remote interfaces is here: "
"https://weechat.org/about/interfaces/"),
"",
N_("Without argument, this command opens buffer with list of relay "
"clients."),
@@ -462,4 +772,43 @@ relay_command_init ()
" || raw"
" || tlscertkey",
&relay_command_relay, NULL, NULL);
weechat_hook_command (
"remote",
N_("control of remote relay servers"),
/* TRANSLATORS: only text between angle brackets (eg: "<name>") must be translated */
N_("list|listfull [<name>]"
" || add <name> <url> [-<option>[=<value>]]"
" || connect <name>"
" || rename <name> <new_name>"
" || del <name>"),
WEECHAT_CMD_ARGS_DESC(
N_("raw[list]: list remote relay servers"),
N_("raw[listfull]: list remote relay servers (verbose)"),
N_("raw[add]: add a remote relay server"),
N_("name: name of remote relay server, for internal and display use; "
"this name is used to connect to the server and to set server "
"options: relay.remote.name.xxx"),
N_("url: URL of the remote, format is https://example.com:9000 "
"or http://example.com:9000 (plain-text connection, not recommended)"),
N_("option: set option for remote: password or totp_secret"),
N_("raw[connect]: connect to a remote relay server"),
N_("raw[rename]: rename a remote relay server"),
N_("raw[del]: delete a remote relay server"),
"",
N_("Without argument, this command opens buffer with list of relay "
"clients."),
"",
N_("Examples:"),
AI(" /remote add example https://localhost:9000 "
"-password=my_secret_password -totp_secret=secrettotp"),
AI(" /remote connect example"),
AI(" /remote del example")),
"list %(relay_remotes)"
" || listfull %(relay_remotes)"
" || add %(relay_remotes) https://localhost:9000 "
"-password=${xxx}|-totp_secret=${xxx}|%*"
" || connect %(relay_remotes)"
" || rename %(relay_remotes) %(relay_remotes)"
" || del %(relay_remotes)",
&relay_command_remote, NULL, NULL);
}
+33
View File
@@ -25,6 +25,7 @@
#include "../weechat-plugin.h"
#include "relay.h"
#include "relay-remote.h"
#include "relay-server.h"
@@ -155,6 +156,35 @@ relay_completion_free_port_cb (const void *pointer, void *data,
return WEECHAT_RC_OK;
}
/*
* Adds relay remotes to completion list.
*/
int
relay_completion_remotes_cb (const void *pointer, void *data,
const char *completion_item,
struct t_gui_buffer *buffer,
struct t_gui_completion *completion)
{
struct t_relay_remote *ptr_remote;
/* make C compiler happy */
(void) pointer;
(void) data;
(void) buffer;
(void) completion_item;
for (ptr_remote = relay_remotes; ptr_remote;
ptr_remote = ptr_remote->next_remote)
{
weechat_completion_list_add (completion,
ptr_remote->name,
0, WEECHAT_LIST_POS_SORT);
}
return WEECHAT_RC_OK;
}
/*
* Hooks completions.
*/
@@ -172,4 +202,7 @@ relay_completion_init ()
weechat_hook_completion ("relay_free_port",
N_("first free port for relay plugin"),
&relay_completion_free_port_cb, NULL, NULL);
weechat_hook_completion ("relay_remotes",
N_("relay remotes"),
&relay_completion_remotes_cb, NULL, NULL);
}
+230 -4
View File
@@ -21,6 +21,7 @@
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <regex.h>
@@ -31,10 +32,11 @@
#include "../weechat-plugin.h"
#include "relay.h"
#include "relay-config.h"
#include "relay-client.h"
#include "relay-config.h"
#include "relay-buffer.h"
#include "relay-network.h"
#include "relay-remote.h"
#include "relay-server.h"
#include "irc/relay-irc.h"
@@ -49,6 +51,7 @@ struct t_config_section *relay_config_section_network = NULL;
struct t_config_section *relay_config_section_irc = NULL;
struct t_config_section *relay_config_section_port = NULL;
struct t_config_section *relay_config_section_path = NULL;
struct t_config_section *relay_config_section_remote = NULL;
/* relay config, look section */
@@ -959,6 +962,217 @@ relay_config_create_option_port_path (const void *pointer, void *data,
return rc;
}
/*
* Creates an option for a remote.
*
* Returns pointer to new option, NULL if error.
*/
struct t_config_option *
relay_config_create_remote_option (const char *remote_name, int index_option,
const char *value)
{
struct t_config_option *ptr_option;
int length;
char *option_name;
ptr_option = NULL;
length = strlen (remote_name) + 1 +
strlen (relay_remote_option_string[index_option]) + 1;
option_name = malloc (length);
if (!option_name)
return NULL;
snprintf (option_name, length, "%s.%s",
remote_name, relay_remote_option_string[index_option]);
switch (index_option)
{
case RELAY_REMOTE_OPTION_URL:
ptr_option = weechat_config_new_option (
relay_config_file, relay_config_section_remote,
option_name, "string",
N_("remote URL"),
NULL, 0, 0, value, NULL, 0,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
break;
case RELAY_REMOTE_OPTION_PASSWORD:
ptr_option = weechat_config_new_option (
relay_config_file, relay_config_section_remote,
option_name, "string",
N_("password"),
NULL, 0, 0, value, NULL, 0,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
break;
case RELAY_REMOTE_OPTION_TOTP_SECRET:
ptr_option = weechat_config_new_option (
relay_config_file, relay_config_section_remote,
option_name, "string",
N_("TOTP secret"),
NULL, 0, 0, value, NULL, 0,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
break;
case RELAY_REMOTE_NUM_OPTIONS:
break;
}
free (option_name);
return ptr_option;
}
/*
* Creates option for a temporary remote (when reading configuration file).
*/
void
relay_config_create_option_temp (struct t_relay_remote *temp_remote,
int index_option, const char *value)
{
struct t_config_option *new_option;
new_option = relay_config_create_remote_option (temp_remote->name,
index_option, value);
if (new_option
&& (index_option >= 0) && (index_option < RELAY_REMOTE_NUM_OPTIONS))
{
temp_remote->options[index_option] = new_option;
}
}
/*
* Uses temporary remotes (created by reading configuration file).
*/
void
relay_config_use_temp_remotes ()
{
struct t_relay_remote *ptr_temp_remote, *next_temp_remote;
int i, num_options_ok;
for (ptr_temp_remote = relay_remotes_temp; ptr_temp_remote;
ptr_temp_remote = ptr_temp_remote->next_remote)
{
num_options_ok = 0;
for (i = 0; i < RELAY_REMOTE_NUM_OPTIONS; i++)
{
if (!ptr_temp_remote->options[i])
{
ptr_temp_remote->options[i] =
relay_config_create_remote_option (
ptr_temp_remote->name,
i,
relay_remote_option_default[i]);
}
if (ptr_temp_remote->options[i])
num_options_ok++;
}
if (num_options_ok == RELAY_REMOTE_NUM_OPTIONS)
{
relay_remote_new_with_options (ptr_temp_remote->name,
ptr_temp_remote->options);
}
else
{
for (i = 0; i < RELAY_REMOTE_NUM_OPTIONS; i++)
{
if (ptr_temp_remote->options[i])
{
weechat_config_option_free (ptr_temp_remote->options[i]);
ptr_temp_remote->options[i] = NULL;
}
}
}
}
/* free all temporary remotes */
while (relay_remotes_temp)
{
next_temp_remote = relay_remotes_temp->next_remote;
if (relay_remotes_temp->name)
free (relay_remotes_temp->name);
free (relay_remotes_temp);
relay_remotes_temp = next_temp_remote;
}
last_relay_remote_temp = NULL;
}
/*
* Reads a remote option in relay configuration file.
*/
int
relay_config_remote_read_cb (const void *pointer, void *data,
struct t_config_file *config_file,
struct t_config_section *section,
const char *option_name, const char *value)
{
char *pos_option, *remote_name;
struct t_relay_remote *ptr_temp_remote;
int index_option;
/* make C compiler happy */
(void) pointer;
(void) data;
(void) config_file;
(void) section;
if (!option_name)
return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE;
pos_option = strchr (option_name, '.');
if (!pos_option)
return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE;
remote_name = weechat_strndup (option_name, pos_option - option_name);
if (!remote_name)
return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE;
pos_option++;
/* search temporary remote */
for (ptr_temp_remote = relay_remotes_temp; ptr_temp_remote;
ptr_temp_remote = ptr_temp_remote->next_remote)
{
if (strcmp (ptr_temp_remote->name, remote_name) == 0)
break;
}
if (!ptr_temp_remote)
{
/* create new temporary remote */
ptr_temp_remote = relay_remote_alloc (remote_name);
if (ptr_temp_remote)
relay_remote_add (ptr_temp_remote, &relay_remotes_temp, &last_relay_remote_temp);
}
if (ptr_temp_remote)
{
index_option = relay_remote_search_option (pos_option);
if (index_option >= 0)
{
relay_config_create_option_temp (ptr_temp_remote, index_option,
value);
}
else
{
weechat_printf (NULL,
_("%sWarning: unknown option for section \"%s\": "
"%s (value: \"%s\")"),
weechat_prefix ("error"),
RELAY_CONFIG_SECTION_REMOTE,
option_name, value);
}
}
free (remote_name);
return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE;
}
/*
* Reloads relay configuration file.
*/
@@ -1196,10 +1410,10 @@ relay_config_init ()
NULL, NULL, NULL,
&relay_config_refresh_cb, NULL, NULL,
NULL, NULL, NULL);
relay_config_color_status[RELAY_STATUS_WAITING_AUTH] = weechat_config_new_option (
relay_config_color_status[RELAY_STATUS_AUTHENTICATING] = weechat_config_new_option (
relay_config_file, relay_config_section_color,
"status_waiting_auth", "color",
N_("text color for \"waiting authentication\" status"),
"status_authenticating", "color",
N_("text color for \"authenticating\" status"),
NULL, 0, 0, "yellow", NULL, 0,
NULL, NULL, NULL,
&relay_config_refresh_cb, NULL, NULL,
@@ -1518,6 +1732,17 @@ relay_config_init ()
&relay_config_create_option_port_path, NULL, NULL,
NULL, NULL, NULL);
/* remote */
relay_config_section_remote = weechat_config_new_section (
relay_config_file,
RELAY_CONFIG_SECTION_REMOTE,
0, 0,
&relay_config_remote_read_cb, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL);
return 1;
}
@@ -1538,6 +1763,7 @@ relay_config_read ()
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);
relay_config_use_temp_remotes ();
}
return rc;
}
+4
View File
@@ -24,6 +24,7 @@
#define RELAY_CONFIG_NAME "relay"
#define RELAY_CONFIG_PRIO_NAME (TO_STR(RELAY_PLUGIN_PRIORITY) "|" RELAY_CONFIG_NAME)
#define RELAY_CONFIG_SECTION_REMOTE "remote"
#define RELAY_CONFIG_VERSION 2
@@ -85,6 +86,9 @@ extern int relay_config_create_option_port_path (const void *pointer, void *data
const char *value);
extern int relay_config_check_path_length (const char *path);
extern int relay_config_check_path_available (const char *path);
extern struct t_config_option *relay_config_create_remote_option (const char *remote_name,
int index_option,
const char *value);
extern int relay_config_init ();
extern int relay_config_read ();
extern int relay_config_write ();
+2 -2
View File
@@ -69,7 +69,7 @@ relay_info_info_relay_client_count_cb (const void *pointer, void *data,
protocol = relay_protocol_search (items[0]);
if (protocol < 0)
{
status = relay_client_status_search (items[0]);
status = relay_status_search (items[0]);
if (status < 0)
goto end;
}
@@ -86,7 +86,7 @@ relay_info_info_relay_client_count_cb (const void *pointer, void *data,
}
if (strcmp (items[1], "*") != 0)
{
status = relay_client_status_search (items[1]);
status = relay_status_search (items[1]);
if (status < 0)
goto end;
}
+677
View File
@@ -0,0 +1,677 @@
/*
* relay-remote.c - remote relay server functions for relay plugin
*
* Copyright (C) 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 <unistd.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <gnutls/gnutls.h>
#include "../weechat-plugin.h"
#include "relay.h"
#include "relay-config.h"
#include "relay-remote.h"
char *relay_remote_option_string[RELAY_REMOTE_NUM_OPTIONS] =
{ "url", "password", "totp_secret" };
char *relay_remote_option_default[RELAY_REMOTE_NUM_OPTIONS] =
{ "", "", "" };
struct t_relay_remote *relay_remotes = NULL;
struct t_relay_remote *last_relay_remote = NULL;
int relay_remotes_count = 0; /* number of remotes */
struct t_relay_remote *relay_remotes_temp = NULL; /* first temp. remote */
struct t_relay_remote *last_relay_remote_temp = NULL; /* last temp. remote */
/*
* Searches for a remote option name.
*
* Returns index of option in enum t_relay_remote_option, -1 if not found.
*/
int
relay_remote_search_option (const char *option_name)
{
int i;
if (!option_name)
return -1;
for (i = 0; i < RELAY_REMOTE_NUM_OPTIONS; i++)
{
if (strcmp (relay_remote_option_string[i], option_name) == 0)
return i;
}
/* remote option not found */
return -1;
}
/*
* Checks if a remote pointer is valid.
*
* Returns:
* 1: remote exists
* 0: remote does not exist
*/
int
relay_remote_valid (struct t_relay_remote *remote)
{
struct t_relay_remote *ptr_remote;
if (!remote)
return 0;
for (ptr_remote = relay_remotes; ptr_remote;
ptr_remote = ptr_remote->next_remote)
{
if (ptr_remote == remote)
return 1;
}
/* remote not found */
return 0;
}
/*
* Searches for a remote by name.
*
* Returns pointer to remote found, NULL if not found.
*/
struct t_relay_remote *
relay_remote_search (const char *name)
{
struct t_relay_remote *ptr_remote;
if (!name || !name[0])
return NULL;
for (ptr_remote = relay_remotes; ptr_remote;
ptr_remote = ptr_remote->next_remote)
{
if (strcmp (ptr_remote->name, name) == 0)
return ptr_remote;
}
/* remote not found */
return NULL;
}
/*
* Searches for a remote by number (first remote is 0).
*
* Returns pointer to remote found, NULL if not found.
*/
struct t_relay_remote *
relay_remote_search_by_number (int number)
{
struct t_relay_remote *ptr_remote;
int i;
i = 0;
for (ptr_remote = relay_remotes; ptr_remote;
ptr_remote = ptr_remote->next_remote)
{
if (i == number)
return ptr_remote;
i++;
}
/* remote not found */
return NULL;
}
/*
* Checks if a remote name is valid: it must contain only alphabetic chars
* or digits.
*
* Returns:
* 1: name is valid
* 0: name is invalid
*/
int
relay_remote_name_valid (const char *name)
{
const char *ptr_name;
if (!name || !name[0])
return 0;
ptr_name = name;
while (ptr_name[0])
{
if (!isalnum ((unsigned char)ptr_name[0]))
return 0;
ptr_name++;
}
/* name is valid */
return 1;
}
/*
* Checks if a remote URL is valid;
*
* Returns:
* 1: URL is valid
* 0: URL is invalid
*/
int
relay_remote_url_valid (const char *url)
{
const char *pos;
if (!url || !url[0])
return 0;
/* URL must start with "https://" or "http://" */
if ((strncmp (url, "https://", 8) != 0) && (strncmp (url, "http://", 7) != 0))
return 0;
pos = strchr (url + 7, ':');
/* invalid port? */
if (pos && !isdigit ((unsigned char)pos[1]))
return 0;
/* URL is valid */
return 1;
}
/*
* Sends a signal with the status of remote ("relay_remote_xxx").
*/
void
relay_remote_send_signal (struct t_relay_remote *remote)
{
char signal[128];
snprintf (signal, sizeof (signal),
"relay_remote_%s",
relay_status_name[remote->status]);
weechat_hook_signal_send (signal, WEECHAT_HOOK_SIGNAL_POINTER, remote);
}
/*
* Allocates and initializes new remote structure.
*
* Returns pointer to new remote, NULL if error.
*/
struct t_relay_remote *
relay_remote_alloc (const char *name)
{
struct t_relay_remote *new_remote;
int i;
if (!relay_remote_name_valid (name))
return NULL;
if (relay_remote_search (name))
return NULL;
new_remote = malloc (sizeof (*new_remote));
if (!new_remote)
return NULL;
new_remote->name = strdup (name);
for (i = 0; i < RELAY_REMOTE_NUM_OPTIONS; i++)
{
new_remote->options[i] = NULL;
}
new_remote->address = NULL;
new_remote->port = 0;
new_remote->tls = 0;
new_remote->status = RELAY_STATUS_DISCONNECTED;
new_remote->sock = -1;
new_remote->gnutls_sess = NULL;
new_remote->prev_remote = NULL;
new_remote->next_remote = NULL;
return new_remote;
}
/*
* Searches for position of remote in list (to keep remotes sorted by name).
*/
struct t_relay_remote *
relay_remote_find_pos (struct t_relay_remote *remote,
struct t_relay_remote *list_remotes)
{
struct t_relay_remote *ptr_remote;
for (ptr_remote = list_remotes; ptr_remote;
ptr_remote = ptr_remote->next_remote)
{
if (weechat_strcmp (remote->name, ptr_remote->name) < 0)
return ptr_remote;
}
/* position not found */
return NULL;
}
/*
* Adds a remote in a linked list.
*/
void
relay_remote_add (struct t_relay_remote *remote,
struct t_relay_remote **list_remotes,
struct t_relay_remote **last_list_remote)
{
struct t_relay_remote *pos_remote;
pos_remote = relay_remote_find_pos (remote, *list_remotes);
if (pos_remote)
{
/* add remote before "pos_remote" */
remote->prev_remote = pos_remote->prev_remote;
remote->next_remote = pos_remote;
if (pos_remote->prev_remote)
(pos_remote->prev_remote)->next_remote = remote;
else
*list_remotes = remote;
pos_remote->prev_remote = remote;
}
else
{
/* add remote to end of list */
remote->prev_remote = *last_list_remote;
remote->next_remote = NULL;
if (*last_list_remote)
(*last_list_remote)->next_remote = remote;
else
*list_remotes = remote;
*last_list_remote = remote;
}
}
/*
* Creates a new remote with options.
*
* Returns pointer to new remote, NULL if error.
*/
struct t_relay_remote *
relay_remote_new_with_options (const char *name, struct t_config_option **options)
{
struct t_relay_remote *new_remote;
int i;
new_remote = relay_remote_alloc (name);
if (!new_remote)
return NULL;
if (!relay_remote_url_valid (weechat_config_string (options[RELAY_REMOTE_OPTION_URL])))
{
free (new_remote);
return NULL;
}
for (i = 0; i < RELAY_REMOTE_NUM_OPTIONS; i++)
{
new_remote->options[i] = options[i];
}
relay_remote_add (new_remote, &relay_remotes, &last_relay_remote);
relay_remotes_count++;
relay_remote_send_signal (new_remote);
return new_remote;
}
/*
* Creates a new remote.
*
* Returns pointer to new remote, NULL if error.
*/
struct t_relay_remote *
relay_remote_new (const char *name, const char *url, const char *password,
const char *totp_secret)
{
struct t_config_option *option[RELAY_REMOTE_NUM_OPTIONS];
const char *value[RELAY_REMOTE_NUM_OPTIONS];
struct t_relay_remote *new_remote;
int i;
if (!name || !name[0] || !url || !url[0])
return NULL;
new_remote = malloc (sizeof (*new_remote));
if (!new_remote)
return NULL;
value[RELAY_REMOTE_OPTION_URL] = url;
value[RELAY_REMOTE_OPTION_PASSWORD] = password;
value[RELAY_REMOTE_OPTION_TOTP_SECRET] = totp_secret;
for (i = 0; i < RELAY_REMOTE_NUM_OPTIONS; i++)
{
option[i] = relay_config_create_remote_option (name, i, value[i]);
}
new_remote = relay_remote_new_with_options (name, option);
if (!new_remote)
{
for (i = 0; i < RELAY_REMOTE_NUM_OPTIONS; i++)
{
weechat_config_option_free (option[i]);
}
}
return new_remote;
}
/*
* Creates a new remote using an infolist.
*
* This is called to restore remotes after /upgrade.
*/
struct t_relay_remote *
relay_remote_new_with_infolist (struct t_infolist *infolist)
{
struct t_relay_remote *new_remote;
new_remote = malloc (sizeof (*new_remote));
if (!new_remote)
return NULL;
new_remote->address = strdup (weechat_infolist_string (infolist, "name"));
new_remote->address = strdup (weechat_infolist_string (infolist, "address"));
new_remote->port = weechat_infolist_integer (infolist, "port");
new_remote->tls = weechat_infolist_integer (infolist, "tls");
new_remote->status = weechat_infolist_integer (infolist, "status");
new_remote->sock = weechat_infolist_integer (infolist, "sock");
new_remote->gnutls_sess = NULL;
new_remote->prev_remote = NULL;
new_remote->next_remote = relay_remotes;
if (relay_remotes)
relay_remotes->prev_remote = new_remote;
else
last_relay_remote = new_remote;
relay_remotes = new_remote;
relay_remotes_count++;
return new_remote;
}
/*
* Sets status for a remote.
*/
void
relay_remote_set_status (struct t_relay_remote *remote,
enum t_relay_status status)
{
/*
* IMPORTANT: if changes are made in this function or sub-functions called,
* please also update the function relay_remote_add_to_infolist:
* when the flag force_disconnected_state is set to 1 we simulate
* a disconnected state for remote in infolist (used on /upgrade -save)
*/
remote->status = status;
relay_remote_send_signal (remote);
}
/*
* Renames a remote.
*
* Returns:
* 1: OK
* 0: error (remote not renamed)
*/
int
relay_remote_rename (struct t_relay_remote *remote, const char *name)
{
int length, i;
char *option_name;
if (!remote || !name || !name[0] || !relay_remote_name_valid (name)
|| relay_remote_search (name))
{
return 0;
}
length = strlen (name) + 64;
option_name = malloc (length);
if (!option_name)
return 0;
for (i = 0; i < RELAY_REMOTE_NUM_OPTIONS; i++)
{
if (remote->options[i])
{
snprintf (option_name, length,
"%s.%s",
name,
relay_remote_option_string[i]);
weechat_config_option_rename (remote->options[i], option_name);
}
}
if (remote->name)
free (remote->name);
remote->name = strdup (name);
free (option_name);
/* re-insert remote in list (for sorting remotes by name) */
if (remote->prev_remote)
(remote->prev_remote)->next_remote = remote->next_remote;
else
relay_remotes = remote->next_remote;
if (remote->next_remote)
(remote->next_remote)->prev_remote = remote->prev_remote;
else
last_relay_remote = remote->prev_remote;
relay_remote_add (remote, &relay_remotes, &last_relay_remote);
return 1;
}
/*
* Deletes a remote.
*/
void
relay_remote_free (struct t_relay_remote *remote)
{
int i;
if (!remote)
return;
/* remove remote from list */
if (remote->prev_remote)
(remote->prev_remote)->next_remote = remote->next_remote;
if (remote->next_remote)
(remote->next_remote)->prev_remote = remote->prev_remote;
if (relay_remotes == remote)
relay_remotes = remote->next_remote;
if (last_relay_remote == remote)
last_relay_remote = remote->prev_remote;
/* free data */
if (remote->name)
free (remote->name);
for (i = 0; i < RELAY_REMOTE_NUM_OPTIONS; i++)
{
if (remote->options[i])
weechat_config_option_free (remote->options[i]);
}
if (remote->address)
free (remote->address);
free (remote);
relay_remotes_count--;
}
/*
* Removes all remotes.
*/
void
relay_remote_free_all ()
{
while (relay_remotes)
{
relay_remote_free (relay_remotes);
}
}
/*
* Disconnects one remote.
*/
void
relay_remote_disconnect (struct t_relay_remote *remote)
{
if (remote->sock >= 0)
{
relay_remote_set_status (remote, RELAY_STATUS_DISCONNECTED);
}
}
/*
* Disconnects all remotes.
*/
void
relay_remote_disconnect_all ()
{
struct t_relay_remote *ptr_remote;
for (ptr_remote = relay_remotes; ptr_remote;
ptr_remote = ptr_remote->next_remote)
{
relay_remote_disconnect (ptr_remote);
}
}
/*
* Adds a remote in an infolist.
*
* If force_disconnected_state == 1, the infolist contains the remote
* in a disconnected state (but the remote is unchanged, still connected if it
* was).
*
* Returns:
* 1: OK
* 0: error
*/
int
relay_remote_add_to_infolist (struct t_infolist *infolist,
struct t_relay_remote *remote,
int force_disconnected_state)
{
struct t_infolist_item *ptr_item;
if (!infolist || !remote)
return 0;
ptr_item = weechat_infolist_new_item (infolist);
if (!ptr_item)
return 0;
if (!weechat_infolist_new_var_string (ptr_item, "name", remote->name))
return 0;
if (!weechat_infolist_new_var_string (ptr_item, "address", remote->address))
return 0;
if (!weechat_infolist_new_var_integer (ptr_item, "port", remote->port))
return 0;
if (!weechat_infolist_new_var_integer (ptr_item, "tls", remote->tls))
return 0;
if (!RELAY_STATUS_HAS_ENDED(remote->status) && force_disconnected_state)
{
if (!weechat_infolist_new_var_integer (ptr_item, "status", RELAY_STATUS_DISCONNECTED))
return 0;
if (!weechat_infolist_new_var_integer (ptr_item, "sock", -1))
return 0;
}
else
{
if (!weechat_infolist_new_var_integer (ptr_item, "status", remote->status))
return 0;
if (!weechat_infolist_new_var_integer (ptr_item, "sock", remote->sock))
return 0;
}
return 1;
}
/*
* Prints remotes in WeeChat log file (usually for crash dump).
*/
void
relay_remote_print_log ()
{
struct t_relay_remote *ptr_remote;
for (ptr_remote = relay_remotes; ptr_remote;
ptr_remote = ptr_remote->next_remote)
{
weechat_log_printf ("");
weechat_log_printf ("[relay remote (addr:0x%lx)]", ptr_remote);
weechat_log_printf (" name. . . . . . . . . : '%s'", ptr_remote->name);
weechat_log_printf (" url . . . . . . . . . : '%s'",
weechat_config_string (ptr_remote->options[RELAY_REMOTE_OPTION_URL]));
weechat_log_printf (" password. . . . . . . : '%s'",
weechat_config_string (ptr_remote->options[RELAY_REMOTE_OPTION_PASSWORD]));
weechat_log_printf (" totp_secret . . . . . : '%s'",
weechat_config_string (ptr_remote->options[RELAY_REMOTE_OPTION_TOTP_SECRET]));
weechat_log_printf (" address . . . . . . . : '%s'", ptr_remote->address);
weechat_log_printf (" port. . . . . . . . . : %d", ptr_remote->port);
weechat_log_printf (" tls . . . . . . . . . : %d", ptr_remote->tls);
weechat_log_printf (" status. . . . . . . . : %d (%s)",
ptr_remote->status,
relay_status_string[ptr_remote->status]);
weechat_log_printf (" sock. . . . . . . . . : %d", ptr_remote->sock);
weechat_log_printf (" gnutls_sess . . . . . : 0x%lx", ptr_remote->gnutls_sess);
weechat_log_printf (" prev_remote . . . . . : 0x%lx", ptr_remote->prev_remote);
weechat_log_printf (" next_remote . . . . . : 0x%lx", ptr_remote->next_remote);
}
}
+87
View File
@@ -0,0 +1,87 @@
/*
* Copyright (C) 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_REMOTE_H
#define WEECHAT_PLUGIN_RELAY_REMOTE_H
#include <gnutls/gnutls.h>
enum t_relay_remote_option
{
RELAY_REMOTE_OPTION_URL = 0, /* remote URL */
RELAY_REMOTE_OPTION_PASSWORD, /* password for remote relay */
RELAY_REMOTE_OPTION_TOTP_SECRET, /* TOTP secret for remote relay */
/* number of relay remote options */
RELAY_REMOTE_NUM_OPTIONS,
};
/* relay remote */
struct t_relay_remote
{
char *name; /* internal remote name */
struct t_config_option *options[RELAY_REMOTE_NUM_OPTIONS];
char *address; /* address */
int port; /* port number */
int tls; /* 1 if TLS is enabled */
enum t_relay_status status; /* status (connecting, active,..) */
int sock; /* connected socket */
gnutls_session_t gnutls_sess; /* gnutls session (only if TLS used) */
struct t_relay_remote *prev_remote;/* link to previous remote */
struct t_relay_remote *next_remote;/* link to next remote */
};
extern char *relay_remote_option_string[];
extern char *relay_remote_option_default[];
extern struct t_relay_remote *relay_remotes;
extern struct t_relay_remote *last_relay_remote;
extern int relay_remotes_count;
extern struct t_relay_remote *relay_remotes_temp;
extern struct t_relay_remote *last_relay_remote_temp;
extern int relay_remote_search_option (const char *option_name);
extern int relay_remote_valid (struct t_relay_remote *remote);
extern struct t_relay_remote *relay_remote_search (const char *name);
extern struct t_relay_remote *relay_remote_search_by_number (int number);
extern int relay_remote_name_valid (const char *name);
extern int relay_remote_url_valid (const char *url);
extern struct t_relay_remote *relay_remote_alloc (const char *name);
extern void relay_remote_add (struct t_relay_remote *remote,
struct t_relay_remote **list_remotes,
struct t_relay_remote **last_list_remote);
extern struct t_relay_remote *relay_remote_new_with_options (const char *name,
struct t_config_option **options);
extern struct t_relay_remote *relay_remote_new (const char *name,
const char *url,
const char *password,
const char *totp_secret);
extern struct t_relay_remote *relay_remote_new_with_infolist (struct t_infolist *infolist);
extern void relay_remote_set_status (struct t_relay_remote *remote,
enum t_relay_status status);
extern int relay_remote_rename (struct t_relay_remote *remote, const char *name);
extern void relay_remote_free (struct t_relay_remote *remote);
extern void relay_remote_free_all ();
extern void relay_remote_disconnect (struct t_relay_remote *remote);
extern void relay_remote_disconnect_all ();
extern int relay_remote_add_to_infolist (struct t_infolist *infolist,
struct t_relay_remote *remote,
int force_disconnected_state);
extern void relay_remote_print_log ();
#endif /* WEECHAT_PLUGIN_RELAY_REMOTE_H */
+35
View File
@@ -32,6 +32,7 @@
#include "relay-info.h"
#include "relay-network.h"
#include "relay-raw.h"
#include "relay-remote.h"
#include "relay-server.h"
#include "relay-upgrade.h"
@@ -49,6 +50,15 @@ struct t_weechat_plugin *weechat_relay_plugin = NULL;
char *relay_protocol_string[] = /* strings for protocols */
{ "weechat", "irc", "api" };
char *relay_status_string[] = /* status strings for display */
{ N_("connecting"), N_("authenticating"),
N_("connected"), N_("authentication failed"), N_("disconnected")
};
char *relay_status_name[] = /* name of status (for signal/info) */
{ "connecting", "waiting_auth",
"connected", "auth_failed", "disconnected"
};
struct t_hdata *relay_hdata_buffer = NULL;
struct t_hdata *relay_hdata_lines = NULL;
struct t_hdata *relay_hdata_line = NULL;
@@ -89,6 +99,30 @@ relay_protocol_search (const char *name)
return -1;
}
/*
* Searches for a status.
*
* Returns index of status in enum t_relay_status, -1 if status is not found.
*/
int
relay_status_search (const char *name)
{
int i;
if (!name)
return -1;
for (i = 0; i < RELAY_NUM_STATUS; i++)
{
if (strcmp (relay_status_name[i], name) == 0)
return i;
}
/* status not found */
return -1;
}
/*
* Callback for signal "upgrade".
*/
@@ -191,6 +225,7 @@ relay_debug_dump_cb (const void *pointer, void *data,
relay_server_print_log ();
relay_client_print_log ();
relay_remote_print_log ();
weechat_log_printf ("");
weechat_log_printf ("***** End of \"%s\" plugin dump *****",
+20
View File
@@ -49,13 +49,33 @@ enum t_relay_protocol
RELAY_NUM_PROTOCOLS,
};
/* client/remote status */
enum t_relay_status
{
RELAY_STATUS_CONNECTING = 0, /* network connection in progress */
RELAY_STATUS_AUTHENTICATING, /* authentication in progress */
RELAY_STATUS_CONNECTED, /* connected and authenticated */
RELAY_STATUS_AUTH_FAILED, /* authentication failed */
RELAY_STATUS_DISCONNECTED, /* disconnected */
/* number of relay status */
RELAY_NUM_STATUS,
};
#define RELAY_STATUS_HAS_ENDED(status) \
((status == RELAY_STATUS_AUTH_FAILED) || \
(status == RELAY_STATUS_DISCONNECTED))
#define RELAY_COLOR_CHAT weechat_color("chat")
#define RELAY_COLOR_CHAT_HOST weechat_color("chat_host")
#define RELAY_COLOR_CHAT_BUFFER weechat_color("chat_buffer")
#define RELAY_COLOR_CHAT_CLIENT weechat_color(weechat_config_string(relay_config_color_client))
extern char *relay_protocol_string[];
extern char *relay_status_string[];
extern char *relay_status_name[];
extern int relay_protocol_search (const char *name);
extern int relay_status_search (const char *name);
#endif /* WEECHAT_PLUGIN_RELAY_H */
@@ -225,7 +225,7 @@ RELAY_WEECHAT_PROTOCOL_CALLBACK(handshake)
RELAY_WEECHAT_PROTOCOL_MIN_ARGS(0);
if (client->status != RELAY_STATUS_WAITING_AUTH)
if (client->status != RELAY_STATUS_AUTHENTICATING)
return WEECHAT_RC_OK;
/* only one handshake is allowed */
@@ -1724,7 +1724,7 @@ relay_weechat_protocol_recv (struct t_relay_client *client, const char *data)
{ NULL, NULL }
};
if (!data || !data[0] || RELAY_CLIENT_HAS_ENDED(client))
if (!data || !data[0] || RELAY_STATUS_HAS_ENDED(client->status))
return;
/* display debug message */
+3 -3
View File
@@ -286,12 +286,12 @@ relay_weechat_alloc_with_infolist (struct t_relay_client *client,
&relay_weechat_free_buffers_nicklist);
RELAY_WEECHAT_DATA(client, hook_timer_nicklist) = NULL;
if (!RELAY_CLIENT_HAS_ENDED(client))
if (!RELAY_STATUS_HAS_ENDED(client->status))
relay_weechat_hook_signals (client);
}
/*
* Returns the client initial status: it is always "waiting_auth" for weechat
* Returns the client initial status: it is always "authenticating" for weechat
* protocol because we always expect the "init" command, even without any
* password.
*/
@@ -302,7 +302,7 @@ relay_weechat_get_initial_status (struct t_relay_client *client)
/* make C compiler happy */
(void) client;
return RELAY_STATUS_WAITING_AUTH;
return RELAY_STATUS_AUTHENTICATING;
}
/*
@@ -126,7 +126,7 @@ TEST(RelayApi, AllocWithInfolist)
TEST(RelayApi, GetInitialStatus)
{
LONGS_EQUAL(RELAY_STATUS_WAITING_AUTH, relay_api_get_initial_status (NULL));
LONGS_EQUAL(RELAY_STATUS_AUTHENTICATING, relay_api_get_initial_status (NULL));
}
/*