2138 lines
62 KiB
C
2138 lines
62 KiB
C
/*
|
|
* gui-line.c - line functions (used by all GUI)
|
|
*
|
|
* 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/>.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#include "../core/weechat.h"
|
|
#include "../core/wee-config.h"
|
|
#include "../core/wee-hashtable.h"
|
|
#include "../core/wee-hdata.h"
|
|
#include "../core/wee-hook.h"
|
|
#include "../core/wee-infolist.h"
|
|
#include "../core/wee-log.h"
|
|
#include "../core/wee-string.h"
|
|
#include "../plugins/plugin.h"
|
|
#include "gui-line.h"
|
|
#include "gui-buffer.h"
|
|
#include "gui-chat.h"
|
|
#include "gui-color.h"
|
|
#include "gui-filter.h"
|
|
#include "gui-hotlist.h"
|
|
#include "gui-nicklist.h"
|
|
#include "gui-window.h"
|
|
|
|
|
|
/*
|
|
* Allocates structure "t_gui_lines" and initializes it.
|
|
*
|
|
* Returns pointer to new lines, NULL if error.
|
|
*/
|
|
|
|
struct t_gui_lines *
|
|
gui_lines_alloc ()
|
|
{
|
|
struct t_gui_lines *new_lines;
|
|
|
|
new_lines = malloc (sizeof (*new_lines));
|
|
if (new_lines)
|
|
{
|
|
new_lines->first_line = NULL;
|
|
new_lines->last_line = NULL;
|
|
new_lines->last_read_line = NULL;
|
|
new_lines->lines_count = 0;
|
|
new_lines->first_line_not_read = 0;
|
|
new_lines->lines_hidden = 0;
|
|
new_lines->buffer_max_length = 0;
|
|
new_lines->buffer_max_length_refresh = 0;
|
|
new_lines->prefix_max_length = CONFIG_INTEGER(config_look_prefix_align_min);
|
|
new_lines->prefix_max_length_refresh = 0;
|
|
}
|
|
|
|
return new_lines;
|
|
}
|
|
|
|
/*
|
|
* Frees a "t_gui_lines" structure.
|
|
*/
|
|
|
|
void
|
|
gui_lines_free (struct t_gui_lines *lines)
|
|
{
|
|
if (!lines)
|
|
return;
|
|
|
|
free (lines);
|
|
}
|
|
|
|
/*
|
|
* Allocates array with tags in a line_data.
|
|
*/
|
|
|
|
void
|
|
gui_line_tags_alloc (struct t_gui_line_data *line_data, const char *tags)
|
|
{
|
|
if (tags)
|
|
{
|
|
line_data->tags_array = string_split_shared (tags, ",", NULL, 0, 0,
|
|
&line_data->tags_count);
|
|
}
|
|
else
|
|
{
|
|
line_data->tags_count = 0;
|
|
line_data->tags_array = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Frees array with tags in a line_data.
|
|
*/
|
|
|
|
void
|
|
gui_line_tags_free (struct t_gui_line_data *line_data)
|
|
{
|
|
if (!line_data)
|
|
return;
|
|
|
|
if (line_data->tags_array)
|
|
{
|
|
string_free_split_shared (line_data->tags_array);
|
|
line_data->tags_count = 0;
|
|
line_data->tags_array = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Checks if prefix on line is a nick and is the same as nick on previous/next
|
|
* line (according to direction: if < 0, check if it's the same nick as
|
|
* previous line, otherwise next line).
|
|
*
|
|
* Returns:
|
|
* 1: prefix is a nick and same as nick on previous/next line
|
|
* 0: prefix is not a nick, or different from nick on previous/next line
|
|
*/
|
|
|
|
int
|
|
gui_line_prefix_is_same_nick (struct t_gui_line *line, int direction)
|
|
{
|
|
const char *nick, *nick_other;
|
|
struct t_gui_line *other_line;
|
|
|
|
/*
|
|
* if line is not displayed, has a highlight, or does not have a tag
|
|
* beginning with "prefix_nick" => display standard prefix
|
|
*/
|
|
if (!line->data->displayed || line->data->highlight
|
|
|| !gui_line_search_tag_starting_with (line, "prefix_nick"))
|
|
return 0;
|
|
|
|
/* no nick on line => display standard prefix */
|
|
nick = gui_line_get_nick_tag (line);
|
|
if (!nick)
|
|
return 0;
|
|
|
|
/*
|
|
* previous line is not found => display standard prefix
|
|
*/
|
|
other_line = (direction < 0) ?
|
|
gui_line_get_prev_displayed (line) :
|
|
gui_line_get_next_displayed (line);
|
|
if (!other_line)
|
|
return 0;
|
|
|
|
/* buffer is not the same as the other line => display standard prefix */
|
|
if (line->data->buffer != other_line->data->buffer)
|
|
return 0;
|
|
|
|
/*
|
|
* the other line does not have a tag beginning with "prefix_nick"
|
|
* => display standard prefix
|
|
*/
|
|
if (!gui_line_search_tag_starting_with (other_line, "prefix_nick"))
|
|
return 0;
|
|
|
|
/* no nick on previous line => display standard prefix */
|
|
nick_other = gui_line_get_nick_tag (other_line);
|
|
if (!nick_other)
|
|
return 0;
|
|
|
|
/* prefix can be hidden/replaced if nicks are equal */
|
|
return (strcmp (nick, nick_other) == 0) ? 1 : 0;
|
|
}
|
|
|
|
/*
|
|
* Gets prefix and its length (for display only).
|
|
*
|
|
* If the prefix can be hidden (same nick as previous message), and if the
|
|
* option is enabled (not empty string), then returns empty prefix or prefix
|
|
* from option.
|
|
*/
|
|
|
|
void
|
|
gui_line_get_prefix_for_display (struct t_gui_line *line,
|
|
char **prefix, int *length,
|
|
char **color, int *prefix_is_nick)
|
|
{
|
|
const char *tag_prefix_nick;
|
|
|
|
if (CONFIG_STRING(config_look_prefix_same_nick)
|
|
&& CONFIG_STRING(config_look_prefix_same_nick)[0]
|
|
&& gui_line_prefix_is_same_nick (line, -1))
|
|
{
|
|
if (CONFIG_STRING(config_look_prefix_same_nick_middle)
|
|
&& CONFIG_STRING(config_look_prefix_same_nick_middle)[0]
|
|
&& gui_line_prefix_is_same_nick (line, 1))
|
|
{
|
|
/* same nick: return empty prefix or value from option */
|
|
if (strcmp (CONFIG_STRING(config_look_prefix_same_nick_middle), " ") == 0)
|
|
{
|
|
/* return empty prefix */
|
|
if (prefix)
|
|
*prefix = gui_chat_prefix_empty;
|
|
if (length)
|
|
*length = 0;
|
|
if (color)
|
|
*color = NULL;
|
|
}
|
|
else
|
|
{
|
|
/* return prefix from option "weechat.look.prefix_same_nick_middle" */
|
|
if (prefix)
|
|
*prefix = CONFIG_STRING(config_look_prefix_same_nick_middle);
|
|
if (length)
|
|
*length = config_length_prefix_same_nick_middle;
|
|
if (color)
|
|
{
|
|
tag_prefix_nick = gui_line_search_tag_starting_with (line,
|
|
"prefix_nick_");
|
|
*color = (tag_prefix_nick) ? (char *)(tag_prefix_nick + 12) : NULL;
|
|
}
|
|
}
|
|
if (prefix_is_nick)
|
|
*prefix_is_nick = 0;
|
|
}
|
|
else
|
|
{
|
|
/* same nick: return empty prefix or value from option */
|
|
if (strcmp (CONFIG_STRING(config_look_prefix_same_nick), " ") == 0)
|
|
{
|
|
/* return empty prefix */
|
|
if (prefix)
|
|
*prefix = gui_chat_prefix_empty;
|
|
if (length)
|
|
*length = 0;
|
|
if (color)
|
|
*color = NULL;
|
|
}
|
|
else
|
|
{
|
|
/* return prefix from option "weechat.look.prefix_same_nick" */
|
|
if (prefix)
|
|
*prefix = CONFIG_STRING(config_look_prefix_same_nick);
|
|
if (length)
|
|
*length = config_length_prefix_same_nick;
|
|
if (color)
|
|
{
|
|
tag_prefix_nick = gui_line_search_tag_starting_with (line,
|
|
"prefix_nick_");
|
|
*color = (tag_prefix_nick) ? (char *)(tag_prefix_nick + 12) : NULL;
|
|
}
|
|
}
|
|
if (prefix_is_nick)
|
|
*prefix_is_nick = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* not same nick: return prefix from line */
|
|
if (prefix)
|
|
*prefix = line->data->prefix;
|
|
if (length)
|
|
*length = line->data->prefix_length;
|
|
if (color)
|
|
*color = NULL;
|
|
if (prefix_is_nick)
|
|
*prefix_is_nick = gui_line_search_tag_starting_with (line, "prefix_nick_") ? 1 : 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Gets alignment for a line.
|
|
*/
|
|
|
|
int
|
|
gui_line_get_align (struct t_gui_buffer *buffer, struct t_gui_line *line,
|
|
int with_suffix, int first_line)
|
|
{
|
|
int length_time, length_buffer, length_suffix, prefix_length, prefix_is_nick;
|
|
|
|
/* return immediately if line has no time (not aligned) */
|
|
if (line->data->date == 0)
|
|
return 0;
|
|
|
|
/* return immediately if alignment for end of lines is "time" */
|
|
if (!first_line
|
|
&& (CONFIG_INTEGER(config_look_align_end_of_lines) == CONFIG_LOOK_ALIGN_END_OF_LINES_TIME))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* length of time */
|
|
if (buffer->time_for_each_line)
|
|
{
|
|
length_time = (gui_chat_time_length == 0) ? 0 : gui_chat_time_length + 1;
|
|
}
|
|
else
|
|
length_time = 0;
|
|
|
|
/* return immediately if alignment for end of lines is "buffer" */
|
|
if (!first_line
|
|
&& (CONFIG_INTEGER(config_look_align_end_of_lines) == CONFIG_LOOK_ALIGN_END_OF_LINES_BUFFER))
|
|
{
|
|
return length_time;
|
|
}
|
|
|
|
/* length of buffer name (when many buffers are merged) */
|
|
if (buffer->mixed_lines && (buffer->active != 2))
|
|
{
|
|
if ((CONFIG_INTEGER(config_look_prefix_buffer_align) == CONFIG_LOOK_PREFIX_BUFFER_ALIGN_NONE)
|
|
&& (CONFIG_INTEGER(config_look_prefix_align) == CONFIG_LOOK_PREFIX_ALIGN_NONE))
|
|
length_buffer = gui_chat_strlen_screen (gui_buffer_get_short_name (line->data->buffer)) + 1;
|
|
else
|
|
{
|
|
if (CONFIG_INTEGER(config_look_prefix_buffer_align) == CONFIG_LOOK_PREFIX_BUFFER_ALIGN_NONE)
|
|
length_buffer = buffer->mixed_lines->buffer_max_length + 1;
|
|
else
|
|
length_buffer = ((CONFIG_INTEGER(config_look_prefix_buffer_align_max) > 0)
|
|
&& (buffer->mixed_lines->buffer_max_length > CONFIG_INTEGER(config_look_prefix_buffer_align_max))) ?
|
|
CONFIG_INTEGER(config_look_prefix_buffer_align_max) + 1 : buffer->mixed_lines->buffer_max_length + 1;
|
|
}
|
|
}
|
|
else
|
|
length_buffer = 0;
|
|
|
|
/* return immediately if alignment for end of lines is "prefix" */
|
|
if (!first_line
|
|
&& (CONFIG_INTEGER(config_look_align_end_of_lines) == CONFIG_LOOK_ALIGN_END_OF_LINES_PREFIX))
|
|
{
|
|
return length_time + length_buffer;
|
|
}
|
|
|
|
/* length of prefix */
|
|
gui_line_get_prefix_for_display (line, NULL, &prefix_length, NULL,
|
|
&prefix_is_nick);
|
|
if (prefix_is_nick)
|
|
prefix_length += config_length_nick_prefix_suffix;
|
|
|
|
if (CONFIG_INTEGER(config_look_prefix_align) == CONFIG_LOOK_PREFIX_ALIGN_NONE)
|
|
{
|
|
return length_time + length_buffer + prefix_length + ((prefix_length > 0) ? 1 : 0);
|
|
}
|
|
|
|
length_suffix = 0;
|
|
if (with_suffix)
|
|
{
|
|
if (CONFIG_STRING(config_look_prefix_suffix)
|
|
&& CONFIG_STRING(config_look_prefix_suffix)[0])
|
|
length_suffix = gui_chat_strlen_screen (CONFIG_STRING(config_look_prefix_suffix)) + 1;
|
|
}
|
|
|
|
return length_time + ((buffer->lines->prefix_max_length > 0) ? 1 : 0)
|
|
+ length_buffer
|
|
+ (((CONFIG_INTEGER(config_look_prefix_align_max) > 0)
|
|
&& (buffer->lines->prefix_max_length > CONFIG_INTEGER(config_look_prefix_align_max))) ?
|
|
CONFIG_INTEGER(config_look_prefix_align_max) : buffer->lines->prefix_max_length)
|
|
+ length_suffix;
|
|
}
|
|
|
|
/*
|
|
* Checks if a line is displayed (no filter on line or filters disabled).
|
|
*
|
|
* Returns:
|
|
* 1: line is displayed
|
|
* 0: line is hidden
|
|
*/
|
|
|
|
int
|
|
gui_line_is_displayed (struct t_gui_line *line)
|
|
{
|
|
/* line is hidden if filters are enabled and flag "displayed" is not set */
|
|
if (gui_filters_enabled && !line->data->displayed)
|
|
return 0;
|
|
|
|
/* in all other cases, line is displayed */
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Gets the first line displayed of a buffer.
|
|
*
|
|
* Returns pointer to first line displayed, NULL if not found.
|
|
*/
|
|
|
|
struct t_gui_line *
|
|
gui_line_get_first_displayed (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_line *ptr_line;
|
|
|
|
ptr_line = buffer->lines->first_line;
|
|
while (ptr_line && !gui_line_is_displayed (ptr_line))
|
|
{
|
|
ptr_line = ptr_line->next_line;
|
|
}
|
|
|
|
return ptr_line;
|
|
}
|
|
|
|
/*
|
|
* Gets the last line displayed of a buffer.
|
|
*
|
|
* Returns pointer to last line displayed, NULL if not found.
|
|
*/
|
|
|
|
struct t_gui_line *
|
|
gui_line_get_last_displayed (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_line *ptr_line;
|
|
|
|
ptr_line = buffer->lines->last_line;
|
|
while (ptr_line && !gui_line_is_displayed (ptr_line))
|
|
{
|
|
ptr_line = ptr_line->prev_line;
|
|
}
|
|
|
|
return ptr_line;
|
|
}
|
|
|
|
/*
|
|
* Gets previous line displayed.
|
|
*
|
|
* Returns pointer to previous line displayed, NULL if not found.
|
|
*/
|
|
|
|
struct t_gui_line *
|
|
gui_line_get_prev_displayed (struct t_gui_line *line)
|
|
{
|
|
if (line)
|
|
{
|
|
line = line->prev_line;
|
|
while (line && !gui_line_is_displayed (line))
|
|
{
|
|
line = line->prev_line;
|
|
}
|
|
}
|
|
return line;
|
|
}
|
|
|
|
/*
|
|
* Gets next line displayed.
|
|
*
|
|
* Returns pointer to next line displayed, NULL if not found.
|
|
*/
|
|
|
|
struct t_gui_line *
|
|
gui_line_get_next_displayed (struct t_gui_line *line)
|
|
{
|
|
if (line)
|
|
{
|
|
line = line->next_line;
|
|
while (line && !gui_line_is_displayed (line))
|
|
{
|
|
line = line->next_line;
|
|
}
|
|
}
|
|
return line;
|
|
}
|
|
|
|
/*
|
|
* Searches for text in a line.
|
|
*
|
|
* Returns:
|
|
* 1: text found in line
|
|
* 0: text not found in line
|
|
*/
|
|
|
|
int
|
|
gui_line_search_text (struct t_gui_buffer *buffer, struct t_gui_line *line)
|
|
{
|
|
char *prefix, *message;
|
|
int rc;
|
|
|
|
if (!line || !line->data->message
|
|
|| !buffer->input_buffer || !buffer->input_buffer[0])
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
rc = 0;
|
|
|
|
if ((buffer->text_search_where & GUI_TEXT_SEARCH_IN_PREFIX)
|
|
&& line->data->prefix)
|
|
{
|
|
prefix = gui_color_decode (line->data->prefix, NULL);
|
|
if (prefix)
|
|
{
|
|
if (buffer->text_search_regex)
|
|
{
|
|
if (buffer->text_search_regex_compiled)
|
|
{
|
|
if (regexec (buffer->text_search_regex_compiled,
|
|
prefix, 0, NULL, 0) == 0)
|
|
{
|
|
rc = 1;
|
|
}
|
|
}
|
|
}
|
|
else if ((buffer->text_search_exact
|
|
&& (strstr (prefix, buffer->input_buffer)))
|
|
|| (!buffer->text_search_exact
|
|
&& (string_strcasestr (prefix, buffer->input_buffer))))
|
|
{
|
|
rc = 1;
|
|
}
|
|
free (prefix);
|
|
}
|
|
}
|
|
|
|
if (!rc && (buffer->text_search_where & GUI_TEXT_SEARCH_IN_MESSAGE))
|
|
{
|
|
message = gui_color_decode (line->data->message, NULL);
|
|
if (message)
|
|
{
|
|
if (buffer->text_search_regex)
|
|
{
|
|
if (buffer->text_search_regex_compiled)
|
|
{
|
|
if (regexec (buffer->text_search_regex_compiled,
|
|
message, 0, NULL, 0) == 0)
|
|
{
|
|
rc = 1;
|
|
}
|
|
}
|
|
}
|
|
else if ((buffer->text_search_exact
|
|
&& (strstr (message, buffer->input_buffer)))
|
|
|| (!buffer->text_search_exact
|
|
&& (string_strcasestr (message, buffer->input_buffer))))
|
|
{
|
|
rc = 1;
|
|
}
|
|
free (message);
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* Checks if a line matches regex.
|
|
*
|
|
* Returns:
|
|
* 1: line matches regex
|
|
* 0: line does not match regex
|
|
*/
|
|
|
|
int
|
|
gui_line_match_regex (struct t_gui_line_data *line_data, regex_t *regex_prefix,
|
|
regex_t *regex_message)
|
|
{
|
|
char *prefix, *message;
|
|
int match_prefix, match_message;
|
|
|
|
if (!line_data || (!regex_prefix && !regex_message))
|
|
return 0;
|
|
|
|
prefix = NULL;
|
|
message = NULL;
|
|
|
|
match_prefix = 1;
|
|
match_message = 1;
|
|
|
|
if (line_data->prefix)
|
|
{
|
|
prefix = gui_color_decode (line_data->prefix, NULL);
|
|
if (!prefix
|
|
|| (regex_prefix && (regexec (regex_prefix, prefix, 0, NULL, 0) != 0)))
|
|
match_prefix = 0;
|
|
}
|
|
else
|
|
{
|
|
if (regex_prefix)
|
|
match_prefix = 0;
|
|
}
|
|
|
|
if (line_data->message)
|
|
{
|
|
message = gui_color_decode (line_data->message, NULL);
|
|
if (!message
|
|
|| (regex_message && (regexec (regex_message, message, 0, NULL, 0) != 0)))
|
|
match_message = 0;
|
|
}
|
|
else
|
|
{
|
|
if (regex_message)
|
|
match_message = 0;
|
|
}
|
|
|
|
if (prefix)
|
|
free (prefix);
|
|
if (message)
|
|
free (message);
|
|
|
|
return (match_prefix && match_message);
|
|
}
|
|
|
|
/*
|
|
* Checks if a line has tag "no_filter" (which means that line should never been
|
|
* filtered: it is always displayed).
|
|
*
|
|
* Returns:
|
|
* 1: line has tag "no_filter"
|
|
* 0: line does not have tag "no_filter"
|
|
*/
|
|
|
|
int
|
|
gui_line_has_tag_no_filter (struct t_gui_line_data *line_data)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < line_data->tags_count; i++)
|
|
{
|
|
if (strcmp (line_data->tags_array[i], GUI_FILTER_TAG_NO_FILTER) == 0)
|
|
return 1;
|
|
}
|
|
|
|
/* tag not found, line may be filtered */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Checks if line matches tags.
|
|
*
|
|
* Returns:
|
|
* 1: line matches tags
|
|
* 0: line does not match tags
|
|
*/
|
|
|
|
int
|
|
gui_line_match_tags (struct t_gui_line_data *line_data,
|
|
int tags_count, char ***tags_array)
|
|
{
|
|
int i, j, k, match, tag_found, tag_negated;
|
|
const char *ptr_tag;
|
|
|
|
if (!line_data)
|
|
return 0;
|
|
|
|
for (i = 0; i < tags_count; i++)
|
|
{
|
|
match = 1;
|
|
for (j = 0; tags_array[i][j]; j++)
|
|
{
|
|
ptr_tag = tags_array[i][j];
|
|
tag_found = 0;
|
|
tag_negated = 0;
|
|
|
|
/* check if tag is negated (prefixed with a '!') */
|
|
if ((ptr_tag[0] == '!') && ptr_tag[1])
|
|
{
|
|
ptr_tag++;
|
|
tag_negated = 1;
|
|
}
|
|
|
|
if (strcmp (ptr_tag, "*") == 0)
|
|
{
|
|
tag_found = 1;
|
|
}
|
|
else
|
|
{
|
|
for (k = 0; k < line_data->tags_count; k++)
|
|
{
|
|
if (string_match (line_data->tags_array[k], ptr_tag, 0))
|
|
{
|
|
tag_found = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (tag_found && tag_negated)
|
|
return 0;
|
|
if ((!tag_found && !tag_negated) || (tag_found && tag_negated))
|
|
{
|
|
match = 0;
|
|
break;
|
|
}
|
|
}
|
|
if (match)
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Returns pointer on tag starting with "tag", NULL if such tag is not found.
|
|
*/
|
|
|
|
const char *
|
|
gui_line_search_tag_starting_with (struct t_gui_line *line, const char *tag)
|
|
{
|
|
int i, length;
|
|
|
|
if (!line || !tag)
|
|
return NULL;
|
|
|
|
length = strlen (tag);
|
|
|
|
for (i = 0; i < line->data->tags_count; i++)
|
|
{
|
|
if (strncmp (line->data->tags_array[i], tag, length) == 0)
|
|
return line->data->tags_array[i];
|
|
}
|
|
|
|
/* tag not found */
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Gets nick in tags: returns "xxx" if tag "nick_xxx" is found.
|
|
*/
|
|
|
|
const char *
|
|
gui_line_get_nick_tag (struct t_gui_line *line)
|
|
{
|
|
const char *tag;
|
|
|
|
tag = gui_line_search_tag_starting_with (line, "nick_");
|
|
if (!tag)
|
|
return NULL;
|
|
|
|
return tag + 5;
|
|
}
|
|
|
|
/*
|
|
* Checks if a line has highlight (with a string in global highlight or buffer
|
|
* highlight).
|
|
*
|
|
* Returns:
|
|
* 1: line has highlight
|
|
* 0: line has no highlight
|
|
*/
|
|
|
|
int
|
|
gui_line_has_highlight (struct t_gui_line *line)
|
|
{
|
|
int rc, i, no_highlight, action, length;
|
|
char *msg_no_color, *ptr_msg_no_color, *highlight_words;
|
|
const char *ptr_nick;
|
|
|
|
/*
|
|
* highlights are disabled on this buffer? (special value "-" means that
|
|
* buffer does not want any highlight)
|
|
*/
|
|
if (line->data->buffer->highlight_words
|
|
&& (strcmp (line->data->buffer->highlight_words, "-") == 0))
|
|
return 0;
|
|
|
|
/*
|
|
* check if highlight is disabled for line; also check if the line is an
|
|
* action message (for example tag "irc_action") and get pointer on the nick
|
|
* (tag "nick_xxx"), these info will be used later (see below)
|
|
*/
|
|
no_highlight = 0;
|
|
action = 0;
|
|
ptr_nick = NULL;
|
|
for (i = 0; i < line->data->tags_count; i++)
|
|
{
|
|
if (strcmp (line->data->tags_array[i], GUI_CHAT_TAG_NO_HIGHLIGHT) == 0)
|
|
no_highlight = 1;
|
|
else if (strncmp (line->data->tags_array[i], "nick_", 5) == 0)
|
|
ptr_nick = line->data->tags_array[i] + 5;
|
|
else
|
|
{
|
|
length = strlen (line->data->tags_array[i]);
|
|
if ((length >= 7)
|
|
&& (strcmp (line->data->tags_array[i] + length - 7, "_action") == 0))
|
|
{
|
|
action = 1;
|
|
}
|
|
}
|
|
}
|
|
if (no_highlight)
|
|
return 0;
|
|
|
|
/*
|
|
* check if highlight is forced by a tag
|
|
* (with global option "weechat.look.highlight_tags")
|
|
*/
|
|
if (config_highlight_tags
|
|
&& gui_line_match_tags (line->data,
|
|
config_num_highlight_tags,
|
|
config_highlight_tags))
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* check if highlight is forced by a tag
|
|
* (with buffer property "highlight_tags")
|
|
*/
|
|
if (line->data->buffer->highlight_tags
|
|
&& gui_line_match_tags (line->data,
|
|
line->data->buffer->highlight_tags_count,
|
|
line->data->buffer->highlight_tags_array))
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* check that line matches highlight tags, if any (if no tag is specified,
|
|
* then any tag is allowed)
|
|
*/
|
|
if (line->data->buffer->highlight_tags_restrict_count > 0)
|
|
{
|
|
if (!gui_line_match_tags (line->data,
|
|
line->data->buffer->highlight_tags_restrict_count,
|
|
line->data->buffer->highlight_tags_restrict_array))
|
|
return 0;
|
|
}
|
|
|
|
/* remove color codes from line message */
|
|
msg_no_color = gui_color_decode (line->data->message, NULL);
|
|
if (!msg_no_color)
|
|
return 0;
|
|
ptr_msg_no_color = msg_no_color;
|
|
|
|
/*
|
|
* if the line is an action message and that we know the nick, we skip
|
|
* the nick if it is at beginning of message (to not highlight an action
|
|
* from another user if his nick is in our highlight settings)
|
|
*/
|
|
if (action && ptr_nick)
|
|
{
|
|
length = strlen (ptr_nick);
|
|
if (strncmp (ptr_msg_no_color, ptr_nick, length) == 0)
|
|
{
|
|
/* skip nick at beginning (for example: "FlashCode") */
|
|
ptr_msg_no_color += length;
|
|
}
|
|
else if (ptr_msg_no_color[0]
|
|
&& (strncmp (ptr_msg_no_color + 1, ptr_nick, length) == 0))
|
|
{
|
|
/* skip prefix and nick at beginning (for example: "@FlashCode") */
|
|
ptr_msg_no_color += length + 1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* there is highlight on line if one of buffer highlight words matches line
|
|
* or one of global highlight words matches line
|
|
*/
|
|
highlight_words = gui_buffer_string_replace_local_var (line->data->buffer,
|
|
line->data->buffer->highlight_words);
|
|
rc = string_has_highlight (ptr_msg_no_color,
|
|
(highlight_words) ?
|
|
highlight_words : line->data->buffer->highlight_words);
|
|
if (highlight_words)
|
|
free (highlight_words);
|
|
|
|
if (!rc)
|
|
{
|
|
highlight_words = gui_buffer_string_replace_local_var (line->data->buffer,
|
|
CONFIG_STRING(config_look_highlight));
|
|
rc = string_has_highlight (ptr_msg_no_color,
|
|
(highlight_words) ?
|
|
highlight_words : CONFIG_STRING(config_look_highlight));
|
|
if (highlight_words)
|
|
free (highlight_words);
|
|
}
|
|
|
|
if (!rc && config_highlight_regex)
|
|
{
|
|
rc = string_has_highlight_regex_compiled (ptr_msg_no_color,
|
|
config_highlight_regex);
|
|
}
|
|
|
|
if (!rc && line->data->buffer->highlight_regex_compiled)
|
|
{
|
|
rc = string_has_highlight_regex_compiled (ptr_msg_no_color,
|
|
line->data->buffer->highlight_regex_compiled);
|
|
}
|
|
|
|
free (msg_no_color);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* Checks if nick of line is offline (not in nicklist any more).
|
|
*
|
|
* Returns:
|
|
* 1: nick is offline
|
|
* 0: nick is still there (in nicklist)
|
|
*/
|
|
|
|
int
|
|
gui_line_has_offline_nick (struct t_gui_line *line)
|
|
{
|
|
const char *nick;
|
|
|
|
if (line && gui_line_search_tag_starting_with (line, "prefix_nick"))
|
|
{
|
|
nick = gui_line_get_nick_tag (line);
|
|
if (nick
|
|
&& (line->data->buffer->nicklist_root
|
|
&& (line->data->buffer->nicklist_root->nicks
|
|
|| line->data->buffer->nicklist_root->children))
|
|
&& !gui_nicklist_search_nick (line->data->buffer, NULL, nick))
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Computes "buffer_max_length" for a "t_gui_lines" structure.
|
|
*/
|
|
|
|
void
|
|
gui_line_compute_buffer_max_length (struct t_gui_buffer *buffer,
|
|
struct t_gui_lines *lines)
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
int length;
|
|
const char *short_name;
|
|
|
|
lines->buffer_max_length = 0;
|
|
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
short_name = gui_buffer_get_short_name (ptr_buffer);
|
|
if (ptr_buffer->number == buffer->number)
|
|
{
|
|
length = gui_chat_strlen_screen (short_name);
|
|
if (length > lines->buffer_max_length)
|
|
lines->buffer_max_length = length;
|
|
}
|
|
}
|
|
|
|
lines->buffer_max_length_refresh = 0;
|
|
}
|
|
|
|
/*
|
|
* Computes "prefix_max_length" for a "t_gui_lines" structure.
|
|
*/
|
|
|
|
void
|
|
gui_line_compute_prefix_max_length (struct t_gui_lines *lines)
|
|
{
|
|
struct t_gui_line *ptr_line;
|
|
int prefix_length, prefix_is_nick;
|
|
|
|
lines->prefix_max_length = CONFIG_INTEGER(config_look_prefix_align_min);
|
|
|
|
for (ptr_line = lines->first_line; ptr_line;
|
|
ptr_line = ptr_line->next_line)
|
|
{
|
|
if (ptr_line->data->displayed)
|
|
{
|
|
gui_line_get_prefix_for_display (ptr_line, NULL, &prefix_length,
|
|
NULL, &prefix_is_nick);
|
|
if (prefix_is_nick)
|
|
prefix_length += config_length_nick_prefix_suffix;
|
|
if (prefix_length > lines->prefix_max_length)
|
|
lines->prefix_max_length = prefix_length;
|
|
}
|
|
}
|
|
|
|
lines->prefix_max_length_refresh = 0;
|
|
}
|
|
|
|
/*
|
|
* Adds a line to a "t_gui_lines" structure.
|
|
*/
|
|
|
|
void
|
|
gui_line_add_to_list (struct t_gui_lines *lines,
|
|
struct t_gui_line *line)
|
|
{
|
|
int prefix_length, prefix_is_nick;
|
|
|
|
if (lines->last_line)
|
|
(lines->last_line)->next_line = line;
|
|
else
|
|
lines->first_line = line;
|
|
line->prev_line = lines->last_line;
|
|
line->next_line = NULL;
|
|
lines->last_line = line;
|
|
|
|
/*
|
|
* adjust "prefix_max_length" if this prefix length is > max
|
|
* (only if the line is displayed
|
|
*/
|
|
if (line->data->displayed)
|
|
{
|
|
gui_line_get_prefix_for_display (line, NULL, &prefix_length, NULL,
|
|
&prefix_is_nick);
|
|
if (prefix_is_nick)
|
|
prefix_length += config_length_nick_prefix_suffix;
|
|
if (prefix_length > lines->prefix_max_length)
|
|
lines->prefix_max_length = prefix_length;
|
|
}
|
|
else
|
|
{
|
|
/* adjust "lines_hidden" if the line is hidden */
|
|
(lines->lines_hidden)++;
|
|
}
|
|
|
|
lines->lines_count++;
|
|
}
|
|
|
|
/*
|
|
* Frees data in a line.
|
|
*/
|
|
|
|
void
|
|
gui_line_free_data (struct t_gui_line *line)
|
|
{
|
|
if (line->data->str_time)
|
|
free (line->data->str_time);
|
|
gui_line_tags_free (line->data);
|
|
if (line->data->prefix)
|
|
string_shared_free (line->data->prefix);
|
|
if (line->data->message)
|
|
free (line->data->message);
|
|
free (line->data);
|
|
|
|
line->data = NULL;
|
|
}
|
|
|
|
/*
|
|
* Removes a line from a "t_gui_lines" structure.
|
|
*/
|
|
|
|
void
|
|
gui_line_remove_from_list (struct t_gui_buffer *buffer,
|
|
struct t_gui_lines *lines,
|
|
struct t_gui_line *line,
|
|
int free_data)
|
|
{
|
|
struct t_gui_window *ptr_win;
|
|
struct t_gui_window_scroll *ptr_scroll;
|
|
int prefix_length, prefix_is_nick;
|
|
|
|
for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window)
|
|
{
|
|
/* reset scroll for any window scroll starting with this line */
|
|
for (ptr_scroll = ptr_win->scroll; ptr_scroll;
|
|
ptr_scroll = ptr_scroll->next_scroll)
|
|
{
|
|
if (ptr_scroll->start_line == line)
|
|
{
|
|
ptr_scroll->start_line = ptr_scroll->start_line->next_line;
|
|
ptr_scroll->start_line_pos = 0;
|
|
if (ptr_scroll->start_line)
|
|
{
|
|
gui_buffer_ask_chat_refresh (buffer, 2);
|
|
}
|
|
else
|
|
{
|
|
ptr_scroll->first_line_displayed = 1;
|
|
ptr_scroll->scrolling = 0;
|
|
ptr_scroll->lines_after = 0;
|
|
gui_window_ask_refresh (1);
|
|
}
|
|
}
|
|
|
|
if (ptr_scroll->text_search_start_line == line)
|
|
ptr_scroll->text_search_start_line = NULL;
|
|
}
|
|
/* remove line from coords */
|
|
gui_window_coords_remove_line (ptr_win, line);
|
|
}
|
|
|
|
gui_line_get_prefix_for_display (line, NULL, &prefix_length, NULL,
|
|
&prefix_is_nick);
|
|
if (prefix_is_nick)
|
|
prefix_length += config_length_nick_prefix_suffix;
|
|
if (prefix_length == lines->prefix_max_length)
|
|
lines->prefix_max_length_refresh = 1;
|
|
|
|
/* move read marker if it was on line we are removing */
|
|
if (lines->last_read_line == line)
|
|
{
|
|
lines->last_read_line = lines->last_read_line->prev_line;
|
|
lines->first_line_not_read = (lines->last_read_line) ? 0 : 1;
|
|
gui_buffer_ask_chat_refresh (buffer, 1);
|
|
}
|
|
|
|
/* adjust "lines_hidden" if the line was hidden */
|
|
if (!line->data->displayed && (lines->lines_hidden > 0))
|
|
(lines->lines_hidden)--;
|
|
|
|
/* free data */
|
|
if (free_data)
|
|
gui_line_free_data (line);
|
|
|
|
/* remove line from list */
|
|
if (line->prev_line)
|
|
(line->prev_line)->next_line = line->next_line;
|
|
if (line->next_line)
|
|
(line->next_line)->prev_line = line->prev_line;
|
|
if (lines->first_line == line)
|
|
lines->first_line = line->next_line;
|
|
if (lines->last_line == line)
|
|
lines->last_line = line->prev_line;
|
|
|
|
lines->lines_count--;
|
|
|
|
free (line);
|
|
}
|
|
|
|
/*
|
|
* Adds line to mixed lines for a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_line_mixed_add (struct t_gui_lines *lines,
|
|
struct t_gui_line_data *line_data)
|
|
{
|
|
struct t_gui_line *new_line;
|
|
|
|
new_line = malloc (sizeof (*new_line));
|
|
if (new_line)
|
|
{
|
|
new_line->data = line_data;
|
|
gui_line_add_to_list (lines, new_line);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Frees all mixed lines matching a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_line_mixed_free_buffer (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_line *ptr_line, *ptr_next_line;
|
|
|
|
if (buffer->mixed_lines)
|
|
{
|
|
ptr_line = buffer->mixed_lines->first_line;
|
|
while (ptr_line)
|
|
{
|
|
ptr_next_line = ptr_line->next_line;
|
|
|
|
if (ptr_line->data->buffer == buffer)
|
|
{
|
|
gui_line_remove_from_list (buffer,
|
|
buffer->mixed_lines,
|
|
ptr_line,
|
|
0);
|
|
}
|
|
|
|
ptr_line = ptr_next_line;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Frees all mixed lines in a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_line_mixed_free_all (struct t_gui_buffer *buffer)
|
|
{
|
|
if (buffer->mixed_lines)
|
|
{
|
|
while (buffer->mixed_lines->first_line)
|
|
{
|
|
gui_line_remove_from_list (buffer,
|
|
buffer->mixed_lines,
|
|
buffer->mixed_lines->first_line,
|
|
0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Deletes a line from a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_line_free (struct t_gui_buffer *buffer, struct t_gui_line *line)
|
|
{
|
|
struct t_gui_line *ptr_line;
|
|
|
|
if (!buffer || !line)
|
|
return;
|
|
|
|
/* first remove mixed line if it exists */
|
|
if (buffer->mixed_lines)
|
|
{
|
|
for (ptr_line = buffer->mixed_lines->first_line; ptr_line;
|
|
ptr_line = ptr_line->next_line)
|
|
{
|
|
if (ptr_line->data == line->data)
|
|
{
|
|
gui_line_remove_from_list (buffer,
|
|
buffer->mixed_lines,
|
|
ptr_line,
|
|
0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* remove line from lines list */
|
|
gui_line_remove_from_list (buffer, buffer->own_lines, line, 1);
|
|
}
|
|
|
|
/*
|
|
* Deletes all formatted lines from a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_line_free_all (struct t_gui_buffer *buffer)
|
|
{
|
|
while (buffer->own_lines->first_line)
|
|
{
|
|
gui_line_free (buffer, buffer->own_lines->first_line);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Gets notify level for a line.
|
|
*
|
|
* Returns notify level of line, -1 if tag "notify_none" is found (meaning no
|
|
* notify at all for line).
|
|
*/
|
|
|
|
int
|
|
gui_line_get_notify_level (struct t_gui_line *line)
|
|
{
|
|
int i, notify_level, *max_notify_level;
|
|
const char *nick;
|
|
|
|
notify_level = GUI_HOTLIST_LOW;
|
|
|
|
for (i = 0; i < line->data->tags_count; i++)
|
|
{
|
|
if (string_strcasecmp (line->data->tags_array[i], "notify_none") == 0)
|
|
notify_level = -1;
|
|
if (string_strcasecmp (line->data->tags_array[i], "notify_highlight") == 0)
|
|
notify_level = GUI_HOTLIST_HIGHLIGHT;
|
|
if (string_strcasecmp (line->data->tags_array[i], "notify_private") == 0)
|
|
notify_level = GUI_HOTLIST_PRIVATE;
|
|
if (string_strcasecmp (line->data->tags_array[i], "notify_message") == 0)
|
|
notify_level = GUI_HOTLIST_MESSAGE;
|
|
}
|
|
|
|
max_notify_level = NULL;
|
|
nick = gui_line_get_nick_tag (line);
|
|
if (nick)
|
|
{
|
|
max_notify_level = hashtable_get (line->data->buffer->hotlist_max_level_nicks,
|
|
nick);
|
|
}
|
|
if (max_notify_level && (*max_notify_level < notify_level))
|
|
notify_level = *max_notify_level;
|
|
|
|
return notify_level;
|
|
}
|
|
|
|
/*
|
|
* Gets highlight flag for a line, using the notify level in the line.
|
|
*
|
|
* Returns 1 for highlight otherwise 0.
|
|
*/
|
|
|
|
int
|
|
gui_line_get_highlight (struct t_gui_line *line)
|
|
{
|
|
int highlight, *max_notify_level;
|
|
const char *nick;
|
|
|
|
if (line->data->notify_level == GUI_HOTLIST_HIGHLIGHT)
|
|
{
|
|
highlight = 1;
|
|
}
|
|
else
|
|
{
|
|
max_notify_level = NULL;
|
|
nick = gui_line_get_nick_tag (line);
|
|
if (nick)
|
|
{
|
|
max_notify_level = hashtable_get (line->data->buffer->hotlist_max_level_nicks,
|
|
nick);
|
|
}
|
|
if (max_notify_level && (*max_notify_level < GUI_HOTLIST_HIGHLIGHT))
|
|
highlight = 0;
|
|
else
|
|
highlight = gui_line_has_highlight (line);
|
|
}
|
|
|
|
return highlight;
|
|
}
|
|
|
|
/*
|
|
* Creates a new line for a buffer.
|
|
*/
|
|
|
|
struct t_gui_line *
|
|
gui_line_new (struct t_gui_buffer *buffer, int y, time_t date,
|
|
time_t date_printed, const char *tags,
|
|
const char *prefix, const char *message)
|
|
{
|
|
struct t_gui_line *new_line;
|
|
struct t_gui_line_data *new_line_data;
|
|
|
|
/* create new line */
|
|
new_line = malloc (sizeof (*new_line));
|
|
if (!new_line)
|
|
return NULL;
|
|
|
|
/* create data for line */
|
|
new_line_data = malloc (sizeof (*new_line_data));
|
|
if (!new_line_data)
|
|
{
|
|
free (new_line);
|
|
return NULL;
|
|
}
|
|
new_line->data = new_line_data;
|
|
|
|
/* fill data in new line */
|
|
new_line->data->buffer = buffer;
|
|
new_line->data->message = (message) ? strdup (message) : strdup ("");
|
|
|
|
if (buffer->type == GUI_BUFFER_TYPE_FORMATTED)
|
|
{
|
|
new_line->data->y = -1;
|
|
new_line->data->date = date;
|
|
new_line->data->date_printed = date_printed;
|
|
new_line->data->str_time = gui_chat_get_time_string (date);
|
|
gui_line_tags_alloc (new_line->data, tags);
|
|
new_line->data->refresh_needed = 0;
|
|
new_line->data->prefix = (prefix) ?
|
|
(char *)string_shared_get (prefix) : ((date != 0) ? (char *)string_shared_get ("") : NULL);
|
|
new_line->data->prefix_length = (prefix) ?
|
|
gui_chat_strlen_screen (prefix) : 0;
|
|
new_line->data->notify_level = gui_line_get_notify_level (new_line);
|
|
new_line->data->highlight = gui_line_get_highlight (new_line);
|
|
}
|
|
else
|
|
{
|
|
new_line->data->y = y;
|
|
new_line->data->date = 0;
|
|
new_line->data->date_printed = 0;
|
|
new_line->data->str_time = NULL;
|
|
new_line->data->tags_count = 0;
|
|
new_line->data->tags_array = NULL;
|
|
new_line->data->refresh_needed = 1;
|
|
new_line->data->prefix = NULL;
|
|
new_line->data->prefix_length = 0;
|
|
new_line->data->notify_level = 0;
|
|
new_line->data->highlight = 0;
|
|
}
|
|
|
|
/* set display flag (check if line is filtered or not) */
|
|
new_line->data->displayed = gui_filter_check_line (new_line->data);
|
|
|
|
new_line->prev_line = NULL;
|
|
new_line->next_line = NULL;
|
|
|
|
return new_line;
|
|
}
|
|
|
|
/*
|
|
* Updates data in a line via the hook_line.
|
|
*/
|
|
|
|
void
|
|
gui_line_hook_update (struct t_gui_line *line,
|
|
struct t_hashtable *hashtable,
|
|
struct t_hashtable *hashtable2)
|
|
{
|
|
const char *ptr_value, *ptr_value2;
|
|
struct t_gui_buffer *ptr_buffer;
|
|
unsigned long value_pointer;
|
|
long value;
|
|
char *error;
|
|
int rc, tags_updated, notify_level_updated, highlight_updated;
|
|
|
|
tags_updated = 0;
|
|
notify_level_updated = 0;
|
|
highlight_updated = 0;
|
|
|
|
ptr_value2 = hashtable_get (hashtable2, "buffer_name");
|
|
if (ptr_value2)
|
|
{
|
|
if (ptr_value2[0])
|
|
{
|
|
ptr_buffer = gui_buffer_search_by_full_name (ptr_value2);
|
|
if (gui_chat_buffer_valid (ptr_buffer, line->data->buffer->type))
|
|
line->data->buffer = ptr_buffer;
|
|
}
|
|
else
|
|
{
|
|
line->data->buffer = NULL;
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ptr_value2 = hashtable_get (hashtable2, "buffer");
|
|
if (ptr_value2)
|
|
{
|
|
if (ptr_value2[0])
|
|
{
|
|
if ((ptr_value2[0] == '0') && (ptr_value2[1] == 'x'))
|
|
{
|
|
rc = sscanf (ptr_value2 + 2, "%lx", &value_pointer);
|
|
ptr_buffer = (struct t_gui_buffer *)value_pointer;
|
|
if ((rc != EOF) && (rc >= 1)
|
|
&& gui_chat_buffer_valid (ptr_buffer, line->data->buffer->type))
|
|
{
|
|
line->data->buffer = ptr_buffer;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
line->data->buffer = NULL;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (line->data->buffer->type == GUI_BUFFER_TYPE_FREE)
|
|
{
|
|
/* the field "y" can be changed on buffer with free content */
|
|
ptr_value = hashtable_get (hashtable2, "y");
|
|
if (ptr_value)
|
|
{
|
|
error = NULL;
|
|
value = strtol (ptr_value, &error, 10);
|
|
if (error && !error[0] && (value >= 0))
|
|
line->data->y = value;
|
|
}
|
|
}
|
|
|
|
ptr_value2 = hashtable_get (hashtable2, "date");
|
|
if (ptr_value2)
|
|
{
|
|
error = NULL;
|
|
value = strtol (ptr_value2, &error, 10);
|
|
if (error && !error[0] && (value >= 0))
|
|
{
|
|
line->data->date = (time_t)value;
|
|
if (line->data->str_time)
|
|
free (line->data->str_time);
|
|
line->data->str_time = gui_chat_get_time_string (line->data->date);
|
|
}
|
|
}
|
|
|
|
ptr_value2 = hashtable_get (hashtable2, "date_printed");
|
|
if (ptr_value2)
|
|
{
|
|
error = NULL;
|
|
value = strtol (ptr_value2, &error, 10);
|
|
if (error && !error[0] && (value >= 0))
|
|
line->data->date_printed = (time_t)value;
|
|
}
|
|
|
|
ptr_value = hashtable_get (hashtable, "str_time");
|
|
ptr_value2 = hashtable_get (hashtable2, "str_time");
|
|
if (ptr_value2 && (!ptr_value || (strcmp (ptr_value, ptr_value2) != 0)))
|
|
{
|
|
if (line->data->str_time)
|
|
free (line->data->str_time);
|
|
line->data->str_time = (ptr_value2) ? strdup (ptr_value2) : NULL;
|
|
}
|
|
|
|
ptr_value = hashtable_get (hashtable, "tags");
|
|
ptr_value2 = hashtable_get (hashtable2, "tags");
|
|
if (ptr_value2 && (!ptr_value || (strcmp (ptr_value, ptr_value2) != 0)))
|
|
{
|
|
tags_updated = 1;
|
|
gui_line_tags_free (line->data);
|
|
gui_line_tags_alloc (line->data, ptr_value2);
|
|
}
|
|
|
|
ptr_value2 = hashtable_get (hashtable2, "notify_level");
|
|
if (ptr_value2)
|
|
{
|
|
error = NULL;
|
|
value = strtol (ptr_value2, &error, 10);
|
|
if (error && !error[0] && (value >= -1) && (value <= GUI_HOTLIST_MAX))
|
|
{
|
|
notify_level_updated = 1;
|
|
line->data->notify_level = value;
|
|
}
|
|
}
|
|
|
|
ptr_value2 = hashtable_get (hashtable2, "highlight");
|
|
if (ptr_value2)
|
|
{
|
|
error = NULL;
|
|
value = strtol (ptr_value2, &error, 10);
|
|
if (error && !error[0])
|
|
{
|
|
highlight_updated = 1;
|
|
line->data->highlight = (value) ? 1 : 0;
|
|
}
|
|
}
|
|
|
|
ptr_value = hashtable_get (hashtable, "prefix");
|
|
ptr_value2 = hashtable_get (hashtable2, "prefix");
|
|
if (ptr_value2 && (!ptr_value || (strcmp (ptr_value, ptr_value2) != 0)))
|
|
{
|
|
if (line->data->prefix)
|
|
string_shared_free (line->data->prefix);
|
|
line->data->prefix = (char *)string_shared_get (
|
|
(ptr_value2) ? ptr_value2 : "");
|
|
line->data->prefix_length = (line->data->prefix) ?
|
|
gui_chat_strlen_screen (line->data->prefix) : 0;
|
|
}
|
|
|
|
ptr_value = hashtable_get (hashtable, "message");
|
|
ptr_value2 = hashtable_get (hashtable2, "message");
|
|
if (ptr_value2 && (!ptr_value || (strcmp (ptr_value, ptr_value2) != 0)))
|
|
{
|
|
if (line->data->message)
|
|
free (line->data->message);
|
|
line->data->message = (ptr_value2) ? strdup (ptr_value2) : NULL;
|
|
}
|
|
|
|
/* if tags were updated but not notify_level, adjust notify level */
|
|
if (tags_updated && !notify_level_updated)
|
|
line->data->notify_level = gui_line_get_notify_level (line);
|
|
|
|
/* adjust flag "displayed" if tags were updated */
|
|
if (tags_updated)
|
|
line->data->displayed = gui_filter_check_line (line->data);
|
|
|
|
if ((tags_updated || notify_level_updated) && !highlight_updated)
|
|
line->data->highlight = gui_line_get_highlight (line);
|
|
}
|
|
|
|
/*
|
|
* Adds a new line in a buffer with formatted content.
|
|
*/
|
|
|
|
void
|
|
gui_line_add (struct t_gui_line *line)
|
|
{
|
|
struct t_gui_window *ptr_win;
|
|
char *message_for_signal;
|
|
int lines_removed;
|
|
time_t current_time;
|
|
|
|
/*
|
|
* remove line(s) if necessary, according to history options:
|
|
* max_lines: if > 0, keep only N lines in buffer
|
|
* max_minutes: if > 0, keep only lines from last N minutes
|
|
*/
|
|
lines_removed = 0;
|
|
current_time = time (NULL);
|
|
while (line->data->buffer->own_lines->first_line
|
|
&& (((CONFIG_INTEGER(config_history_max_buffer_lines_number) > 0)
|
|
&& (line->data->buffer->own_lines->lines_count + 1 >
|
|
CONFIG_INTEGER(config_history_max_buffer_lines_number)))
|
|
|| ((CONFIG_INTEGER(config_history_max_buffer_lines_minutes) > 0)
|
|
&& (current_time - line->data->buffer->own_lines->first_line->data->date_printed >
|
|
CONFIG_INTEGER(config_history_max_buffer_lines_minutes) * 60))))
|
|
{
|
|
gui_line_free (line->data->buffer,
|
|
line->data->buffer->own_lines->first_line);
|
|
lines_removed++;
|
|
}
|
|
|
|
/* add line to lines list */
|
|
gui_line_add_to_list (line->data->buffer->own_lines, line);
|
|
|
|
/* update hotlist and/or send signals for line */
|
|
if (line->data->displayed)
|
|
{
|
|
if (line->data->highlight)
|
|
{
|
|
(void) gui_hotlist_add (line->data->buffer,
|
|
GUI_HOTLIST_HIGHLIGHT, NULL);
|
|
if (!weechat_upgrading)
|
|
{
|
|
message_for_signal = gui_chat_build_string_prefix_message (line);
|
|
if (message_for_signal)
|
|
{
|
|
(void) hook_signal_send ("weechat_highlight",
|
|
WEECHAT_HOOK_SIGNAL_STRING,
|
|
message_for_signal);
|
|
free (message_for_signal);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!weechat_upgrading
|
|
&& (line->data->notify_level == GUI_HOTLIST_PRIVATE))
|
|
{
|
|
message_for_signal = gui_chat_build_string_prefix_message (line);
|
|
if (message_for_signal)
|
|
{
|
|
(void) hook_signal_send ("weechat_pv",
|
|
WEECHAT_HOOK_SIGNAL_STRING,
|
|
message_for_signal);
|
|
free (message_for_signal);
|
|
}
|
|
}
|
|
if (line->data->notify_level >= GUI_HOTLIST_MIN)
|
|
{
|
|
(void) gui_hotlist_add (line->data->buffer,
|
|
line->data->notify_level, NULL);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
(void) hook_signal_send ("buffer_lines_hidden",
|
|
WEECHAT_HOOK_SIGNAL_POINTER,
|
|
line->data->buffer);
|
|
}
|
|
|
|
/* add mixed line, if buffer is attached to at least one other buffer */
|
|
if (line->data->buffer->mixed_lines)
|
|
{
|
|
gui_line_mixed_add (line->data->buffer->mixed_lines, line->data);
|
|
}
|
|
|
|
/*
|
|
* if some lines were removed, force a full refresh if at least one window
|
|
* is displaying buffer and that number of lines in buffer is lower than
|
|
* window height
|
|
*/
|
|
if (lines_removed > 0)
|
|
{
|
|
for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window)
|
|
{
|
|
if ((ptr_win->buffer == line->data->buffer)
|
|
&& (line->data->buffer->own_lines->lines_count < ptr_win->win_chat_height))
|
|
{
|
|
gui_buffer_ask_chat_refresh (line->data->buffer, 2);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
(void) hook_signal_send ("buffer_line_added",
|
|
WEECHAT_HOOK_SIGNAL_POINTER, line);
|
|
}
|
|
|
|
/*
|
|
* Adds or updates a line in a buffer with free content.
|
|
*
|
|
* Ba careful: when replacing an existing line in the buffer, the "line"
|
|
* pointer received as parameter is freed and then becomes invalid.
|
|
* So this pointer must not be used after the call to this function.
|
|
*/
|
|
|
|
void
|
|
gui_line_add_y (struct t_gui_line *line)
|
|
{
|
|
struct t_gui_line *ptr_line;
|
|
struct t_gui_window *ptr_win;
|
|
int old_line_displayed;
|
|
|
|
/* search if line exists for "y" */
|
|
for (ptr_line = line->data->buffer->own_lines->first_line; ptr_line;
|
|
ptr_line = ptr_line->next_line)
|
|
{
|
|
if (ptr_line->data->y >= line->data->y)
|
|
break;
|
|
}
|
|
|
|
if (ptr_line && (ptr_line->data->y == line->data->y))
|
|
{
|
|
/* replace line data with the new data */
|
|
old_line_displayed = ptr_line->data->displayed;
|
|
if (ptr_line->data->message)
|
|
{
|
|
/* remove line from coords if the content is changing */
|
|
for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window)
|
|
{
|
|
gui_window_coords_remove_line (ptr_win, ptr_line);
|
|
}
|
|
}
|
|
|
|
/* replace ptr_line by line in list */
|
|
gui_line_free_data (ptr_line);
|
|
ptr_line->data = line->data;
|
|
free (line);
|
|
}
|
|
else
|
|
{
|
|
/* add line to lines list */
|
|
old_line_displayed = 1;
|
|
if (ptr_line)
|
|
{
|
|
/* add before line found */
|
|
line->prev_line = ptr_line->prev_line;
|
|
line->next_line = ptr_line;
|
|
if (ptr_line->prev_line)
|
|
(ptr_line->prev_line)->next_line = line;
|
|
else
|
|
line->data->buffer->own_lines->first_line = line;
|
|
ptr_line->prev_line = line;
|
|
}
|
|
else
|
|
{
|
|
/* add at end of list */
|
|
line->prev_line = line->data->buffer->own_lines->last_line;
|
|
if (line->data->buffer->own_lines->first_line)
|
|
line->data->buffer->own_lines->last_line->next_line = line;
|
|
else
|
|
line->data->buffer->own_lines->first_line = line;
|
|
line->data->buffer->own_lines->last_line = line;
|
|
line->next_line = NULL;
|
|
}
|
|
ptr_line = line;
|
|
|
|
line->data->buffer->own_lines->lines_count++;
|
|
}
|
|
|
|
/* check if line is filtered or not */
|
|
if (old_line_displayed && !ptr_line->data->displayed)
|
|
{
|
|
(ptr_line->data->buffer->own_lines->lines_hidden)++;
|
|
(void) hook_signal_send ("buffer_lines_hidden",
|
|
WEECHAT_HOOK_SIGNAL_POINTER,
|
|
ptr_line->data->buffer);
|
|
}
|
|
else if (!old_line_displayed && ptr_line->data->displayed)
|
|
{
|
|
if (ptr_line->data->buffer->own_lines->lines_hidden > 0)
|
|
(ptr_line->data->buffer->own_lines->lines_hidden)--;
|
|
}
|
|
|
|
ptr_line->data->refresh_needed = 1;
|
|
|
|
gui_buffer_ask_chat_refresh (ptr_line->data->buffer, 1);
|
|
}
|
|
|
|
/*
|
|
* Clears prefix and message on a line (used on buffers with free content only).
|
|
*/
|
|
|
|
void
|
|
gui_line_clear (struct t_gui_line *line)
|
|
{
|
|
if (line->data->prefix)
|
|
string_shared_free (line->data->prefix);
|
|
line->data->prefix = (char *)string_shared_get ("");
|
|
|
|
if (line->data->message)
|
|
free (line->data->message);
|
|
line->data->message = strdup ("");
|
|
}
|
|
|
|
/*
|
|
* Mixes lines of a buffer (or group of buffers) with a new buffer.
|
|
*/
|
|
|
|
void
|
|
gui_line_mix_buffers (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_buffer *ptr_buffer, *ptr_buffer_found;
|
|
struct t_gui_lines *new_lines;
|
|
struct t_gui_line *ptr_line1, *ptr_line2;
|
|
|
|
/* search first other buffer with same number */
|
|
ptr_buffer_found = NULL;
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
if ((ptr_buffer != buffer) && (ptr_buffer->number == buffer->number))
|
|
{
|
|
ptr_buffer_found = ptr_buffer;
|
|
break;
|
|
}
|
|
}
|
|
if (!ptr_buffer_found)
|
|
return;
|
|
|
|
/* mix all lines (sorting by date) to a new structure "new_lines" */
|
|
new_lines = gui_lines_alloc ();
|
|
if (!new_lines)
|
|
return;
|
|
ptr_line1 = ptr_buffer_found->lines->first_line;
|
|
ptr_line2 = buffer->lines->first_line;
|
|
while (ptr_line1 || ptr_line2)
|
|
{
|
|
if (!ptr_line1)
|
|
{
|
|
gui_line_mixed_add (new_lines, ptr_line2->data);
|
|
ptr_line2 = ptr_line2->next_line;
|
|
}
|
|
else
|
|
{
|
|
if (!ptr_line2)
|
|
{
|
|
gui_line_mixed_add (new_lines, ptr_line1->data);
|
|
ptr_line1 = ptr_line1->next_line;
|
|
}
|
|
else
|
|
{
|
|
/* look for older line by comparing time */
|
|
if (ptr_line1->data->date <= ptr_line2->data->date)
|
|
{
|
|
while (ptr_line1
|
|
&& (ptr_line1->data->date <= ptr_line2->data->date))
|
|
{
|
|
gui_line_mixed_add (new_lines, ptr_line1->data);
|
|
ptr_line1 = ptr_line1->next_line;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (ptr_line2
|
|
&& (ptr_line1->data->date > ptr_line2->data->date))
|
|
{
|
|
gui_line_mixed_add (new_lines, ptr_line2->data);
|
|
ptr_line2 = ptr_line2->next_line;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ask refresh of prefix/buffer max length for mixed lines */
|
|
new_lines->prefix_max_length_refresh = 1;
|
|
new_lines->buffer_max_length_refresh = 1;
|
|
|
|
/* free old mixed lines */
|
|
if (ptr_buffer_found->mixed_lines)
|
|
{
|
|
gui_line_mixed_free_all (ptr_buffer_found);
|
|
free (ptr_buffer_found->mixed_lines);
|
|
}
|
|
|
|
/* use new structure with mixed lines in all buffers with correct number */
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
if (ptr_buffer->number == buffer->number)
|
|
{
|
|
ptr_buffer->mixed_lines = new_lines;
|
|
ptr_buffer->lines = ptr_buffer->mixed_lines;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Returns hdata for lines.
|
|
*/
|
|
|
|
struct t_hdata *
|
|
gui_line_hdata_lines_cb (const void *pointer, void *data,
|
|
const char *hdata_name)
|
|
{
|
|
struct t_hdata *hdata;
|
|
|
|
/* make C compiler happy */
|
|
(void) pointer;
|
|
(void) data;
|
|
|
|
hdata = hdata_new (NULL, hdata_name, NULL, NULL, 0, 0, NULL, NULL);
|
|
if (hdata)
|
|
{
|
|
HDATA_VAR(struct t_gui_lines, first_line, POINTER, 0, NULL, "line");
|
|
HDATA_VAR(struct t_gui_lines, last_line, POINTER, 0, NULL, "line");
|
|
HDATA_VAR(struct t_gui_lines, last_read_line, POINTER, 0, NULL, "line");
|
|
HDATA_VAR(struct t_gui_lines, lines_count, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_lines, first_line_not_read, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_lines, lines_hidden, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_lines, buffer_max_length, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_lines, buffer_max_length_refresh, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_lines, prefix_max_length, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_lines, prefix_max_length_refresh, INTEGER, 0, NULL, NULL);
|
|
}
|
|
return hdata;
|
|
}
|
|
|
|
/*
|
|
* Returns hdata for line.
|
|
*/
|
|
|
|
struct t_hdata *
|
|
gui_line_hdata_line_cb (const void *pointer, void *data,
|
|
const char *hdata_name)
|
|
{
|
|
struct t_hdata *hdata;
|
|
|
|
/* make C compiler happy */
|
|
(void) pointer;
|
|
(void) data;
|
|
|
|
hdata = hdata_new (NULL, hdata_name, "prev_line", "next_line",
|
|
0, 0, NULL, NULL);
|
|
if (hdata)
|
|
{
|
|
HDATA_VAR(struct t_gui_line, data, POINTER, 0, NULL, "line_data");
|
|
HDATA_VAR(struct t_gui_line, prev_line, POINTER, 0, NULL, hdata_name);
|
|
HDATA_VAR(struct t_gui_line, next_line, POINTER, 0, NULL, hdata_name);
|
|
}
|
|
return hdata;
|
|
}
|
|
|
|
/*
|
|
* Callback for updating data of a line.
|
|
*/
|
|
|
|
int
|
|
gui_line_hdata_line_data_update_cb (void *data,
|
|
struct t_hdata *hdata,
|
|
void *pointer,
|
|
struct t_hashtable *hashtable)
|
|
{
|
|
const char *value;
|
|
struct t_gui_line_data *line_data;
|
|
struct t_gui_window *ptr_win;
|
|
int rc, update_coords;
|
|
|
|
/* make C compiler happy */
|
|
(void) data;
|
|
|
|
line_data = (struct t_gui_line_data *)pointer;
|
|
|
|
rc = 0;
|
|
update_coords = 0;
|
|
|
|
if (hashtable_has_key (hashtable, "date"))
|
|
{
|
|
value = hashtable_get (hashtable, "date");
|
|
if (value)
|
|
{
|
|
hdata_set (hdata, pointer, "date", value);
|
|
if (line_data->str_time)
|
|
free (line_data->str_time);
|
|
line_data->str_time = gui_chat_get_time_string (line_data->date);
|
|
rc++;
|
|
update_coords = 1;
|
|
}
|
|
}
|
|
|
|
if (hashtable_has_key (hashtable, "date_printed"))
|
|
{
|
|
value = hashtable_get (hashtable, "date_printed");
|
|
if (value)
|
|
{
|
|
hdata_set (hdata, pointer, "date_printed", value);
|
|
rc++;
|
|
}
|
|
}
|
|
|
|
if (hashtable_has_key (hashtable, "tags_array"))
|
|
{
|
|
value = hashtable_get (hashtable, "tags_array");
|
|
gui_line_tags_free (line_data);
|
|
gui_line_tags_alloc (line_data, value);
|
|
rc++;
|
|
}
|
|
|
|
if (hashtable_has_key (hashtable, "prefix"))
|
|
{
|
|
value = hashtable_get (hashtable, "prefix");
|
|
hdata_set (hdata, pointer, "prefix", value);
|
|
line_data->prefix_length = (line_data->prefix) ?
|
|
gui_chat_strlen_screen (line_data->prefix) : 0;
|
|
line_data->buffer->lines->prefix_max_length_refresh = 1;
|
|
rc++;
|
|
update_coords = 1;
|
|
}
|
|
|
|
if (hashtable_has_key (hashtable, "message"))
|
|
{
|
|
value = hashtable_get (hashtable, "message");
|
|
hdata_set (hdata, pointer, "message", value);
|
|
rc++;
|
|
update_coords = 1;
|
|
}
|
|
|
|
if (rc > 0)
|
|
{
|
|
if (update_coords)
|
|
{
|
|
for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window)
|
|
{
|
|
gui_window_coords_remove_line_data (ptr_win, line_data);
|
|
}
|
|
}
|
|
gui_filter_buffer (line_data->buffer, line_data);
|
|
gui_buffer_ask_chat_refresh (line_data->buffer, 1);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* Returns hdata for line data.
|
|
*/
|
|
|
|
struct t_hdata *
|
|
gui_line_hdata_line_data_cb (const void *pointer, void *data,
|
|
const char *hdata_name)
|
|
{
|
|
struct t_hdata *hdata;
|
|
|
|
/* make C compiler happy */
|
|
(void) pointer;
|
|
(void) data;
|
|
|
|
hdata = hdata_new (NULL, hdata_name, NULL, NULL,
|
|
0, 0, &gui_line_hdata_line_data_update_cb, NULL);
|
|
if (hdata)
|
|
{
|
|
HDATA_VAR(struct t_gui_line_data, buffer, POINTER, 0, NULL, "buffer");
|
|
HDATA_VAR(struct t_gui_line_data, y, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_line_data, date, TIME, 1, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_line_data, date_printed, TIME, 1, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_line_data, str_time, STRING, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_line_data, tags_count, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_line_data, tags_array, SHARED_STRING, 1, "tags_count", NULL);
|
|
HDATA_VAR(struct t_gui_line_data, displayed, CHAR, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_line_data, notify_level, CHAR, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_line_data, highlight, CHAR, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_line_data, refresh_needed, CHAR, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_line_data, prefix, SHARED_STRING, 1, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_line_data, prefix_length, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_line_data, message, STRING, 1, NULL, NULL);
|
|
}
|
|
return hdata;
|
|
}
|
|
|
|
/*
|
|
* Adds a line in an infolist.
|
|
*
|
|
* Returns:
|
|
* 1: OK
|
|
* 0: error
|
|
*/
|
|
|
|
int
|
|
gui_line_add_to_infolist (struct t_infolist *infolist,
|
|
struct t_gui_lines *lines,
|
|
struct t_gui_line *line)
|
|
{
|
|
struct t_infolist_item *ptr_item;
|
|
int i, length;
|
|
char option_name[64], *tags;
|
|
|
|
if (!infolist || !line)
|
|
return 0;
|
|
|
|
ptr_item = infolist_new_item (infolist);
|
|
if (!ptr_item)
|
|
return 0;
|
|
|
|
if (!infolist_new_var_integer (ptr_item, "y", line->data->y))
|
|
return 0;
|
|
if (!infolist_new_var_time (ptr_item, "date", line->data->date))
|
|
return 0;
|
|
if (!infolist_new_var_time (ptr_item, "date_printed", line->data->date_printed))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "str_time", line->data->str_time))
|
|
return 0;
|
|
|
|
/* write tags */
|
|
if (!infolist_new_var_integer (ptr_item, "tags_count", line->data->tags_count))
|
|
return 0;
|
|
length = 0;
|
|
for (i = 0; i < line->data->tags_count; i++)
|
|
{
|
|
snprintf (option_name, sizeof (option_name), "tag_%05d", i + 1);
|
|
if (!infolist_new_var_string (ptr_item, option_name,
|
|
line->data->tags_array[i]))
|
|
return 0;
|
|
length += strlen (line->data->tags_array[i]) + 1;
|
|
}
|
|
tags = malloc (length + 1);
|
|
if (!tags)
|
|
return 0;
|
|
tags[0] = '\0';
|
|
for (i = 0; i < line->data->tags_count; i++)
|
|
{
|
|
strcat (tags, line->data->tags_array[i]);
|
|
if (i < line->data->tags_count - 1)
|
|
strcat (tags, ",");
|
|
}
|
|
if (!infolist_new_var_string (ptr_item, "tags", tags))
|
|
{
|
|
free (tags);
|
|
return 0;
|
|
}
|
|
free (tags);
|
|
|
|
if (!infolist_new_var_integer (ptr_item, "displayed", line->data->displayed))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "notify_level", line->data->notify_level))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "highlight", line->data->highlight))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "prefix", line->data->prefix))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "message", line->data->message))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "last_read_line",
|
|
(lines->last_read_line == line) ? 1 : 0))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Prints lines structure infos in WeeChat log file (usually for crash dump).
|
|
*/
|
|
|
|
void
|
|
gui_lines_print_log (struct t_gui_lines *lines)
|
|
{
|
|
if (lines)
|
|
{
|
|
log_printf (" first_line . . . . . . . : 0x%lx", lines->first_line);
|
|
log_printf (" last_line. . . . . . . . : 0x%lx", lines->last_line);
|
|
log_printf (" last_read_line . . . . . : 0x%lx", lines->last_read_line);
|
|
log_printf (" lines_count. . . . . . . : %d", lines->lines_count);
|
|
log_printf (" first_line_not_read. . . : %d", lines->first_line_not_read);
|
|
log_printf (" lines_hidden . . . . . . : %d", lines->lines_hidden);
|
|
log_printf (" buffer_max_length. . . . : %d", lines->buffer_max_length);
|
|
log_printf (" buffer_max_length_refresh: %d", lines->buffer_max_length_refresh);
|
|
log_printf (" prefix_max_length. . . . : %d", lines->prefix_max_length);
|
|
log_printf (" prefix_max_length_refresh: %d", lines->prefix_max_length_refresh);
|
|
}
|
|
}
|