1
0
mirror of https://github.com/weechat/weechat.git synced 2026-07-03 08:13:14 +02:00
Files
weechat/src/plugins/relay/weechat/relay-weechat-msg.c
T
2018-01-05 00:54:18 +01:00

1108 lines
39 KiB
C

/*
* relay-weechat-msg.c - build binary messages for WeeChat protocol
*
* Copyright (C) 2003-2018 Sébastien Helleu <flashcode@flashtux.org>
*
* This file is part of WeeChat, the extensible chat client.
*
* WeeChat is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <errno.h>
#include <arpa/inet.h>
#include <zlib.h>
#include "../../weechat-plugin.h"
#include "../relay.h"
#include "relay-weechat.h"
#include "relay-weechat-msg.h"
#include "relay-weechat-nicklist.h"
#include "../relay-buffer.h"
#include "../relay-client.h"
#include "../relay-config.h"
#include "../relay-raw.h"
/*
* Builds a new message (for sending to client).
*
* Returns pointer to new message, NULL if error.
*/
struct t_relay_weechat_msg *
relay_weechat_msg_new (const char *id)
{
struct t_relay_weechat_msg *new_msg;
new_msg = malloc (sizeof (*new_msg));
if (!new_msg)
return NULL;
new_msg->id = (id) ? strdup (id) : NULL;
new_msg->data = malloc (RELAY_WEECHAT_MSG_INITIAL_ALLOC);
if (!new_msg->data)
{
free (new_msg);
return NULL;
}
new_msg->data_alloc = RELAY_WEECHAT_MSG_INITIAL_ALLOC;
new_msg->data_size = 0;
/* add size and compression flag (they will be set later) */
relay_weechat_msg_add_int (new_msg, 0);
relay_weechat_msg_add_char (new_msg, 0);
/* add id */
relay_weechat_msg_add_string (new_msg, id);
return new_msg;
}
/*
* Adds some bytes to a message.
*/
void
relay_weechat_msg_add_bytes (struct t_relay_weechat_msg *msg,
const void *buffer, int size)
{
char *ptr;
if (!msg || !msg->data)
return;
while (msg->data_size + size > msg->data_alloc)
{
msg->data_alloc *= 2;
ptr = realloc (msg->data, msg->data_alloc);
if (!ptr)
{
free (msg->data);
msg->data = NULL;
msg->data_alloc = 0;
msg->data_size = 0;
return;
}
msg->data = ptr;
}
memcpy (msg->data + msg->data_size, buffer, size);
msg->data_size += size;
}
/*
* Sets some bytes in a message.
*/
void
relay_weechat_msg_set_bytes (struct t_relay_weechat_msg *msg,
int position, const void *buffer, int size)
{
if (!msg || !msg->data || (position + size) > msg->data_size)
return;
memcpy (msg->data + position, buffer, size);
}
/*
* Adds type to a message.
*/
void
relay_weechat_msg_add_type (struct t_relay_weechat_msg *msg, const char *string)
{
if (string)
relay_weechat_msg_add_bytes (msg, string, strlen (string));
}
/*
* Adds a char to a message.
*/
void
relay_weechat_msg_add_char (struct t_relay_weechat_msg *msg, char c)
{
relay_weechat_msg_add_bytes (msg, &c, 1);
}
/*
* Adds an integer to a message.
*/
void
relay_weechat_msg_add_int (struct t_relay_weechat_msg *msg, int value)
{
uint32_t value32;
value32 = htonl ((uint32_t)value);
relay_weechat_msg_add_bytes (msg, &value32, 4);
}
/*
* Adds a long integer to a message.
*/
void
relay_weechat_msg_add_long (struct t_relay_weechat_msg *msg, long value)
{
char str_long[128];
unsigned char length;
snprintf (str_long, sizeof (str_long), "%ld", value);
length = strlen (str_long);
relay_weechat_msg_add_bytes (msg, &length, 1);
relay_weechat_msg_add_bytes (msg, str_long, length);
}
/*
* Adds length + string to a message.
*/
void
relay_weechat_msg_add_string (struct t_relay_weechat_msg *msg,
const char *string)
{
int length;
if (string)
{
length = strlen (string);
relay_weechat_msg_add_int (msg, length);
if (length > 0)
relay_weechat_msg_add_bytes (msg, string, length);
}
else
{
relay_weechat_msg_add_int (msg, -1);
}
}
/*
* Adds buffer (length + data) to a message.
*/
void
relay_weechat_msg_add_buffer (struct t_relay_weechat_msg *msg,
void *buffer, int length)
{
if (buffer)
{
relay_weechat_msg_add_int (msg, length);
if (length > 0)
relay_weechat_msg_add_bytes (msg, buffer, length);
}
else
{
relay_weechat_msg_add_int (msg, -1);
}
}
/*
* Adds a pointer to a message.
*/
void
relay_weechat_msg_add_pointer (struct t_relay_weechat_msg *msg, void *pointer)
{
char str_pointer[128];
unsigned char length;
snprintf (str_pointer, sizeof (str_pointer),
"%lx", (long unsigned int)pointer);
length = strlen (str_pointer);
relay_weechat_msg_add_bytes (msg, &length, 1);
relay_weechat_msg_add_bytes (msg, str_pointer, length);
}
/*
* Adds a time to a message.
*/
void
relay_weechat_msg_add_time (struct t_relay_weechat_msg *msg, time_t time)
{
char str_time[128];
unsigned char length;
snprintf (str_time, sizeof (str_time), "%lld", (long long)time);
length = strlen (str_time);
relay_weechat_msg_add_bytes (msg, &length, 1);
relay_weechat_msg_add_bytes (msg, str_time, length);
}
/*
* Adds items of hashtable to a message.
*/
void
relay_weechat_msg_hashtable_map_cb (void *data,
struct t_hashtable *hashtable,
const void *key, const void *value)
{
struct t_relay_weechat_msg *msg;
char *types[2] = { "type_keys", "type_values" };
const void *pointers[2];
const char *type;
int i;
msg = (struct t_relay_weechat_msg *)data;
pointers[0] = key;
pointers[1] = value;
for (i = 0; i < 2; i++)
{
type = weechat_hashtable_get_string (hashtable, types[i]);
if (strcmp (type, WEECHAT_HASHTABLE_INTEGER) == 0)
relay_weechat_msg_add_int (msg, *((int *)pointers[i]));
else if (strcmp (type, WEECHAT_HASHTABLE_STRING) == 0)
relay_weechat_msg_add_string (msg, (const char *)pointers[i]);
else if (strcmp (type, WEECHAT_HASHTABLE_POINTER) == 0)
relay_weechat_msg_add_pointer (msg, (void *)pointers[i]);
else if (strcmp (type, WEECHAT_HASHTABLE_BUFFER) == 0)
relay_weechat_msg_add_pointer (msg, (void *)pointers[i]);
else if (strcmp (type, WEECHAT_HASHTABLE_TIME) == 0)
relay_weechat_msg_add_time (msg, *((time_t *)pointers[i]));
}
}
/*
* Adds a hashtable to a message.
*/
void
relay_weechat_msg_add_hashtable (struct t_relay_weechat_msg *msg,
struct t_hashtable *hashtable)
{
char *types[2] = { "type_keys", "type_values" };
const char *type;
int i, count;
for (i = 0; i < 2; i++)
{
type = weechat_hashtable_get_string (hashtable, types[i]);
if (strcmp (type, WEECHAT_HASHTABLE_INTEGER) == 0)
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_INT);
else if (strcmp (type, WEECHAT_HASHTABLE_STRING) == 0)
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_STRING);
else if (strcmp (type, WEECHAT_HASHTABLE_POINTER) == 0)
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_POINTER);
else if (strcmp (type, WEECHAT_HASHTABLE_BUFFER) == 0)
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_POINTER);
else if (strcmp (type, WEECHAT_HASHTABLE_TIME) == 0)
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_TIME);
}
/* number of items */
count = weechat_hashtable_get_integer (hashtable, "items_count");
relay_weechat_msg_add_int (msg, count);
/* add all items */
weechat_hashtable_map (hashtable,
&relay_weechat_msg_hashtable_map_cb, msg);
}
/*
* Adds recursively hdata for a path to a message.
*
* Returns the number of hdata objects added to message.
*/
int
relay_weechat_msg_add_hdata_path (struct t_relay_weechat_msg *msg,
char **list_path,
int index_path,
void **path_pointers,
struct t_hdata *hdata,
void *pointer,
char **list_keys)
{
int num_added, i, j, count, count_all, var_type, array_size, max_array_size;
int length;
char *pos, *pos2, *str_count, *error, *name;
void *sub_pointer;
struct t_hdata *sub_hdata;
const char *sub_hdata_name;
num_added = 0;
count_all = 0;
count = 0;
pos = strchr (list_path[index_path], '(');
if (pos)
{
pos2 = strchr (pos + 1, ')');
if (pos2 && (pos2 > pos + 1))
{
str_count = weechat_strndup (pos + 1, pos2 - (pos + 1));
if (str_count)
{
if (strcmp (str_count, "*") == 0)
count_all = 1;
else
{
error = NULL;
count = (int)strtol (str_count, &error, 10);
if (error && !error[0])
{
if (count > 0)
count--;
else if (count < 0)
count++;
}
else
count = 0;
}
free (str_count);
}
}
}
while (pointer)
{
path_pointers[index_path] = pointer;
if (list_path[index_path + 1])
{
/* recursive call with next path */
pos = strchr (list_path[index_path + 1], '(');
if (pos)
pos[0] = '\0';
sub_pointer = weechat_hdata_pointer (hdata, pointer, list_path[index_path + 1]);
sub_hdata_name = weechat_hdata_get_var_hdata (hdata, list_path[index_path + 1]);
if (pos)
pos[0] = '(';
if (sub_pointer && sub_hdata_name)
{
sub_hdata = weechat_hdata_get (sub_hdata_name);
if (sub_hdata)
{
num_added += relay_weechat_msg_add_hdata_path (msg,
list_path,
index_path + 1,
path_pointers,
sub_hdata,
sub_pointer,
list_keys);
}
}
}
else
{
/* last path? then get pointer + values and fill message with them */
for (i = 0; list_path[i]; i++)
{
relay_weechat_msg_add_pointer (msg, path_pointers[i]);
}
for (i = 0; list_keys[i]; i++)
{
var_type = weechat_hdata_get_var_type (hdata, list_keys[i]);
if ((var_type >= 0) && (var_type != WEECHAT_HDATA_OTHER))
{
max_array_size = 1;
array_size = weechat_hdata_get_var_array_size (hdata,
pointer,
list_keys[i]);
if (array_size >= 0)
{
switch (var_type)
{
case WEECHAT_HDATA_CHAR:
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_CHAR);
break;
case WEECHAT_HDATA_INTEGER:
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_INT);
break;
case WEECHAT_HDATA_LONG:
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_LONG);
break;
case WEECHAT_HDATA_STRING:
case WEECHAT_HDATA_SHARED_STRING:
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_STRING);
break;
case WEECHAT_HDATA_POINTER:
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_POINTER);
break;
case WEECHAT_HDATA_TIME:
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_TIME);
break;
case WEECHAT_HDATA_HASHTABLE:
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_HASHTABLE);
break;
}
relay_weechat_msg_add_int (msg, array_size);
max_array_size = array_size;
}
length = 16 + strlen (list_keys[i]) + 1;
name = malloc (length);
if (name)
{
for (j = 0; j < max_array_size; j++)
{
snprintf (name, length, "%d|%s", j, list_keys[i]);
switch (var_type)
{
case WEECHAT_HDATA_CHAR:
relay_weechat_msg_add_char (msg,
weechat_hdata_char (hdata,
pointer,
name));
break;
case WEECHAT_HDATA_INTEGER:
relay_weechat_msg_add_int (msg,
weechat_hdata_integer (hdata,
pointer,
name));
break;
case WEECHAT_HDATA_LONG:
relay_weechat_msg_add_long (msg,
weechat_hdata_long (hdata,
pointer,
name));
break;
case WEECHAT_HDATA_STRING:
case WEECHAT_HDATA_SHARED_STRING:
relay_weechat_msg_add_string (msg,
weechat_hdata_string (hdata,
pointer,
name));
break;
case WEECHAT_HDATA_POINTER:
relay_weechat_msg_add_pointer (msg,
weechat_hdata_pointer (hdata,
pointer,
name));
break;
case WEECHAT_HDATA_TIME:
relay_weechat_msg_add_time (msg,
weechat_hdata_time (hdata,
pointer,
name));
break;
case WEECHAT_HDATA_HASHTABLE:
relay_weechat_msg_add_hashtable (msg,
weechat_hdata_hashtable (hdata,
pointer,
name));
break;
}
}
free (name);
}
}
}
num_added++;
}
if (count_all)
{
pointer = weechat_hdata_move (hdata, pointer, 1);
}
else if (count == 0)
pointer = NULL;
else if (count > 0)
{
pointer = weechat_hdata_move (hdata, pointer, 1);
count--;
}
else
{
pointer = weechat_hdata_move (hdata, pointer, -1);
count++;
}
if (!pointer)
break;
}
return num_added;
}
/*
* Adds a hdata to a message.
*
* Argument path has format:
* hdata_head:ptr->var->var->...->var
* where ptr can be a list name or a pointer (0x12345)
*
* Argument keys is optional: if not NULL, comma-separated list of keys to
* return for hdata.
*
* Returns:
* 1: hdata added to message
* 0: error (hdata NOT added to message)
*/
int
relay_weechat_msg_add_hdata (struct t_relay_weechat_msg *msg,
const char *path, const char *keys)
{
struct t_hdata *ptr_hdata_head, *ptr_hdata;
char *hdata_head, *pos, **list_keys, *keys_types, **list_path;
char *path_returned;
const char *hdata_name, *array_size;
void *pointer, **path_pointers;
long unsigned int value;
int rc, num_keys, num_path, i, type, pos_count, count, rc_sscanf;
uint32_t count32;
rc = 0;
hdata_head = NULL;
list_keys = NULL;
num_keys = 0;
keys_types = NULL;
list_path = NULL;
num_path = 0;
path_returned = NULL;
/* extract hdata name (head) from path */
pos = strchr (path, ':');
if (!pos)
goto end;
hdata_head = weechat_strndup (path, pos - path);
if (!hdata_head)
goto end;
ptr_hdata_head = weechat_hdata_get (hdata_head);
if (!ptr_hdata_head)
goto end;
/* split path */
list_path = weechat_string_split (pos + 1, "/", 0, 0, &num_path);
if (!list_path)
goto end;
/* extract pointer from first path (direct pointer or list name) */
pointer = NULL;
pos = strchr (list_path[0], '(');
if (pos)
pos[0] = '\0';
if (strncmp (list_path[0], "0x", 2) == 0)
{
rc_sscanf = sscanf (list_path[0], "%lx", &value);
if ((rc_sscanf != EOF) && (rc_sscanf != 0))
{
pointer = (void *)value;
if (!weechat_hdata_check_pointer (ptr_hdata_head, NULL, pointer))
{
if (weechat_relay_plugin->debug >= 1)
{
weechat_printf (NULL,
_("%s: invalid pointer in hdata path: "
"\"%s\""),
RELAY_PLUGIN_NAME,
path);
}
goto end;
}
}
}
else
pointer = weechat_hdata_get_list (ptr_hdata_head, list_path[0]);
if (pos)
pos[0] = '(';
if (!pointer)
goto end;
/*
* build string with path where:
* - counters are removed
* - variable names are replaced by hdata name
*/
path_returned = malloc (strlen (path) * 2);
if (!path_returned)
goto end;
ptr_hdata = ptr_hdata_head;
strcpy (path_returned, hdata_head);
for (i = 1; i < num_path; i++)
{
pos = strchr (list_path[i], '(');
if (pos)
pos[0] = '\0';
hdata_name = weechat_hdata_get_var_hdata (ptr_hdata, list_path[i]);
if (!hdata_name)
goto end;
ptr_hdata = weechat_hdata_get (hdata_name);
if (!ptr_hdata)
goto end;
strcat (path_returned, "/");
strcat (path_returned, hdata_name);
if (pos)
pos[0] = '(';
}
/* split keys */
if (!keys)
keys = weechat_hdata_get_string (ptr_hdata, "var_keys");
list_keys = weechat_string_split (keys, ",", 0, 0, &num_keys);
if (!list_keys)
goto end;
/* build string with list of keys with types: "key1:type1,key2:type2,..." */
keys_types = malloc (strlen (keys) + (num_keys * 8) + 1);
if (!keys_types)
goto end;
keys_types[0] = '\0';
for (i = 0; i < num_keys; i++)
{
type = weechat_hdata_get_var_type (ptr_hdata, list_keys[i]);
if ((type >= 0) && (type != WEECHAT_HDATA_OTHER))
{
if (keys_types[0])
strcat (keys_types, ",");
strcat (keys_types, list_keys[i]);
strcat (keys_types, ":");
array_size = weechat_hdata_get_var_array_size_string (ptr_hdata,
NULL,
list_keys[i]);
if (array_size)
strcat (keys_types, RELAY_WEECHAT_MSG_OBJ_ARRAY);
else
{
switch (type)
{
case WEECHAT_HDATA_CHAR:
strcat (keys_types, RELAY_WEECHAT_MSG_OBJ_CHAR);
break;
case WEECHAT_HDATA_INTEGER:
strcat (keys_types, RELAY_WEECHAT_MSG_OBJ_INT);
break;
case WEECHAT_HDATA_LONG:
strcat (keys_types, RELAY_WEECHAT_MSG_OBJ_LONG);
break;
case WEECHAT_HDATA_STRING:
case WEECHAT_HDATA_SHARED_STRING:
strcat (keys_types, RELAY_WEECHAT_MSG_OBJ_STRING);
break;
case WEECHAT_HDATA_POINTER:
strcat (keys_types, RELAY_WEECHAT_MSG_OBJ_POINTER);
break;
case WEECHAT_HDATA_TIME:
strcat (keys_types, RELAY_WEECHAT_MSG_OBJ_TIME);
break;
case WEECHAT_HDATA_HASHTABLE:
strcat (keys_types, RELAY_WEECHAT_MSG_OBJ_HASHTABLE);
break;
}
}
}
}
if (!keys_types[0])
goto end;
/* start hdata in message */
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_HDATA);
relay_weechat_msg_add_string (msg, path_returned);
relay_weechat_msg_add_string (msg, keys_types);
/* "count" will be set later, with number of objects in hdata */
pos_count = msg->data_size;
count = 0;
relay_weechat_msg_add_int (msg, 0);
path_pointers = malloc (sizeof (*path_pointers) * num_path);
if (path_pointers)
{
count = relay_weechat_msg_add_hdata_path (msg,
list_path,
0,
path_pointers,
ptr_hdata_head,
pointer,
list_keys);
free (path_pointers);
}
count32 = htonl ((uint32_t)count);
relay_weechat_msg_set_bytes (msg, pos_count, &count32, 4);
rc = 1;
end:
if (list_keys)
weechat_string_free_split (list_keys);
if (keys_types)
free (keys_types);
if (list_path)
weechat_string_free_split (list_path);
if (path_returned)
free (path_returned);
if (hdata_head)
free (hdata_head);
return rc;
}
/*
* Adds an infolist to a message.
*/
void
relay_weechat_msg_add_infolist (struct t_relay_weechat_msg *msg,
const char *name,
void *pointer,
const char *arguments)
{
struct t_infolist *ptr_infolist;
const char *fields;
char **list_fields;
void *buf_ptr;
int num_fields, i, buf_size;
int pos_count_items, count_items, pos_count_vars, count_vars;
uint32_t count32;
ptr_infolist = weechat_infolist_get (name, pointer, arguments);
if (!ptr_infolist)
return;
/* start infolist in message */
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_INFOLIST);
relay_weechat_msg_add_string (msg, name);
/* count of items will be set later, with number of items in infolist */
pos_count_items = msg->data_size;
count_items = 0;
relay_weechat_msg_add_int (msg, 0);
while (weechat_infolist_next (ptr_infolist))
{
fields = weechat_infolist_fields (ptr_infolist);
if (fields)
{
list_fields = weechat_string_split (fields, ",", 0, 0, &num_fields);
if (list_fields)
{
count_items++;
pos_count_vars = msg->data_size;
count_vars = 0;
relay_weechat_msg_add_int (msg, 0);
for (i = 0; i < num_fields; i++)
{
if (strlen (list_fields[i]) > 2)
{
count_vars++;
relay_weechat_msg_add_string (msg, list_fields[i] + 2);
switch (list_fields[i][0])
{
case 'i':
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_INT);
relay_weechat_msg_add_int (msg,
weechat_infolist_integer (ptr_infolist,
list_fields[i] + 2));
break;
case 's':
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_STRING);
relay_weechat_msg_add_string (msg,
weechat_infolist_string (ptr_infolist,
list_fields[i] + 2));
break;
case 'p':
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_POINTER);
relay_weechat_msg_add_pointer (msg,
weechat_infolist_pointer (ptr_infolist,
list_fields[i] + 2));
break;
case 'b':
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_BUFFER);
buf_ptr = weechat_infolist_buffer (ptr_infolist,
list_fields[i] + 2,
&buf_size);
relay_weechat_msg_add_buffer (msg, buf_ptr, buf_size);
break;
case 't':
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_TIME);
relay_weechat_msg_add_time (msg,
weechat_infolist_time (ptr_infolist,
list_fields[i] + 2));
break;
}
}
}
/* set count of variables in item */
count32 = htonl ((uint32_t)count_vars);
relay_weechat_msg_set_bytes (msg, pos_count_vars, &count32, 4);
weechat_string_free_split (list_fields);
}
}
}
/* set count of items */
count32 = htonl ((uint32_t)count_items);
relay_weechat_msg_set_bytes (msg, pos_count_items, &count32, 4);
weechat_infolist_free (ptr_infolist);
}
/*
* Adds nicklist for a buffer, as hdata object.
*
* Argument "nicklist" contains nicklist diffs. If it is NULL or don't have
* items inside, full nicklist is sent.
*
* Returns the number of nicks+groups added to message.
*/
int
relay_weechat_msg_add_nicklist_buffer (struct t_relay_weechat_msg *msg,
struct t_gui_buffer *buffer,
struct t_relay_weechat_nicklist *nicklist)
{
int count, i;
struct t_hdata *ptr_hdata_group, *ptr_hdata_nick;
struct t_gui_nick_group *ptr_group;
struct t_gui_nick *ptr_nick;
count = 0;
if (nicklist)
{
/* send nicklist diffs */
for (i = 0; i < nicklist->items_count; i++)
{
relay_weechat_msg_add_pointer (msg, buffer);
relay_weechat_msg_add_pointer (msg, nicklist->items[i].pointer);
relay_weechat_msg_add_char (msg, nicklist->items[i].diff);
relay_weechat_msg_add_char (msg, nicklist->items[i].group);
relay_weechat_msg_add_char (msg, nicklist->items[i].visible);
relay_weechat_msg_add_int (msg, nicklist->items[i].level);
relay_weechat_msg_add_string (msg, nicklist->items[i].name);
relay_weechat_msg_add_string (msg, nicklist->items[i].color);
relay_weechat_msg_add_string (msg, nicklist->items[i].prefix);
relay_weechat_msg_add_string (msg, nicklist->items[i].prefix_color);
count++;
}
}
else
{
/* send full nicklist */
ptr_hdata_group = weechat_hdata_get ("nick_group");
ptr_hdata_nick = weechat_hdata_get ("nick");
ptr_group = NULL;
ptr_nick = NULL;
weechat_nicklist_get_next_item (buffer, &ptr_group, &ptr_nick);
while (ptr_group || ptr_nick)
{
if (ptr_nick)
{
relay_weechat_msg_add_pointer (msg, buffer);
relay_weechat_msg_add_pointer (msg, ptr_nick);
relay_weechat_msg_add_char (msg, 0); /* group */
relay_weechat_msg_add_char (msg,
(char)weechat_hdata_integer(ptr_hdata_nick,
ptr_nick,
"visible"));
relay_weechat_msg_add_int (msg, 0); /* level */
relay_weechat_msg_add_string (msg,
weechat_hdata_string (ptr_hdata_nick,
ptr_nick,
"name"));
relay_weechat_msg_add_string (msg,
weechat_hdata_string (ptr_hdata_nick,
ptr_nick,
"color"));
relay_weechat_msg_add_string (msg,
weechat_hdata_string (ptr_hdata_nick,
ptr_nick,
"prefix"));
relay_weechat_msg_add_string (msg,
weechat_hdata_string (ptr_hdata_nick,
ptr_nick,
"prefix_color"));
count++;
}
else
{
relay_weechat_msg_add_pointer (msg, buffer);
relay_weechat_msg_add_pointer (msg, ptr_group);
relay_weechat_msg_add_char (msg, 1); /* group */
relay_weechat_msg_add_char (msg,
(char)weechat_hdata_integer(ptr_hdata_group,
ptr_group,
"visible"));
relay_weechat_msg_add_int (msg,
weechat_hdata_integer (ptr_hdata_group,
ptr_group,
"level"));
relay_weechat_msg_add_string (msg,
weechat_hdata_string (ptr_hdata_group,
ptr_group,
"name"));
relay_weechat_msg_add_string (msg,
weechat_hdata_string (ptr_hdata_group,
ptr_group,
"color"));
relay_weechat_msg_add_string (msg, NULL); /* prefix */
relay_weechat_msg_add_string (msg, NULL); /* prefix_color */
count++;
}
weechat_nicklist_get_next_item (buffer, &ptr_group, &ptr_nick);
}
}
return count;
}
/*
* Adds nicklist for one or all buffers, as hdata object.
*
* Argument "nicklist" contains nicklist diffs. If it is NULL or don't have
* items inside, full nicklist is sent.
*/
void
relay_weechat_msg_add_nicklist (struct t_relay_weechat_msg *msg,
struct t_gui_buffer *buffer,
struct t_relay_weechat_nicklist *nicklist)
{
char str_vars[512];
struct t_hdata *ptr_hdata;
struct t_gui_buffer *ptr_buffer;
int pos_count, count;
uint32_t count32;
snprintf (str_vars, sizeof (str_vars),
"%sgroup:chr,visible:chr,level:int,"
"name:str,color:str,"
"prefix:str,prefix_color:str",
(nicklist) ? "_diff:chr," : "");
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_HDATA);
relay_weechat_msg_add_string (msg, "buffer/nicklist_item");
relay_weechat_msg_add_string (msg, str_vars);
/* "count" will be set later, with number of objects in hdata */
pos_count = msg->data_size;
count = 0;
relay_weechat_msg_add_int (msg, 0);
if (buffer)
{
count += relay_weechat_msg_add_nicklist_buffer (msg, buffer, nicklist);
}
else
{
ptr_hdata = weechat_hdata_get ("buffer");
ptr_buffer = weechat_hdata_get_list (ptr_hdata, "gui_buffers");
while (ptr_buffer)
{
count += relay_weechat_msg_add_nicklist_buffer (msg, ptr_buffer, NULL);
ptr_buffer = weechat_hdata_move (ptr_hdata, ptr_buffer, 1);
}
}
count32 = htonl ((uint32_t)count);
relay_weechat_msg_set_bytes (msg, pos_count, &count32, 4);
}
/*
* Sends a message.
*/
void
relay_weechat_msg_send (struct t_relay_client *client,
struct t_relay_weechat_msg *msg)
{
uint32_t size32;
char compression, raw_message[1024];
int rc;
Bytef *dest;
uLongf dest_size;
struct timeval tv1, tv2;
long long time_diff;
if (weechat_config_integer (relay_config_network_compression_level) > 0)
{
switch (RELAY_WEECHAT_DATA(client, compression))
{
case RELAY_WEECHAT_COMPRESSION_ZLIB:
dest_size = compressBound (msg->data_size - 5);
dest = malloc (dest_size + 5);
if (dest)
{
gettimeofday (&tv1, NULL);
rc = compress2 (dest + 5, &dest_size,
(Bytef *)(msg->data + 5), msg->data_size - 5,
weechat_config_integer (relay_config_network_compression_level));
gettimeofday (&tv2, NULL);
time_diff = weechat_util_timeval_diff (&tv1, &tv2);
if ((rc == Z_OK) && ((int)dest_size + 5 < msg->data_size))
{
/* set size and compression flag */
size32 = htonl ((uint32_t)(dest_size + 5));
memcpy (dest, &size32, 4);
dest[4] = RELAY_WEECHAT_COMPRESSION_ZLIB;
/* display message in raw buffer */
snprintf (raw_message, sizeof (raw_message),
"obj: %d/%d bytes (%d%%, %.2fms), id: %s",
(int)dest_size + 5,
msg->data_size,
100 - ((((int)dest_size + 5) * 100) / msg->data_size),
((float)time_diff) / 1000,
msg->id);
/* send compressed data */
relay_client_send (client, RELAY_CLIENT_MSG_STANDARD,
(const char *)dest, dest_size + 5,
raw_message);
free (dest);
return;
}
free (dest);
}
break;
default:
break;
}
}
/* compression failed (or not asked), send uncompressed message */
/* set size and compression flag */
size32 = htonl ((uint32_t)msg->data_size);
relay_weechat_msg_set_bytes (msg, 0, &size32, 4);
compression = RELAY_WEECHAT_COMPRESSION_OFF;
relay_weechat_msg_set_bytes (msg, 4, &compression, 1);
/* send uncompressed data */
snprintf (raw_message, sizeof (raw_message),
"obj: %d bytes, id: %s", msg->data_size, msg->id);
relay_client_send (client, RELAY_CLIENT_MSG_STANDARD,
msg->data, msg->data_size, raw_message);
}
/*
* Frees a message.
*/
void
relay_weechat_msg_free (struct t_relay_weechat_msg *msg)
{
if (!msg)
return;
if (msg->id)
free (msg->id);
if (msg->data)
free (msg->data);
free (msg);
}