mirror of
https://github.com/weechat/weechat.git
synced 2026-06-27 21:36:37 +02:00
562 lines
15 KiB
C
562 lines
15 KiB
C
/*
|
|
* Copyright (c) 2003-2006 by FlashCode <flashcode@flashtux.org>
|
|
* See README for License detail, AUTHORS for developers list.
|
|
*
|
|
* This program 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 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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 this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
/* irc-channel.c: manages a chat (channel or private chat) */
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
|
|
#include "../common/weechat.h"
|
|
#include "irc.h"
|
|
#include "../common/log.h"
|
|
#include "../common/utf8.h"
|
|
#include "../common/util.h"
|
|
#include "../common/weeconfig.h"
|
|
#include "../gui/gui.h"
|
|
|
|
|
|
char *channel_modes = "iklmnstp";
|
|
|
|
|
|
/*
|
|
* channel_new: allocate a new channel for a server and add it to the server queue
|
|
*/
|
|
|
|
t_irc_channel *
|
|
channel_new (t_irc_server *server, int channel_type, char *channel_name)
|
|
{
|
|
t_irc_channel *new_channel;
|
|
|
|
/* alloc memory for new channel */
|
|
if ((new_channel = (t_irc_channel *) malloc (sizeof (t_irc_channel))) == NULL)
|
|
{
|
|
fprintf (stderr, _("%s cannot allocate new channel"), WEECHAT_ERROR);
|
|
return NULL;
|
|
}
|
|
|
|
/* initialize new channel */
|
|
new_channel->type = channel_type;
|
|
new_channel->dcc_chat = NULL;
|
|
new_channel->name = strdup (channel_name);
|
|
new_channel->topic = NULL;
|
|
new_channel->modes = (char *) malloc (NUM_CHANNEL_MODES + 1);
|
|
memset (new_channel->modes, ' ', NUM_CHANNEL_MODES);
|
|
new_channel->modes[NUM_CHANNEL_MODES] = '\0';
|
|
new_channel->limit = 0;
|
|
new_channel->key = NULL;
|
|
new_channel->nicks_count = 0;
|
|
new_channel->checking_away = 0;
|
|
new_channel->away_message = NULL;
|
|
new_channel->cycle = 0;
|
|
new_channel->close = 0;
|
|
new_channel->nicks = NULL;
|
|
new_channel->last_nick = NULL;
|
|
|
|
/* add new channel to queue */
|
|
new_channel->prev_channel = server->last_channel;
|
|
new_channel->next_channel = NULL;
|
|
if (server->channels)
|
|
server->last_channel->next_channel = new_channel;
|
|
else
|
|
server->channels = new_channel;
|
|
server->last_channel = new_channel;
|
|
|
|
/* all is ok, return address of new channel */
|
|
return new_channel;
|
|
}
|
|
|
|
/*
|
|
* channel_free: free a channel and remove it from channels queue
|
|
*/
|
|
|
|
void
|
|
channel_free (t_irc_server *server, t_irc_channel *channel)
|
|
{
|
|
t_irc_channel *new_channels;
|
|
|
|
if (!server || !channel)
|
|
return;
|
|
|
|
/* close DCC CHAT */
|
|
if ((t_irc_dcc *)(channel->dcc_chat) &&
|
|
(!DCC_ENDED(((t_irc_dcc *)(channel->dcc_chat))->status)))
|
|
{
|
|
((t_irc_dcc *)(channel->dcc_chat))->channel = NULL;
|
|
dcc_close ((t_irc_dcc *)(channel->dcc_chat), DCC_ABORTED);
|
|
dcc_redraw (1);
|
|
}
|
|
|
|
/* remove channel from queue */
|
|
if (server->last_channel == channel)
|
|
server->last_channel = channel->prev_channel;
|
|
if (channel->prev_channel)
|
|
{
|
|
(channel->prev_channel)->next_channel = channel->next_channel;
|
|
new_channels = server->channels;
|
|
}
|
|
else
|
|
new_channels = channel->next_channel;
|
|
|
|
if (channel->next_channel)
|
|
(channel->next_channel)->prev_channel = channel->prev_channel;
|
|
|
|
/* free data */
|
|
if (channel->name)
|
|
free (channel->name);
|
|
if (channel->topic)
|
|
free (channel->topic);
|
|
nick_free_all (channel);
|
|
if (channel->away_message)
|
|
free (channel->away_message);
|
|
free (channel);
|
|
server->channels = new_channels;
|
|
}
|
|
|
|
/*
|
|
* channel_free_all: free all allocated channels
|
|
*/
|
|
|
|
void
|
|
channel_free_all (t_irc_server *server)
|
|
{
|
|
/* remove all channels for the server */
|
|
while (server->channels)
|
|
channel_free (server, server->channels);
|
|
}
|
|
|
|
/*
|
|
* channel_search: returns pointer on a channel with name
|
|
* WARNING: DCC chat channels are not returned by this function
|
|
*/
|
|
|
|
t_irc_channel *
|
|
channel_search (t_irc_server *server, char *channel_name)
|
|
{
|
|
t_irc_channel *ptr_channel;
|
|
|
|
if (!server || !channel_name)
|
|
return NULL;
|
|
|
|
for (ptr_channel = server->channels; ptr_channel;
|
|
ptr_channel = ptr_channel->next_channel)
|
|
{
|
|
if ((ptr_channel->type != CHANNEL_TYPE_DCC_CHAT)
|
|
&& (ascii_strcasecmp (ptr_channel->name, channel_name) == 0))
|
|
return ptr_channel;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* channel_search_any: returns pointer on a channel with name
|
|
*/
|
|
|
|
t_irc_channel *
|
|
channel_search_any (t_irc_server *server, char *channel_name)
|
|
{
|
|
t_irc_channel *ptr_channel;
|
|
|
|
if (!server || !channel_name)
|
|
return NULL;
|
|
|
|
for (ptr_channel = server->channels; ptr_channel;
|
|
ptr_channel = ptr_channel->next_channel)
|
|
{
|
|
if (ascii_strcasecmp (ptr_channel->name, channel_name) == 0)
|
|
return ptr_channel;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* channel_search_any_without_buffer: returns pointer on a channel with name
|
|
* looks only for channels without buffer
|
|
*/
|
|
|
|
t_irc_channel *
|
|
channel_search_any_without_buffer (t_irc_server *server, char *channel_name)
|
|
{
|
|
t_irc_channel *ptr_channel;
|
|
|
|
if (!server || !channel_name)
|
|
return NULL;
|
|
|
|
for (ptr_channel = server->channels; ptr_channel;
|
|
ptr_channel = ptr_channel->next_channel)
|
|
{
|
|
if (!ptr_channel->buffer
|
|
&& (ascii_strcasecmp (ptr_channel->name, channel_name) == 0))
|
|
return ptr_channel;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* channel_search_dcc: returns pointer on a DCC chat channel with name
|
|
*/
|
|
|
|
t_irc_channel *
|
|
channel_search_dcc (t_irc_server *server, char *channel_name)
|
|
{
|
|
t_irc_channel *ptr_channel;
|
|
|
|
if (!server || !channel_name)
|
|
return NULL;
|
|
|
|
for (ptr_channel = server->channels; ptr_channel;
|
|
ptr_channel = ptr_channel->next_channel)
|
|
{
|
|
if ((ptr_channel->type == CHANNEL_TYPE_DCC_CHAT)
|
|
&& (ascii_strcasecmp (ptr_channel->name, channel_name) == 0))
|
|
return ptr_channel;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* string_is_channel: returns 1 if string is channel
|
|
*/
|
|
|
|
int
|
|
string_is_channel (char *string)
|
|
{
|
|
char first_char[2];
|
|
|
|
if (!string)
|
|
return 0;
|
|
|
|
first_char[0] = string[0];
|
|
first_char[1] = '\0';
|
|
return (strpbrk (first_char, CHANNEL_PREFIX)) ? 1 : 0;
|
|
}
|
|
|
|
/*
|
|
* channel_get_charset_decode_iso: get decode iso value for channel
|
|
* if not found for channel, look for server
|
|
* if not found for server, look for global
|
|
*/
|
|
|
|
char *
|
|
channel_get_charset_decode_iso (t_irc_server *server, t_irc_channel *channel)
|
|
{
|
|
char *pos, *result;
|
|
int length;
|
|
|
|
if (!server)
|
|
return (cfg_look_charset_decode_iso) ?
|
|
strdup (cfg_look_charset_decode_iso) : strdup ("");
|
|
|
|
if (!channel)
|
|
return server_get_charset_decode_iso (server);
|
|
|
|
config_option_list_get_value (&(server->charset_decode_iso),
|
|
channel->name, &pos, &length);
|
|
if (pos && (length > 0))
|
|
{
|
|
result = strdup (pos);
|
|
result[length] = '\0';
|
|
return result;
|
|
}
|
|
|
|
return server_get_charset_decode_iso (server);
|
|
}
|
|
|
|
/*
|
|
* channel_get_charset_decode_utf: get decode utf value for channel
|
|
* if not found for channel, look for server
|
|
* if not found for server, look for global
|
|
*/
|
|
|
|
char *
|
|
channel_get_charset_decode_utf (t_irc_server *server, t_irc_channel *channel)
|
|
{
|
|
char *pos, *result;
|
|
int length;
|
|
|
|
if (!server)
|
|
return (cfg_look_charset_decode_utf) ?
|
|
strdup (cfg_look_charset_decode_utf) : strdup ("");
|
|
|
|
if (!channel)
|
|
return server_get_charset_decode_utf (server);
|
|
|
|
config_option_list_get_value (&(server->charset_decode_utf),
|
|
channel->name, &pos, &length);
|
|
if (pos && (length > 0))
|
|
{
|
|
result = strdup (pos);
|
|
result[length] = '\0';
|
|
return result;
|
|
}
|
|
|
|
return server_get_charset_decode_utf (server);
|
|
}
|
|
|
|
/*
|
|
* channel_get_charset_encode: get encode value for channel
|
|
* if not found for channel, look for server
|
|
* if not found for server, look for global
|
|
*/
|
|
|
|
char *
|
|
channel_get_charset_encode (t_irc_server *server, t_irc_channel *channel)
|
|
{
|
|
char *pos, *result;
|
|
int length;
|
|
|
|
if (!server)
|
|
return (cfg_look_charset_encode) ?
|
|
strdup (cfg_look_charset_encode) : strdup ("");
|
|
|
|
if (!channel)
|
|
return server_get_charset_encode (server);
|
|
|
|
config_option_list_get_value (&(server->charset_encode),
|
|
channel->name, &pos, &length);
|
|
if (pos && (length > 0))
|
|
{
|
|
result = strdup (pos);
|
|
result[length] = '\0';
|
|
return result;
|
|
}
|
|
|
|
return server_get_charset_encode (server);
|
|
}
|
|
|
|
/*
|
|
* channel_iconv_decode: convert string to local charset
|
|
*/
|
|
|
|
char *
|
|
channel_iconv_decode (t_irc_server *server, t_irc_channel *channel, char *string)
|
|
{
|
|
char *from_charset, *string2;
|
|
|
|
if (!local_utf8 || !utf8_is_valid (string))
|
|
{
|
|
if (local_utf8)
|
|
from_charset = channel_get_charset_decode_iso (server, channel);
|
|
else
|
|
from_charset = channel_get_charset_decode_utf (server, channel);
|
|
string2 = weechat_iconv (from_charset,
|
|
(cfg_look_charset_internal && cfg_look_charset_internal[0]) ?
|
|
cfg_look_charset_internal : local_charset,
|
|
string);
|
|
free (from_charset);
|
|
return string2;
|
|
}
|
|
else
|
|
return strdup (string);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
|
|
char *
|
|
channel_iconv_encode (t_irc_server *server, t_irc_channel *channel, char *string)
|
|
{
|
|
char *to_charset, *string2;
|
|
|
|
to_charset = channel_get_charset_encode (server, channel);
|
|
string2 = weechat_iconv ((cfg_look_charset_internal && cfg_look_charset_internal[0]) ?
|
|
cfg_look_charset_internal : local_charset,
|
|
to_charset,
|
|
string);
|
|
free (to_charset);
|
|
return string2;
|
|
}
|
|
|
|
/*
|
|
* channel_remove_away: remove away for all nicks on a channel
|
|
*/
|
|
|
|
void
|
|
channel_remove_away (t_irc_channel *channel)
|
|
{
|
|
t_irc_nick *ptr_nick;
|
|
|
|
if (channel->type == CHANNEL_TYPE_CHANNEL)
|
|
{
|
|
for (ptr_nick = channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick)
|
|
{
|
|
NICK_SET_FLAG(ptr_nick, 0, NICK_AWAY);
|
|
}
|
|
gui_nicklist_draw (channel->buffer, 0, 0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* channel_check_away: check for away on a channel
|
|
*/
|
|
|
|
void
|
|
channel_check_away (t_irc_server *server, t_irc_channel *channel, int force)
|
|
{
|
|
if (channel->type == CHANNEL_TYPE_CHANNEL)
|
|
{
|
|
if (force || (cfg_irc_away_check_max_nicks == 0) ||
|
|
(channel->nicks_count <= cfg_irc_away_check_max_nicks))
|
|
{
|
|
channel->checking_away++;
|
|
server_sendf (server, "WHO %s\r\n", channel->name);
|
|
}
|
|
else
|
|
channel_remove_away (channel);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* channel_set_away: set/unset away status for a channel
|
|
*/
|
|
|
|
void
|
|
channel_set_away (t_irc_channel *channel, char *nick, int is_away)
|
|
{
|
|
t_irc_nick *ptr_nick;
|
|
|
|
if (channel->type == CHANNEL_TYPE_CHANNEL)
|
|
{
|
|
ptr_nick = nick_search (channel, nick);
|
|
if (ptr_nick)
|
|
nick_set_away (channel, ptr_nick, is_away);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* channel_create_dcc: create DCC CHAT channel
|
|
*/
|
|
|
|
int
|
|
channel_create_dcc (t_irc_dcc *ptr_dcc)
|
|
{
|
|
t_irc_channel *ptr_channel;
|
|
|
|
ptr_channel = channel_search_dcc (ptr_dcc->server, ptr_dcc->nick);
|
|
if (!ptr_channel)
|
|
{
|
|
ptr_channel = channel_new (ptr_dcc->server, CHANNEL_TYPE_DCC_CHAT,
|
|
ptr_dcc->nick);
|
|
if (!ptr_channel)
|
|
return 0;
|
|
gui_buffer_new (gui_current_window, ptr_dcc->server, ptr_channel,
|
|
BUFFER_TYPE_STANDARD, 0);
|
|
}
|
|
|
|
if (ptr_channel->dcc_chat &&
|
|
(!DCC_ENDED(((t_irc_dcc *)(ptr_channel->dcc_chat))->status)))
|
|
return 0;
|
|
|
|
ptr_channel->dcc_chat = ptr_dcc;
|
|
ptr_dcc->channel = ptr_channel;
|
|
gui_window_redraw_buffer (ptr_channel->buffer);
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* channel_get_notify_level: get channel notify level
|
|
*/
|
|
|
|
int
|
|
channel_get_notify_level (t_irc_server *server, t_irc_channel *channel)
|
|
{
|
|
char *name, *pos, *pos2;
|
|
int notify;
|
|
|
|
if ((!server) || (!channel))
|
|
return NOTIFY_LEVEL_DEFAULT;
|
|
|
|
if ((!server->notify_levels) || (!server->notify_levels[0]))
|
|
return NOTIFY_LEVEL_DEFAULT;
|
|
|
|
name = (char *) malloc (strlen (channel->name) + 2);
|
|
strcpy (name, channel->name);
|
|
strcat (name, ":");
|
|
pos = strstr (server->notify_levels, name);
|
|
free (name);
|
|
if (!pos)
|
|
return NOTIFY_LEVEL_DEFAULT;
|
|
|
|
pos2 = pos + strlen (channel->name);
|
|
if (pos2[0] != ':')
|
|
return NOTIFY_LEVEL_DEFAULT;
|
|
pos2++;
|
|
if (!pos2[0])
|
|
return NOTIFY_LEVEL_DEFAULT;
|
|
|
|
notify = (int)(pos2[0] - '0');
|
|
if ((notify < NOTIFY_LEVEL_MIN) || (notify > NOTIFY_LEVEL_MAX))
|
|
return NOTIFY_LEVEL_DEFAULT;
|
|
else
|
|
return notify;
|
|
}
|
|
|
|
/*
|
|
* server_set_notify_level: set channel notify level
|
|
*/
|
|
|
|
void
|
|
channel_set_notify_level (t_irc_server *server, t_irc_channel *channel, int notify)
|
|
{
|
|
char level_string[2];
|
|
|
|
if ((!server) || (!channel))
|
|
return;
|
|
|
|
if (notify == NOTIFY_LEVEL_DEFAULT)
|
|
config_option_list_remove (&(server->notify_levels), channel->name);
|
|
else
|
|
{
|
|
level_string[0] = notify + '0';
|
|
level_string[1] = '\0';
|
|
config_option_list_set (&(server->notify_levels), channel->name, level_string);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* channel_print_log: print channel infos in log (usually for crash dump)
|
|
*/
|
|
|
|
void
|
|
channel_print_log (t_irc_channel *channel)
|
|
{
|
|
weechat_log_printf ("=> channel %s (addr:0x%X)]\n", channel->name, channel);
|
|
weechat_log_printf (" type . . . . : %d\n", channel->type);
|
|
weechat_log_printf (" dcc_chat . . : 0x%X\n", channel->dcc_chat);
|
|
weechat_log_printf (" topic. . . . : '%s'\n", channel->topic);
|
|
weechat_log_printf (" modes. . . . : '%s'\n", channel->modes);
|
|
weechat_log_printf (" limit. . . . : %d\n", channel->limit);
|
|
weechat_log_printf (" key. . . . . : '%s'\n", channel->key);
|
|
weechat_log_printf (" checking_away: %d\n", channel->checking_away);
|
|
weechat_log_printf (" away_message : '%s'\n", channel->away_message);
|
|
weechat_log_printf (" cycle. . . . : %d\n", channel->cycle);
|
|
weechat_log_printf (" close. . . . : %d\n", channel->close);
|
|
weechat_log_printf (" nicks. . . . : 0x%X\n", channel->nicks);
|
|
weechat_log_printf (" last_nick. . : 0x%X\n", channel->last_nick);
|
|
weechat_log_printf (" buffer . . . : 0x%X\n", channel->buffer);
|
|
weechat_log_printf (" prev_channel : 0x%X\n", channel->prev_channel);
|
|
weechat_log_printf (" next_channel : 0x%X\n", channel->next_channel);
|
|
}
|