mirror of
https://github.com/weechat/weechat.git
synced 2026-06-27 05:16:38 +02:00
391 lines
12 KiB
C
391 lines
12 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2023-2026 Sébastien Helleu <flashcode@flashtux.org>
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*
|
|
* 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/>.
|
|
*/
|
|
|
|
/* API protocol for relay to client */
|
|
|
|
#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"
|
|
|
|
|
|
/*
|
|
* Return buffer id.
|
|
*/
|
|
|
|
long long
|
|
relay_api_get_buffer_id (struct t_gui_buffer *buffer)
|
|
{
|
|
const char *ptr_id;
|
|
long long id;
|
|
|
|
if (!buffer)
|
|
return -1;
|
|
|
|
ptr_id = weechat_buffer_get_string (buffer, "id");
|
|
if (!ptr_id)
|
|
return -1;
|
|
|
|
if (!weechat_util_parse_longlong (ptr_id, 10, &id))
|
|
return -1;
|
|
|
|
return id;
|
|
}
|
|
|
|
/*
|
|
* Return 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
|
|
*/
|
|
|
|
int
|
|
relay_api_search_colors (const char *colors)
|
|
{
|
|
if (!colors)
|
|
return -1;
|
|
|
|
if (strcmp (colors, "ansi") == 0)
|
|
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 -1;
|
|
}
|
|
|
|
/*
|
|
* Hook 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, sync_input))
|
|
{
|
|
if (!RELAY_API_DATA(client, hook_signal_input))
|
|
{
|
|
RELAY_API_DATA(client, hook_signal_input) =
|
|
weechat_hook_signal ("input_prompt_changed;"
|
|
"input_text_changed;"
|
|
"input_text_cursor_moved",
|
|
&relay_api_protocol_signal_input_cb,
|
|
client, NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (RELAY_API_DATA(client, hook_signal_input))
|
|
{
|
|
weechat_unhook (RELAY_API_DATA(client, hook_signal_input));
|
|
RELAY_API_DATA(client, hook_signal_input) = NULL;
|
|
}
|
|
}
|
|
if (!RELAY_API_DATA(client, hook_signal_upgrade))
|
|
{
|
|
RELAY_API_DATA(client, hook_signal_upgrade) =
|
|
weechat_hook_signal ("upgrade*;quit",
|
|
&relay_api_protocol_signal_upgrade_cb,
|
|
client, NULL);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Unhook 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_input))
|
|
{
|
|
weechat_unhook (RELAY_API_DATA(client, hook_signal_input));
|
|
RELAY_API_DATA(client, hook_signal_input) = 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;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Read HTTP request from a client.
|
|
*/
|
|
|
|
void
|
|
relay_api_recv_http (struct t_relay_client *client)
|
|
{
|
|
relay_api_protocol_recv_http (client);
|
|
}
|
|
|
|
/*
|
|
* Read 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);
|
|
}
|
|
|
|
/*
|
|
* Close 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);
|
|
}
|
|
|
|
/*
|
|
* Initialize 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_input) = NULL;
|
|
RELAY_API_DATA(client, hook_signal_upgrade) = NULL;
|
|
RELAY_API_DATA(client, buffers_closing) = weechat_hashtable_new (
|
|
32,
|
|
WEECHAT_HASHTABLE_POINTER,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
NULL,
|
|
NULL);
|
|
RELAY_API_DATA(client, sync_enabled) = 0;
|
|
RELAY_API_DATA(client, sync_nicks) = 0;
|
|
RELAY_API_DATA(client, sync_input) = 0;
|
|
RELAY_API_DATA(client, sync_colors) = RELAY_API_COLORS_ANSI;
|
|
}
|
|
|
|
/*
|
|
* Initialize 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_input) = NULL;
|
|
RELAY_API_DATA(client, hook_signal_upgrade) = NULL;
|
|
RELAY_API_DATA(client, buffers_closing) = weechat_hashtable_new (
|
|
32,
|
|
WEECHAT_HASHTABLE_POINTER,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
NULL,
|
|
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_input) = weechat_infolist_integer (
|
|
infolist, "sync_input");
|
|
RELAY_API_DATA(client, sync_colors) = weechat_infolist_integer (
|
|
infolist, "sync_colors");
|
|
|
|
if (!RELAY_STATUS_HAS_ENDED(client->status)
|
|
&& RELAY_API_DATA(client, sync_enabled))
|
|
{
|
|
relay_api_hook_signals (client);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Return the client initial status: it is always "authenticating" for API
|
|
* protocol because we always expect the client to authenticate.
|
|
*/
|
|
|
|
enum t_relay_status
|
|
relay_api_get_initial_status (struct t_relay_client *client)
|
|
{
|
|
/* make C compiler happy */
|
|
(void) client;
|
|
|
|
return RELAY_STATUS_AUTHENTICATING;
|
|
}
|
|
|
|
/*
|
|
* Free relay data specific to API protocol.
|
|
*/
|
|
|
|
void
|
|
relay_api_free (struct t_relay_client *client)
|
|
{
|
|
if (!client)
|
|
return;
|
|
|
|
if (client->protocol_data)
|
|
{
|
|
weechat_unhook (RELAY_API_DATA(client, hook_signal_buffer));
|
|
weechat_unhook (RELAY_API_DATA(client, hook_hsignal_nicklist));
|
|
weechat_unhook (RELAY_API_DATA(client, hook_signal_input));
|
|
weechat_unhook (RELAY_API_DATA(client, hook_signal_upgrade));
|
|
weechat_hashtable_free (RELAY_API_DATA(client, buffers_closing));
|
|
|
|
free (client->protocol_data);
|
|
|
|
client->protocol_data = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Add 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).
|
|
*
|
|
* Return:
|
|
* 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_input", RELAY_API_DATA(client, hook_signal_input)))
|
|
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_input", RELAY_API_DATA(client, sync_input)))
|
|
return 0;
|
|
if (!weechat_infolist_new_var_integer (item, "sync_colors", RELAY_API_DATA(client, sync_colors)))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Print 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. . . : %p", RELAY_API_DATA(client, hook_signal_buffer));
|
|
weechat_log_printf (" hook_hsignal_nicklist . : %p", RELAY_API_DATA(client, hook_hsignal_nicklist));
|
|
weechat_log_printf (" hook_signal_input . . . : %p", RELAY_API_DATA(client, hook_signal_input));
|
|
weechat_log_printf (" hook_signal_upgrade . . : %p", RELAY_API_DATA(client, hook_signal_upgrade));
|
|
weechat_log_printf (" buffers_closing. . . . .: %p (hashtable: '%s')",
|
|
RELAY_API_DATA(client, buffers_closing),
|
|
weechat_hashtable_get_string (
|
|
RELAY_API_DATA(client, buffers_closing),
|
|
"keys_values"));
|
|
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_input. . . . . . . : %d", RELAY_API_DATA(client, sync_input));
|
|
weechat_log_printf (" sync_colors . . . . . . : %d", RELAY_API_DATA(client, sync_colors));
|
|
}
|
|
}
|