1
0
mirror of https://github.com/weechat/weechat.git synced 2026-06-27 21:36:37 +02:00
Files
weechat/src/irc/irc-channel.c
T
2006-07-23 11:19:09 +00:00

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