mirror of
https://github.com/weechat/weechat.git
synced 2026-06-27 13:26:38 +02:00
cf6aca1619
This pointer is the first argument received by callbacks, and the existing argument "data" is now automatically freed by WeeChat when the object containing the callback is removed. With this new pointer, the linked list of callbacks in scripts has been removed. This will improve speed of scripts (using a lot of hooks), reduce memory used by scripts and reduce time to unload scripts. Following functions are affected in the C API: * exec_on_files * config_new * config_new_section * config_new_option * hook_command * hook_command_run * hook_timer * hook_fd * hook_process * hook_process_hashtable * hook_connect * hook_print * hook_signal * hook_hsignal * hook_config * hook_completion * hook_modifier * hook_info * hook_info_hashtable * hook_infolist * hook_hdata * hook_focus * unhook_all_plugin * buffer_new * bar_item_new * upgrade_new * upgrade_read
1220 lines
37 KiB
C
1220 lines
37 KiB
C
/*
|
|
* irc-notify.c - notify lists for IRC plugin
|
|
*
|
|
* Copyright (C) 2010-2016 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 <stddef.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "../weechat-plugin.h"
|
|
#include "irc.h"
|
|
#include "irc-notify.h"
|
|
#include "irc-color.h"
|
|
#include "irc-config.h"
|
|
#include "irc-message.h"
|
|
#include "irc-nick.h"
|
|
#include "irc-redirect.h"
|
|
#include "irc-server.h"
|
|
|
|
|
|
/* timers to run "ison" and "whois" commands */
|
|
struct t_hook *irc_notify_timer_ison = NULL; /* timer for "ison" */
|
|
struct t_hook *irc_notify_timer_whois = NULL; /* timer for "whois" */
|
|
|
|
/* hsignal for redirected commands */
|
|
struct t_hook *irc_notify_hsignal = NULL;
|
|
|
|
|
|
/*
|
|
* Checks if a notify pointer is valid.
|
|
*
|
|
* If server is NULL, searches in all servers.
|
|
*
|
|
* Returns:
|
|
* 1: notify exists
|
|
* 0: notify does not exist
|
|
*/
|
|
|
|
int
|
|
irc_notify_valid (struct t_irc_server *server, struct t_irc_notify *notify)
|
|
{
|
|
struct t_irc_server *ptr_server;
|
|
struct t_irc_notify *ptr_notify;
|
|
|
|
if (!notify)
|
|
return 0;
|
|
|
|
if (server)
|
|
{
|
|
for (ptr_notify = server->notify_list; ptr_notify;
|
|
ptr_notify = ptr_notify->next_notify)
|
|
{
|
|
if (ptr_notify == notify)
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (ptr_server = irc_servers; ptr_server;
|
|
ptr_server = ptr_server->next_server)
|
|
{
|
|
for (ptr_notify = ptr_server->notify_list; ptr_notify;
|
|
ptr_notify = ptr_notify->next_notify)
|
|
{
|
|
if (ptr_notify == notify)
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* notify not found */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Searches for a notify.
|
|
*
|
|
* Returns pointer to notify found, NULL if not found.
|
|
*/
|
|
|
|
struct t_irc_notify *
|
|
irc_notify_search (struct t_irc_server *server, const char *nick)
|
|
{
|
|
struct t_irc_notify *ptr_notify;
|
|
|
|
if (!server || !nick)
|
|
return NULL;
|
|
|
|
for (ptr_notify = server->notify_list; ptr_notify;
|
|
ptr_notify = ptr_notify->next_notify)
|
|
{
|
|
if (irc_server_strcasecmp (server, ptr_notify->nick, nick) == 0)
|
|
return ptr_notify;
|
|
}
|
|
|
|
/* notify not found */
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Sets server option "notify" with notify list on server.
|
|
*/
|
|
|
|
void
|
|
irc_notify_set_server_option (struct t_irc_server *server)
|
|
{
|
|
char *str, *str2;
|
|
struct t_irc_notify *ptr_notify;
|
|
int total_length, length;
|
|
|
|
if (!server)
|
|
return;
|
|
|
|
if (server->notify_list)
|
|
{
|
|
str = NULL;
|
|
total_length = 0;
|
|
for (ptr_notify = server->notify_list; ptr_notify;
|
|
ptr_notify = ptr_notify->next_notify)
|
|
{
|
|
length = strlen (ptr_notify->nick) + 32;
|
|
if (!str)
|
|
{
|
|
total_length += length + 1;
|
|
str = malloc (total_length);
|
|
if (str)
|
|
str[0] = '\0';
|
|
}
|
|
else
|
|
{
|
|
total_length += length;
|
|
str2 = realloc (str, total_length);
|
|
if (!str2)
|
|
{
|
|
if (str)
|
|
free (str);
|
|
return;
|
|
}
|
|
str = str2;
|
|
}
|
|
if (str)
|
|
{
|
|
if (str[0])
|
|
strcat (str, ",");
|
|
strcat (str, ptr_notify->nick);
|
|
if (ptr_notify->check_away)
|
|
strcat (str, " away");
|
|
}
|
|
}
|
|
if (str)
|
|
{
|
|
weechat_config_option_set (server->options[IRC_SERVER_OPTION_NOTIFY],
|
|
str, 0);
|
|
free (str);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
weechat_config_option_set (server->options[IRC_SERVER_OPTION_NOTIFY],
|
|
"", 0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Adds a new notify.
|
|
*
|
|
* Returns pointer to new notify, NULL if error.
|
|
*/
|
|
|
|
struct t_irc_notify *
|
|
irc_notify_new (struct t_irc_server *server, const char *nick, int check_away)
|
|
{
|
|
struct t_irc_notify *new_notify;
|
|
|
|
if (!server || !nick || !nick[0]
|
|
|| ((server->monitor > 0)
|
|
&& ((server->notify_count >= server->monitor))))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
new_notify = malloc (sizeof (*new_notify));
|
|
if (new_notify)
|
|
{
|
|
new_notify->server = server;
|
|
new_notify->nick = strdup (nick);
|
|
new_notify->check_away = check_away;
|
|
new_notify->is_on_server = -1;
|
|
new_notify->away_message = NULL;
|
|
new_notify->ison_received = 0;
|
|
|
|
/* add notify to notify list on server */
|
|
new_notify->prev_notify = server->last_notify;
|
|
if (server->notify_list)
|
|
server->last_notify->next_notify = new_notify;
|
|
else
|
|
server->notify_list = new_notify;
|
|
server->last_notify = new_notify;
|
|
new_notify->next_notify = NULL;
|
|
|
|
server->notify_count++;
|
|
}
|
|
|
|
return new_notify;
|
|
}
|
|
|
|
/*
|
|
* Checks now if a nick is connected with ison/monitor + whois (if away checking
|
|
* is enabled).
|
|
*
|
|
* It is called when a notify is added.
|
|
*/
|
|
|
|
void
|
|
irc_notify_check_now (struct t_irc_notify *notify)
|
|
{
|
|
/* don't send anything if we are not connected to the server */
|
|
if (!notify->server->is_connected)
|
|
return;
|
|
|
|
if (notify->server->monitor > 0)
|
|
{
|
|
/* send MONITOR for nick */
|
|
irc_server_sendf (notify->server, IRC_SERVER_SEND_OUTQ_PRIO_LOW, NULL,
|
|
"MONITOR + %s", notify->nick);
|
|
}
|
|
else
|
|
{
|
|
/* send ISON for nick (MONITOR not supported on server) */
|
|
irc_redirect_new (notify->server, "ison", "notify", 1, NULL, 0, NULL);
|
|
irc_server_sendf (notify->server, IRC_SERVER_SEND_OUTQ_PRIO_LOW, NULL,
|
|
"ISON :%s", notify->nick);
|
|
}
|
|
|
|
if (notify->check_away)
|
|
{
|
|
/* send WHOIS for nick */
|
|
irc_redirect_new (notify->server, "whois", "notify", 1, notify->nick, 0,
|
|
"301,401");
|
|
irc_server_sendf (notify->server, IRC_SERVER_SEND_OUTQ_PRIO_LOW, NULL,
|
|
"WHOIS :%s", notify->nick);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Builds a message with nicks (ISON or MONITOR).
|
|
*
|
|
* Argument "message" must be "ISON :" or "MONITOR + " or "MONITOR - ".
|
|
* Argument "separator" must be " " for ISON and "," for MONITOR.
|
|
* Argument "num_nicks" is set with the number of nicks added in message.
|
|
*
|
|
* Note: result must be freed after use.
|
|
*/
|
|
|
|
char *
|
|
irc_notify_build_message_with_nicks (struct t_irc_server *server,
|
|
const char *irc_message,
|
|
const char *separator,
|
|
int *num_nicks)
|
|
{
|
|
char *message, *message2;
|
|
int length, total_length, length_separator;
|
|
struct t_irc_notify *ptr_notify;
|
|
|
|
*num_nicks = 0;
|
|
|
|
length = strlen (irc_message) + 1;
|
|
total_length = length;
|
|
length_separator = strlen (separator);
|
|
|
|
message = malloc (length);
|
|
if (!message)
|
|
return NULL;
|
|
snprintf (message, length, "%s", irc_message);
|
|
|
|
for (ptr_notify = server->notify_list; ptr_notify;
|
|
ptr_notify = ptr_notify->next_notify)
|
|
{
|
|
length = strlen (ptr_notify->nick);
|
|
total_length += length + length_separator;
|
|
message2 = realloc (message, total_length);
|
|
if (!message2)
|
|
{
|
|
if (message)
|
|
free (message);
|
|
message = NULL;
|
|
break;
|
|
}
|
|
message = message2;
|
|
if (*num_nicks > 0)
|
|
strcat (message, separator);
|
|
strcat (message, ptr_notify->nick);
|
|
|
|
(*num_nicks)++;
|
|
}
|
|
|
|
return message;
|
|
}
|
|
|
|
/*
|
|
* Sends the MONITOR message (after server connection or if the option
|
|
* "irc.server.xxx.notify" is changed).
|
|
*/
|
|
|
|
void
|
|
irc_notify_send_monitor (struct t_irc_server *server)
|
|
{
|
|
struct t_hashtable *hashtable;
|
|
char *message, hash_key[32];
|
|
const char *str_message;
|
|
int num_nicks, number;
|
|
|
|
message = irc_notify_build_message_with_nicks (server,
|
|
"MONITOR + ",
|
|
",",
|
|
&num_nicks);
|
|
if (message && (num_nicks > 0))
|
|
{
|
|
hashtable = irc_message_split (server, message);
|
|
if (hashtable)
|
|
{
|
|
number = 1;
|
|
while (1)
|
|
{
|
|
snprintf (hash_key, sizeof (hash_key), "msg%d", number);
|
|
str_message = weechat_hashtable_get (hashtable,
|
|
hash_key);
|
|
if (!str_message)
|
|
break;
|
|
irc_server_sendf (server,
|
|
IRC_SERVER_SEND_OUTQ_PRIO_LOW,
|
|
NULL, "%s", str_message);
|
|
number++;
|
|
}
|
|
weechat_hashtable_free (hashtable);
|
|
}
|
|
}
|
|
if (message)
|
|
free (message);
|
|
}
|
|
|
|
/*
|
|
* Creates a notify list for server with option "irc.server.xxx.notify".
|
|
*/
|
|
|
|
void
|
|
irc_notify_new_for_server (struct t_irc_server *server)
|
|
{
|
|
const char *notify;
|
|
char **items, *pos_params, **params;
|
|
int i, j, num_items, num_params, check_away;
|
|
|
|
irc_notify_free_all (server);
|
|
|
|
notify = IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_NOTIFY);
|
|
if (!notify || !notify[0])
|
|
return;
|
|
|
|
items = weechat_string_split (notify, ",", 0, 0, &num_items);
|
|
if (items)
|
|
{
|
|
for (i = 0; i < num_items; i++)
|
|
{
|
|
check_away = 0;
|
|
pos_params = strchr (items[i], ' ');
|
|
if (pos_params)
|
|
{
|
|
pos_params[0] = '\0';
|
|
pos_params++;
|
|
while (pos_params[0] == ' ')
|
|
{
|
|
pos_params++;
|
|
}
|
|
params = weechat_string_split (pos_params, "/", 0, 0,
|
|
&num_params);
|
|
if (params)
|
|
{
|
|
for (j = 0; j < num_params; j++)
|
|
{
|
|
if (weechat_strcasecmp (params[j], "away") == 0)
|
|
check_away = 1;
|
|
}
|
|
weechat_string_free_split (params);
|
|
}
|
|
}
|
|
irc_notify_new (server, items[i], check_away);
|
|
}
|
|
weechat_string_free_split (items);
|
|
}
|
|
|
|
/* if we are using MONITOR, send it now with new nicks monitored */
|
|
if (server->is_connected && (server->monitor > 0))
|
|
irc_notify_send_monitor (server);
|
|
}
|
|
|
|
/*
|
|
* Creates a notify list for all servers with option "irc.server.xxx.notify".
|
|
*/
|
|
|
|
void
|
|
irc_notify_new_for_all_servers ()
|
|
{
|
|
struct t_irc_server *ptr_server;
|
|
|
|
for (ptr_server = irc_servers; ptr_server;
|
|
ptr_server = ptr_server->next_server)
|
|
{
|
|
irc_notify_new_for_server (ptr_server);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Removes a notify on a server.
|
|
*/
|
|
|
|
void
|
|
irc_notify_free (struct t_irc_server *server, struct t_irc_notify *notify,
|
|
int remove_monitor)
|
|
{
|
|
(void) weechat_hook_signal_send ("irc_notify_removing",
|
|
WEECHAT_HOOK_SIGNAL_POINTER, notify);
|
|
|
|
/* free data */
|
|
if (notify->nick)
|
|
{
|
|
if ((server->monitor > 0) && remove_monitor
|
|
&& (server->is_connected) && !irc_signal_upgrade_received)
|
|
{
|
|
/* remove one monitored nick */
|
|
irc_server_sendf (notify->server,
|
|
IRC_SERVER_SEND_OUTQ_PRIO_LOW, NULL,
|
|
"MONITOR - %s", notify->nick);
|
|
}
|
|
free (notify->nick);
|
|
}
|
|
if (notify->away_message)
|
|
free (notify->away_message);
|
|
|
|
/* remove notify from list */
|
|
if (notify->prev_notify)
|
|
(notify->prev_notify)->next_notify = notify->next_notify;
|
|
if (notify->next_notify)
|
|
(notify->next_notify)->prev_notify = notify->prev_notify;
|
|
if (server->notify_list == notify)
|
|
server->notify_list = notify->next_notify;
|
|
if (server->last_notify == notify)
|
|
server->last_notify = notify->prev_notify;
|
|
|
|
free (notify);
|
|
|
|
if (server->notify_count > 0)
|
|
server->notify_count--;
|
|
|
|
(void) weechat_hook_signal_send ("irc_notify_removed",
|
|
WEECHAT_HOOK_SIGNAL_STRING, NULL);
|
|
}
|
|
|
|
/*
|
|
* Removes all notify on a server.
|
|
*/
|
|
|
|
void
|
|
irc_notify_free_all (struct t_irc_server *server)
|
|
{
|
|
/* remove all monitored nicks */
|
|
if ((server->monitor > 0) && (server->is_connected)
|
|
&& !irc_signal_upgrade_received)
|
|
{
|
|
irc_server_sendf (server, IRC_SERVER_SEND_OUTQ_PRIO_LOW, NULL,
|
|
"MONITOR C");
|
|
}
|
|
|
|
/* free notify list */
|
|
while (server->notify_list)
|
|
{
|
|
irc_notify_free (server, server->notify_list, 0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Displays a notify.
|
|
*/
|
|
|
|
void
|
|
irc_notify_display (struct t_irc_server *server, struct t_gui_buffer *buffer,
|
|
struct t_irc_notify *notify)
|
|
{
|
|
if ((notify->is_on_server < 0)
|
|
|| (!notify->is_on_server && !notify->away_message))
|
|
{
|
|
weechat_printf (
|
|
buffer,
|
|
" %s%s%s @ %s%s%s: %s%s",
|
|
irc_nick_color_for_msg (server, 1, NULL, notify->nick),
|
|
notify->nick,
|
|
IRC_COLOR_RESET,
|
|
IRC_COLOR_CHAT_SERVER,
|
|
notify->server->name,
|
|
IRC_COLOR_RESET,
|
|
(notify->is_on_server < 0) ? "" : IRC_COLOR_MESSAGE_QUIT,
|
|
(notify->is_on_server < 0) ?
|
|
/* TRANSLATORS: "unknown" is the status for /notify when ison answer has not been received (check pending) */
|
|
_("unknown") :
|
|
_("offline"));
|
|
}
|
|
else
|
|
{
|
|
weechat_printf (
|
|
buffer,
|
|
" %s%s%s @ %s%s%s: %s%s %s%s%s%s%s%s",
|
|
irc_nick_color_for_msg (server, 1, NULL, notify->nick),
|
|
notify->nick,
|
|
IRC_COLOR_RESET,
|
|
IRC_COLOR_CHAT_SERVER,
|
|
notify->server->name,
|
|
IRC_COLOR_RESET,
|
|
IRC_COLOR_MESSAGE_JOIN,
|
|
_("online"),
|
|
IRC_COLOR_RESET,
|
|
(notify->away_message) ? " (" : "",
|
|
(notify->away_message) ? _("away") : "",
|
|
(notify->away_message) ? ": \"" : "",
|
|
(notify->away_message) ? notify->away_message : "",
|
|
(notify->away_message) ? "\")" : "");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Displays notify list for a server (or all servers if server is NULL).
|
|
*/
|
|
|
|
void
|
|
irc_notify_display_list (struct t_irc_server *server)
|
|
{
|
|
struct t_irc_notify *ptr_notify;
|
|
struct t_irc_server *ptr_server;
|
|
int count;
|
|
|
|
if (server)
|
|
{
|
|
if (server->notify_list)
|
|
{
|
|
weechat_printf (server->buffer, "");
|
|
weechat_printf (server->buffer,
|
|
_("Notify list for %s%s%s:"),
|
|
IRC_COLOR_CHAT_SERVER,
|
|
server->name,
|
|
IRC_COLOR_RESET);
|
|
for (ptr_notify = server->notify_list; ptr_notify;
|
|
ptr_notify = ptr_notify->next_notify)
|
|
{
|
|
irc_notify_display (server, server->buffer, ptr_notify);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
weechat_printf (server->buffer,
|
|
_("Notify list is empty on this server"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
count = 0;
|
|
for (ptr_server = irc_servers; ptr_server;
|
|
ptr_server = ptr_server->next_server)
|
|
{
|
|
for (ptr_notify = ptr_server->notify_list; ptr_notify;
|
|
ptr_notify = ptr_notify->next_notify)
|
|
{
|
|
if (count == 0)
|
|
{
|
|
weechat_printf (NULL, "");
|
|
weechat_printf (NULL, _("Notify list for all servers:"));
|
|
}
|
|
irc_notify_display (ptr_server, NULL, ptr_notify);
|
|
count++;
|
|
}
|
|
}
|
|
if (count == 0)
|
|
{
|
|
weechat_printf (NULL,
|
|
_("Notify list is empty on all servers"));
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Gets tags for message displayed (concatenation of "irc_notify" and tags from
|
|
* option).
|
|
*/
|
|
|
|
const char *
|
|
irc_notify_get_tags (struct t_config_option *option, const char *type,
|
|
const char *nick)
|
|
{
|
|
static char string[1024];
|
|
const char *tags;
|
|
|
|
tags = weechat_config_string (option);
|
|
|
|
snprintf (string, sizeof (string), "irc_notify,irc_notify_%s,nick_%s%s%s",
|
|
type,
|
|
nick,
|
|
(tags && tags[0]) ? "," : "",
|
|
(tags && tags[0]) ? tags : "");
|
|
|
|
return string;
|
|
}
|
|
|
|
/*
|
|
* Sends a signal on a notify event.
|
|
*/
|
|
|
|
void
|
|
irc_notify_send_signal (struct t_irc_notify *notify,
|
|
const char *type,
|
|
const char *away_message)
|
|
{
|
|
char signal[128], *data;
|
|
int length;
|
|
|
|
snprintf (signal, sizeof (signal), "irc_notify_%s", type);
|
|
|
|
length = strlen (notify->server->name) + 1 + strlen (notify->nick) + 1
|
|
+ ((away_message) ? strlen (away_message) : 0) + 1;
|
|
data = malloc (length);
|
|
if (data)
|
|
{
|
|
snprintf (data, length, "%s,%s%s%s",
|
|
notify->server->name,
|
|
notify->nick,
|
|
(away_message && away_message[0]) ? "," : "",
|
|
(away_message && away_message[0]) ? away_message : "");
|
|
}
|
|
|
|
(void) weechat_hook_signal_send (signal, WEECHAT_HOOK_SIGNAL_STRING, data);
|
|
|
|
if (data)
|
|
free (data);
|
|
}
|
|
|
|
/*
|
|
* Sets flag "is_on_server" for a notify and display message if user was not on
|
|
* server.
|
|
*/
|
|
|
|
void
|
|
irc_notify_set_is_on_server (struct t_irc_notify *notify, const char *host,
|
|
int is_on_server)
|
|
{
|
|
if (!notify)
|
|
return;
|
|
|
|
/* same status, then do nothing */
|
|
if (notify->is_on_server == is_on_server)
|
|
return;
|
|
|
|
weechat_printf_tags (
|
|
notify->server->buffer,
|
|
irc_notify_get_tags (irc_config_look_notify_tags_ison,
|
|
(is_on_server) ? "join" : "quit",
|
|
notify->nick),
|
|
(notify->is_on_server < 0) ?
|
|
((is_on_server) ?
|
|
_("%snotify: %s%s%s%s%s%s%s%s%s is connected") :
|
|
_("%snotify: %s%s%s%s%s%s%s%s%s is offline")) :
|
|
((is_on_server) ?
|
|
_("%snotify: %s%s%s%s%s%s%s%s%s has connected") :
|
|
_("%snotify: %s%s%s%s%s%s%s%s%s has quit")),
|
|
weechat_prefix ("network"),
|
|
irc_nick_color_for_msg (notify->server, 1, NULL, notify->nick),
|
|
notify->nick,
|
|
(host && host[0]) ? IRC_COLOR_CHAT_DELIMITERS : "",
|
|
(host && host[0]) ? " (" : "",
|
|
(host && host[0]) ? IRC_COLOR_CHAT_HOST : "",
|
|
(host && host[0]) ? host : "",
|
|
(host && host[0]) ? IRC_COLOR_CHAT_DELIMITERS : "",
|
|
(host && host[0]) ? ")" : "",
|
|
(is_on_server) ? IRC_COLOR_MESSAGE_JOIN : IRC_COLOR_MESSAGE_QUIT);
|
|
irc_notify_send_signal (notify, (is_on_server) ? "join" : "quit", NULL);
|
|
|
|
notify->is_on_server = is_on_server;
|
|
}
|
|
|
|
/*
|
|
* Sets away message for a notify and display message if away status has
|
|
* changed.
|
|
*/
|
|
|
|
void
|
|
irc_notify_set_away_message (struct t_irc_notify *notify,
|
|
const char *away_message)
|
|
{
|
|
if (!notify)
|
|
return;
|
|
|
|
/* same away message, then do nothing */
|
|
if ((!notify->away_message && !away_message)
|
|
|| (notify->away_message && away_message
|
|
&& (strcmp (notify->away_message, away_message) == 0)))
|
|
return;
|
|
|
|
if (!notify->away_message && away_message)
|
|
{
|
|
weechat_printf_tags (
|
|
notify->server->buffer,
|
|
irc_notify_get_tags (
|
|
irc_config_look_notify_tags_whois, "away", notify->nick),
|
|
_("%snotify: %s%s%s is now away: \"%s\""),
|
|
weechat_prefix ("network"),
|
|
irc_nick_color_for_msg (notify->server, 1, NULL, notify->nick),
|
|
notify->nick,
|
|
IRC_COLOR_RESET,
|
|
away_message);
|
|
irc_notify_send_signal (notify, "away", away_message);
|
|
}
|
|
else if (notify->away_message && !away_message)
|
|
{
|
|
weechat_printf_tags (
|
|
notify->server->buffer,
|
|
irc_notify_get_tags (
|
|
irc_config_look_notify_tags_whois, "back", notify->nick),
|
|
_("%snotify: %s%s%s is back"),
|
|
weechat_prefix ("network"),
|
|
irc_nick_color_for_msg (notify->server, 1, NULL, notify->nick),
|
|
notify->nick,
|
|
IRC_COLOR_RESET);
|
|
irc_notify_send_signal (notify, "back", NULL);
|
|
}
|
|
else if (notify->away_message && away_message)
|
|
{
|
|
weechat_printf_tags (
|
|
notify->server->buffer,
|
|
irc_notify_get_tags (
|
|
irc_config_look_notify_tags_whois, "still_away", notify->nick),
|
|
_("%snotify: %s%s%s is still away: \"%s\""),
|
|
weechat_prefix ("network"),
|
|
irc_nick_color_for_msg (notify->server, 1, NULL, notify->nick),
|
|
notify->nick,
|
|
IRC_COLOR_RESET,
|
|
away_message);
|
|
irc_notify_send_signal (notify, "still_away", away_message);
|
|
}
|
|
|
|
if (notify->away_message)
|
|
free (notify->away_message);
|
|
notify->away_message = (away_message) ? strdup (away_message) : NULL;
|
|
}
|
|
|
|
/*
|
|
* Callback for hsignal on redirected commands "ison" and "whois".
|
|
*/
|
|
|
|
int
|
|
irc_notify_hsignal_cb (const void *pointer, void *data, const char *signal,
|
|
struct t_hashtable *hashtable)
|
|
{
|
|
const char *error, *server, *pattern, *command, *output;
|
|
char **messages, **nicks_sent, **nicks_recv, *irc_cmd, *arguments;
|
|
char *ptr_args, *pos;
|
|
int i, j, num_messages, num_nicks_sent, num_nicks_recv, nick_was_sent;
|
|
int away_message_updated, no_such_nick;
|
|
struct t_irc_server *ptr_server;
|
|
struct t_irc_notify *ptr_notify;
|
|
|
|
/* make C compiler happy */
|
|
(void) pointer;
|
|
(void) data;
|
|
(void) signal;
|
|
|
|
error = weechat_hashtable_get (hashtable, "error");
|
|
server = weechat_hashtable_get (hashtable, "server");
|
|
pattern = weechat_hashtable_get (hashtable, "pattern");
|
|
command = weechat_hashtable_get (hashtable, "command");
|
|
output = weechat_hashtable_get (hashtable, "output");
|
|
|
|
/* if there is an error on redirection, just ignore result */
|
|
if (error && error[0])
|
|
return WEECHAT_RC_OK;
|
|
|
|
/* missing things in redirection */
|
|
if (!server || !pattern || !command || !output)
|
|
return WEECHAT_RC_OK;
|
|
|
|
/* search server */
|
|
ptr_server = irc_server_search (server);
|
|
if (!ptr_server)
|
|
return WEECHAT_RC_OK;
|
|
|
|
/* search for start of arguments in command sent to server */
|
|
ptr_args = strchr (command, ' ');
|
|
if (!ptr_args)
|
|
return WEECHAT_RC_OK;
|
|
ptr_args++;
|
|
while ((ptr_args[0] == ' ') || (ptr_args[0] == ':'))
|
|
{
|
|
ptr_args++;
|
|
}
|
|
if (!ptr_args[0])
|
|
return WEECHAT_RC_OK;
|
|
|
|
/* read output of command */
|
|
if (strcmp (pattern, "ison") == 0)
|
|
{
|
|
/* redirection of command "ison" */
|
|
messages = weechat_string_split (output, "\n", 0, 0, &num_messages);
|
|
if (messages)
|
|
{
|
|
nicks_sent = weechat_string_split (ptr_args, " ", 0, 0,
|
|
&num_nicks_sent);
|
|
if (!nicks_sent)
|
|
return WEECHAT_RC_OK;
|
|
for (ptr_notify = ptr_server->notify_list;
|
|
ptr_notify;
|
|
ptr_notify = ptr_notify->next_notify)
|
|
{
|
|
ptr_notify->ison_received = 0;
|
|
}
|
|
for (i = 0; i < num_messages; i++)
|
|
{
|
|
irc_message_parse (ptr_server, messages[i], NULL, NULL, NULL,
|
|
NULL, NULL, NULL, &arguments, NULL, NULL,
|
|
NULL, NULL, NULL);
|
|
if (arguments)
|
|
{
|
|
pos = strchr (arguments, ' ');
|
|
if (pos)
|
|
{
|
|
pos++;
|
|
while ((pos[0] == ' ') || (pos[0] == ':'))
|
|
{
|
|
pos++;
|
|
}
|
|
if (pos[0])
|
|
{
|
|
nicks_recv = weechat_string_split (pos, " ", 0, 0,
|
|
&num_nicks_recv);
|
|
if (nicks_recv)
|
|
{
|
|
for (j = 0; j < num_nicks_recv; j++)
|
|
{
|
|
for (ptr_notify = ptr_server->notify_list;
|
|
ptr_notify;
|
|
ptr_notify = ptr_notify->next_notify)
|
|
{
|
|
if (irc_server_strcasecmp (ptr_server,
|
|
ptr_notify->nick,
|
|
nicks_recv[j]) == 0)
|
|
{
|
|
irc_notify_set_is_on_server (ptr_notify,
|
|
NULL,
|
|
1);
|
|
ptr_notify->ison_received = 1;
|
|
}
|
|
}
|
|
}
|
|
weechat_string_free_split (nicks_recv);
|
|
}
|
|
}
|
|
}
|
|
free (arguments);
|
|
}
|
|
}
|
|
for (ptr_notify = ptr_server->notify_list;
|
|
ptr_notify;
|
|
ptr_notify = ptr_notify->next_notify)
|
|
{
|
|
if (!ptr_notify->ison_received)
|
|
{
|
|
nick_was_sent = 0;
|
|
for (j = 0; j < num_nicks_sent; j++)
|
|
{
|
|
if (irc_server_strcasecmp (ptr_server,
|
|
nicks_sent[j],
|
|
ptr_notify->nick) == 0)
|
|
{
|
|
nick_was_sent = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (nick_was_sent)
|
|
{
|
|
irc_notify_set_is_on_server (ptr_notify, NULL, 0);
|
|
}
|
|
}
|
|
|
|
}
|
|
weechat_string_free_split (messages);
|
|
}
|
|
}
|
|
else if (strcmp (pattern, "whois") == 0)
|
|
{
|
|
/* redirection of command "whois" */
|
|
ptr_notify = irc_notify_search (ptr_server, ptr_args);
|
|
if (ptr_notify)
|
|
{
|
|
away_message_updated = 0;
|
|
no_such_nick = 0;
|
|
messages = weechat_string_split (output, "\n", 0, 0, &num_messages);
|
|
if (messages)
|
|
{
|
|
for (i = 0; i < num_messages; i++)
|
|
{
|
|
irc_message_parse (ptr_server, messages[0], NULL, NULL,
|
|
NULL, NULL, &irc_cmd, NULL, &arguments,
|
|
NULL, NULL, NULL, NULL, NULL);
|
|
if (irc_cmd && arguments)
|
|
{
|
|
if (strcmp (irc_cmd, "401") == 0)
|
|
{
|
|
/* no such nick/channel */
|
|
no_such_nick = 1;
|
|
}
|
|
else if (strcmp (irc_cmd, "301") == 0)
|
|
{
|
|
/* away message */
|
|
pos = strchr (arguments, ':');
|
|
if (pos)
|
|
{
|
|
pos++;
|
|
/* nick is away */
|
|
irc_notify_set_away_message (ptr_notify, pos);
|
|
away_message_updated = 1;
|
|
}
|
|
}
|
|
}
|
|
if (irc_cmd)
|
|
free (irc_cmd);
|
|
if (arguments)
|
|
free (arguments);
|
|
}
|
|
}
|
|
if (!away_message_updated && !no_such_nick)
|
|
{
|
|
/* nick is back */
|
|
irc_notify_set_away_message (ptr_notify, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Timer called to send "ison" command to servers.
|
|
*/
|
|
|
|
int
|
|
irc_notify_timer_ison_cb (const void *pointer, void *data, int remaining_calls)
|
|
{
|
|
char *message, hash_key[32];
|
|
const char *str_message;
|
|
int num_nicks, number;
|
|
struct t_irc_server *ptr_server;
|
|
struct t_hashtable *hashtable;
|
|
|
|
/* make C compiler happy */
|
|
(void) pointer;
|
|
(void) data;
|
|
(void) remaining_calls;
|
|
|
|
for (ptr_server = irc_servers; ptr_server;
|
|
ptr_server = ptr_server->next_server)
|
|
{
|
|
if (ptr_server->is_connected
|
|
&& ptr_server->notify_list
|
|
&& (ptr_server->monitor == 0))
|
|
{
|
|
message = irc_notify_build_message_with_nicks (ptr_server,
|
|
"ISON :",
|
|
" ",
|
|
&num_nicks);
|
|
if (message && (num_nicks > 0))
|
|
{
|
|
hashtable = irc_message_split (ptr_server, message);
|
|
if (hashtable)
|
|
{
|
|
number = 1;
|
|
while (1)
|
|
{
|
|
snprintf (hash_key, sizeof (hash_key), "msg%d", number);
|
|
str_message = weechat_hashtable_get (hashtable,
|
|
hash_key);
|
|
if (!str_message)
|
|
break;
|
|
irc_redirect_new (ptr_server, "ison", "notify", 1,
|
|
NULL, 0, NULL);
|
|
irc_server_sendf (ptr_server,
|
|
IRC_SERVER_SEND_OUTQ_PRIO_LOW,
|
|
NULL, "%s", str_message);
|
|
number++;
|
|
}
|
|
weechat_hashtable_free (hashtable);
|
|
}
|
|
}
|
|
if (message)
|
|
free (message);
|
|
}
|
|
}
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Timer called to send "whois" command to servers.
|
|
*/
|
|
|
|
int
|
|
irc_notify_timer_whois_cb (const void *pointer, void *data,
|
|
int remaining_calls)
|
|
{
|
|
struct t_irc_server *ptr_server;
|
|
struct t_irc_notify *ptr_notify, *ptr_next_notify;
|
|
|
|
/* make C compiler happy */
|
|
(void) pointer;
|
|
(void) data;
|
|
(void) remaining_calls;
|
|
|
|
for (ptr_server = irc_servers; ptr_server;
|
|
ptr_server = ptr_server->next_server)
|
|
{
|
|
if (ptr_server->is_connected && ptr_server->notify_list)
|
|
{
|
|
ptr_notify = ptr_server->notify_list;
|
|
while (ptr_notify)
|
|
{
|
|
ptr_next_notify = ptr_notify->next_notify;
|
|
|
|
if (ptr_notify->check_away)
|
|
{
|
|
/*
|
|
* redirect whois, and get only 2 messages:
|
|
* 301: away message
|
|
* 401: no such nick/channel
|
|
*/
|
|
irc_redirect_new (ptr_server, "whois", "notify", 1,
|
|
ptr_notify->nick, 0, "301,401");
|
|
irc_server_sendf (ptr_server,
|
|
IRC_SERVER_SEND_OUTQ_PRIO_LOW, NULL,
|
|
"WHOIS :%s", ptr_notify->nick);
|
|
}
|
|
|
|
ptr_notify = ptr_next_notify;
|
|
}
|
|
}
|
|
}
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Returns hdata for notify.
|
|
*/
|
|
|
|
struct t_hdata *
|
|
irc_notify_hdata_notify_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, "prev_notify", "next_notify",
|
|
0, 0, NULL, NULL);
|
|
if (hdata)
|
|
{
|
|
WEECHAT_HDATA_VAR(struct t_irc_notify, server, POINTER, 0, NULL, "irc_server");
|
|
WEECHAT_HDATA_VAR(struct t_irc_notify, nick, STRING, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_irc_notify, check_away, INTEGER, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_irc_notify, is_on_server, INTEGER, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_irc_notify, away_message, STRING, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_irc_notify, ison_received, INTEGER, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_irc_notify, prev_notify, POINTER, 0, NULL, hdata_name);
|
|
WEECHAT_HDATA_VAR(struct t_irc_notify, next_notify, POINTER, 0, NULL, hdata_name);
|
|
}
|
|
return hdata;
|
|
}
|
|
|
|
/*
|
|
* Adds a notify in an infolist.
|
|
*
|
|
* Returns:
|
|
* 1: OK
|
|
* 0: error
|
|
*/
|
|
|
|
int
|
|
irc_notify_add_to_infolist (struct t_infolist *infolist,
|
|
struct t_irc_notify *notify)
|
|
{
|
|
struct t_infolist_item *ptr_item;
|
|
|
|
if (!infolist || !notify)
|
|
return 0;
|
|
|
|
ptr_item = weechat_infolist_new_item (infolist);
|
|
if (!ptr_item)
|
|
return 0;
|
|
|
|
if (!weechat_infolist_new_var_pointer (ptr_item, "server", notify->server))
|
|
return 0;
|
|
if (!weechat_infolist_new_var_string (ptr_item, "server_name", notify->server->name))
|
|
return 0;
|
|
if (!weechat_infolist_new_var_string (ptr_item, "nick", notify->nick))
|
|
return 0;
|
|
if (!weechat_infolist_new_var_integer (ptr_item, "check_away", notify->check_away))
|
|
return 0;
|
|
if (!weechat_infolist_new_var_integer (ptr_item, "is_on_server", notify->is_on_server))
|
|
return 0;
|
|
if (!weechat_infolist_new_var_string (ptr_item, "away_message", notify->away_message))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Prints notify infos in WeeChat log file (usually for crash dump).
|
|
*/
|
|
|
|
void
|
|
irc_notify_print_log (struct t_irc_server *server)
|
|
{
|
|
struct t_irc_notify *ptr_notify;
|
|
|
|
for (ptr_notify = server->notify_list; ptr_notify;
|
|
ptr_notify = ptr_notify->next_notify)
|
|
{
|
|
weechat_log_printf ("");
|
|
weechat_log_printf (" => notify (addr:0x%lx):", ptr_notify);
|
|
weechat_log_printf (" server. . . . . . . : 0x%lx", ptr_notify->server);
|
|
weechat_log_printf (" nick. . . . . . . . : '%s'", ptr_notify->nick);
|
|
weechat_log_printf (" check_away. . . . . : %d", ptr_notify->check_away);
|
|
weechat_log_printf (" is_on_server. . . . : %d", ptr_notify->is_on_server);
|
|
weechat_log_printf (" away_message. . . . : '%s'", ptr_notify->away_message);
|
|
weechat_log_printf (" ison_received . . . : %d", ptr_notify->ison_received);
|
|
weechat_log_printf (" prev_notify . . . . : 0x%lx", ptr_notify->prev_notify);
|
|
weechat_log_printf (" next_notify . . . . : 0x%lx", ptr_notify->next_notify);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Hooks timer to send "ison" command.
|
|
*/
|
|
|
|
void
|
|
irc_notify_hook_timer_ison ()
|
|
{
|
|
if (irc_notify_timer_ison)
|
|
weechat_unhook (irc_notify_timer_ison);
|
|
|
|
irc_notify_timer_ison = weechat_hook_timer (
|
|
60 * 1000 * weechat_config_integer (irc_config_network_notify_check_ison),
|
|
0, 0, &irc_notify_timer_ison_cb, NULL, NULL);
|
|
}
|
|
|
|
/*
|
|
* Hooks timer to send "whois" command.
|
|
*/
|
|
|
|
void
|
|
irc_notify_hook_timer_whois ()
|
|
{
|
|
if (irc_notify_timer_whois)
|
|
weechat_unhook (irc_notify_timer_whois);
|
|
|
|
irc_notify_timer_whois = weechat_hook_timer (
|
|
60 * 1000 * weechat_config_integer (irc_config_network_notify_check_whois),
|
|
0, 0, &irc_notify_timer_whois_cb, NULL, NULL);
|
|
}
|
|
|
|
/*
|
|
* Hooks timers and hsignal.
|
|
*/
|
|
|
|
void
|
|
irc_notify_init ()
|
|
{
|
|
irc_notify_hook_timer_ison ();
|
|
irc_notify_hook_timer_whois ();
|
|
|
|
irc_notify_hsignal = weechat_hook_hsignal ("irc_redirection_notify_*",
|
|
&irc_notify_hsignal_cb,
|
|
NULL, NULL);
|
|
}
|
|
|
|
/*
|
|
* Removes timers and hsignal.
|
|
*/
|
|
|
|
void
|
|
irc_notify_end ()
|
|
{
|
|
if (irc_notify_timer_ison)
|
|
weechat_unhook (irc_notify_timer_ison);
|
|
if (irc_notify_timer_whois)
|
|
weechat_unhook (irc_notify_timer_whois);
|
|
if (irc_notify_hsignal)
|
|
weechat_unhook (irc_notify_hsignal);
|
|
}
|