1
0
mirror of https://github.com/weechat/weechat.git synced 2026-06-12 14:14:48 +02:00
Files
weechat/src/plugins/irc/irc-list.c
T

1345 lines
37 KiB
C

/*
* irc-list.c - functions for IRC list buffer
*
* Copyright (C) 2023 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 <time.h>
#include "../weechat-plugin.h"
#include "irc.h"
#include "irc-list.h"
#include "irc-buffer.h"
#include "irc-color.h"
#include "irc-config.h"
#include "irc-input.h"
#include "irc-message.h"
#include "irc-server.h"
struct t_hdata *irc_list_hdata_list_channel = NULL;
struct t_hashtable *irc_list_filter_hashtable_pointers = NULL;
struct t_hashtable *irc_list_filter_hashtable_extra_vars = NULL;
struct t_hashtable *irc_list_filter_hashtable_options = NULL;
/*
* Compares two channels in list.
*/
int
irc_list_compare_cb (void *data, struct t_arraylist *arraylist,
void *pointer1, void *pointer2)
{
struct t_irc_server *ptr_server;
const char *ptr_field;
int i, reverse, case_sensitive, rc;
/* make C compiler happy */
(void) arraylist;
ptr_server = data;
if (!ptr_server)
return 1;
for (i = 0; i < ptr_server->list->sort_fields_count; i++)
{
reverse = 1;
case_sensitive = 1;
ptr_field = ptr_server->list->sort_fields[i];
while ((ptr_field[0] == '-') || (ptr_field[0] == '~'))
{
if (ptr_field[0] == '-')
reverse *= -1;
else if (ptr_field[0] == '~')
case_sensitive ^= 1;
ptr_field++;
}
rc = weechat_hdata_compare (irc_list_hdata_list_channel,
pointer1, pointer2,
ptr_field,
case_sensitive);
rc *= reverse;
if (rc != 0)
return rc;
}
return 1;
}
/*
* Frees a channel in list.
*/
void
irc_list_free_cb (void *data, struct t_arraylist *arraylist, void *pointer)
{
struct t_irc_list_channel *ptr_channel;
/* make C compiler happy */
(void) data;
(void) arraylist;
ptr_channel = (struct t_irc_list_channel *)pointer;
if (ptr_channel)
{
if (ptr_channel->name)
free (ptr_channel->name);
if (ptr_channel->name2)
free (ptr_channel->name2);
if (ptr_channel->topic)
free (ptr_channel->topic);
free (ptr_channel);
}
}
/*
* Sets the local variable "filter" in the list buffer.
*/
void
irc_list_buffer_set_localvar_filter (struct t_gui_buffer *buffer,
struct t_irc_server *server)
{
if (!buffer || !server)
return;
weechat_buffer_set (buffer, "localvar_set_filter",
(server->list->filter) ? server->list->filter : "*");
}
/*
* Sets filter for list of channels.
*/
void
irc_list_set_filter (struct t_irc_server *server, const char *filter)
{
if (server->list->filter)
{
free (server->list->filter);
server->list->filter = NULL;
}
server->list->filter = (filter && (strcmp (filter, "*") != 0)) ?
strdup (filter) : NULL;
irc_list_buffer_set_localvar_filter (server->list->buffer, server);
}
/*
* Sets sort for list of channels.
*
*/
void
irc_list_set_sort (struct t_irc_server *server, const char *sort)
{
if (server->list->sort)
{
free (server->list->sort);
server->list->sort = NULL;
}
if (server->list->sort_fields)
{
weechat_string_free_split (server->list->sort_fields);
server->list->sort_fields = NULL;
}
server->list->sort_fields_count = 0;
server->list->sort = strdup (
(sort && sort[0]) ?
sort : weechat_config_string (irc_config_look_list_buffer_sort));
if (server->list->sort)
{
server->list->sort_fields = weechat_string_split (
server->list->sort,
",",
NULL,
WEECHAT_STRING_SPLIT_STRIP_LEFT
| WEECHAT_STRING_SPLIT_STRIP_RIGHT
| WEECHAT_STRING_SPLIT_COLLAPSE_SEPS,
0,
&server->list->sort_fields_count);
}
}
/*
* Adds the properties of an irc list channel in a hashtable
* (keys and values must be strings).
*/
void
irc_list_add_channel_in_hashtable (struct t_hashtable *hashtable,
struct t_irc_list_channel *channel)
{
char str_number[32];
weechat_hashtable_set (hashtable, "name", channel->name);
weechat_hashtable_set (hashtable, "name2", channel->name2);
snprintf (str_number, sizeof (str_number), "%d", channel->users);
weechat_hashtable_set (hashtable, "users", str_number);
weechat_hashtable_set (hashtable, "topic", channel->topic);
}
/*
* Checks if a string matches a mask.
*
* If mask has no "*" inside, it just checks if "mask" is inside the "string".
* If mask has at least one "*" inside, the function weechat_string_match is
* used.
*
* Returns:
* 1: string matches mask
* 0: string does not match mask
*/
int
irc_list_string_match (const char *string, const char *mask)
{
if (strchr (mask, '*'))
return weechat_string_match (string, mask, 0);
else
return (weechat_strcasestr (string, mask)) ? 1 : 0;
}
/*
* Checks if a channel matches filter.
*
* Return:
* 1: channel matches filter
* 0: channel does NOT match filter
*/
int
irc_list_channel_match_filter (struct t_irc_server *server,
struct t_irc_list_channel *channel)
{
char *error, *result;
long number;
int match;
/* no filter? then any channel is matching */
if (!server->list->filter)
return 1;
if (strncmp (server->list->filter, "c:", 2) == 0)
{
/* filter by evaluated condition */
weechat_hashtable_set (irc_list_filter_hashtable_pointers,
"irc_list_channel", channel);
irc_list_add_channel_in_hashtable (irc_list_filter_hashtable_extra_vars,
channel);
result = weechat_string_eval_expression (
server->list->filter + 2,
irc_list_filter_hashtable_pointers,
irc_list_filter_hashtable_extra_vars,
irc_list_filter_hashtable_options);
match = (result && (strcmp (result, "1") == 0)) ? 1 : 0;
if (result)
free (result);
return match;
}
if (strncmp (server->list->filter, "n:", 2) == 0)
{
/* filter by channel name */
if (channel->name
&& irc_list_string_match (channel->name, server->list->filter + 2))
{
return 1;
}
}
else if (strncmp (server->list->filter, "t:", 2) == 0)
{
/* filter by topic */
if (channel->topic
&& irc_list_string_match (channel->topic, server->list->filter + 2))
{
return 1;
}
}
else if (strncmp (server->list->filter, "u:>", 3) == 0)
{
/* filter by users (> N)*/
error = NULL;
number = strtol (server->list->filter + 3, &error, 10);
if (error && !error[0] && channel->users > (int)number)
return 1;
}
else if (strncmp (server->list->filter, "u:<", 3) == 0)
{
/* filter by users (< N)*/
error = NULL;
number = strtol (server->list->filter + 3, &error, 10);
if (error && !error[0] && channel->users < (int)number)
return 1;
}
else if (strncmp (server->list->filter, "u:", 2) == 0)
{
/* filter by users */
error = NULL;
number = strtol (server->list->filter + 2, &error, 10);
if (error && !error[0] && channel->users >= (int)number)
return 1;
}
else
{
if (channel->name
&& irc_list_string_match (channel->name, server->list->filter))
{
return 1;
}
if (channel->topic
&& irc_list_string_match (channel->topic, server->list->filter))
{
return 1;
}
}
return 0;
}
/*
* Filters channels: apply filter and use sort to build the list
* "filter_channels" that are pointers to t_irc_list_channel structs
* stored in main list "channels".
*/
void
irc_list_filter_channels (struct t_irc_server *server)
{
struct t_irc_list_channel *ptr_channel;
int i, list_size;
if (server->list->filter_channels)
{
weechat_arraylist_clear (server->list->filter_channels);
}
else
{
server->list->filter_channels = weechat_arraylist_new (
16, 1, 0,
&irc_list_compare_cb, server,
NULL, NULL);
}
if (!server->list->sort)
{
irc_list_set_sort (
server,
weechat_config_string (irc_config_look_list_buffer_sort));
}
list_size = weechat_arraylist_size (server->list->channels);
for (i = 0; i < list_size; i++)
{
ptr_channel = (struct t_irc_list_channel *)weechat_arraylist_get (
server->list->channels, i);
if (!ptr_channel)
continue;
if (irc_list_channel_match_filter (server, ptr_channel))
weechat_arraylist_add (server->list->filter_channels, ptr_channel);
}
}
/*
* Parses output of redirected /list (string with raw IRC messages separated
* by newlines) and returns an arraylist of parsed channels, or NULL if no
* valid message (322) was found in output.
*
* Returns:
* 1: OK
* 0: error
*/
int
irc_list_parse_messages (struct t_irc_server *server, const char *output)
{
struct t_irc_list_channel *channel;
char **irc_msgs, *command, **params, *error;
const char *ptr_name;
int i, count_irc_msgs, num_params, length, keep_colors;
long number;
if (server->list->channels)
{
weechat_arraylist_free (server->list->channels);
server->list->channels = NULL;
}
irc_msgs = weechat_string_split (output, "\n", NULL, 0, 0, &count_irc_msgs);
if (!irc_msgs)
return 0;
server->list->channels = weechat_arraylist_new (
16, 0, 1,
NULL, NULL,
&irc_list_free_cb, NULL);
if (!server->list->channels)
{
weechat_string_free_split (irc_msgs);
return 0;
}
server->list->name_max_length = 0;
keep_colors = (weechat_config_boolean (
irc_config_look_list_buffer_topic_strip_colors)) ?
0 : 1;
for (i = 0; i < count_irc_msgs; i++)
{
irc_message_parse (server, irc_msgs[i],
NULL, /* tags */
NULL, /* message_without_tags */
NULL, /* nick */
NULL, /* user */
NULL, /* host */
&command,
NULL, /* channel */
NULL, /* arguments */
NULL, /* text */
&params,
&num_params,
NULL, /* pos_command */
NULL, /* pos_arguments */
NULL, /* pos_channel */
NULL); /* pos_text */
if (command
&& (strcmp (command, "322") == 0)
&& params
&& (num_params >= 3))
{
channel = malloc (sizeof (*channel));
if (channel)
{
channel->name = strdup (params[1]);
ptr_name = params[1] + 1;
while (ptr_name[0] && (ptr_name[0] == params[1][0]))
{
ptr_name++;
}
channel->name2 = strdup (ptr_name);
error = NULL;
number = strtol (params[2], &error, 10);
channel->users = (error && !error[0]) ? number : 0;
channel->topic = (num_params > 3) ?
irc_color_decode (params[3], keep_colors) : NULL;
length = weechat_utf8_strlen_screen (channel->name);
if (length > server->list->name_max_length)
server->list->name_max_length = length;
weechat_arraylist_add (server->list->channels, channel);
}
}
if (command)
free (command);
if (params)
weechat_string_free_split (params);
}
weechat_string_free_split (irc_msgs);
irc_list_filter_channels (server);
return 1;
}
/*
* Sets title of list buffer.
*/
void
irc_list_buffer_set_title (struct t_irc_server *server)
{
int num_channels, num_channels_total;
char str_title[8192];
if (!server || !server->list->buffer)
return;
num_channels = (server->list->filter_channels) ?
weechat_arraylist_size (server->list->filter_channels) : 0;
num_channels_total = (server->list->channels) ?
weechat_arraylist_size (server->list->channels) : 0;
snprintf (str_title, sizeof (str_title),
_("%d channels (total: %d) | Filter: %s | Sort: %s | "
"Key(input): "
"ctrl+j=join channel, "
"($)=refresh, "
"(q)=close buffer"),
num_channels,
num_channels_total,
(server->list->filter) ? server->list->filter : "*",
(server->list->sort) ? server->list->sort : "");
weechat_buffer_set (server->list->buffer, "title", str_title);
}
/*
* Displays a line.
*/
void
irc_list_display_line (struct t_irc_server *server, int line)
{
struct t_irc_list_channel *ptr_channel;
const char *ptr_color;
char str_spaces[1024], color[256];
int num_spaces;
ptr_channel = (struct t_irc_list_channel *)weechat_arraylist_get (
server->list->filter_channels, line);
/* line color */
if (line == server->list->selected_line)
{
snprintf (color, sizeof (color),
"%s,%s",
weechat_config_string (irc_config_color_list_buffer_line_selected),
weechat_config_string (irc_config_color_list_buffer_line_selected_bg));
ptr_color = weechat_color (color);
}
else
{
ptr_color = NULL;
}
/* channel name */
str_spaces[0] = '\0';
num_spaces = server->list->name_max_length
- weechat_utf8_strlen_screen (ptr_channel->name);
if (num_spaces > 0)
{
if (num_spaces >= (int)sizeof (str_spaces))
num_spaces = sizeof (str_spaces) - 1;
memset (str_spaces, ' ', num_spaces);
str_spaces[num_spaces] = '\0';
}
/* display the line */
weechat_printf_y (
server->list->buffer,
line,
"%s%s%s %7d %s",
(ptr_color) ? ptr_color : "",
ptr_channel->name,
str_spaces,
ptr_channel->users,
ptr_channel->topic);
}
/*
* Updates list of channels in list buffer.
*/
void
irc_list_buffer_refresh (struct t_irc_server *server, int clear)
{
int num_channels, i;
if (!server || !server->list->buffer)
return;
num_channels = weechat_arraylist_size (server->list->filter_channels);
if (clear)
{
weechat_buffer_clear (server->list->buffer);
server->list->selected_line = 0;
}
for (i = 0; i < num_channels; i++)
{
irc_list_display_line (server, i);
}
irc_list_buffer_set_title (server);
}
/*
* Sets current selected line.
*/
void
irc_list_set_current_line (struct t_irc_server *server, int line)
{
int old_line;
if ((line >= 0) && (line < weechat_arraylist_size (server->list->filter_channels)))
{
old_line = server->list->selected_line;
server->list->selected_line = line;
if (old_line != server->list->selected_line)
irc_list_display_line (server, old_line);
irc_list_display_line (server, server->list->selected_line);
irc_list_buffer_set_title (server);
}
}
/*
* Gets info about a window.
*/
void
irc_list_get_window_info (struct t_gui_window *window,
int *start_line_y, int *chat_height)
{
struct t_hdata *hdata_window, *hdata_window_scroll, *hdata_line;
struct t_hdata *hdata_line_data;
void *window_scroll, *start_line, *line_data;
hdata_window = weechat_hdata_get ("window");
hdata_window_scroll = weechat_hdata_get ("window_scroll");
hdata_line = weechat_hdata_get ("line");
hdata_line_data = weechat_hdata_get ("line_data");
*start_line_y = 0;
window_scroll = weechat_hdata_pointer (hdata_window, window, "scroll");
if (window_scroll)
{
start_line = weechat_hdata_pointer (hdata_window_scroll, window_scroll,
"start_line");
if (start_line)
{
line_data = weechat_hdata_pointer (hdata_line, start_line, "data");
if (line_data)
{
*start_line_y = weechat_hdata_integer (hdata_line_data,
line_data, "y");
}
}
}
*chat_height = weechat_hdata_integer (hdata_window, window,
"win_chat_height");
}
/*
* Checks if current line is outside window and adjusts scroll if needed.
*/
void
irc_list_check_line_outside_window (struct t_irc_server *server)
{
struct t_gui_window *window;
int start_line_y, chat_height;
int selected_y;
char str_command[256];
window = weechat_window_search_with_buffer (server->list->buffer);
if (!window)
return;
irc_list_get_window_info (window, &start_line_y, &chat_height);
selected_y = server->list->selected_line;
if ((start_line_y > selected_y)
|| (start_line_y < selected_y - chat_height + 1))
{
snprintf (str_command, sizeof (str_command),
"/window scroll -window %d %s%d",
weechat_window_get_integer (window, "number"),
(start_line_y > selected_y) ? "-" : "+",
(start_line_y > selected_y) ?
start_line_y - selected_y :
selected_y - start_line_y - chat_height + 1);
weechat_command (server->list->buffer, str_command);
}
}
/*
* Callback for signal "window_scrolled".
*/
int
irc_list_window_scrolled_cb (const void *pointer, void *data,
const char *signal, const char *type_data,
void *signal_data)
{
struct t_gui_buffer *ptr_buffer;
struct t_irc_server *ptr_server;
int start_line_y, chat_height, line, num_channels;
/* make C compiler happy */
(void) pointer;
(void) data;
(void) signal;
(void) type_data;
/* search the /list buffer */
ptr_buffer = weechat_window_get_pointer (signal_data, "buffer");
for (ptr_server = irc_servers; ptr_server;
ptr_server = ptr_server->next_server)
{
if (ptr_server->list->buffer == ptr_buffer)
break;
}
if (!ptr_server)
return WEECHAT_RC_OK;
irc_list_get_window_info (signal_data, &start_line_y, &chat_height);
line = ptr_server->list->selected_line;
while (line < start_line_y)
{
line += chat_height;
}
while (line >= start_line_y + chat_height)
{
line -= chat_height;
}
if (line < start_line_y)
line = start_line_y + 1;
num_channels = weechat_arraylist_size (ptr_server->list->filter_channels);
if ((num_channels > 0) && (line >= num_channels))
line = num_channels - 1;
irc_list_set_current_line (ptr_server, line);
return WEECHAT_RC_OK;
}
/*
* Moves N lines up/down in buffer
* (negative lines = move up, positive lines = move down).
*/
void
irc_list_move_line_relative (struct t_irc_server *server, int num_lines)
{
int num_channels, line;
num_channels = weechat_arraylist_size (server->list->filter_channels);
if (num_channels == 0)
return;
line = server->list->selected_line + num_lines;
if (line < 0)
line = 0;
if ((num_channels > 0) && (line >= num_channels))
line = num_channels - 1;
if (line != server->list->selected_line)
{
irc_list_set_current_line (server, line);
irc_list_check_line_outside_window (server);
}
}
/*
* Moves to line N (0 = first line, -1 = last line).
*/
void
irc_list_move_line_absolute (struct t_irc_server *server, int line_number)
{
int num_channels, line;
num_channels = weechat_arraylist_size (server->list->filter_channels);
if (num_channels == 0)
return;
line = line_number;
if (line < 0)
line = (num_channels > 0) ? num_channels - 1 : 0;
if ((num_channels > 0) && (line >= num_channels))
line = num_channels - 1;
if (line != server->list->selected_line)
{
irc_list_set_current_line (server, line);
irc_list_check_line_outside_window (server);
}
}
/*
* Scrolls horizontally with percent
* (negative: scroll to the left, positive: scroll to the right).
*/
void
irc_list_scroll_horizontal (struct t_irc_server *server, int percent)
{
struct t_gui_window *ptr_window;
char str_command[512];
if (percent < -100)
percent = -100;
else if (percent > 100)
percent = 100;
ptr_window = weechat_window_search_with_buffer (server->list->buffer);
if (!ptr_window)
return;
snprintf (str_command, sizeof (str_command),
"/window scroll_horiz -window %d %d%%",
weechat_window_get_integer (ptr_window, "number"),
percent);
weechat_command (server->list->buffer, str_command);
}
/*
* Joins channel on current selected line.
*/
void
irc_list_join_channel (struct t_irc_server *server)
{
struct t_irc_list_channel *ptr_channel;
int num_channels;
char str_command[1024];
num_channels = weechat_arraylist_size (server->list->filter_channels);
if ((num_channels == 0) || (server->list->selected_line >= num_channels))
return;
ptr_channel = (struct t_irc_list_channel *)weechat_arraylist_get (
server->list->filter_channels,
server->list->selected_line);
if (!ptr_channel)
return;
snprintf (str_command, sizeof (str_command),
"/join %s", ptr_channel->name);
weechat_command (server->list->buffer, str_command);
}
/*
* Callback for input data in list buffer.
*/
int
irc_list_buffer_input_data (struct t_gui_buffer *buffer, const char *input_data)
{
struct t_irc_server *ptr_server;
const char *ptr_server_name, *ptr_input;
int i;
char *actions[][2] = {
{ "<<", "/list -go 0" },
{ ">>", "/list -go end" },
{ "<", "/list -left" },
{ ">", "/list -right" },
{ NULL, NULL },
};
/* close buffer */
if (strcmp (input_data, "q") == 0)
{
weechat_buffer_close (buffer);
return WEECHAT_RC_OK;
}
ptr_server_name = weechat_buffer_get_string (buffer, "localvar_server");
if (!ptr_server_name)
return WEECHAT_RC_OK;
ptr_server = irc_server_search (ptr_server_name);
if (!ptr_server)
return WEECHAT_RC_OK;
/* refresh buffer */
if (strcmp (input_data, "$") == 0)
{
weechat_command (ptr_server->list->buffer, "/list");
return WEECHAT_RC_OK;
}
/* join channel */
if (strcmp (input_data, "j") == 0)
{
irc_list_join_channel (ptr_server);
return WEECHAT_RC_OK;
}
/* change sort of channels */
if (strncmp (input_data, "s:", 2) == 0)
{
irc_list_set_sort (ptr_server, input_data + 2);
irc_list_filter_channels (ptr_server);
irc_list_buffer_refresh (ptr_server, 1);
weechat_buffer_set (buffer, "display", "1");
return WEECHAT_RC_OK;
}
/* execute action */
for (i = 0; actions[i][0]; i++)
{
if (strcmp (input_data, actions[i][0]) == 0)
{
weechat_command (buffer, actions[i][1]);
return WEECHAT_RC_OK;
}
}
/* filter channels with given text */
ptr_input = input_data;
while (ptr_input[0] == ' ')
{
ptr_input++;
}
if (ptr_input[0])
{
irc_list_set_filter (ptr_server, ptr_input);
irc_list_filter_channels (ptr_server);
irc_list_buffer_refresh (ptr_server, 1);
weechat_buffer_set (buffer, "display", "1");
}
return WEECHAT_RC_OK;
}
/*
* Creates buffer with list of channels for a server.
*
* Returns pointer to newly created buffer, NULL if error.
*/
struct t_gui_buffer *
irc_list_create_buffer (struct t_irc_server *server)
{
struct t_hashtable *buffer_props;
struct t_gui_buffer *buffer;
char buffer_name[1024], str_number[32];
int buffer_position, current_buffer_number;
buffer_props = weechat_hashtable_new (
32,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_STRING,
NULL, NULL);
if (buffer_props)
{
weechat_hashtable_set (buffer_props, "type", "free");
weechat_hashtable_set (buffer_props, "localvar_set_type", "list");
weechat_hashtable_set (buffer_props, "localvar_set_server", server->name);
weechat_hashtable_set (buffer_props, "localvar_set_channel", server->name);
weechat_hashtable_set (buffer_props, "localvar_set_no_log", "1");
/* disable all highlights on this buffer */
weechat_hashtable_set (buffer_props, "highlight_words", "-");
/* set keys on buffer */
weechat_hashtable_set (buffer_props, "key_bind_up", "/list -up");
weechat_hashtable_set (buffer_props, "key_bind_down", "/list -down");
weechat_hashtable_set (buffer_props, "key_bind_meta-home", "/list -go 0");
weechat_hashtable_set (buffer_props, "key_bind_meta-end", "/list -go end");
weechat_hashtable_set (buffer_props, "key_bind_f11", "/list -left");
weechat_hashtable_set (buffer_props, "key_bind_f12", "/list -right");
weechat_hashtable_set (buffer_props, "key_bind_ctrl-j", "/list -join");
}
current_buffer_number = weechat_buffer_get_integer (
weechat_current_buffer (), "number");
snprintf (buffer_name, sizeof (buffer_name), "list_%s", server->name);
buffer = weechat_buffer_new_props (
buffer_name,
buffer_props,
&irc_input_data_cb, NULL, NULL,
&irc_buffer_close_cb, NULL, NULL);
if (buffer_props)
weechat_hashtable_free (buffer_props);
irc_list_buffer_set_localvar_filter (buffer, server);
if (weechat_buffer_get_integer (buffer, "layout_number") < 1)
{
buffer_position = weechat_config_enum (irc_config_look_new_list_position);
switch (buffer_position)
{
case IRC_CONFIG_LOOK_BUFFER_POSITION_NONE:
/* do nothing */
break;
case IRC_CONFIG_LOOK_BUFFER_POSITION_NEXT:
/* move buffer to current number + 1 */
snprintf (str_number, sizeof (str_number),
"%d", current_buffer_number + 1);
weechat_buffer_set (buffer, "number", str_number);
break;
case IRC_CONFIG_LOOK_BUFFER_POSITION_NEAR_SERVER:
/* move buffer after last channel/pv of server */
irc_buffer_move_near_server (
server,
1, /* list_buffer */
-1, /* channel_type */
buffer);
break;
}
}
return buffer;
}
/*
* Callback for redirected /list command.
*/
int
irc_list_hsignal_redirect_list_cb (const void *pointer,
void *data,
const char *signal,
struct t_hashtable *hashtable)
{
struct t_irc_server *ptr_server;
const char *ptr_error, *ptr_server_name, *ptr_output;
/* make C compiler happy */
(void) pointer;
(void) data;
(void) signal;
ptr_error = weechat_hashtable_get (hashtable, "error");
if (ptr_error && ptr_error[0])
{
weechat_printf (
NULL,
_("%s%s: error in redirection of /list: %s"),
weechat_prefix ("error"), IRC_PLUGIN_NAME, ptr_error);
return WEECHAT_RC_OK;
}
ptr_server_name = weechat_hashtable_get (hashtable, "server");
if (!ptr_server_name)
return WEECHAT_RC_OK;
ptr_server = irc_server_search (ptr_server_name);
if (!ptr_server || !ptr_server->buffer)
return WEECHAT_RC_OK;
ptr_output = weechat_hashtable_get (hashtable, "output");
if (!ptr_output)
return WEECHAT_RC_OK;
if (!irc_list_hdata_list_channel)
{
irc_list_hdata_list_channel = weechat_hdata_get ("irc_list_channel");
if (!irc_list_hdata_list_channel)
return WEECHAT_RC_OK;
}
irc_list_parse_messages (ptr_server, ptr_output);
if (!ptr_server->list->channels)
return WEECHAT_RC_OK;
irc_list_buffer_refresh (ptr_server, 1);
return WEECHAT_RC_OK;
}
/*
* Resets lists used by list buffer.
*/
void
irc_list_reset (struct t_irc_server *server)
{
if (!server)
return;
if (server->list->channels)
weechat_arraylist_clear (server->list->channels);
if (server->list->filter_channels)
weechat_arraylist_clear (server->list->filter_channels);
server->list->name_max_length = 0;
if (!server->list->sort)
{
irc_list_set_sort (
server,
weechat_config_string (irc_config_look_list_buffer_sort));
}
server->list->selected_line = 0;
}
/*
* Frees a list structure in a server.
*/
struct t_irc_list *
irc_list_alloc ()
{
struct t_irc_list *list;
list = malloc (sizeof (*list));
if (!list)
return NULL;
list->buffer = NULL;
list->channels = NULL;
list->filter_channels = NULL;
list->name_max_length = 0;
list->filter = NULL;
list->sort = NULL;
list->sort_fields = NULL;
list->sort_fields_count = 0;
list->selected_line = 0;
return list;
}
/*
* Frees data in a list structure.
*/
void
irc_list_free_data (struct t_irc_server *server)
{
if (!server || !server->list)
return;
if (server->list->channels)
{
weechat_arraylist_free (server->list->channels);
server->list->channels = NULL;
}
if (server->list->filter_channels)
{
weechat_arraylist_free (server->list->filter_channels);
server->list->filter_channels = NULL;
}
server->list->name_max_length = 0;
if (server->list->filter)
{
free (server->list->filter);
server->list->filter = NULL;
}
if (server->list->sort)
{
free (server->list->sort);
server->list->sort = NULL;
}
if (server->list->sort_fields)
{
weechat_string_free_split (server->list->sort_fields);
server->list->sort_fields = NULL;
}
server->list->sort_fields_count = 0;
server->list->selected_line = 0;
}
/*
* Frees a list structure in a server.
*/
void
irc_list_free (struct t_irc_server *server)
{
if (!server || !server->list)
return;
if (server->list->buffer)
weechat_buffer_close (server->list->buffer);
irc_list_free_data (server);
free (server->list);
server->list = NULL;
}
/*
* Returns hdata for irc_list_channel.
*/
struct t_hdata *
irc_list_hdata_list_channel_cb (const void *pointer, void *data,
const char *hdata_name)
{
struct t_hdata *hdata;
/* make C compiler happy */
(void) pointer;
(void) data;
hdata = weechat_hdata_new (hdata_name, NULL, NULL, 0, 0, NULL, NULL);
if (hdata)
{
WEECHAT_HDATA_VAR(struct t_irc_list_channel, name, STRING, 0, NULL, NULL);
WEECHAT_HDATA_VAR(struct t_irc_list_channel, name2, STRING, 0, NULL, NULL);
WEECHAT_HDATA_VAR(struct t_irc_list_channel, users, INTEGER, 0, NULL, NULL);
WEECHAT_HDATA_VAR(struct t_irc_list_channel, topic, STRING, 0, NULL, NULL);
}
return hdata;
}
/*
* Returns hdata for irc_list.
*/
struct t_hdata *
irc_list_hdata_list_cb (const void *pointer, void *data, const char *hdata_name)
{
struct t_hdata *hdata;
/* make C compiler happy */
(void) pointer;
(void) data;
hdata = weechat_hdata_new (hdata_name, NULL, NULL, 0, 0, NULL, NULL);
if (hdata)
{
WEECHAT_HDATA_VAR(struct t_irc_list, buffer, POINTER, 0, NULL, "buffer");
WEECHAT_HDATA_VAR(struct t_irc_list, channels, POINTER, 0, NULL, NULL);
WEECHAT_HDATA_VAR(struct t_irc_list, filter_channels, POINTER, 0, NULL, NULL);
WEECHAT_HDATA_VAR(struct t_irc_list, name_max_length, INTEGER, 0, NULL, NULL);
WEECHAT_HDATA_VAR(struct t_irc_list, filter, STRING, 0, NULL, NULL);
WEECHAT_HDATA_VAR(struct t_irc_list, sort, STRING, 0, NULL, NULL);
WEECHAT_HDATA_VAR(struct t_irc_list, sort_fields, POINTER, 0, NULL, NULL);
WEECHAT_HDATA_VAR(struct t_irc_list, sort_fields_count, INTEGER, 0, NULL, NULL);
WEECHAT_HDATA_VAR(struct t_irc_list, selected_line, INTEGER, 0, NULL, NULL);
}
return hdata;
}
/*
* Callback called when a mouse action occurs in irc list buffer.
*/
int
irc_list_mouse_hsignal_cb (const void *pointer, void *data, const char *signal,
struct t_hashtable *hashtable)
{
const char *ptr_key, *ptr_chat_line_y, *ptr_buffer_pointer;
struct t_gui_buffer *ptr_buffer;
unsigned long value;
char str_command[1024];
int rc;
/* make C compiler happy */
(void) pointer;
(void) data;
(void) signal;
ptr_key = weechat_hashtable_get (hashtable, "_key");
ptr_buffer_pointer = weechat_hashtable_get (hashtable, "_buffer");
ptr_chat_line_y = weechat_hashtable_get (hashtable, "_chat_line_y");
if (!ptr_key || !ptr_buffer_pointer || !ptr_chat_line_y)
return WEECHAT_RC_OK;
rc = sscanf (ptr_buffer_pointer, "%lx", &value);
if ((rc == EOF) || (rc == 0))
return WEECHAT_RC_OK;
ptr_buffer = (struct t_gui_buffer *)value;
if (!ptr_buffer)
return WEECHAT_RC_OK;
snprintf (str_command, sizeof (str_command),
"/list -go %s",
ptr_chat_line_y);
weechat_command (ptr_buffer, str_command);
if (weechat_string_match (ptr_key, "button2*", 1))
weechat_command (ptr_buffer, "/list -join");
return WEECHAT_RC_OK;
}
/*
* Initializes irc list.
*/
void
irc_list_init ()
{
struct t_hashtable *keys;
irc_list_filter_hashtable_pointers = weechat_hashtable_new (
8,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_POINTER,
NULL, NULL);
irc_list_filter_hashtable_extra_vars = weechat_hashtable_new (
32,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_STRING,
NULL, NULL);
irc_list_filter_hashtable_options = weechat_hashtable_new (
8,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_STRING,
NULL, NULL);
if (irc_list_filter_hashtable_options)
{
weechat_hashtable_set (irc_list_filter_hashtable_options,
"type", "condition");
}
weechat_hook_hsignal (IRC_LIST_MOUSE_HSIGNAL,
&irc_list_mouse_hsignal_cb, NULL, NULL);
keys = weechat_hashtable_new (32,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_STRING,
NULL, NULL);
if (keys)
{
weechat_hashtable_set (
keys,
"@chat(" IRC_PLUGIN_NAME ".list_*):button1",
"/window ${_window_number};/list -go ${_chat_line_y}");
weechat_hashtable_set (
keys,
"@chat(" IRC_PLUGIN_NAME ".list_*):button2*",
"hsignal:" IRC_LIST_MOUSE_HSIGNAL);
weechat_hashtable_set (
keys,
"@chat(" IRC_PLUGIN_NAME ".list_*):wheelup",
"/list -up 5");
weechat_hashtable_set (
keys,
"@chat(" IRC_PLUGIN_NAME ".list_*):wheeldown",
"/list -down 5");
weechat_hashtable_set (keys, "__quiet", "1");
weechat_key_bind ("mouse", keys);
weechat_hashtable_free (keys);
}
}
/*
* Ends irc list.
*/
void
irc_list_end ()
{
if (irc_list_filter_hashtable_pointers)
{
weechat_hashtable_free (irc_list_filter_hashtable_pointers);
irc_list_filter_hashtable_pointers = NULL;
}
if (irc_list_filter_hashtable_extra_vars)
{
weechat_hashtable_free (irc_list_filter_hashtable_extra_vars);
irc_list_filter_hashtable_extra_vars = NULL;
}
if (irc_list_filter_hashtable_options)
{
weechat_hashtable_free (irc_list_filter_hashtable_options);
irc_list_filter_hashtable_options = NULL;
}
irc_list_hdata_list_channel = NULL;
}