1682 lines
56 KiB
C
1682 lines
56 KiB
C
/*
|
|
* relay-weechat-protocol.c - WeeChat protocol for relay to client
|
|
*
|
|
* Copyright (C) 2003-2020 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 "../../weechat-plugin.h"
|
|
#include "../relay.h"
|
|
#include "relay-weechat.h"
|
|
#include "relay-weechat-protocol.h"
|
|
#include "relay-weechat-msg.h"
|
|
#include "relay-weechat-nicklist.h"
|
|
#include "../relay-buffer.h"
|
|
#include "../relay-client.h"
|
|
#include "../relay-auth.h"
|
|
#include "../relay-config.h"
|
|
#include "../relay-raw.h"
|
|
|
|
|
|
/*
|
|
* Checks if the buffer pointer is a relay buffer (relay raw/list).
|
|
*
|
|
* Returns:
|
|
* 1: buffer is a relay buffer (raw/list)
|
|
* 0: buffer is NOT a relay buffer
|
|
*/
|
|
|
|
int
|
|
relay_weechat_is_relay_buffer (struct t_gui_buffer *buffer)
|
|
{
|
|
return ((relay_raw_buffer && (buffer == relay_raw_buffer))
|
|
|| (relay_buffer && (buffer == relay_buffer))) ? 1 : 0;
|
|
}
|
|
|
|
/*
|
|
* Gets buffer pointer with argument from a command.
|
|
*
|
|
* The argument "arg" can be a pointer ("0x12345678") or a full name
|
|
* ("irc.freenode.#weechat").
|
|
*
|
|
* Returns pointer to buffer found, NULL if not found.
|
|
*/
|
|
|
|
struct t_gui_buffer *
|
|
relay_weechat_protocol_get_buffer (const char *arg)
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
unsigned long value;
|
|
int rc;
|
|
struct t_hdata *ptr_hdata;
|
|
|
|
ptr_buffer = NULL;
|
|
|
|
if (strncmp (arg, "0x", 2) == 0)
|
|
{
|
|
rc = sscanf (arg, "%lx", &value);
|
|
if ((rc != EOF) && (rc != 0))
|
|
ptr_buffer = (struct t_gui_buffer *)value;
|
|
if (ptr_buffer)
|
|
{
|
|
ptr_hdata = weechat_hdata_get ("buffer");
|
|
if (!weechat_hdata_check_pointer (ptr_hdata,
|
|
weechat_hdata_get_list (ptr_hdata, "gui_buffers"),
|
|
ptr_buffer))
|
|
{
|
|
/* invalid pointer! */
|
|
ptr_buffer = NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
ptr_buffer = weechat_buffer_search ("==", arg);
|
|
|
|
return ptr_buffer;
|
|
}
|
|
|
|
/*
|
|
* Gets integer value of a synchronization flag.
|
|
*/
|
|
|
|
int
|
|
relay_weechat_protocol_sync_flag (const char *flag)
|
|
{
|
|
if (strcmp (flag, "buffer") == 0)
|
|
return RELAY_WEECHAT_PROTOCOL_SYNC_BUFFER;
|
|
if (strcmp (flag, "nicklist") == 0)
|
|
return RELAY_WEECHAT_PROTOCOL_SYNC_NICKLIST;
|
|
if (strcmp (flag, "buffers") == 0)
|
|
return RELAY_WEECHAT_PROTOCOL_SYNC_BUFFERS;
|
|
if (strcmp (flag, "upgrade") == 0)
|
|
return RELAY_WEECHAT_PROTOCOL_SYNC_UPGRADE;
|
|
|
|
/* unknown flag */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Checks if buffer is synchronized with at least one of the flags given.
|
|
*
|
|
* First searches buffer with full_name in hashtable "buffers_sync" (if buffer
|
|
* is not NULL).
|
|
* If buffer is NULL or not found, searches "*" (which means "all buffers").
|
|
*
|
|
* The "flags" argument can be a combination (logical OR) of:
|
|
* RELAY_WEECHAT_PROTOCOL_SYNC_BUFFER
|
|
* RELAY_WEECHAT_PROTOCOL_SYNC_NICKLIST
|
|
* RELAY_WEECHAT_PROTOCOL_SYNC_BUFFERS
|
|
* RELAY_WEECHAT_PROTOCOL_SYNC_UPGRADE
|
|
*
|
|
* Returns:
|
|
* 1: buffer is synchronized with at least one flag given
|
|
* 0: buffer is NOT synchronized with any of the flags given
|
|
*/
|
|
|
|
int
|
|
relay_weechat_protocol_is_sync (struct t_relay_client *ptr_client,
|
|
struct t_gui_buffer *buffer, int flags)
|
|
{
|
|
int *ptr_flags;
|
|
|
|
/* search buffer using its full name */
|
|
if (buffer)
|
|
{
|
|
ptr_flags = weechat_hashtable_get (RELAY_WEECHAT_DATA(ptr_client, buffers_sync),
|
|
weechat_buffer_get_string (buffer, "full_name"));
|
|
if (ptr_flags)
|
|
return ((*ptr_flags) & flags) ? 1 : 0;
|
|
}
|
|
|
|
/* search special name "*" as fallback */
|
|
ptr_flags = weechat_hashtable_get (RELAY_WEECHAT_DATA(ptr_client, buffers_sync),
|
|
"*");
|
|
if (ptr_flags)
|
|
return ((*ptr_flags) & flags) ? 1 : 0;
|
|
|
|
/*
|
|
* buffer not found at all in hashtable (neither name, neither "*")
|
|
* => it is NOT synchronized
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Replies to a client handshake command.
|
|
*/
|
|
|
|
void
|
|
relay_weechat_protocol_handshake_reply (struct t_relay_client *client,
|
|
const char *command)
|
|
{
|
|
struct t_relay_weechat_msg *msg;
|
|
struct t_hashtable *hashtable;
|
|
char *totp_secret, string[64];
|
|
|
|
totp_secret = weechat_string_eval_expression (
|
|
weechat_config_string (relay_config_network_totp_secret),
|
|
NULL, NULL, NULL);
|
|
|
|
hashtable = weechat_hashtable_new (32,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
NULL, NULL);
|
|
if (hashtable)
|
|
{
|
|
weechat_hashtable_set (
|
|
hashtable,
|
|
"auth_password",
|
|
(client->auth_password >= 0) ?
|
|
relay_auth_password_name[client->auth_password] : "");
|
|
snprintf (string, sizeof (string), "%d", client->hash_iterations);
|
|
weechat_hashtable_set (
|
|
hashtable,
|
|
"hash_iterations",
|
|
string);
|
|
weechat_hashtable_set (
|
|
hashtable,
|
|
"nonce",
|
|
client->nonce);
|
|
weechat_hashtable_set (
|
|
hashtable,
|
|
"totp",
|
|
(totp_secret && totp_secret[0]) ? "on" : "off");
|
|
|
|
msg = relay_weechat_msg_new (command);
|
|
if (msg)
|
|
{
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_HASHTABLE);
|
|
relay_weechat_msg_add_hashtable (msg, hashtable);
|
|
|
|
/* send message */
|
|
relay_weechat_msg_send (client, msg);
|
|
relay_weechat_msg_free (msg);
|
|
}
|
|
|
|
weechat_hashtable_free (hashtable);
|
|
}
|
|
|
|
if (totp_secret)
|
|
free (totp_secret);
|
|
}
|
|
|
|
|
|
/*
|
|
* Callback for command "handshake" (from client).
|
|
*/
|
|
|
|
RELAY_WEECHAT_PROTOCOL_CALLBACK(handshake)
|
|
{
|
|
char **options, **auths, *pos;
|
|
int i, j, index_auth, auth_found, auth_allowed, compression;
|
|
int password_received, plain_text_password;
|
|
|
|
RELAY_WEECHAT_PROTOCOL_MIN_ARGS(0);
|
|
|
|
if (client->status != RELAY_STATUS_WAITING_AUTH)
|
|
return WEECHAT_RC_OK;
|
|
|
|
auth_found = -1;
|
|
password_received = 0;
|
|
|
|
options = (argc > 0) ?
|
|
weechat_string_split_command (argv_eol[0], ',') : NULL;
|
|
if (options)
|
|
{
|
|
for (i = 0; options[i]; i++)
|
|
{
|
|
pos = strchr (options[i], '=');
|
|
if (pos)
|
|
{
|
|
pos[0] = '\0';
|
|
pos++;
|
|
if (strcmp (options[i], "password") == 0)
|
|
{
|
|
password_received = 1;
|
|
auths = weechat_string_split (
|
|
pos,
|
|
":",
|
|
NULL,
|
|
WEECHAT_STRING_SPLIT_STRIP_LEFT
|
|
| WEECHAT_STRING_SPLIT_STRIP_RIGHT
|
|
| WEECHAT_STRING_SPLIT_COLLAPSE_SEPS,
|
|
0,
|
|
NULL);
|
|
if (auths)
|
|
{
|
|
for (j = 0; auths[j]; j++)
|
|
{
|
|
index_auth = relay_auth_password_search (
|
|
auths[j]);
|
|
if ((index_auth >= 0) && (index_auth > auth_found))
|
|
{
|
|
auth_allowed = weechat_string_match_list (
|
|
relay_auth_password_name[index_auth],
|
|
(const char **)relay_config_network_auth_password_list,
|
|
1);
|
|
if (auth_allowed)
|
|
auth_found = index_auth;
|
|
}
|
|
}
|
|
weechat_string_free_split (auths);
|
|
}
|
|
}
|
|
else if (strcmp (options[i], "compression") == 0)
|
|
{
|
|
compression = relay_weechat_compression_search (pos);
|
|
if (compression >= 0)
|
|
RELAY_WEECHAT_DATA(client, compression) = compression;
|
|
}
|
|
}
|
|
}
|
|
weechat_string_free_split_command (options);
|
|
}
|
|
|
|
if (!password_received)
|
|
{
|
|
plain_text_password = weechat_string_match_list (
|
|
relay_auth_password_name[0],
|
|
(const char **)relay_config_network_auth_password_list,
|
|
1);
|
|
if (plain_text_password)
|
|
auth_found = 0;
|
|
}
|
|
|
|
client->auth_password = auth_found;
|
|
|
|
relay_weechat_protocol_handshake_reply (client, command);
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Callback for command "init" (from client).
|
|
*
|
|
* Format is: init arg1=value1,arg2=value2
|
|
*
|
|
* Allowed arguments:
|
|
* password plain text password (recommended with SSL only)
|
|
* password_hash hashed password, value is: algorithm:[parameters:]hash
|
|
* supported algorithms: sha256, sha512 and pbkdf2
|
|
* for pbkdf2, parameters are: algorithm, salt, iterations
|
|
* hash is given in hexadecimal
|
|
* totp time-based one time password used as secondary
|
|
* authentication factor
|
|
* compression zlib (default) or off
|
|
*
|
|
* Message looks like:
|
|
* init password=mypass
|
|
* init password=mypass,compression=zlib
|
|
* init password=mypass,compression=off
|
|
* init password_hash=sha256:71c480df93d6ae2f1efad1447c66c9…,totp=123456
|
|
* init password_hash=pbkdf2:sha256:414232…:100000:01757d53157c…,totp=123456
|
|
*/
|
|
|
|
RELAY_WEECHAT_PROTOCOL_CALLBACK(init)
|
|
{
|
|
char **options, *pos, *relay_password, *totp_secret, *info_totp_args, *info_totp;
|
|
int i, compression, length, password_received, totp_received;
|
|
|
|
RELAY_WEECHAT_PROTOCOL_MIN_ARGS(0);
|
|
|
|
relay_password = weechat_string_eval_expression (
|
|
weechat_config_string (relay_config_network_password),
|
|
NULL, NULL, NULL);
|
|
totp_secret = weechat_string_eval_expression (
|
|
weechat_config_string (relay_config_network_totp_secret),
|
|
NULL, NULL, NULL);
|
|
|
|
password_received = 0;
|
|
totp_received = 0;
|
|
|
|
options = (argc > 0) ?
|
|
weechat_string_split_command (argv_eol[0], ',') : NULL;
|
|
if (options)
|
|
{
|
|
for (i = 0; options[i]; i++)
|
|
{
|
|
pos = strchr (options[i], '=');
|
|
if (pos)
|
|
{
|
|
pos[0] = '\0';
|
|
pos++;
|
|
if (strcmp (options[i], "password") == 0)
|
|
{
|
|
password_received = 1;
|
|
if (relay_auth_password (client, pos, relay_password))
|
|
RELAY_WEECHAT_DATA(client, password_ok) = 1;
|
|
}
|
|
else if (strcmp (options[i], "password_hash") == 0)
|
|
{
|
|
password_received = 1;
|
|
if (relay_auth_password_hash (client, pos, relay_password))
|
|
RELAY_WEECHAT_DATA(client, password_ok) = 1;
|
|
}
|
|
else if (strcmp (options[i], "totp") == 0)
|
|
{
|
|
totp_received = 1;
|
|
if (totp_secret)
|
|
{
|
|
length = strlen (totp_secret) + strlen (pos) + 16 + 1;
|
|
info_totp_args = malloc (length);
|
|
if (info_totp_args)
|
|
{
|
|
/* validate the OTP received from the client */
|
|
snprintf (info_totp_args, length,
|
|
"%s,%s,0,%d",
|
|
totp_secret, /* the shared secret */
|
|
pos, /* the OTP from client */
|
|
weechat_config_integer (relay_config_network_totp_window));
|
|
info_totp = weechat_info_get ("totp_validate", info_totp_args);
|
|
if (info_totp && (strcmp (info_totp, "1") == 0))
|
|
RELAY_WEECHAT_DATA(client, totp_ok) = 1;
|
|
if (info_totp)
|
|
free (info_totp);
|
|
free (info_totp_args);
|
|
}
|
|
}
|
|
}
|
|
else if (strcmp (options[i], "compression") == 0)
|
|
{
|
|
compression = relay_weechat_compression_search (pos);
|
|
if (compression >= 0)
|
|
RELAY_WEECHAT_DATA(client, compression) = compression;
|
|
}
|
|
}
|
|
}
|
|
weechat_string_free_split_command (options);
|
|
}
|
|
|
|
/* if no password received and password is empty, it's OK */
|
|
if (!password_received && (!relay_password || !relay_password[0]))
|
|
RELAY_WEECHAT_DATA(client, password_ok) = 1;
|
|
|
|
/* if no TOTP received and totp_secret is empty, it's OK */
|
|
if (!totp_received && (!totp_secret || !totp_secret[0]))
|
|
RELAY_WEECHAT_DATA(client, totp_ok) = 1;
|
|
|
|
if (RELAY_WEECHAT_DATA(client, password_ok)
|
|
&& RELAY_WEECHAT_DATA(client, totp_ok))
|
|
{
|
|
weechat_hook_signal_send ("relay_client_auth_ok",
|
|
WEECHAT_HOOK_SIGNAL_POINTER,
|
|
client);
|
|
relay_client_set_status (client, RELAY_STATUS_CONNECTED);
|
|
}
|
|
else
|
|
{
|
|
relay_client_set_status (client, RELAY_STATUS_AUTH_FAILED);
|
|
}
|
|
|
|
if (relay_password)
|
|
free (relay_password);
|
|
if (totp_secret)
|
|
free (totp_secret);
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Callback for command "hdata" (from client).
|
|
*
|
|
* Message looks like:
|
|
* hdata buffer:gui_buffers(*) number,name,type,nicklist,title
|
|
* hdata buffer:gui_buffers(*)/own_lines/first_line(*)/data date,displayed,prefix,message
|
|
*/
|
|
|
|
RELAY_WEECHAT_PROTOCOL_CALLBACK(hdata)
|
|
{
|
|
struct t_relay_weechat_msg *msg;
|
|
|
|
RELAY_WEECHAT_PROTOCOL_MIN_ARGS(1);
|
|
|
|
msg = relay_weechat_msg_new (id);
|
|
if (msg)
|
|
{
|
|
if (!relay_weechat_msg_add_hdata (msg, argv[0],
|
|
(argc > 1) ? argv_eol[1] : NULL))
|
|
{
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_HDATA);
|
|
relay_weechat_msg_add_string (msg, NULL); /* h-path */
|
|
relay_weechat_msg_add_string (msg, NULL); /* keys */
|
|
relay_weechat_msg_add_int (msg, 0); /* count */
|
|
}
|
|
relay_weechat_msg_send (client, msg);
|
|
relay_weechat_msg_free (msg);
|
|
}
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Callback for command "info" (from client).
|
|
*
|
|
* Message looks like:
|
|
* info version
|
|
*/
|
|
|
|
RELAY_WEECHAT_PROTOCOL_CALLBACK(info)
|
|
{
|
|
struct t_relay_weechat_msg *msg;
|
|
char *info;
|
|
|
|
RELAY_WEECHAT_PROTOCOL_MIN_ARGS(1);
|
|
|
|
msg = relay_weechat_msg_new (id);
|
|
if (msg)
|
|
{
|
|
info = weechat_info_get (argv[0],
|
|
(argc > 1) ? argv_eol[1] : NULL);
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_INFO);
|
|
relay_weechat_msg_add_string (msg, argv[0]);
|
|
relay_weechat_msg_add_string (msg, info);
|
|
relay_weechat_msg_send (client, msg);
|
|
relay_weechat_msg_free (msg);
|
|
if (info)
|
|
free (info);
|
|
}
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Callback for command "infolist" (from client).
|
|
*
|
|
* Message looks like:
|
|
* infolist buffer
|
|
*/
|
|
|
|
RELAY_WEECHAT_PROTOCOL_CALLBACK(infolist)
|
|
{
|
|
struct t_relay_weechat_msg *msg;
|
|
unsigned long value;
|
|
char *args;
|
|
int rc;
|
|
|
|
RELAY_WEECHAT_PROTOCOL_MIN_ARGS(1);
|
|
|
|
msg = relay_weechat_msg_new (id);
|
|
if (msg)
|
|
{
|
|
value = 0;
|
|
args = NULL;
|
|
if (argc > 1)
|
|
{
|
|
rc = sscanf (argv[1], "%lx", &value);
|
|
if ((rc == EOF) || (rc == 0))
|
|
value = 0;
|
|
if (argc > 2)
|
|
args = argv_eol[2];
|
|
}
|
|
relay_weechat_msg_add_infolist (msg, argv[0], (void *)value, args);
|
|
relay_weechat_msg_send (client, msg);
|
|
relay_weechat_msg_free (msg);
|
|
}
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Callback for command "nicklist" (from client).
|
|
*
|
|
* Message looks like:
|
|
* nicklist irc.freenode.#weechat
|
|
* nicklist 0x12345678
|
|
*/
|
|
|
|
RELAY_WEECHAT_PROTOCOL_CALLBACK(nicklist)
|
|
{
|
|
struct t_relay_weechat_msg *msg;
|
|
struct t_gui_buffer *ptr_buffer;
|
|
|
|
RELAY_WEECHAT_PROTOCOL_MIN_ARGS(0);
|
|
|
|
ptr_buffer = NULL;
|
|
|
|
if (argc > 0)
|
|
{
|
|
ptr_buffer = relay_weechat_protocol_get_buffer (argv[0]);
|
|
if (!ptr_buffer)
|
|
{
|
|
if (weechat_relay_plugin->debug >= 1)
|
|
{
|
|
weechat_printf (NULL,
|
|
_("%s: invalid buffer pointer in message: "
|
|
"\"%s %s\""),
|
|
RELAY_PLUGIN_NAME,
|
|
command,
|
|
argv_eol[0]);
|
|
}
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
}
|
|
|
|
msg = relay_weechat_msg_new (id);
|
|
if (msg)
|
|
{
|
|
relay_weechat_msg_add_nicklist (msg, ptr_buffer, NULL);
|
|
relay_weechat_msg_send (client, msg);
|
|
relay_weechat_msg_free (msg);
|
|
}
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Callback for command "input" (from client).
|
|
*
|
|
* Message looks like:
|
|
* input core.weechat /help filter
|
|
* input irc.freenode.#weechat hello guys!
|
|
* input 0x12345678 hello guys!
|
|
*/
|
|
|
|
RELAY_WEECHAT_PROTOCOL_CALLBACK(input)
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
struct t_hashtable *options;
|
|
const char *ptr_weechat_commands;
|
|
char *pos;
|
|
|
|
RELAY_WEECHAT_PROTOCOL_MIN_ARGS(1);
|
|
|
|
ptr_buffer = relay_weechat_protocol_get_buffer (argv[0]);
|
|
if (!ptr_buffer)
|
|
{
|
|
if (weechat_relay_plugin->debug >= 1)
|
|
{
|
|
weechat_printf (NULL,
|
|
_("%s: invalid buffer pointer in message: "
|
|
"\"%s %s\""),
|
|
RELAY_PLUGIN_NAME,
|
|
command,
|
|
argv[0]);
|
|
}
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
pos = strchr (argv_eol[0], ' ');
|
|
if (!pos)
|
|
return WEECHAT_RC_OK;
|
|
|
|
pos++;
|
|
options = weechat_hashtable_new (8,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
NULL, NULL);
|
|
if (!options)
|
|
{
|
|
weechat_printf (NULL,
|
|
_("%s%s: not enough memory"),
|
|
weechat_prefix ("error"), RELAY_PLUGIN_NAME);
|
|
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, pos, options);
|
|
|
|
weechat_hashtable_free (options);
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Callback for signals "buffer_*".
|
|
*/
|
|
|
|
int
|
|
relay_weechat_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_line *ptr_line;
|
|
struct t_hdata *ptr_hdata_line, *ptr_hdata_line_data;
|
|
struct t_gui_line_data *ptr_line_data;
|
|
struct t_gui_buffer *ptr_buffer;
|
|
struct t_relay_weechat_msg *msg;
|
|
char cmd_hdata[64], str_signal[128];
|
|
const char *ptr_old_full_name;
|
|
int *ptr_old_flags, flags;
|
|
|
|
/* 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;
|
|
|
|
snprintf (str_signal, sizeof (str_signal), "_%s", signal);
|
|
|
|
if (strcmp (signal, "buffer_opened") == 0)
|
|
{
|
|
ptr_buffer = (struct t_gui_buffer *)signal_data;
|
|
if (!ptr_buffer)
|
|
return WEECHAT_RC_OK;
|
|
|
|
/* send signal only if sync with flag "buffers" or "buffer" */
|
|
if (relay_weechat_protocol_is_sync (ptr_client, ptr_buffer,
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_BUFFERS |
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_BUFFER))
|
|
{
|
|
msg = relay_weechat_msg_new (str_signal);
|
|
if (msg)
|
|
{
|
|
snprintf (cmd_hdata, sizeof (cmd_hdata),
|
|
"buffer:0x%lx", (unsigned long)ptr_buffer);
|
|
relay_weechat_msg_add_hdata (msg, cmd_hdata,
|
|
"number,full_name,short_name,"
|
|
"nicklist,title,local_variables,"
|
|
"prev_buffer,next_buffer");
|
|
relay_weechat_msg_send (ptr_client, msg);
|
|
relay_weechat_msg_free (msg);
|
|
}
|
|
}
|
|
}
|
|
else if (strcmp (signal, "buffer_type_changed") == 0)
|
|
{
|
|
ptr_buffer = (struct t_gui_buffer *)signal_data;
|
|
if (!ptr_buffer)
|
|
return WEECHAT_RC_OK;
|
|
|
|
/* send signal only if sync with flag "buffers" or "buffer" */
|
|
if (relay_weechat_protocol_is_sync (ptr_client, ptr_buffer,
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_BUFFERS |
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_BUFFER))
|
|
{
|
|
msg = relay_weechat_msg_new (str_signal);
|
|
if (msg)
|
|
{
|
|
snprintf (cmd_hdata, sizeof (cmd_hdata),
|
|
"buffer:0x%lx", (unsigned long)ptr_buffer);
|
|
relay_weechat_msg_add_hdata (msg, cmd_hdata,
|
|
"number,full_name,type");
|
|
relay_weechat_msg_send (ptr_client, msg);
|
|
relay_weechat_msg_free (msg);
|
|
}
|
|
}
|
|
}
|
|
else if (strcmp (signal, "buffer_moved") == 0)
|
|
{
|
|
ptr_buffer = (struct t_gui_buffer *)signal_data;
|
|
if (!ptr_buffer)
|
|
return WEECHAT_RC_OK;
|
|
|
|
/* send signal only if sync with flag "buffers" or "buffer" */
|
|
if (relay_weechat_protocol_is_sync (ptr_client, ptr_buffer,
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_BUFFERS |
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_BUFFER))
|
|
{
|
|
msg = relay_weechat_msg_new (str_signal);
|
|
if (msg)
|
|
{
|
|
snprintf (cmd_hdata, sizeof (cmd_hdata),
|
|
"buffer:0x%lx", (unsigned long)ptr_buffer);
|
|
relay_weechat_msg_add_hdata (msg, cmd_hdata,
|
|
"number,full_name,"
|
|
"prev_buffer,next_buffer");
|
|
relay_weechat_msg_send (ptr_client, msg);
|
|
relay_weechat_msg_free (msg);
|
|
}
|
|
}
|
|
}
|
|
else if ((strcmp (signal, "buffer_merged") == 0)
|
|
|| (strcmp (signal, "buffer_unmerged") == 0))
|
|
{
|
|
ptr_buffer = (struct t_gui_buffer *)signal_data;
|
|
if (!ptr_buffer)
|
|
return WEECHAT_RC_OK;
|
|
|
|
/* send signal only if sync with flag "buffers" or "buffer" */
|
|
if (relay_weechat_protocol_is_sync (ptr_client, ptr_buffer,
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_BUFFERS |
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_BUFFER))
|
|
{
|
|
msg = relay_weechat_msg_new (str_signal);
|
|
if (msg)
|
|
{
|
|
snprintf (cmd_hdata, sizeof (cmd_hdata),
|
|
"buffer:0x%lx", (unsigned long)ptr_buffer);
|
|
relay_weechat_msg_add_hdata (msg, cmd_hdata,
|
|
"number,full_name,"
|
|
"prev_buffer,next_buffer");
|
|
relay_weechat_msg_send (ptr_client, msg);
|
|
relay_weechat_msg_free (msg);
|
|
}
|
|
}
|
|
}
|
|
else if ((strcmp (signal, "buffer_hidden") == 0)
|
|
|| (strcmp (signal, "buffer_unhidden") == 0))
|
|
{
|
|
ptr_buffer = (struct t_gui_buffer *)signal_data;
|
|
if (!ptr_buffer)
|
|
return WEECHAT_RC_OK;
|
|
|
|
/* send signal only if sync with flag "buffers" or "buffer" */
|
|
if (relay_weechat_protocol_is_sync (ptr_client, ptr_buffer,
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_BUFFERS |
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_BUFFER))
|
|
{
|
|
msg = relay_weechat_msg_new (str_signal);
|
|
if (msg)
|
|
{
|
|
snprintf (cmd_hdata, sizeof (cmd_hdata),
|
|
"buffer:0x%lx", (unsigned long)ptr_buffer);
|
|
relay_weechat_msg_add_hdata (msg, cmd_hdata,
|
|
"number,full_name,"
|
|
"prev_buffer,next_buffer");
|
|
relay_weechat_msg_send (ptr_client, msg);
|
|
relay_weechat_msg_free (msg);
|
|
}
|
|
}
|
|
}
|
|
else if (strcmp (signal, "buffer_renamed") == 0)
|
|
{
|
|
ptr_buffer = (struct t_gui_buffer *)signal_data;
|
|
if (!ptr_buffer)
|
|
return WEECHAT_RC_OK;
|
|
|
|
/* rename old buffer name if present in hashtable "buffers_sync" */
|
|
ptr_old_full_name = weechat_buffer_get_string (ptr_buffer,
|
|
"old_full_name");
|
|
if (ptr_old_full_name && ptr_old_full_name[0])
|
|
{
|
|
ptr_old_flags = weechat_hashtable_get (
|
|
RELAY_WEECHAT_DATA(ptr_client, buffers_sync),
|
|
ptr_old_full_name);
|
|
if (ptr_old_flags)
|
|
{
|
|
flags = *ptr_old_flags;
|
|
weechat_hashtable_remove (
|
|
RELAY_WEECHAT_DATA(ptr_client, buffers_sync),
|
|
ptr_old_full_name);
|
|
weechat_hashtable_set (
|
|
RELAY_WEECHAT_DATA(ptr_client, buffers_sync),
|
|
weechat_buffer_get_string (ptr_buffer, "full_name"),
|
|
&flags);
|
|
}
|
|
}
|
|
|
|
/* send signal only if sync with flag "buffers" or "buffer" */
|
|
if (relay_weechat_protocol_is_sync (ptr_client, ptr_buffer,
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_BUFFERS |
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_BUFFER))
|
|
{
|
|
msg = relay_weechat_msg_new (str_signal);
|
|
if (msg)
|
|
{
|
|
snprintf (cmd_hdata, sizeof (cmd_hdata),
|
|
"buffer:0x%lx", (unsigned long)ptr_buffer);
|
|
relay_weechat_msg_add_hdata (msg, cmd_hdata,
|
|
"number,full_name,short_name,"
|
|
"local_variables");
|
|
relay_weechat_msg_send (ptr_client, msg);
|
|
relay_weechat_msg_free (msg);
|
|
}
|
|
}
|
|
}
|
|
else if (strcmp (signal, "buffer_title_changed") == 0)
|
|
{
|
|
ptr_buffer = (struct t_gui_buffer *)signal_data;
|
|
if (!ptr_buffer)
|
|
return WEECHAT_RC_OK;
|
|
|
|
/* send signal only if sync with flag "buffers" or "buffer" */
|
|
if (relay_weechat_protocol_is_sync (ptr_client, ptr_buffer,
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_BUFFERS |
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_BUFFER))
|
|
{
|
|
msg = relay_weechat_msg_new (str_signal);
|
|
if (msg)
|
|
{
|
|
snprintf (cmd_hdata, sizeof (cmd_hdata),
|
|
"buffer:0x%lx", (unsigned long)ptr_buffer);
|
|
relay_weechat_msg_add_hdata (msg, cmd_hdata,
|
|
"number,full_name,title");
|
|
relay_weechat_msg_send (ptr_client, msg);
|
|
relay_weechat_msg_free (msg);
|
|
}
|
|
}
|
|
}
|
|
else if (strncmp (signal, "buffer_localvar_", 16) == 0)
|
|
{
|
|
ptr_buffer = (struct t_gui_buffer *)signal_data;
|
|
if (!ptr_buffer)
|
|
return WEECHAT_RC_OK;
|
|
|
|
/* send signal only if sync with flag "buffers" or "buffer" */
|
|
if (relay_weechat_protocol_is_sync (ptr_client, ptr_buffer,
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_BUFFERS |
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_BUFFER))
|
|
{
|
|
msg = relay_weechat_msg_new (str_signal);
|
|
if (msg)
|
|
{
|
|
snprintf (cmd_hdata, sizeof (cmd_hdata),
|
|
"buffer:0x%lx", (unsigned long)ptr_buffer);
|
|
relay_weechat_msg_add_hdata (msg, cmd_hdata,
|
|
"number,full_name,local_variables");
|
|
relay_weechat_msg_send (ptr_client, msg);
|
|
relay_weechat_msg_free (msg);
|
|
}
|
|
}
|
|
}
|
|
else if (strcmp (signal, "buffer_cleared") == 0)
|
|
{
|
|
ptr_buffer = (struct t_gui_buffer *)signal_data;
|
|
if (!ptr_buffer || relay_weechat_is_relay_buffer (ptr_buffer))
|
|
return WEECHAT_RC_OK;
|
|
|
|
/* send signal only if sync with flag "buffer" */
|
|
if (relay_weechat_protocol_is_sync (ptr_client, ptr_buffer,
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_BUFFER))
|
|
{
|
|
msg = relay_weechat_msg_new (str_signal);
|
|
if (msg)
|
|
{
|
|
snprintf (cmd_hdata, sizeof (cmd_hdata),
|
|
"buffer:0x%lx", (unsigned long)ptr_buffer);
|
|
relay_weechat_msg_add_hdata (msg, cmd_hdata,
|
|
"number,full_name");
|
|
relay_weechat_msg_send (ptr_client, msg);
|
|
relay_weechat_msg_free (msg);
|
|
}
|
|
}
|
|
}
|
|
else if (strcmp (signal, "buffer_line_added") == 0)
|
|
{
|
|
ptr_line = (struct t_gui_line *)signal_data;
|
|
if (!ptr_line)
|
|
return WEECHAT_RC_OK;
|
|
|
|
ptr_hdata_line = weechat_hdata_get ("line");
|
|
if (!ptr_hdata_line)
|
|
return WEECHAT_RC_OK;
|
|
|
|
ptr_hdata_line_data = weechat_hdata_get ("line_data");
|
|
if (!ptr_hdata_line_data)
|
|
return WEECHAT_RC_OK;
|
|
|
|
ptr_line_data = weechat_hdata_pointer (ptr_hdata_line, ptr_line, "data");
|
|
if (!ptr_line_data)
|
|
return WEECHAT_RC_OK;
|
|
|
|
ptr_buffer = weechat_hdata_pointer (ptr_hdata_line_data, ptr_line_data,
|
|
"buffer");
|
|
if (!ptr_buffer || relay_weechat_is_relay_buffer (ptr_buffer))
|
|
return WEECHAT_RC_OK;
|
|
|
|
/* send signal only if sync with flag "buffer" */
|
|
if (relay_weechat_protocol_is_sync (ptr_client, ptr_buffer,
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_BUFFER))
|
|
{
|
|
msg = relay_weechat_msg_new (str_signal);
|
|
if (msg)
|
|
{
|
|
snprintf (cmd_hdata, sizeof (cmd_hdata),
|
|
"line_data:0x%lx",
|
|
(unsigned long)ptr_line_data);
|
|
relay_weechat_msg_add_hdata (msg, cmd_hdata,
|
|
"buffer,date,date_printed,"
|
|
"displayed,highlight,tags_array,"
|
|
"prefix,message");
|
|
relay_weechat_msg_send (ptr_client, msg);
|
|
relay_weechat_msg_free (msg);
|
|
}
|
|
}
|
|
}
|
|
else if (strcmp (signal, "buffer_closing") == 0)
|
|
{
|
|
ptr_buffer = (struct t_gui_buffer *)signal_data;
|
|
if (!ptr_buffer)
|
|
return WEECHAT_RC_OK;
|
|
|
|
/* send signal only if sync with flag "buffers" or "buffer" */
|
|
if (relay_weechat_protocol_is_sync (ptr_client, ptr_buffer,
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_BUFFERS |
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_BUFFER))
|
|
{
|
|
msg = relay_weechat_msg_new (str_signal);
|
|
if (msg)
|
|
{
|
|
snprintf (cmd_hdata, sizeof (cmd_hdata),
|
|
"buffer:0x%lx", (unsigned long)ptr_buffer);
|
|
relay_weechat_msg_add_hdata (msg, cmd_hdata,
|
|
"number,full_name");
|
|
relay_weechat_msg_send (ptr_client, msg);
|
|
relay_weechat_msg_free (msg);
|
|
}
|
|
}
|
|
|
|
/* remove buffer from hashtables */
|
|
weechat_hashtable_remove (
|
|
RELAY_WEECHAT_DATA(ptr_client, buffers_sync),
|
|
weechat_buffer_get_string (ptr_buffer, "full_name"));
|
|
weechat_hashtable_remove (
|
|
RELAY_WEECHAT_DATA(ptr_client, buffers_nicklist),
|
|
ptr_buffer);
|
|
}
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Callback for entries in hashtable "buffers_nicklist" of client (sends
|
|
* nicklist for each buffer in this hashtable).
|
|
*/
|
|
|
|
void
|
|
relay_weechat_protocol_nicklist_map_cb (void *data,
|
|
struct t_hashtable *hashtable,
|
|
const void *key,
|
|
const void *value)
|
|
{
|
|
struct t_relay_client *ptr_client;
|
|
struct t_gui_buffer *ptr_buffer;
|
|
struct t_relay_weechat_nicklist *ptr_nicklist;
|
|
struct t_hdata *ptr_hdata;
|
|
struct t_relay_weechat_msg *msg;
|
|
|
|
/* make C compiler happy */
|
|
(void) hashtable;
|
|
|
|
ptr_client = (struct t_relay_client *)data;
|
|
ptr_buffer = (struct t_gui_buffer *)key;
|
|
ptr_nicklist = (struct t_relay_weechat_nicklist *)value;
|
|
|
|
ptr_hdata = weechat_hdata_get ("buffer");
|
|
if (ptr_hdata)
|
|
{
|
|
if (weechat_hdata_check_pointer (ptr_hdata,
|
|
weechat_hdata_get_list (ptr_hdata, "gui_buffers"),
|
|
ptr_buffer))
|
|
{
|
|
/*
|
|
* if no diff at all, or if diffs are bigger than nicklist:
|
|
* send whole nicklist
|
|
*/
|
|
if (ptr_nicklist
|
|
&& ((ptr_nicklist->items_count == 0)
|
|
|| (ptr_nicklist->items_count >= weechat_buffer_get_integer (ptr_buffer, "nicklist_count") + 1)))
|
|
{
|
|
ptr_nicklist = NULL;
|
|
}
|
|
|
|
/* send nicklist diffs or full nicklist */
|
|
msg = relay_weechat_msg_new ((ptr_nicklist) ? "_nicklist_diff" : "_nicklist");
|
|
if (msg)
|
|
{
|
|
relay_weechat_msg_add_nicklist (msg, ptr_buffer, ptr_nicklist);
|
|
relay_weechat_msg_send (ptr_client, msg);
|
|
relay_weechat_msg_free (msg);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Callback for nicklist timer.
|
|
*/
|
|
|
|
int
|
|
relay_weechat_protocol_timer_nicklist_cb (const void *pointer, void *data,
|
|
int remaining_calls)
|
|
{
|
|
struct t_relay_client *ptr_client;
|
|
|
|
/* make C compiler happy */
|
|
(void) data;
|
|
(void) remaining_calls;
|
|
|
|
ptr_client = (struct t_relay_client *)pointer;
|
|
if (!ptr_client || !relay_client_valid (ptr_client))
|
|
return WEECHAT_RC_OK;
|
|
|
|
weechat_hashtable_map (RELAY_WEECHAT_DATA(ptr_client, buffers_nicklist),
|
|
&relay_weechat_protocol_nicklist_map_cb,
|
|
ptr_client);
|
|
|
|
weechat_hashtable_remove_all (RELAY_WEECHAT_DATA(ptr_client, buffers_nicklist));
|
|
|
|
RELAY_WEECHAT_DATA(ptr_client, hook_timer_nicklist) = NULL;
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Callback for hsignals "nicklist_*".
|
|
*/
|
|
|
|
int
|
|
relay_weechat_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_nick_group *parent_group, *group;
|
|
struct t_gui_nick *nick;
|
|
struct t_gui_buffer *ptr_buffer;
|
|
struct t_relay_weechat_nicklist *ptr_nicklist;
|
|
char diff;
|
|
|
|
/* 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;
|
|
|
|
/* check if buffer is synchronized with flag "nicklist" */
|
|
ptr_buffer = weechat_hashtable_get (hashtable, "buffer");
|
|
if (!relay_weechat_protocol_is_sync (ptr_client, ptr_buffer,
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_NICKLIST))
|
|
return WEECHAT_RC_OK;
|
|
|
|
parent_group = weechat_hashtable_get (hashtable, "parent_group");
|
|
group = weechat_hashtable_get (hashtable, "group");
|
|
nick = weechat_hashtable_get (hashtable, "nick");
|
|
|
|
/* if there is no parent group (for example "root" group), ignore the signal */
|
|
if (!parent_group)
|
|
return WEECHAT_RC_OK;
|
|
|
|
ptr_nicklist = weechat_hashtable_get (RELAY_WEECHAT_DATA(ptr_client,
|
|
buffers_nicklist),
|
|
ptr_buffer);
|
|
if (!ptr_nicklist)
|
|
{
|
|
ptr_nicklist = relay_weechat_nicklist_new ();
|
|
if (!ptr_nicklist)
|
|
return WEECHAT_RC_OK;
|
|
ptr_nicklist->nicklist_count = weechat_buffer_get_integer (ptr_buffer,
|
|
"nicklist_count");
|
|
weechat_hashtable_set (RELAY_WEECHAT_DATA(ptr_client, buffers_nicklist),
|
|
ptr_buffer,
|
|
ptr_nicklist);
|
|
}
|
|
|
|
/* set diff type */
|
|
diff = RELAY_WEECHAT_NICKLIST_DIFF_UNKNOWN;
|
|
if ((strcmp (signal, "nicklist_group_added") == 0)
|
|
|| (strcmp (signal, "nicklist_nick_added") == 0))
|
|
{
|
|
diff = RELAY_WEECHAT_NICKLIST_DIFF_ADDED;
|
|
}
|
|
else if ((strcmp (signal, "nicklist_group_removing") == 0)
|
|
|| (strcmp (signal, "nicklist_nick_removing") == 0))
|
|
{
|
|
diff = RELAY_WEECHAT_NICKLIST_DIFF_REMOVED;
|
|
}
|
|
else if ((strcmp (signal, "nicklist_group_changed") == 0)
|
|
|| (strcmp (signal, "nicklist_nick_changed") == 0))
|
|
{
|
|
diff = RELAY_WEECHAT_NICKLIST_DIFF_CHANGED;
|
|
}
|
|
|
|
if (diff != RELAY_WEECHAT_NICKLIST_DIFF_UNKNOWN)
|
|
{
|
|
/*
|
|
* add items if nicklist was not empty or very small (otherwise we will
|
|
* send full nicklist)
|
|
*/
|
|
if (ptr_nicklist->nicklist_count > 1)
|
|
{
|
|
/* add nicklist item for parent group and group/nick */
|
|
relay_weechat_nicklist_add_item (ptr_nicklist,
|
|
RELAY_WEECHAT_NICKLIST_DIFF_PARENT,
|
|
parent_group, NULL);
|
|
relay_weechat_nicklist_add_item (ptr_nicklist, diff, group, nick);
|
|
}
|
|
|
|
/* add timer to send nicklist */
|
|
if (RELAY_WEECHAT_DATA(ptr_client, hook_timer_nicklist))
|
|
{
|
|
weechat_unhook (RELAY_WEECHAT_DATA(ptr_client, hook_timer_nicklist));
|
|
RELAY_WEECHAT_DATA(ptr_client, hook_timer_nicklist) = NULL;
|
|
}
|
|
relay_weechat_hook_timer_nicklist (ptr_client);
|
|
}
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Callback for signals "upgrade*".
|
|
*/
|
|
|
|
int
|
|
relay_weechat_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;
|
|
struct t_relay_weechat_msg *msg;
|
|
char str_signal[128];
|
|
|
|
/* 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;
|
|
|
|
snprintf (str_signal, sizeof (str_signal), "_%s", signal);
|
|
|
|
if ((strcmp (signal, "upgrade") == 0)
|
|
|| (strcmp (signal, "upgrade_ended") == 0))
|
|
{
|
|
/* send signal only if client is synchronized with flag "upgrade" */
|
|
if (relay_weechat_protocol_is_sync (ptr_client, NULL,
|
|
RELAY_WEECHAT_PROTOCOL_SYNC_UPGRADE))
|
|
{
|
|
msg = relay_weechat_msg_new (str_signal);
|
|
if (msg)
|
|
{
|
|
relay_weechat_msg_send (ptr_client, msg);
|
|
relay_weechat_msg_free (msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Callback for command "sync" (from client).
|
|
*
|
|
* Message looks like:
|
|
* sync
|
|
* sync * buffer
|
|
* sync irc.freenode.#weechat buffer,nicklist
|
|
*/
|
|
|
|
RELAY_WEECHAT_PROTOCOL_CALLBACK(sync)
|
|
{
|
|
char **buffers, **flags;
|
|
const char *ptr_full_name;
|
|
int num_buffers, num_flags, i, add_flags, mask, *ptr_old_flags, new_flags;
|
|
struct t_gui_buffer *ptr_buffer;
|
|
|
|
RELAY_WEECHAT_PROTOCOL_MIN_ARGS(0);
|
|
|
|
buffers = weechat_string_split ((argc > 0) ? argv[0] : "*",
|
|
",",
|
|
NULL,
|
|
WEECHAT_STRING_SPLIT_STRIP_LEFT
|
|
| WEECHAT_STRING_SPLIT_STRIP_RIGHT
|
|
| WEECHAT_STRING_SPLIT_COLLAPSE_SEPS,
|
|
0,
|
|
&num_buffers);
|
|
if (buffers)
|
|
{
|
|
add_flags = RELAY_WEECHAT_PROTOCOL_SYNC_ALL;
|
|
if (argc > 1)
|
|
{
|
|
add_flags = 0;
|
|
flags = weechat_string_split (argv[1], ",", NULL,
|
|
WEECHAT_STRING_SPLIT_STRIP_LEFT
|
|
| WEECHAT_STRING_SPLIT_STRIP_RIGHT
|
|
| WEECHAT_STRING_SPLIT_COLLAPSE_SEPS,
|
|
0, &num_flags);
|
|
if (flags)
|
|
{
|
|
for (i = 0; i < num_flags; i++)
|
|
{
|
|
add_flags |= relay_weechat_protocol_sync_flag (flags[i]);
|
|
}
|
|
weechat_string_free_split (flags);
|
|
}
|
|
}
|
|
if (add_flags)
|
|
{
|
|
for (i = 0; i < num_buffers; i++)
|
|
{
|
|
ptr_full_name = NULL;
|
|
mask = RELAY_WEECHAT_PROTOCOL_SYNC_FOR_BUFFER;
|
|
|
|
if (strcmp (buffers[i], "*") == 0)
|
|
{
|
|
ptr_full_name = buffers[i];
|
|
mask = RELAY_WEECHAT_PROTOCOL_SYNC_ALL;
|
|
}
|
|
else
|
|
{
|
|
ptr_buffer = relay_weechat_protocol_get_buffer (buffers[i]);
|
|
if (ptr_buffer)
|
|
{
|
|
ptr_full_name = weechat_buffer_get_string (ptr_buffer,
|
|
"full_name");
|
|
}
|
|
}
|
|
|
|
if (ptr_full_name)
|
|
{
|
|
ptr_old_flags = weechat_hashtable_get (RELAY_WEECHAT_DATA(client, buffers_sync),
|
|
ptr_full_name);
|
|
new_flags = ((ptr_old_flags) ? *ptr_old_flags : 0);
|
|
new_flags |= (add_flags & mask);
|
|
if (new_flags)
|
|
{
|
|
weechat_hashtable_set (RELAY_WEECHAT_DATA(client, buffers_sync),
|
|
ptr_full_name,
|
|
&new_flags);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
weechat_string_free_split (buffers);
|
|
}
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Callback for command "desync" (from client).
|
|
*
|
|
* Message looks like:
|
|
* desync
|
|
* desync * nicklist
|
|
* desync irc.freenode.#weechat buffer,nicklist
|
|
*/
|
|
|
|
RELAY_WEECHAT_PROTOCOL_CALLBACK(desync)
|
|
{
|
|
char **buffers, **flags;
|
|
const char *ptr_full_name;
|
|
int num_buffers, num_flags, i, sub_flags, mask, *ptr_old_flags, new_flags;
|
|
struct t_gui_buffer *ptr_buffer;
|
|
|
|
RELAY_WEECHAT_PROTOCOL_MIN_ARGS(0);
|
|
|
|
buffers = weechat_string_split ((argc > 0) ? argv[0] : "*",
|
|
",",
|
|
NULL,
|
|
WEECHAT_STRING_SPLIT_STRIP_LEFT
|
|
| WEECHAT_STRING_SPLIT_STRIP_RIGHT
|
|
| WEECHAT_STRING_SPLIT_COLLAPSE_SEPS,
|
|
0,
|
|
&num_buffers);
|
|
if (buffers)
|
|
{
|
|
sub_flags = RELAY_WEECHAT_PROTOCOL_SYNC_ALL;
|
|
if (argc > 1)
|
|
{
|
|
sub_flags = 0;
|
|
flags = weechat_string_split (argv[1], ",", NULL,
|
|
WEECHAT_STRING_SPLIT_STRIP_LEFT
|
|
| WEECHAT_STRING_SPLIT_STRIP_RIGHT
|
|
| WEECHAT_STRING_SPLIT_COLLAPSE_SEPS,
|
|
0, &num_flags);
|
|
if (flags)
|
|
{
|
|
for (i = 0; i < num_flags; i++)
|
|
{
|
|
sub_flags |= relay_weechat_protocol_sync_flag (flags[i]);
|
|
}
|
|
weechat_string_free_split (flags);
|
|
}
|
|
}
|
|
if (sub_flags)
|
|
{
|
|
for (i = 0; i < num_buffers; i++)
|
|
{
|
|
ptr_full_name = NULL;
|
|
mask = RELAY_WEECHAT_PROTOCOL_SYNC_FOR_BUFFER;
|
|
|
|
if (strcmp (buffers[i], "*") == 0)
|
|
{
|
|
ptr_full_name = buffers[i];
|
|
mask = RELAY_WEECHAT_PROTOCOL_SYNC_ALL;
|
|
}
|
|
else
|
|
{
|
|
ptr_buffer = relay_weechat_protocol_get_buffer (buffers[i]);
|
|
if (ptr_buffer)
|
|
{
|
|
ptr_full_name = weechat_buffer_get_string (ptr_buffer,
|
|
"full_name");
|
|
}
|
|
}
|
|
|
|
if (ptr_full_name)
|
|
{
|
|
ptr_old_flags = weechat_hashtable_get (RELAY_WEECHAT_DATA(client, buffers_sync),
|
|
ptr_full_name);
|
|
new_flags = ((ptr_old_flags) ? *ptr_old_flags : 0);
|
|
new_flags &= ~(sub_flags & mask);
|
|
if (new_flags)
|
|
{
|
|
weechat_hashtable_set (RELAY_WEECHAT_DATA(client, buffers_sync),
|
|
ptr_full_name,
|
|
&new_flags);
|
|
}
|
|
else
|
|
{
|
|
weechat_hashtable_remove (RELAY_WEECHAT_DATA(client, buffers_sync),
|
|
ptr_full_name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
weechat_string_free_split (buffers);
|
|
}
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Callback for command "test" (from client).
|
|
*
|
|
* Message looks like:
|
|
* test
|
|
*/
|
|
|
|
RELAY_WEECHAT_PROTOCOL_CALLBACK(test)
|
|
{
|
|
struct t_relay_weechat_msg *msg;
|
|
|
|
RELAY_WEECHAT_PROTOCOL_MIN_ARGS(0);
|
|
|
|
msg = relay_weechat_msg_new (id);
|
|
if (msg)
|
|
{
|
|
/* char */
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_CHAR);
|
|
relay_weechat_msg_add_char (msg, 'A');
|
|
|
|
/* integer */
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_INT);
|
|
relay_weechat_msg_add_int (msg, 123456);
|
|
|
|
/* integer (negative) */
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_INT);
|
|
relay_weechat_msg_add_int (msg, -123456);
|
|
|
|
/* long */
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_LONG);
|
|
relay_weechat_msg_add_long (msg, 1234567890L);
|
|
|
|
/* long (negative) */
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_LONG);
|
|
relay_weechat_msg_add_long (msg, -1234567890L);
|
|
|
|
/* string */
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_STRING);
|
|
relay_weechat_msg_add_string (msg, "a string");
|
|
|
|
/* empty string */
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_STRING);
|
|
relay_weechat_msg_add_string (msg, "");
|
|
|
|
/* NULL string */
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_STRING);
|
|
relay_weechat_msg_add_string (msg, NULL);
|
|
|
|
/* buffer */
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_BUFFER);
|
|
relay_weechat_msg_add_buffer (msg, "buffer", 6);
|
|
|
|
/* NULL buffer */
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_BUFFER);
|
|
relay_weechat_msg_add_buffer (msg, NULL, 0);
|
|
|
|
/* pointer */
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_POINTER);
|
|
relay_weechat_msg_add_pointer (msg, (void *)0x1234abcd);
|
|
|
|
/* NULL pointer */
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_POINTER);
|
|
relay_weechat_msg_add_pointer (msg, NULL);
|
|
|
|
/* time */
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_TIME);
|
|
relay_weechat_msg_add_time (msg, 1321993456);
|
|
|
|
/* array of strings: { "abc", "de" } */
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_ARRAY);
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_STRING);
|
|
relay_weechat_msg_add_int (msg, 2);
|
|
relay_weechat_msg_add_string (msg, "abc");
|
|
relay_weechat_msg_add_string (msg, "de");
|
|
|
|
/* array of integers: { 123, 456, 789 } */
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_ARRAY);
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_INT);
|
|
relay_weechat_msg_add_int (msg, 3);
|
|
relay_weechat_msg_add_int (msg, 123);
|
|
relay_weechat_msg_add_int (msg, 456);
|
|
relay_weechat_msg_add_int (msg, 789);
|
|
|
|
/* send message */
|
|
relay_weechat_msg_send (client, msg);
|
|
relay_weechat_msg_free (msg);
|
|
}
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Callback for command "ping" (from client).
|
|
*
|
|
* Message looks like:
|
|
* ping
|
|
* ping 1370802127000
|
|
*/
|
|
|
|
RELAY_WEECHAT_PROTOCOL_CALLBACK(ping)
|
|
{
|
|
struct t_relay_weechat_msg *msg;
|
|
|
|
RELAY_WEECHAT_PROTOCOL_MIN_ARGS(0);
|
|
|
|
msg = relay_weechat_msg_new ("_pong");
|
|
if (msg)
|
|
{
|
|
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_STRING);
|
|
relay_weechat_msg_add_string (msg, (argc > 0) ? argv_eol[0] : "");
|
|
|
|
/* send message */
|
|
relay_weechat_msg_send (client, msg);
|
|
relay_weechat_msg_free (msg);
|
|
}
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Callback for command "quit" (from client).
|
|
*
|
|
* Message looks like:
|
|
* test
|
|
*/
|
|
|
|
RELAY_WEECHAT_PROTOCOL_CALLBACK(quit)
|
|
{
|
|
RELAY_WEECHAT_PROTOCOL_MIN_ARGS(0);
|
|
|
|
relay_client_set_status (client, RELAY_STATUS_DISCONNECTED);
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Reads a command from a client.
|
|
*/
|
|
|
|
void
|
|
relay_weechat_protocol_recv (struct t_relay_client *client, const char *data)
|
|
{
|
|
char *pos, *id, *command, **argv, **argv_eol;
|
|
int i, argc, return_code;
|
|
struct t_relay_weechat_protocol_cb protocol_cb[] =
|
|
{ { "handshake", &relay_weechat_protocol_cb_handshake },
|
|
{ "init", &relay_weechat_protocol_cb_init },
|
|
{ "hdata", &relay_weechat_protocol_cb_hdata },
|
|
{ "info", &relay_weechat_protocol_cb_info },
|
|
{ "infolist", &relay_weechat_protocol_cb_infolist },
|
|
{ "nicklist", &relay_weechat_protocol_cb_nicklist },
|
|
{ "input", &relay_weechat_protocol_cb_input },
|
|
{ "sync", &relay_weechat_protocol_cb_sync },
|
|
{ "desync", &relay_weechat_protocol_cb_desync },
|
|
{ "test", &relay_weechat_protocol_cb_test },
|
|
{ "ping", &relay_weechat_protocol_cb_ping },
|
|
{ "quit", &relay_weechat_protocol_cb_quit },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
if (!data || !data[0] || RELAY_CLIENT_HAS_ENDED(client))
|
|
return;
|
|
|
|
/* display debug message */
|
|
if (weechat_relay_plugin->debug >= 2)
|
|
{
|
|
weechat_printf (NULL, "%s: recv from client %s%s%s: \"%s\"",
|
|
RELAY_PLUGIN_NAME,
|
|
RELAY_COLOR_CHAT_CLIENT,
|
|
client->desc,
|
|
RELAY_COLOR_CHAT,
|
|
data);
|
|
}
|
|
|
|
/* extract id */
|
|
id = NULL;
|
|
if (data[0] == '(')
|
|
{
|
|
pos = strchr (data, ')');
|
|
if (pos)
|
|
{
|
|
id = weechat_strndup (data + 1, pos - data - 1);
|
|
data = pos + 1;
|
|
while (data[0] == ' ')
|
|
{
|
|
data++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* search end of data */
|
|
pos = strchr (data, ' ');
|
|
if (pos)
|
|
command = weechat_strndup (data, pos - data);
|
|
else
|
|
command = strdup (data);
|
|
|
|
if (!command)
|
|
{
|
|
if (id)
|
|
free (id);
|
|
return;
|
|
}
|
|
|
|
argc = 0;
|
|
argv = NULL;
|
|
argv_eol = NULL;
|
|
|
|
if (pos)
|
|
{
|
|
while (pos[0] == ' ')
|
|
{
|
|
pos++;
|
|
}
|
|
argv = weechat_string_split (pos, " ", NULL,
|
|
WEECHAT_STRING_SPLIT_STRIP_LEFT
|
|
| WEECHAT_STRING_SPLIT_STRIP_RIGHT
|
|
| WEECHAT_STRING_SPLIT_COLLAPSE_SEPS,
|
|
0, &argc);
|
|
argv_eol = weechat_string_split (pos, " ", NULL,
|
|
WEECHAT_STRING_SPLIT_STRIP_LEFT
|
|
| WEECHAT_STRING_SPLIT_COLLAPSE_SEPS
|
|
| WEECHAT_STRING_SPLIT_KEEP_EOL,
|
|
0, NULL);
|
|
}
|
|
|
|
for (i = 0; protocol_cb[i].name; i++)
|
|
{
|
|
if (strcmp (protocol_cb[i].name, command) == 0)
|
|
{
|
|
if ((strcmp (protocol_cb[i].name, "handshake") != 0)
|
|
&& (strcmp (protocol_cb[i].name, "init") != 0)
|
|
&& (!RELAY_WEECHAT_DATA(client, password_ok)
|
|
|| !RELAY_WEECHAT_DATA(client, totp_ok)))
|
|
{
|
|
/*
|
|
* command is not handshake/init and password or totp are not
|
|
* set? then close connection!
|
|
*/
|
|
relay_client_set_status (client,
|
|
RELAY_STATUS_AUTH_FAILED);
|
|
}
|
|
else
|
|
{
|
|
return_code = (int) (protocol_cb[i].cmd_function) (client,
|
|
id,
|
|
protocol_cb[i].name,
|
|
argc,
|
|
argv,
|
|
argv_eol);
|
|
if ((weechat_relay_plugin->debug >= 1)
|
|
&& (return_code == WEECHAT_RC_ERROR))
|
|
{
|
|
weechat_printf (NULL,
|
|
_("%s%s: failed to execute command \"%s\" "
|
|
"for client %s%s%s"),
|
|
weechat_prefix ("error"),
|
|
RELAY_PLUGIN_NAME,
|
|
command,
|
|
RELAY_COLOR_CHAT_CLIENT,
|
|
client->desc,
|
|
RELAY_COLOR_CHAT);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (id)
|
|
free (id);
|
|
free (command);
|
|
if (argv)
|
|
weechat_string_free_split (argv);
|
|
if (argv_eol)
|
|
weechat_string_free_split (argv_eol);
|
|
}
|