1
0
mirror of https://github.com/weechat/weechat.git synced 2026-06-27 13:26:38 +02:00
Files
weechat/src/plugins/irc/irc-notify.c
T
Sébastien Helleu cf6aca1619 core: add pointer in some callbacks (closes #406)
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
2016-03-21 18:11:21 +01:00

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);
}