mirror of
https://github.com/irssi/irssi.git
synced 2026-08-11 04:43:34 +02:00
..adding new files..
git-svn-id: http://svn.irssi.org/repos/irssi/trunk@171 dbcabf3a-b0e7-0310-adc4-f8d773084564
This commit is contained in:
parent
d01b094151
commit
c95034c6de
206 changed files with 31247 additions and 0 deletions
5
src/irc/Makefile.am
Normal file
5
src/irc/Makefile.am
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
SUBDIRS = core dcc flood notifylist
|
||||
|
||||
noinst_LTLIBRARIES = libirc.la
|
||||
|
||||
libirc_la_SOURCES = irc.c
|
||||
61
src/irc/core/Makefile.am
Normal file
61
src/irc/core/Makefile.am
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
noinst_LTLIBRARIES = libirc_core.la
|
||||
|
||||
INCLUDES = \
|
||||
$(GLIB_CFLAGS) \
|
||||
-DSYSCONFDIR=\""$(sysconfdir)"\" \
|
||||
-I$(top_srcdir)/src -I$(top_srcdir)/src/core
|
||||
|
||||
libirc_core_la_SOURCES = \
|
||||
bans.c \
|
||||
ctcp.c \
|
||||
channels.c \
|
||||
channels-query.c \
|
||||
channels-setup.c \
|
||||
channel-events.c \
|
||||
ignore.c \
|
||||
irc.c \
|
||||
irc-core.c \
|
||||
irc-commands.c \
|
||||
irc-rawlog.c \
|
||||
irc-server.c \
|
||||
irc-special-vars.c \
|
||||
ircnet-setup.c \
|
||||
lag.c \
|
||||
masks.c \
|
||||
massjoin.c \
|
||||
modes.c \
|
||||
mode-lists.c \
|
||||
netsplit.c \
|
||||
nicklist.c \
|
||||
query.c \
|
||||
server-idle.c \
|
||||
server-reconnect.c \
|
||||
server-setup.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
bans.h \
|
||||
ctcp.h \
|
||||
channels.h \
|
||||
channels-query.h \
|
||||
channels-setup.h \
|
||||
channel-events.h \
|
||||
ignore.h \
|
||||
irc.h \
|
||||
irc-core.h \
|
||||
irc-commands.h \
|
||||
irc-rawlog.h \
|
||||
irc-server.h \
|
||||
irc-special-vars.h \
|
||||
ircnet-setup.h \
|
||||
lag.h \
|
||||
masks.h \
|
||||
massjoin.h \
|
||||
modes.h \
|
||||
mode-lists.h \
|
||||
module.h \
|
||||
netsplit.h \
|
||||
nicklist.h \
|
||||
query.h \
|
||||
server-idle.h \
|
||||
server-reconnect.h \
|
||||
server-setup.h
|
||||
218
src/irc/core/bans.c
Normal file
218
src/irc/core/bans.c
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
bans.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
|
||||
#include "commands.h"
|
||||
#include "misc.h"
|
||||
#include "signals.h"
|
||||
|
||||
#include "masks.h"
|
||||
#include "modes.h"
|
||||
#include "mode-lists.h"
|
||||
#include "irc.h"
|
||||
#include "nicklist.h"
|
||||
|
||||
static int bantype;
|
||||
|
||||
/* Get ban mask */
|
||||
char *ban_get_mask(CHANNEL_REC *channel, const char *nick)
|
||||
{
|
||||
NICK_REC *rec;
|
||||
char *str, *user, *host;
|
||||
|
||||
g_return_val_if_fail(channel != NULL, NULL);
|
||||
g_return_val_if_fail(nick != NULL, NULL);
|
||||
|
||||
rec = nicklist_find(channel, nick);
|
||||
if (rec == NULL || rec->host == NULL) return NULL;
|
||||
|
||||
str = irc_get_mask(nick, rec->host, bantype);
|
||||
|
||||
/* there's a limit of 10 characters in user mask. so, banning
|
||||
someone with user mask of 10 characters gives us "*1234567890",
|
||||
which is one too much.. so, replace the 10th character with '*' */
|
||||
user = strchr(str, '!');
|
||||
if (user == NULL) return str;
|
||||
|
||||
host = strchr(++user, '@');
|
||||
if (host == NULL) return str;
|
||||
|
||||
if ((int) (host-user) < 10) {
|
||||
/* too long user mask */
|
||||
user[9] = '*';
|
||||
g_memmove(user+10, host, strlen(host)+1);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
void ban_set_type(const char *type)
|
||||
{
|
||||
char bantypestr[5], **list;
|
||||
int n, max;
|
||||
|
||||
g_return_if_fail(type != NULL);
|
||||
|
||||
if (toupper(type[0]) == 'N') {
|
||||
bantype = IRC_MASK_USER | IRC_MASK_DOMAIN;
|
||||
strcpy(bantypestr, "UD");
|
||||
}
|
||||
else if (toupper(type[0]) == 'H') {
|
||||
bantype = IRC_MASK_HOST | IRC_MASK_DOMAIN;
|
||||
strcpy(bantypestr, "HD");
|
||||
}
|
||||
else if (toupper(type[0]) == 'D') {
|
||||
bantype = IRC_MASK_DOMAIN;
|
||||
strcpy(bantypestr, "D");
|
||||
}
|
||||
else if (toupper(type[0]) == 'C') {
|
||||
list = g_strsplit(type, " ", -1);
|
||||
|
||||
max = strarray_length(list);
|
||||
bantype = 0;
|
||||
for (n = 1; n < max; n++) {
|
||||
if (toupper(list[n][0]) == 'N')
|
||||
bantype |= IRC_MASK_NICK;
|
||||
else if (toupper(list[n][0]) == 'U')
|
||||
bantype |= IRC_MASK_USER;
|
||||
else if (toupper(list[n][0]) == 'H')
|
||||
bantype |= IRC_MASK_HOST;
|
||||
else if (toupper(list[n][0]) == 'D')
|
||||
bantype |= IRC_MASK_DOMAIN;
|
||||
}
|
||||
g_strfreev(list);
|
||||
|
||||
bantypestr[0] = '\0';
|
||||
if (bantype & IRC_MASK_NICK) strcat(bantypestr, "N");
|
||||
if (bantype & IRC_MASK_USER) strcat(bantypestr, "U");
|
||||
if (bantype & IRC_MASK_HOST) strcat(bantypestr, "H");
|
||||
if (bantype & IRC_MASK_DOMAIN) strcat(bantypestr, "D");
|
||||
}
|
||||
|
||||
signal_emit("ban type changed", 1, bantypestr);
|
||||
}
|
||||
|
||||
void ban_set(CHANNEL_REC *channel, const char *bans)
|
||||
{
|
||||
GString *str;
|
||||
char **ban, **banlist;
|
||||
|
||||
g_return_if_fail(bans != NULL);
|
||||
|
||||
str = g_string_new(NULL);
|
||||
banlist = g_strsplit(bans, " ", -1);
|
||||
for (ban = banlist; *ban != NULL; ban++) {
|
||||
if (strchr(*ban, '!') != NULL) {
|
||||
/* explicit ban */
|
||||
g_string_sprintfa(str, " %s", *ban);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ban nick */
|
||||
*ban = ban_get_mask(channel, *ban);
|
||||
if (*ban != NULL) {
|
||||
g_string_sprintfa(str, " %s", *ban);
|
||||
g_free(*ban);
|
||||
}
|
||||
}
|
||||
g_strfreev(banlist);
|
||||
|
||||
channel_set_singlemode(channel->server, channel->name, str->str, "+b");
|
||||
g_string_free(str, TRUE);
|
||||
}
|
||||
|
||||
void ban_remove(CHANNEL_REC *channel, const char *bans)
|
||||
{
|
||||
GString *str;
|
||||
GSList *tmp;
|
||||
char **ban, **banlist;
|
||||
|
||||
str = g_string_new(NULL);
|
||||
banlist = g_strsplit(bans, " ", -1);
|
||||
for (ban = banlist; *ban != NULL; ban++) {
|
||||
for (tmp = channel->banlist; tmp != NULL; tmp = tmp->next) {
|
||||
BAN_REC *rec = tmp->data;
|
||||
|
||||
if (match_wildcards(*ban, rec->ban))
|
||||
g_string_sprintfa(str, "%s ", rec->ban);
|
||||
}
|
||||
}
|
||||
g_strfreev(banlist);
|
||||
|
||||
channel_set_singlemode(channel->server, channel->name, str->str, "-b");
|
||||
g_string_free(str, TRUE);
|
||||
}
|
||||
|
||||
static void command_set_ban(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item, int set)
|
||||
{
|
||||
CHANNEL_REC *chanrec;
|
||||
char *params, *channel, *nicks;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
params = cmd_get_params(data, 2 | PARAM_FLAG_OPTCHAN | PARAM_FLAG_GETREST,
|
||||
item, &channel, &nicks);
|
||||
if (!ischannel(*channel)) cmd_param_error(CMDERR_NOT_JOINED);
|
||||
if (*nicks == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
chanrec = channel_find(server, channel);
|
||||
if (chanrec == NULL) cmd_param_error(CMDERR_CHAN_NOT_FOUND);
|
||||
if (!chanrec->wholist) cmd_param_error(CMDERR_CHAN_NOT_SYNCED);
|
||||
|
||||
if (set)
|
||||
ban_set(chanrec, nicks);
|
||||
else
|
||||
ban_remove(chanrec, nicks);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void cmd_bantype(const char *data)
|
||||
{
|
||||
ban_set_type(data);
|
||||
}
|
||||
|
||||
static void cmd_ban(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
command_set_ban(data, server, item, TRUE);
|
||||
}
|
||||
|
||||
static void cmd_unban(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
command_set_ban(data, server, item, FALSE);
|
||||
}
|
||||
|
||||
void bans_init(void)
|
||||
{
|
||||
/* default bantype */
|
||||
bantype = IRC_MASK_USER | IRC_MASK_DOMAIN;
|
||||
command_bind("bantype", NULL, (SIGNAL_FUNC) cmd_bantype);
|
||||
command_bind("ban", NULL, (SIGNAL_FUNC) cmd_ban);
|
||||
command_bind("unban", NULL, (SIGNAL_FUNC) cmd_unban);
|
||||
}
|
||||
|
||||
void bans_deinit(void)
|
||||
{
|
||||
command_unbind("bantype", (SIGNAL_FUNC) cmd_bantype);
|
||||
command_unbind("ban", (SIGNAL_FUNC) cmd_ban);
|
||||
command_unbind("unban", (SIGNAL_FUNC) cmd_unban);
|
||||
}
|
||||
15
src/irc/core/bans.h
Normal file
15
src/irc/core/bans.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef __BANS_H
|
||||
#define __BANS_H
|
||||
|
||||
#include "channels.h"
|
||||
|
||||
void bans_init(void);
|
||||
void bans_deinit(void);
|
||||
|
||||
char *ban_get_mask(CHANNEL_REC *channel, const char *nick);
|
||||
|
||||
void ban_set_type(const char *type);
|
||||
void ban_set(CHANNEL_REC *channel, const char *bans);
|
||||
void ban_remove(CHANNEL_REC *channel, const char *ban);
|
||||
|
||||
#endif
|
||||
241
src/irc/core/channel-events.c
Normal file
241
src/irc/core/channel-events.c
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
channel-events.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
|
||||
#include "misc.h"
|
||||
#include "channels.h"
|
||||
#include "irc.h"
|
||||
|
||||
static void event_cannot_join(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
CHANNEL_REC *chanrec;
|
||||
char *params, *channel;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 2, NULL, &channel);
|
||||
|
||||
if (channel[0] == '!' && channel[1] == '!')
|
||||
channel++; /* server didn't understand !channels */
|
||||
|
||||
chanrec = channel_find(server, channel);
|
||||
if (chanrec != NULL && !chanrec->names_got) {
|
||||
chanrec->left = TRUE;
|
||||
channel_destroy(chanrec);
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_target_unavailable(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *channel;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 2, NULL, &channel);
|
||||
if (ischannel(*channel)) {
|
||||
/* channel is unavailable. */
|
||||
event_cannot_join(data, server);
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void channel_change_topic(IRC_SERVER_REC *server, const char *channel, const char *topic)
|
||||
{
|
||||
CHANNEL_REC *chanrec;
|
||||
|
||||
chanrec = channel_find(server, channel);
|
||||
if (chanrec != NULL) {
|
||||
g_free_not_null(chanrec->topic);
|
||||
chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
|
||||
|
||||
signal_emit("channel topic changed", 1, chanrec);
|
||||
}
|
||||
}
|
||||
static void event_topic_get(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *channel, *topic;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 3, NULL, &channel, &topic);
|
||||
channel_change_topic(server, channel, topic);
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_topic(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *channel, *topic;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 2, &channel, &topic);
|
||||
channel_change_topic(server, channel, topic);
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_join(const char *data, IRC_SERVER_REC *server, const char *nick, const char *address)
|
||||
{
|
||||
char *params, *channel, *tmp;
|
||||
CHANNEL_REC *chanrec;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
if (g_strcasecmp(nick, server->nick) != 0) {
|
||||
/* someone else joined channel, no need to do anything */
|
||||
return;
|
||||
}
|
||||
|
||||
if (server->userhost == NULL)
|
||||
server->userhost = g_strdup(address);
|
||||
|
||||
params = event_get_params(data, 1, &channel);
|
||||
tmp = strchr(channel, 7); /* ^G does something weird.. */
|
||||
if (tmp != NULL) *tmp = '\0';
|
||||
|
||||
if (*channel == '!') {
|
||||
/* !channels have 5 chars long identification string before
|
||||
it's name, it's not known when /join is called so rename
|
||||
!channel here to !ABCDEchannel */
|
||||
char *shortchan;
|
||||
|
||||
shortchan = g_strdup(channel);
|
||||
sprintf(shortchan, "!%s", channel+6);
|
||||
|
||||
chanrec = channel_find(server, shortchan);
|
||||
if (chanrec != NULL) {
|
||||
g_free(chanrec->name);
|
||||
chanrec->name = g_strdup(channel);
|
||||
}
|
||||
|
||||
g_free(shortchan);
|
||||
}
|
||||
|
||||
chanrec = channel_find(server, channel);
|
||||
if (chanrec == NULL) {
|
||||
/* didn't get here with /join command.. */
|
||||
chanrec = channel_create(server, channel, TRUE);
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_part(const char *data, IRC_SERVER_REC *server, const char *nick)
|
||||
{
|
||||
char *params, *channel, *reason;
|
||||
CHANNEL_REC *chanrec;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
if (g_strcasecmp(nick, server->nick) != 0) {
|
||||
/* someone else part, no need to do anything here */
|
||||
return;
|
||||
}
|
||||
|
||||
params = event_get_params(data, 2, &channel, &reason);
|
||||
|
||||
chanrec = channel_find(server, channel);
|
||||
if (chanrec != NULL) {
|
||||
chanrec->left = TRUE;
|
||||
channel_destroy(chanrec);
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_kick(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
CHANNEL_REC *chanrec;
|
||||
char *params, *channel, *nick, *reason;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 3, &channel, &nick, &reason);
|
||||
|
||||
if (g_strcasecmp(nick, server->nick) != 0) {
|
||||
/* someone else was kicked, no need to do anything */
|
||||
g_free(params);
|
||||
return;
|
||||
}
|
||||
|
||||
chanrec = channel_find(server, channel);
|
||||
if (chanrec != NULL) {
|
||||
chanrec->kicked = TRUE;
|
||||
channel_destroy(chanrec);
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_invite(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *channel;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 2, NULL, &channel);
|
||||
g_free_not_null(server->last_invite);
|
||||
server->last_invite = g_strdup(channel);
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
void channel_events_init(void)
|
||||
{
|
||||
signal_add_first("event 403", (SIGNAL_FUNC) event_cannot_join); /* no such channel */
|
||||
signal_add_first("event 405", (SIGNAL_FUNC) event_cannot_join); /* too many channels */
|
||||
signal_add_first("event 407", (SIGNAL_FUNC) event_cannot_join); /* duplicate channel */
|
||||
signal_add_first("event 471", (SIGNAL_FUNC) event_cannot_join); /* channel is full */
|
||||
signal_add_first("event 473", (SIGNAL_FUNC) event_cannot_join); /* invite only */
|
||||
signal_add_first("event 474", (SIGNAL_FUNC) event_cannot_join); /* banned */
|
||||
signal_add_first("event 475", (SIGNAL_FUNC) event_cannot_join); /* bad channel key */
|
||||
signal_add_first("event 476", (SIGNAL_FUNC) event_cannot_join); /* bad channel mask */
|
||||
|
||||
signal_add("event topic", (SIGNAL_FUNC) event_topic);
|
||||
signal_add("event join", (SIGNAL_FUNC) event_join);
|
||||
signal_add("event part", (SIGNAL_FUNC) event_part);
|
||||
signal_add("event kick", (SIGNAL_FUNC) event_kick);
|
||||
signal_add("event invite", (SIGNAL_FUNC) event_invite);
|
||||
signal_add("event 332", (SIGNAL_FUNC) event_topic_get);
|
||||
signal_add_first("event 437", (SIGNAL_FUNC) event_target_unavailable); /* channel/nick unavailable */
|
||||
}
|
||||
|
||||
void channel_events_deinit(void)
|
||||
{
|
||||
signal_remove("event 403", (SIGNAL_FUNC) event_cannot_join); /* no such channel */
|
||||
signal_remove("event 405", (SIGNAL_FUNC) event_cannot_join); /* too many channels */
|
||||
signal_remove("event 407", (SIGNAL_FUNC) event_cannot_join); /* duplicate channel */
|
||||
signal_remove("event 471", (SIGNAL_FUNC) event_cannot_join); /* channel is full */
|
||||
signal_remove("event 473", (SIGNAL_FUNC) event_cannot_join); /* invite only */
|
||||
signal_remove("event 474", (SIGNAL_FUNC) event_cannot_join); /* banned */
|
||||
signal_remove("event 475", (SIGNAL_FUNC) event_cannot_join); /* bad channel key */
|
||||
signal_remove("event 476", (SIGNAL_FUNC) event_cannot_join); /* bad channel mask */
|
||||
|
||||
signal_remove("event topic", (SIGNAL_FUNC) event_topic);
|
||||
signal_remove("event join", (SIGNAL_FUNC) event_join);
|
||||
signal_remove("event part", (SIGNAL_FUNC) event_part);
|
||||
signal_remove("event kick", (SIGNAL_FUNC) event_kick);
|
||||
signal_remove("event invite", (SIGNAL_FUNC) event_invite);
|
||||
signal_remove("event 332", (SIGNAL_FUNC) event_topic_get);
|
||||
signal_remove("event 437", (SIGNAL_FUNC) event_target_unavailable); /* channel/nick unavailable */
|
||||
}
|
||||
7
src/irc/core/channel-events.h
Normal file
7
src/irc/core/channel-events.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef __CHANNEL_EVENTS_H
|
||||
#define __CHANNEL_EVENTS_H
|
||||
|
||||
void channel_events_init(void);
|
||||
void channel_events_deinit(void);
|
||||
|
||||
#endif
|
||||
594
src/irc/core/channels-query.c
Normal file
594
src/irc/core/channels-query.c
Normal file
|
|
@ -0,0 +1,594 @@
|
|||
/*
|
||||
channels-query.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
How the thing works:
|
||||
|
||||
- After channel is joined and NAMES list is got, send "channel query" signal
|
||||
- "channel query" : add channel to server->quries lists
|
||||
|
||||
loop:
|
||||
- Wait for NAMES list from all channels before doing anything else..
|
||||
- After got the last NAMES list, start sending the queries ..
|
||||
- find the query to send, check where server->queries list isn't NULL
|
||||
(mode, who, banlist, ban exceptions, invite list)
|
||||
- if not found anything -> all channels are synced
|
||||
- send "command #chan1,#chan2,#chan3,.." command to server
|
||||
- wait for reply from server, then check if it was last query to be sent to
|
||||
server. If it was, send "channel sync" signal
|
||||
- check if the reply was for last channel in the command list. If so,
|
||||
goto loop
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "modules.h"
|
||||
#include "misc.h"
|
||||
#include "signals.h"
|
||||
|
||||
#include "channels.h"
|
||||
#include "irc.h"
|
||||
#include "modes.h"
|
||||
#include "mode-lists.h"
|
||||
#include "nicklist.h"
|
||||
#include "irc-server.h"
|
||||
#include "server-redirect.h"
|
||||
|
||||
enum {
|
||||
CHANNEL_QUERY_MODE,
|
||||
CHANNEL_QUERY_WHO,
|
||||
CHANNEL_QUERY_BMODE,
|
||||
CHANNEL_QUERY_EMODE,
|
||||
CHANNEL_QUERY_IMODE,
|
||||
|
||||
CHANNEL_QUERIES
|
||||
};
|
||||
|
||||
#define CHANNEL_IS_MODE_QUERY(a) ((a) != CHANNEL_QUERY_WHO)
|
||||
|
||||
typedef struct {
|
||||
char *last_query_chan;
|
||||
GSList *queries[CHANNEL_QUERIES];
|
||||
} SERVER_QUERY_REC;
|
||||
|
||||
static void sig_connected(IRC_SERVER_REC *server)
|
||||
{
|
||||
SERVER_QUERY_REC *rec;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
if (!irc_server_check(server)) return;
|
||||
|
||||
rec = g_new0(SERVER_QUERY_REC, 1);
|
||||
server->chanqueries = rec;
|
||||
}
|
||||
|
||||
static void sig_disconnected(IRC_SERVER_REC *server)
|
||||
{
|
||||
SERVER_QUERY_REC *rec;
|
||||
int n;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
if (!irc_server_check(server)) return;
|
||||
|
||||
rec = server->chanqueries;
|
||||
g_return_if_fail(rec != NULL);
|
||||
|
||||
for (n = 0; n < CHANNEL_QUERIES; n++)
|
||||
g_slist_free(rec->queries[n]);
|
||||
g_free_not_null(rec->last_query_chan);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
/* Add channel to query list */
|
||||
static void channel_query_add(CHANNEL_REC *channel, int query)
|
||||
{
|
||||
SERVER_QUERY_REC *rec;
|
||||
|
||||
g_return_if_fail(channel != NULL);
|
||||
|
||||
rec = channel->server->chanqueries;
|
||||
g_return_if_fail(rec != NULL);
|
||||
|
||||
rec->queries[query] = g_slist_append(rec->queries[query], channel);
|
||||
}
|
||||
|
||||
static void channel_query_remove_all(CHANNEL_REC *channel)
|
||||
{
|
||||
SERVER_QUERY_REC *rec;
|
||||
int n;
|
||||
|
||||
rec = channel->server->chanqueries;
|
||||
g_return_if_fail(rec != NULL);
|
||||
|
||||
/* remove channel from query lists */
|
||||
for (n = 0; n < CHANNEL_QUERIES; n++)
|
||||
rec->queries[n] = g_slist_remove(rec->queries[n], channel);
|
||||
}
|
||||
|
||||
|
||||
static void sig_channel_destroyed(CHANNEL_REC *channel)
|
||||
{
|
||||
g_return_if_fail(channel != NULL);
|
||||
|
||||
if (channel->server != NULL && !channel->synced)
|
||||
channel_query_remove_all(channel);
|
||||
}
|
||||
|
||||
static int channels_have_all_names(IRC_SERVER_REC *server)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
|
||||
CHANNEL_REC *rec = tmp->data;
|
||||
|
||||
if (!rec->names_got)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int find_next_query(SERVER_QUERY_REC *server)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; n < CHANNEL_QUERIES; n++) {
|
||||
if (server->queries[n] != NULL)
|
||||
return n;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void channel_send_query(IRC_SERVER_REC *server, int query)
|
||||
{
|
||||
SERVER_QUERY_REC *rec;
|
||||
CHANNEL_REC *chanrec;
|
||||
GSList *tmp, *chans;
|
||||
char *cmd, *chanstr_commas, *chanstr;
|
||||
int onlyone;
|
||||
|
||||
rec = server->chanqueries;
|
||||
g_return_if_fail(rec != NULL);
|
||||
|
||||
onlyone = (server->no_multi_who && query == CHANNEL_QUERY_WHO) ||
|
||||
(server->no_multi_mode && CHANNEL_IS_MODE_QUERY(query));
|
||||
|
||||
if (onlyone) {
|
||||
chanrec = rec->queries[query]->data;
|
||||
chans = g_slist_append(NULL, chanrec);
|
||||
chanstr_commas = g_strdup(chanrec->name);
|
||||
chanstr = g_strdup(chanrec->name);
|
||||
} else {
|
||||
char *chanstr_spaces;
|
||||
|
||||
chans = rec->queries[query];
|
||||
|
||||
chanstr_commas = gslist_to_string(rec->queries[query], G_STRUCT_OFFSET(CHANNEL_REC, name), ",");
|
||||
chanstr_spaces = gslist_to_string(rec->queries[query], G_STRUCT_OFFSET(CHANNEL_REC, name), " ");
|
||||
|
||||
chanstr = g_strconcat(chanstr_commas, " ", chanstr_spaces, NULL);
|
||||
g_free(chanstr_spaces);
|
||||
}
|
||||
|
||||
switch (query) {
|
||||
case CHANNEL_QUERY_MODE:
|
||||
cmd = g_strdup_printf("MODE %s", chanstr_commas);
|
||||
for (tmp = chans; tmp != NULL; tmp = tmp->next) {
|
||||
chanrec = tmp->data;
|
||||
|
||||
server_redirect_event((SERVER_REC *) server, chanstr, 3,
|
||||
"event 403", "chanquery mode abort", 1,
|
||||
"event 442", "chanquery mode abort", 1, /* "you're not on that channel" */
|
||||
"event 324", "chanquery mode", 1, NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case CHANNEL_QUERY_WHO:
|
||||
cmd = g_strdup_printf("WHO %s", chanstr_commas);
|
||||
|
||||
for (tmp = chans; tmp != NULL; tmp = tmp->next) {
|
||||
chanrec = tmp->data;
|
||||
|
||||
server_redirect_event((SERVER_REC *) server, chanstr, 2,
|
||||
"event 401", "chanquery who abort", 1,
|
||||
"event 315", "chanquery who end", 1,
|
||||
"event 352", "silent event who", 1, NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case CHANNEL_QUERY_BMODE:
|
||||
cmd = g_strdup_printf("MODE %s b", chanstr_commas);
|
||||
for (tmp = chans; tmp != NULL; tmp = tmp->next) {
|
||||
chanrec = tmp->data;
|
||||
|
||||
server_redirect_event((SERVER_REC *) server, chanrec->name, 2,
|
||||
"event 403", "chanquery mode abort", 1,
|
||||
"event 368", "chanquery ban end", 1,
|
||||
"event 367", "chanquery ban", 1, NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case CHANNEL_QUERY_EMODE:
|
||||
cmd = g_strdup_printf("MODE %s e", chanstr_commas);
|
||||
for (tmp = chans; tmp != NULL; tmp = tmp->next) {
|
||||
chanrec = tmp->data;
|
||||
|
||||
server_redirect_event((SERVER_REC *) server, chanrec->name, 4,
|
||||
"event 403", "chanquery mode abort", 1,
|
||||
"event 349", "chanquery eban end", 1,
|
||||
"event 348", "chanquery eban", 1, NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case CHANNEL_QUERY_IMODE:
|
||||
cmd = g_strdup_printf("MODE %s I", chanstr_commas);
|
||||
for (tmp = chans; tmp != NULL; tmp = tmp->next) {
|
||||
chanrec = tmp->data;
|
||||
|
||||
server_redirect_event((SERVER_REC *) server, chanrec->name, 4,
|
||||
"event 403", "chanquery mode abort", 1,
|
||||
"event 347", "chanquery ilist end", 1,
|
||||
"event 346", "chanquery ilist", 1, NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
cmd = NULL;
|
||||
}
|
||||
|
||||
g_free(chanstr);
|
||||
g_free(chanstr_commas);
|
||||
|
||||
/* Get the channel of last query */
|
||||
chanrec = g_slist_last(chans)->data;
|
||||
rec->last_query_chan = g_strdup(chanrec->name);
|
||||
|
||||
if (!onlyone) {
|
||||
/* all channels queried, set to NULL */
|
||||
g_slist_free(rec->queries[query]);
|
||||
rec->queries[query] = NULL;
|
||||
} else {
|
||||
/* remove the first channel from list */
|
||||
rec->queries[query] = g_slist_remove(rec->queries[query], chans->data);
|
||||
}
|
||||
|
||||
/* send the command */
|
||||
irc_send_cmd(server, cmd);
|
||||
g_free(cmd);
|
||||
}
|
||||
|
||||
static void channels_query_check(IRC_SERVER_REC *server)
|
||||
{
|
||||
SERVER_QUERY_REC *rec;
|
||||
int query;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
rec = server->chanqueries;
|
||||
g_return_if_fail(rec != NULL);
|
||||
|
||||
g_free_and_null(rec->last_query_chan);
|
||||
if (!channels_have_all_names(server)) {
|
||||
/* all channels haven't sent /NAMES list yet */
|
||||
return;
|
||||
}
|
||||
|
||||
query = find_next_query(rec);
|
||||
if (query == -1) {
|
||||
/* no queries left */
|
||||
return;
|
||||
}
|
||||
|
||||
channel_send_query(server, query);
|
||||
}
|
||||
|
||||
static void sig_channel_query(CHANNEL_REC *channel)
|
||||
{
|
||||
SERVER_QUERY_REC *rec;
|
||||
|
||||
g_return_if_fail(channel != NULL);
|
||||
|
||||
/* Add channel to query lists */
|
||||
if (!channel->no_modes)
|
||||
channel_query_add(channel, CHANNEL_QUERY_MODE);
|
||||
channel_query_add(channel, CHANNEL_QUERY_WHO);
|
||||
if (!channel->no_modes) {
|
||||
channel_query_add(channel, CHANNEL_QUERY_BMODE);
|
||||
if (channel->server->emode_known) {
|
||||
channel_query_add(channel, CHANNEL_QUERY_EMODE);
|
||||
channel_query_add(channel, CHANNEL_QUERY_IMODE);
|
||||
}
|
||||
}
|
||||
|
||||
rec = channel->server->chanqueries;
|
||||
if (rec->last_query_chan == NULL)
|
||||
channels_query_check(channel->server);
|
||||
}
|
||||
|
||||
/* if there's no more queries in queries in buffer, send the sync signal */
|
||||
static void channel_checksync(CHANNEL_REC *channel)
|
||||
{
|
||||
SERVER_QUERY_REC *rec;
|
||||
int n;
|
||||
|
||||
g_return_if_fail(channel != NULL);
|
||||
|
||||
if (channel->synced)
|
||||
return; /* already synced */
|
||||
|
||||
rec = channel->server->chanqueries;
|
||||
g_return_if_fail(rec != NULL);
|
||||
|
||||
for (n = 0; n < CHANNEL_QUERIES; n++) {
|
||||
if (g_slist_find(rec->queries[n], channel))
|
||||
return;
|
||||
}
|
||||
|
||||
channel->synced = TRUE;
|
||||
signal_emit("channel sync", 1, channel);
|
||||
}
|
||||
|
||||
static void channel_got_query(IRC_SERVER_REC *server, CHANNEL_REC *chanrec, const char *channel)
|
||||
{
|
||||
SERVER_QUERY_REC *rec;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
g_return_if_fail(channel != NULL);
|
||||
|
||||
rec = server->chanqueries;
|
||||
g_return_if_fail(rec != NULL);
|
||||
g_return_if_fail(rec->last_query_chan != NULL);
|
||||
|
||||
/* check if we need to get another query.. */
|
||||
if (g_strcasecmp(rec->last_query_chan, channel) == 0)
|
||||
channels_query_check(server);
|
||||
|
||||
/* check if channel is synced */
|
||||
if (chanrec != NULL) channel_checksync(chanrec);
|
||||
}
|
||||
|
||||
static void event_channel_mode(char *data, IRC_SERVER_REC *server, const char *nick)
|
||||
{
|
||||
CHANNEL_REC *chanrec;
|
||||
char *params, *channel, *mode;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 3 | PARAM_FLAG_GETREST, NULL, &channel, &mode);
|
||||
chanrec = channel_find(server, channel);
|
||||
if (chanrec != NULL)
|
||||
parse_channel_modes(chanrec, nick, mode);
|
||||
channel_got_query(server, chanrec, channel);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void multi_query_remove(IRC_SERVER_REC *server, const char *event, const char *data)
|
||||
{
|
||||
GSList *queue;
|
||||
|
||||
while ((queue = server_redirect_getqueue((SERVER_REC *) server, event, data)) != NULL)
|
||||
server_redirect_remove_next((SERVER_REC *) server, event, queue);
|
||||
}
|
||||
|
||||
static void event_end_of_who(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
CHANNEL_REC *chanrec;
|
||||
NICK_REC *nick;
|
||||
char *params, *channel, **chans;
|
||||
int n, onewho;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 2, NULL, &channel);
|
||||
|
||||
onewho = strchr(channel, ',') != NULL;
|
||||
if (onewho) {
|
||||
/* instead of multiple End of WHO replies we get
|
||||
only this one... */
|
||||
server->one_endofwho = TRUE;
|
||||
multi_query_remove(server, "event 315", data);
|
||||
|
||||
/* check that the WHO actually did return something
|
||||
(that it understood #chan1,#chan2,..) */
|
||||
chanrec = channel_find(server, channel);
|
||||
nick = nicklist_find(chanrec, server->nick);
|
||||
if (nick->host == NULL)
|
||||
server->no_multi_who = TRUE;
|
||||
}
|
||||
|
||||
chans = g_strsplit(channel, ",", -1);
|
||||
for (n = 0; chans[n] != NULL; n++) {
|
||||
chanrec = channel_find(server, chans[n]);
|
||||
if (chanrec == NULL)
|
||||
continue;
|
||||
|
||||
if (onewho && server->no_multi_who) {
|
||||
channel_query_add(chanrec, CHANNEL_QUERY_WHO);
|
||||
continue;
|
||||
}
|
||||
|
||||
chanrec->wholist = TRUE;
|
||||
signal_emit("channel wholist", 1, chanrec);
|
||||
|
||||
/* check if we need can send another query */
|
||||
channel_got_query(server, chanrec, chans[n]);
|
||||
}
|
||||
|
||||
g_strfreev(chans);
|
||||
g_free(params);
|
||||
|
||||
if (onewho && server->no_multi_who) {
|
||||
/* server didn't understand multiple WHO replies,
|
||||
send them again separately */
|
||||
channels_query_check(server);
|
||||
}
|
||||
}
|
||||
|
||||
static void event_end_of_banlist(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
CHANNEL_REC *chanrec;
|
||||
char *params, *channel;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 2, NULL, &channel);
|
||||
chanrec = channel_find(server, channel);
|
||||
|
||||
channel_got_query(server, chanrec, channel);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_end_of_ebanlist(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
CHANNEL_REC *chanrec;
|
||||
char *params, *channel;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 2, NULL, &channel);
|
||||
chanrec = channel_find(server, channel);
|
||||
|
||||
channel_got_query(server, chanrec, channel);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_end_of_invitelist(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
CHANNEL_REC *chanrec;
|
||||
char *params, *channel;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 2, NULL, &channel);
|
||||
chanrec = channel_find(server, channel);
|
||||
|
||||
channel_got_query(server, chanrec, channel);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void channel_lost(IRC_SERVER_REC *server, const char *channel)
|
||||
{
|
||||
CHANNEL_REC *chanrec;
|
||||
|
||||
chanrec = channel_find(server, channel);
|
||||
if (chanrec != NULL) {
|
||||
/* channel not found - probably created a new channel
|
||||
and left it immediately. */
|
||||
channel_query_remove_all(chanrec);
|
||||
}
|
||||
|
||||
channel_got_query(server, chanrec, channel);
|
||||
}
|
||||
|
||||
static void multi_command_error(IRC_SERVER_REC *server, const char *data, int query, const char *event)
|
||||
{
|
||||
CHANNEL_REC *chanrec;
|
||||
char *params, *channel, **chans;
|
||||
int n;
|
||||
|
||||
multi_query_remove(server, event, data);
|
||||
|
||||
params = event_get_params(data, 2, NULL, &channel);
|
||||
|
||||
chans = g_strsplit(channel, ",", -1);
|
||||
for (n = 0; chans[n] != NULL; n++)
|
||||
{
|
||||
chanrec = channel_find(server, chans[n]);
|
||||
if (chanrec != NULL)
|
||||
channel_query_add(chanrec, query);
|
||||
}
|
||||
g_strfreev(chans);
|
||||
g_free(params);
|
||||
|
||||
channels_query_check(server);
|
||||
}
|
||||
|
||||
static void event_mode_abort(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *channel;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
params = event_get_params(data, 2, NULL, &channel);
|
||||
|
||||
if (strchr(channel, ',') == NULL) {
|
||||
channel_lost(server, channel);
|
||||
} else {
|
||||
server->no_multi_mode = TRUE;
|
||||
multi_command_error(server, data, CHANNEL_QUERY_MODE, "event 324");
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_who_abort(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *channel;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
params = event_get_params(data, 2, NULL, &channel);
|
||||
|
||||
if (strchr(channel, ',') == NULL) {
|
||||
channel_lost(server, channel);
|
||||
} else {
|
||||
server->no_multi_who = TRUE;
|
||||
multi_command_error(server, data, CHANNEL_QUERY_WHO, "event 315");
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
void channels_query_init(void)
|
||||
{
|
||||
signal_add("server connected", (SIGNAL_FUNC) sig_connected);
|
||||
signal_add("server disconnected", (SIGNAL_FUNC) sig_disconnected);
|
||||
signal_add("channel query", (SIGNAL_FUNC) sig_channel_query);
|
||||
signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
|
||||
|
||||
signal_add("chanquery mode", (SIGNAL_FUNC) event_channel_mode);
|
||||
signal_add("chanquery who end", (SIGNAL_FUNC) event_end_of_who);
|
||||
|
||||
signal_add("chanquery eban end", (SIGNAL_FUNC) event_end_of_ebanlist);
|
||||
signal_add("chanquery ban end", (SIGNAL_FUNC) event_end_of_banlist);
|
||||
signal_add("chanquery ilist end", (SIGNAL_FUNC) event_end_of_invitelist);
|
||||
signal_add("chanquery mode abort", (SIGNAL_FUNC) event_mode_abort);
|
||||
signal_add("chanquery who abort", (SIGNAL_FUNC) event_who_abort);
|
||||
}
|
||||
|
||||
void channels_query_deinit(void)
|
||||
{
|
||||
signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
|
||||
signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
|
||||
signal_remove("channel query", (SIGNAL_FUNC) sig_channel_query);
|
||||
signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
|
||||
|
||||
signal_remove("chanquery mode", (SIGNAL_FUNC) event_channel_mode);
|
||||
signal_remove("chanquery who end", (SIGNAL_FUNC) event_end_of_who);
|
||||
|
||||
signal_remove("chanquery eban end", (SIGNAL_FUNC) event_end_of_ebanlist);
|
||||
signal_remove("chanquery ban end", (SIGNAL_FUNC) event_end_of_banlist);
|
||||
signal_remove("chanquery ilist end", (SIGNAL_FUNC) event_end_of_invitelist);
|
||||
signal_remove("chanquery mode abort", (SIGNAL_FUNC) event_mode_abort);
|
||||
signal_remove("chanquery who abort", (SIGNAL_FUNC) event_who_abort);
|
||||
}
|
||||
7
src/irc/core/channels-query.h
Normal file
7
src/irc/core/channels-query.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef __CHANNELS_QUERY
|
||||
#define __CHANNELS_QUERY
|
||||
|
||||
void channels_query_init(void);
|
||||
void channels_query_deinit(void);
|
||||
|
||||
#endif
|
||||
215
src/irc/core/channels-setup.c
Normal file
215
src/irc/core/channels-setup.c
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
channels-setup.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
|
||||
#include "channels.h"
|
||||
#include "channels-setup.h"
|
||||
#include "nicklist.h"
|
||||
#include "irc-server.h"
|
||||
#include "server-setup.h"
|
||||
|
||||
#include "lib-config/iconfig.h"
|
||||
#include "settings.h"
|
||||
|
||||
GSList *setupchannels;
|
||||
|
||||
#define ircnet_match(a, b) \
|
||||
((a[0]) == '\0' || (b != NULL && g_strcasecmp(a, b) == 0))
|
||||
|
||||
SETUP_CHANNEL_REC *channels_setup_find(const char *channel, IRC_SERVER_REC *server)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
g_return_val_if_fail(channel != NULL, NULL);
|
||||
g_return_val_if_fail(server != NULL, NULL);
|
||||
|
||||
for (tmp = setupchannels; tmp != NULL; tmp = tmp->next) {
|
||||
SETUP_CHANNEL_REC *rec = tmp->data;
|
||||
|
||||
if (g_strcasecmp(rec->name, channel) == 0 &&
|
||||
ircnet_match(rec->ircnet, server->connrec->ircnet))
|
||||
return rec;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void channels_setup_destroy(SETUP_CHANNEL_REC *channel)
|
||||
{
|
||||
g_return_if_fail(channel != NULL);
|
||||
|
||||
g_free(channel->name);
|
||||
g_free(channel->ircnet);
|
||||
g_free_not_null(channel->password);
|
||||
g_free_not_null(channel->botmasks);
|
||||
g_free_not_null(channel->autosendcmd);
|
||||
g_free_not_null(channel->background);
|
||||
g_free_not_null(channel->font);
|
||||
g_free(channel);
|
||||
|
||||
setupchannels = g_slist_remove(setupchannels, channel);
|
||||
}
|
||||
|
||||
/* connected to server, autojoin to channels. */
|
||||
static void event_connected(IRC_SERVER_REC *server)
|
||||
{
|
||||
GString *chans, *keys;
|
||||
GSList *tmp;
|
||||
int use_keys;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
if (server->connrec->reconnection)
|
||||
return;
|
||||
|
||||
/* join to the channels marked with autojoin in setup */
|
||||
chans = g_string_new(NULL);
|
||||
keys = g_string_new(NULL);
|
||||
|
||||
use_keys = FALSE;
|
||||
for (tmp = setupchannels; tmp != NULL; tmp = tmp->next) {
|
||||
SETUP_CHANNEL_REC *rec = tmp->data;
|
||||
|
||||
if (!rec->autojoin || !ircnet_match(rec->ircnet, server->connrec->ircnet))
|
||||
continue;
|
||||
|
||||
g_string_sprintfa(chans, "%s,", rec->name);
|
||||
g_string_sprintfa(keys, "%s,", rec->password == NULL ? "x" : rec->password);
|
||||
if (rec->password != NULL)
|
||||
use_keys = TRUE;
|
||||
}
|
||||
|
||||
if (chans->len > 0) {
|
||||
g_string_truncate(chans, chans->len-1);
|
||||
g_string_truncate(keys, keys->len-1);
|
||||
if (use_keys) g_string_sprintfa(chans, " %s", keys->str);
|
||||
|
||||
channels_join(server, chans->str, TRUE);
|
||||
}
|
||||
|
||||
g_string_free(chans, TRUE);
|
||||
g_string_free(keys, TRUE);
|
||||
}
|
||||
|
||||
/* channel wholist received: send the auto send command */
|
||||
static void channel_wholist(CHANNEL_REC *channel)
|
||||
{
|
||||
SETUP_CHANNEL_REC *rec;
|
||||
NICK_REC *nick;
|
||||
char **bots, **bot, *str;
|
||||
|
||||
g_return_if_fail(channel != NULL);
|
||||
|
||||
rec = channels_setup_find(channel->name, channel->server);
|
||||
if (rec == NULL || rec->autosendcmd == NULL || !*rec->autosendcmd)
|
||||
return;
|
||||
|
||||
if (rec->botmasks == NULL || !*rec->botmasks) {
|
||||
/* just send the command. */
|
||||
signal_emit("send command", 3, rec->autosendcmd, channel->server, channel);
|
||||
}
|
||||
|
||||
/* find first available bot.. */
|
||||
bots = g_strsplit(rec->botmasks, " ", -1);
|
||||
for (bot = bots; *bot != NULL; bot++) {
|
||||
nick = nicklist_find(channel, *bot);
|
||||
if (nick == NULL)
|
||||
continue;
|
||||
|
||||
/* got one! */
|
||||
str = g_strdup_printf(rec->autosendcmd, nick->nick);
|
||||
signal_emit("send command", 3, str, channel->server, channel);
|
||||
g_free(str);
|
||||
break;
|
||||
}
|
||||
g_strfreev(bots);
|
||||
}
|
||||
|
||||
static SETUP_CHANNEL_REC *setupchannel_add(CONFIG_NODE *node)
|
||||
{
|
||||
SETUP_CHANNEL_REC *rec;
|
||||
char *channel, *ircnet, *password, *botmasks, *autosendcmd, *background, *font;
|
||||
|
||||
g_return_val_if_fail(node != NULL, NULL);
|
||||
|
||||
channel = config_node_get_str(node, "name", NULL);
|
||||
ircnet = config_node_get_str(node, "ircnet", NULL);
|
||||
if (channel == NULL || ircnet == NULL) {
|
||||
/* missing information.. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
password = config_node_get_str(node, "password", NULL);
|
||||
botmasks = config_node_get_str(node, "botmasks", NULL);
|
||||
autosendcmd = config_node_get_str(node, "autosendcmd", NULL);
|
||||
background = config_node_get_str(node, "background", NULL);
|
||||
font = config_node_get_str(node, "font", NULL);
|
||||
|
||||
rec = g_new(SETUP_CHANNEL_REC, 1);
|
||||
rec->autojoin = config_node_get_bool(node, "autojoin", FALSE);
|
||||
rec->name = g_strdup(channel);
|
||||
rec->ircnet = g_strdup(ircnet);
|
||||
rec->password = (password == NULL || *password == '\0') ? NULL : g_strdup(password);
|
||||
rec->botmasks = (botmasks == NULL || *botmasks == '\0') ? NULL : g_strdup(botmasks);
|
||||
rec->autosendcmd = (autosendcmd == NULL || *autosendcmd == '\0') ? NULL : g_strdup(autosendcmd);
|
||||
rec->background = (background == NULL || *background == '\0') ? NULL : g_strdup(background);
|
||||
rec->font = (font == NULL || *font == '\0') ? NULL : g_strdup(font);
|
||||
|
||||
setupchannels = g_slist_append(setupchannels, rec);
|
||||
return rec;
|
||||
}
|
||||
|
||||
static void channels_read_config(void)
|
||||
{
|
||||
CONFIG_NODE *node;
|
||||
GSList *tmp;
|
||||
|
||||
while (setupchannels != NULL)
|
||||
channels_setup_destroy(setupchannels->data);
|
||||
|
||||
/* Read channels */
|
||||
node = iconfig_node_traverse("channels", FALSE);
|
||||
if (node != NULL) {
|
||||
for (tmp = node->value; tmp != NULL; tmp = tmp->next)
|
||||
setupchannel_add(tmp->data);
|
||||
}
|
||||
}
|
||||
|
||||
void channels_setup_init(void)
|
||||
{
|
||||
source_host_ok = FALSE;
|
||||
|
||||
channels_read_config();
|
||||
signal_add("event connected", (SIGNAL_FUNC) event_connected);
|
||||
signal_add("channel wholist", (SIGNAL_FUNC) channel_wholist);
|
||||
signal_add("setup reread", (SIGNAL_FUNC) channels_read_config);
|
||||
}
|
||||
|
||||
void channels_setup_deinit(void)
|
||||
{
|
||||
while (setupchannels != NULL)
|
||||
channels_setup_destroy(setupchannels->data);
|
||||
|
||||
signal_remove("event connected", (SIGNAL_FUNC) event_connected);
|
||||
signal_remove("channel wholist", (SIGNAL_FUNC) channel_wholist);
|
||||
signal_remove("setup reread", (SIGNAL_FUNC) channels_read_config);
|
||||
}
|
||||
27
src/irc/core/channels-setup.h
Normal file
27
src/irc/core/channels-setup.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef __CHANNELS_SETUP_H
|
||||
#define __CHANNELS_SETUP_H
|
||||
|
||||
typedef struct {
|
||||
int autojoin;
|
||||
|
||||
char *name;
|
||||
char *ircnet;
|
||||
char *password;
|
||||
|
||||
char *botmasks;
|
||||
char *autosendcmd;
|
||||
|
||||
char *background;
|
||||
char *font;
|
||||
} SETUP_CHANNEL_REC;
|
||||
|
||||
extern GSList *setupchannels;
|
||||
|
||||
void channels_setup_init(void);
|
||||
void channels_setup_deinit(void);
|
||||
|
||||
void channels_setup_destroy(SETUP_CHANNEL_REC *channel);
|
||||
|
||||
SETUP_CHANNEL_REC *channels_setup_find(const char *channel, IRC_SERVER_REC *server);
|
||||
|
||||
#endif
|
||||
231
src/irc/core/channels.c
Normal file
231
src/irc/core/channels.c
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
channels.c : irssi
|
||||
|
||||
Copyright (C) 1999 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
#include "modules.h"
|
||||
#include "misc.h"
|
||||
|
||||
#include "bans.h"
|
||||
#include "channels.h"
|
||||
#include "channel-events.h"
|
||||
#include "channels-query.h"
|
||||
#include "channels-setup.h"
|
||||
#include "irc.h"
|
||||
#include "modes.h"
|
||||
#include "levels.h"
|
||||
#include "mode-lists.h"
|
||||
#include "massjoin.h"
|
||||
#include "nicklist.h"
|
||||
|
||||
GSList *channels; /* List of all channels */
|
||||
|
||||
CHANNEL_REC *channel_create(IRC_SERVER_REC *server, const char *channel, int automatic)
|
||||
{
|
||||
CHANNEL_REC *rec;
|
||||
|
||||
g_return_val_if_fail(channel != NULL, NULL);
|
||||
|
||||
rec = g_new0(CHANNEL_REC, 1);
|
||||
channels = g_slist_append(channels, rec);
|
||||
if (server != NULL)
|
||||
server->channels = g_slist_append(server->channels, rec);
|
||||
|
||||
MODULE_DATA_INIT(rec);
|
||||
rec->type = module_get_uniq_id("IRC", WI_IRC_CHANNEL);
|
||||
rec->name = g_strdup(channel);
|
||||
rec->server = server;
|
||||
rec->createtime = time(NULL);
|
||||
|
||||
if (*channel == '+')
|
||||
rec->no_modes = TRUE;
|
||||
|
||||
signal_emit("channel created", 2, rec, GINT_TO_POINTER(automatic));
|
||||
|
||||
return rec;
|
||||
}
|
||||
|
||||
void channel_destroy(CHANNEL_REC *channel)
|
||||
{
|
||||
g_return_if_fail(channel != NULL);
|
||||
|
||||
if (channel->destroying) return;
|
||||
channel->destroying = TRUE;
|
||||
|
||||
channels = g_slist_remove(channels, channel);
|
||||
if (channel->server != NULL)
|
||||
channel->server->channels = g_slist_remove(channel->server->channels, channel);
|
||||
signal_emit("channel destroyed", 1, channel);
|
||||
|
||||
if (channel->server != NULL && !channel->left && !channel->kicked) {
|
||||
/* destroying channel record without actually left the channel yet */
|
||||
irc_send_cmdv(channel->server, "PART %s", channel->name);
|
||||
}
|
||||
|
||||
MODULE_DATA_DEINIT(channel);
|
||||
g_free_not_null(channel->topic);
|
||||
g_free_not_null(channel->key);
|
||||
g_free(channel->name);
|
||||
g_free(channel);
|
||||
}
|
||||
|
||||
static CHANNEL_REC *channel_find_server(IRC_SERVER_REC *server, const char *channel)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
|
||||
CHANNEL_REC *rec = tmp->data;
|
||||
|
||||
if (g_strcasecmp(channel, rec->name) == 0)
|
||||
return rec;
|
||||
|
||||
/* check after removing ABCDE from !ABCDEchannel */
|
||||
if (*channel == '!' && *rec->name == '!' &&
|
||||
g_strcasecmp(channel+1, rec->name+6) == 0)
|
||||
return rec;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CHANNEL_REC *channel_find(IRC_SERVER_REC *server, const char *channel)
|
||||
{
|
||||
g_return_val_if_fail(channel != NULL, NULL);
|
||||
|
||||
if (server != NULL)
|
||||
return channel_find_server(server, channel);
|
||||
|
||||
/* find from any server */
|
||||
return gslist_foreach_find(servers, (FOREACH_FIND_FUNC) channel_find_server, (void *) channel);
|
||||
}
|
||||
|
||||
|
||||
char *channel_get_mode(CHANNEL_REC *channel)
|
||||
{
|
||||
GString *mode;
|
||||
char *ret;
|
||||
|
||||
g_return_val_if_fail(channel != NULL, NULL);
|
||||
|
||||
mode = g_string_new(NULL);
|
||||
|
||||
if (channel->mode_secret) g_string_append_c(mode, 's');
|
||||
if (channel->mode_private) g_string_append_c(mode, 'p');
|
||||
if (channel->mode_moderate) g_string_append_c(mode, 'm');
|
||||
if (channel->mode_invite) g_string_append_c(mode, 'i');
|
||||
if (channel->mode_nomsgs) g_string_append_c(mode, 'n');
|
||||
if (channel->mode_optopic) g_string_append_c(mode, 't');
|
||||
if (channel->mode_anonymous) g_string_append_c(mode, 'a');
|
||||
if (channel->mode_reop) g_string_append_c(mode, 'r');
|
||||
if (channel->mode_key) g_string_append_c(mode, 'k');
|
||||
if (channel->limit > 0) g_string_append_c(mode, 'l');
|
||||
|
||||
if (channel->mode_key) g_string_sprintfa(mode, " %s", channel->key);
|
||||
if (channel->limit > 0) g_string_sprintfa(mode, " %d", channel->limit);
|
||||
|
||||
ret = mode->str;
|
||||
g_string_free(mode, FALSE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define get_join_key(key) \
|
||||
(((key) == NULL || *(key) == '\0') ? "x" : (key))
|
||||
|
||||
void channels_join(IRC_SERVER_REC *server, const char *data, int automatic)
|
||||
{
|
||||
CHANNEL_REC *chanrec;
|
||||
GString *outchans, *outkeys;
|
||||
char *params, *channels, *keys;
|
||||
char **chanlist, **keylist, **tmp, **tmpkey, *channel;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &channels, &keys);
|
||||
if (*channels == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
chanlist = g_strsplit(channels, ",", -1);
|
||||
keylist = g_strsplit(keys, ",", -1);
|
||||
|
||||
outchans = g_string_new(NULL);
|
||||
outkeys = g_string_new(NULL);
|
||||
|
||||
tmpkey = keylist;
|
||||
for (tmp = chanlist; *tmp != NULL; tmp++) {
|
||||
channel = ischannel(**tmp) ? g_strdup(*tmp) :
|
||||
g_strdup_printf("#%s", *tmp);
|
||||
|
||||
chanrec = channel_find(server, channel);
|
||||
if (chanrec != NULL) {
|
||||
/* already joined this channel */
|
||||
signal_emit("gui channel open", 1, chanrec);
|
||||
} else {
|
||||
g_string_sprintfa(outchans, "%s,", channel);
|
||||
if (*keys != '\0')
|
||||
g_string_sprintfa(outkeys, "%s,", get_join_key(*tmpkey));
|
||||
|
||||
channel_create(server, channel + (channel[0] == '!' && channel[1] == '!'), automatic);
|
||||
}
|
||||
g_free(channel);
|
||||
|
||||
if (*tmpkey != NULL)
|
||||
tmpkey++;
|
||||
}
|
||||
|
||||
if (outchans->len > 0) {
|
||||
irc_send_cmdv(server, *keys == '\0' ? "JOIN %s" : "JOIN %s %s",
|
||||
outchans->str, outkeys->str);
|
||||
}
|
||||
|
||||
g_string_free(outchans, TRUE);
|
||||
g_string_free(outkeys, TRUE);
|
||||
|
||||
g_strfreev(chanlist);
|
||||
g_strfreev(keylist);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
void channels_init(void)
|
||||
{
|
||||
channel_events_init();
|
||||
channels_query_init();
|
||||
channels_setup_init();
|
||||
|
||||
bans_init();
|
||||
modes_init();
|
||||
mode_lists_init();
|
||||
massjoin_init();
|
||||
nicklist_init();
|
||||
}
|
||||
|
||||
void channels_deinit(void)
|
||||
{
|
||||
channel_events_deinit();
|
||||
channels_query_deinit();
|
||||
channels_setup_deinit();
|
||||
|
||||
bans_deinit();
|
||||
modes_deinit();
|
||||
mode_lists_deinit();
|
||||
massjoin_deinit();
|
||||
nicklist_deinit();
|
||||
}
|
||||
73
src/irc/core/channels.h
Normal file
73
src/irc/core/channels.h
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
#ifndef __CHANNELS_H
|
||||
#define __CHANNELS_H
|
||||
|
||||
#include "irc-server.h"
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
GHashTable *module_data;
|
||||
|
||||
IRC_SERVER_REC *server;
|
||||
char *name;
|
||||
|
||||
int new_data;
|
||||
|
||||
time_t createtime;
|
||||
|
||||
GHashTable *nicks; /* list of nicks */
|
||||
GSList *banlist; /* list of bans */
|
||||
GSList *ebanlist; /* list of ban exceptions */
|
||||
GSList *invitelist; /* invite list */
|
||||
|
||||
char *topic;
|
||||
int limit; /* user limit */
|
||||
char *key; /* password key */
|
||||
|
||||
/* channel mode */
|
||||
int no_modes:1; /* channel doesn't support modes */
|
||||
int mode_invite:1;
|
||||
int mode_secret:1;
|
||||
int mode_private:1;
|
||||
int mode_moderate:1;
|
||||
int mode_nomsgs:1;
|
||||
int mode_optopic:1;
|
||||
int mode_key:1;
|
||||
int mode_anonymous:1;
|
||||
int mode_reop:1;
|
||||
|
||||
int chanop:1; /* You're a channel operator */
|
||||
|
||||
int names_got:1; /* Received /NAMES list */
|
||||
int wholist:1; /* WHO list got */
|
||||
int synced:1; /* Channel synced - all queries done */
|
||||
|
||||
int left:1; /* You just left the channel */
|
||||
int kicked:1; /* You just got kicked */
|
||||
int destroying:1;
|
||||
|
||||
time_t massjoin_start; /* Massjoin start time */
|
||||
int massjoins; /* Number of nicks waiting for massjoin signal.. */
|
||||
int last_massjoins; /* Massjoins when last checked in timeout function */
|
||||
|
||||
GSList *lastmsgs; /* List of nicks who last send message */
|
||||
GSList *lastownmsgs; /* List of nicks who last send message to you */
|
||||
} CHANNEL_REC;
|
||||
|
||||
extern GSList *channels;
|
||||
|
||||
void channels_init(void);
|
||||
void channels_deinit(void);
|
||||
|
||||
/* Create new channel record */
|
||||
CHANNEL_REC *channel_create(IRC_SERVER_REC *server, const char *channel, int automatic);
|
||||
void channel_destroy(CHANNEL_REC *channel);
|
||||
|
||||
/* find channel by name, if `server' is NULL, search from all servers */
|
||||
CHANNEL_REC *channel_find(IRC_SERVER_REC *server, const char *channel);
|
||||
|
||||
char *channel_get_mode(CHANNEL_REC *channel);
|
||||
|
||||
/* Join to channels. `data' contains channels and channel keys */
|
||||
void channels_join(IRC_SERVER_REC *server, const char *data, int automatic);
|
||||
|
||||
#endif
|
||||
193
src/irc/core/ctcp.c
Normal file
193
src/irc/core/ctcp.c
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
ctcp.c : irssi
|
||||
|
||||
Copyright (C) 1999 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
#include "levels.h"
|
||||
#include "special-vars.h"
|
||||
#include "settings.h"
|
||||
#include "irssi-version.h"
|
||||
|
||||
#include "irc.h"
|
||||
#include "irc-server.h"
|
||||
#include "server-idle.h"
|
||||
#include "ignore.h"
|
||||
|
||||
static void ctcp_queue_clean(IRC_SERVER_REC *server)
|
||||
{
|
||||
GSList *tmp, *next;
|
||||
|
||||
for (tmp = server->ctcpqueue; tmp != NULL; tmp = tmp->next) {
|
||||
next = tmp->next;
|
||||
if (!server_idle_find(server, GPOINTER_TO_INT(tmp->data)))
|
||||
server->ctcpqueue = g_slist_remove(server->ctcpqueue, tmp->data);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send CTCP reply with flood protection */
|
||||
void ctcp_send_reply(IRC_SERVER_REC *server, const char *data)
|
||||
{
|
||||
int tag;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
ctcp_queue_clean(server);
|
||||
|
||||
if (g_slist_length(server->ctcpqueue) < settings_get_int("max_ctcp_queue")) {
|
||||
/* Add to first in idle queue */
|
||||
tag = server_idle_add_first(server, data, NULL, 0, NULL);
|
||||
server->ctcpqueue = g_slist_append(server->ctcpqueue, GINT_TO_POINTER(tag));
|
||||
}
|
||||
}
|
||||
|
||||
/* CTCP ping */
|
||||
static void ctcp_ping(const char *data, IRC_SERVER_REC *server, const char *nick)
|
||||
{
|
||||
char *str;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
g_return_if_fail(server != NULL);
|
||||
g_return_if_fail(nick != NULL);
|
||||
|
||||
str = g_strdup_printf("NOTICE %s :\001PING %s\001", nick, data);
|
||||
ctcp_send_reply(server, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
/* CTCP version */
|
||||
static void ctcp_version(const char *data, IRC_SERVER_REC *server, const char *nick)
|
||||
{
|
||||
char *str, *reply;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
g_return_if_fail(nick != NULL);
|
||||
|
||||
reply = parse_special_string(settings_get_str("ctcp_version_reply"), server, NULL, "", NULL);
|
||||
str = g_strdup_printf("NOTICE %s :\001VERSION %s\001", nick, reply);
|
||||
ctcp_send_reply(server, str);
|
||||
g_free(str);
|
||||
g_free(reply);
|
||||
}
|
||||
|
||||
static void ctcp_msg(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr, const char *target)
|
||||
{
|
||||
char *args, *str;
|
||||
|
||||
if (ignore_check(server, nick, addr, target, data, MSGLEVEL_CTCPS))
|
||||
return;
|
||||
|
||||
str = g_strconcat("ctcp msg ", data, NULL);
|
||||
args = strchr(str+9, ' ');
|
||||
if (args != NULL) *args++ = '\0'; else args = "";
|
||||
|
||||
g_strdown(str+9);
|
||||
if (!signal_emit(str, 5, args, server, nick, addr, target))
|
||||
signal_emit("default ctcp msg", 5, data, server, nick, addr, target);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void ctcp_reply(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr, const char *target)
|
||||
{
|
||||
char *args, *str;
|
||||
|
||||
if (ignore_check(server, nick, addr, target, data, MSGLEVEL_CTCPS))
|
||||
return;
|
||||
|
||||
str = g_strconcat("ctcp reply ", data, NULL);
|
||||
args = strchr(str+11, ' ');
|
||||
if (args != NULL) *args++ = '\0'; else args = "";
|
||||
|
||||
g_strdown(str+11);
|
||||
if (!signal_emit(str, 5, args, server, nick, addr, target))
|
||||
signal_emit("default ctcp reply", 5, data, server, nick, addr, target);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void event_privmsg(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr)
|
||||
{
|
||||
char *params, *target, *msg, *ptr;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 2, &target, &msg);
|
||||
|
||||
/* handle only ctcp messages.. */
|
||||
if (*msg == 1) {
|
||||
/* remove the later \001 */
|
||||
ptr = strrchr(++msg, 1);
|
||||
if (ptr != NULL) *ptr = '\0';
|
||||
|
||||
signal_emit("ctcp msg", 5, msg, server, nick, addr, target);
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_notice(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr)
|
||||
{
|
||||
char *params, *target, *ptr, *msg;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 2, &target, &msg); /* Channel or nick name */
|
||||
|
||||
/* handle only ctcp replies */
|
||||
if (*msg == 1) {
|
||||
ptr = strrchr(++msg, 1);
|
||||
if (ptr != NULL) *ptr = '\0';
|
||||
|
||||
signal_emit("ctcp reply", 5, msg, server, nick, addr, target);
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void ctcp_deinit_server(IRC_SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
g_slist_free(server->ctcpqueue);
|
||||
}
|
||||
|
||||
void ctcp_init(void)
|
||||
{
|
||||
settings_add_str("misc", "ctcp_version_reply", PACKAGE" v$J - running on $sysname $sysrelease");
|
||||
settings_add_int("flood", "max_ctcp_queue", 5);
|
||||
|
||||
signal_add("server disconnected", (SIGNAL_FUNC) ctcp_deinit_server);
|
||||
signal_add("event privmsg", (SIGNAL_FUNC) event_privmsg);
|
||||
signal_add("event notice", (SIGNAL_FUNC) event_notice);
|
||||
signal_add("ctcp msg", (SIGNAL_FUNC) ctcp_msg);
|
||||
signal_add("ctcp reply", (SIGNAL_FUNC) ctcp_reply);
|
||||
signal_add("ctcp msg ping", (SIGNAL_FUNC) ctcp_ping);
|
||||
signal_add("ctcp msg version", (SIGNAL_FUNC) ctcp_version);
|
||||
}
|
||||
|
||||
void ctcp_deinit(void)
|
||||
{
|
||||
signal_remove("server disconnected", (SIGNAL_FUNC) ctcp_deinit_server);
|
||||
signal_remove("event privmsg", (SIGNAL_FUNC) event_privmsg);
|
||||
signal_remove("event notice", (SIGNAL_FUNC) event_notice);
|
||||
signal_remove("ctcp msg", (SIGNAL_FUNC) ctcp_msg);
|
||||
signal_remove("ctcp reply", (SIGNAL_FUNC) ctcp_reply);
|
||||
signal_remove("ctcp msg ping", (SIGNAL_FUNC) ctcp_ping);
|
||||
signal_remove("ctcp msg version", (SIGNAL_FUNC) ctcp_version);
|
||||
}
|
||||
10
src/irc/core/ctcp.h
Normal file
10
src/irc/core/ctcp.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef __CTCP_H
|
||||
#define __CTCP_H
|
||||
|
||||
void ctcp_init(void);
|
||||
void ctcp_deinit(void);
|
||||
|
||||
/* Send CTCP reply with flood protection */
|
||||
void ctcp_send_reply(SERVER_REC *server, gchar *data);
|
||||
|
||||
#endif
|
||||
296
src/irc/core/ignore.c
Normal file
296
src/irc/core/ignore.c
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
ignore.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
#include "misc.h"
|
||||
#include "levels.h"
|
||||
#include "lib-config/iconfig.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include "irc.h"
|
||||
#include "masks.h"
|
||||
#include "irc-server.h"
|
||||
|
||||
#include "ignore.h"
|
||||
|
||||
GSList *ignores;
|
||||
|
||||
int ignore_check(IRC_SERVER_REC *server, const char *nick, const char *host,
|
||||
const char *channel, const char *text, int level)
|
||||
{
|
||||
GSList *tmp;
|
||||
int ok, mask_len, patt_len;
|
||||
int best_mask, best_patt, best_ignore;
|
||||
|
||||
g_return_val_if_fail(server != NULL, 0);
|
||||
|
||||
best_mask = 0; best_patt = 0; best_ignore = FALSE;
|
||||
for (tmp = ignores; tmp != NULL; tmp = tmp->next) {
|
||||
IGNORE_REC *rec = tmp->data;
|
||||
|
||||
if ((level & (rec->level|rec->except_level)) == 0)
|
||||
continue;
|
||||
|
||||
/* server */
|
||||
if (rec->servertag != NULL && g_strcasecmp(server->tag, rec->servertag) != 0)
|
||||
continue;
|
||||
|
||||
/* nick mask */
|
||||
mask_len = 0;
|
||||
if (rec->mask != NULL) {
|
||||
if (nick == NULL)
|
||||
continue;
|
||||
|
||||
mask_len = strlen(rec->mask);
|
||||
if (mask_len <= best_mask) continue;
|
||||
|
||||
ok = ((host == NULL || *host == '\0')) ?
|
||||
match_wildcards(rec->mask, nick) :
|
||||
irc_mask_match_address(rec->mask, nick, host);
|
||||
if (!ok) continue;
|
||||
}
|
||||
|
||||
/* channel list */
|
||||
if (rec->channels != NULL) {
|
||||
if (channel == NULL || !ischannel(*channel))
|
||||
continue;
|
||||
if (strarray_find(rec->channels, channel) == -1)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* pattern */
|
||||
patt_len = 0;
|
||||
if (rec->pattern != NULL) {
|
||||
if (!mask_len && !best_mask) {
|
||||
patt_len = strlen(rec->pattern);
|
||||
if (patt_len <= best_patt) continue;
|
||||
}
|
||||
|
||||
ok = rec->regexp ? regexp_match(text, rec->pattern) :
|
||||
rec->fullword ? stristr_full(text, rec->pattern) != NULL :
|
||||
stristr(text, rec->pattern) != NULL;
|
||||
if (!ok) continue;
|
||||
}
|
||||
|
||||
if (mask_len || best_mask)
|
||||
best_mask = mask_len;
|
||||
else if (patt_len)
|
||||
best_patt = patt_len;
|
||||
|
||||
best_ignore = (rec->level & level) != 0;
|
||||
}
|
||||
|
||||
return best_ignore;
|
||||
}
|
||||
|
||||
IGNORE_REC *ignore_find(const char *servertag, const char *mask, char **channels)
|
||||
{
|
||||
GSList *tmp;
|
||||
char **chan;
|
||||
int ignore_servertag;
|
||||
|
||||
if (mask != NULL && *mask == '\0') mask = NULL;
|
||||
|
||||
ignore_servertag = servertag != NULL && strcmp(servertag, "*") == 0;
|
||||
for (tmp = ignores; tmp != NULL; tmp = tmp->next) {
|
||||
IGNORE_REC *rec = tmp->data;
|
||||
|
||||
if (!ignore_servertag) {
|
||||
if ((servertag == NULL && rec->servertag != NULL) ||
|
||||
(servertag != NULL && rec->servertag == NULL))
|
||||
continue;
|
||||
|
||||
if (servertag != NULL && g_strcasecmp(servertag, rec->servertag) != 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((rec->mask == NULL && mask != NULL) ||
|
||||
(rec->mask != NULL && mask == NULL)) continue;
|
||||
|
||||
if (rec->mask != NULL && g_strcasecmp(rec->mask, mask) != 0)
|
||||
continue;
|
||||
|
||||
if ((channels == NULL && rec->channels == NULL))
|
||||
return rec; /* no channels - ok */
|
||||
|
||||
if (channels != NULL && strcmp(*channels, "*") == 0)
|
||||
return rec; /* ignore channels */
|
||||
|
||||
if (channels == NULL || rec->channels == NULL)
|
||||
continue; /* other doesn't have channels */
|
||||
|
||||
if (strarray_length(channels) != strarray_length(rec->channels))
|
||||
continue; /* different amount of channels */
|
||||
|
||||
/* check that channels match */
|
||||
for (chan = channels; *chan != NULL; chan++) {
|
||||
if (strarray_find(rec->channels, *chan) == -1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (*chan == NULL)
|
||||
return rec; /* channels ok */
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ignore_set_config(IGNORE_REC *rec)
|
||||
{
|
||||
CONFIG_NODE *node;
|
||||
char *levelstr;
|
||||
|
||||
if (rec->level == 0 && rec->except_level == 0)
|
||||
return;
|
||||
|
||||
node = iconfig_node_traverse("(ignores", TRUE);
|
||||
node = config_node_section(node, NULL, NODE_TYPE_BLOCK);
|
||||
|
||||
if (rec->mask != NULL) config_node_set_str(node, "mask", rec->mask);
|
||||
if (rec->level) {
|
||||
levelstr = bits2level(rec->level);
|
||||
config_node_set_str(node, "level", levelstr);
|
||||
g_free(levelstr);
|
||||
}
|
||||
if (rec->except_level) {
|
||||
levelstr = bits2level(rec->except_level);
|
||||
config_node_set_str(node, "except_level", levelstr);
|
||||
g_free(levelstr);
|
||||
}
|
||||
config_node_set_str(node, "pattern", rec->pattern);
|
||||
if (rec->regexp) config_node_set_bool(node, "regexp", TRUE);
|
||||
if (rec->fullword) config_node_set_bool(node, "fullword", TRUE);
|
||||
|
||||
if (rec->channels != NULL && *rec->channels != NULL) {
|
||||
node = config_node_section(node, "channels", NODE_TYPE_LIST);
|
||||
config_node_add_list(node, rec->channels);
|
||||
}
|
||||
}
|
||||
|
||||
static int ignore_index(IGNORE_REC *find)
|
||||
{
|
||||
GSList *tmp;
|
||||
int index;
|
||||
|
||||
index = 0;
|
||||
for (tmp = ignores; tmp != NULL; tmp = tmp->next) {
|
||||
IGNORE_REC *rec = tmp->data;
|
||||
|
||||
if (rec->servertag != NULL)
|
||||
continue;
|
||||
|
||||
if (rec == find)
|
||||
return index;
|
||||
index++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ignore_remove_config(IGNORE_REC *rec)
|
||||
{
|
||||
CONFIG_NODE *node;
|
||||
|
||||
node = iconfig_node_traverse("ignores", FALSE);
|
||||
if (node != NULL) config_node_list_remove(node, ignore_index(rec));
|
||||
}
|
||||
|
||||
void ignore_add_rec(IGNORE_REC *rec)
|
||||
{
|
||||
ignores = g_slist_append(ignores, rec);
|
||||
ignore_set_config(rec);
|
||||
}
|
||||
|
||||
static void ignore_destroy(IGNORE_REC *rec)
|
||||
{
|
||||
ignores = g_slist_remove(ignores, rec);
|
||||
|
||||
if (rec->channels != NULL) g_strfreev(rec->channels);
|
||||
g_free_not_null(rec->mask);
|
||||
g_free_not_null(rec->servertag);
|
||||
g_free_not_null(rec->pattern);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
void ignore_update_rec(IGNORE_REC *rec)
|
||||
{
|
||||
if (rec->level == 0 && rec->except_level == 0) {
|
||||
/* unignored everything */
|
||||
ignore_remove_config(rec);
|
||||
ignore_destroy(rec);
|
||||
} else {
|
||||
/* unignore just some levels.. */
|
||||
ignore_remove_config(rec);
|
||||
ignores = g_slist_remove(ignores, rec);
|
||||
|
||||
ignores = g_slist_append(ignores, rec);
|
||||
ignore_set_config(rec);
|
||||
}
|
||||
}
|
||||
|
||||
static void read_ignores(void)
|
||||
{
|
||||
IGNORE_REC *rec;
|
||||
CONFIG_NODE *node;
|
||||
GSList *tmp;
|
||||
|
||||
while (ignores != NULL)
|
||||
ignore_destroy(ignores->data);
|
||||
|
||||
node = iconfig_node_traverse("ignores", FALSE);
|
||||
if (node == NULL) return;
|
||||
|
||||
for (tmp = node->value; tmp != NULL; tmp = tmp->next) {
|
||||
node = tmp->data;
|
||||
|
||||
if (node->type != NODE_TYPE_BLOCK)
|
||||
continue;
|
||||
|
||||
rec = g_new0(IGNORE_REC, 1);
|
||||
ignores = g_slist_append(ignores, rec);
|
||||
|
||||
rec->mask = g_strdup(config_node_get_str(node, "mask", NULL));
|
||||
rec->pattern = g_strdup(config_node_get_str(node, "pattern", NULL));
|
||||
rec->level = level2bits(config_node_get_str(node, "level", 0));
|
||||
rec->except_level = level2bits(config_node_get_str(node, "except_level", 0));
|
||||
rec->regexp = config_node_get_bool(node, "regexp", FALSE);
|
||||
rec->fullword = config_node_get_bool(node, "fullword", FALSE);
|
||||
|
||||
node = config_node_section(node, "channels", -1);
|
||||
if (node != NULL) rec->channels = config_node_get_list(node);
|
||||
}
|
||||
}
|
||||
|
||||
void ignore_init(void)
|
||||
{
|
||||
ignores = NULL;
|
||||
|
||||
read_ignores();
|
||||
signal_add("setup reread", (SIGNAL_FUNC) read_ignores);
|
||||
}
|
||||
|
||||
void ignore_deinit(void)
|
||||
{
|
||||
while (ignores != NULL)
|
||||
ignore_destroy(ignores->data);
|
||||
|
||||
signal_remove("setup reread", (SIGNAL_FUNC) read_ignores);
|
||||
}
|
||||
30
src/irc/core/ignore.h
Normal file
30
src/irc/core/ignore.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef __IGNORE_H
|
||||
#define __IGNORE_H
|
||||
|
||||
typedef struct {
|
||||
char *mask; /* nick mask */
|
||||
char *servertag; /* this is for autoignoring */
|
||||
char **channels; /* ignore only in these channels */
|
||||
char *pattern; /* text body must match this pattern */
|
||||
|
||||
int level; /* ignore these levels */
|
||||
int except_level; /* don't ignore these levels */
|
||||
|
||||
int regexp:1;
|
||||
int fullword:1;
|
||||
} IGNORE_REC;
|
||||
|
||||
extern GSList *ignores;
|
||||
|
||||
int ignore_check(IRC_SERVER_REC *server, const char *nick, const char *host,
|
||||
const char *channel, const char *text, int level);
|
||||
|
||||
IGNORE_REC *ignore_find(const char *servertag, const char *mask, char **channels);
|
||||
|
||||
void ignore_add_rec(IGNORE_REC *rec);
|
||||
void ignore_update_rec(IGNORE_REC *rec);
|
||||
|
||||
void ignore_init(void);
|
||||
void ignore_deinit(void);
|
||||
|
||||
#endif
|
||||
878
src/irc/core/irc-commands.c
Normal file
878
src/irc/core/irc-commands.c
Normal file
|
|
@ -0,0 +1,878 @@
|
|||
/*
|
||||
irc-commands.c : irssi
|
||||
|
||||
Copyright (C) 1999 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "commands.h"
|
||||
#include "misc.h"
|
||||
#include "special-vars.h"
|
||||
#include "settings.h"
|
||||
#include "common-setup.h"
|
||||
|
||||
#include "bans.h"
|
||||
#include "channels.h"
|
||||
#include "irc-server.h"
|
||||
#include "irc.h"
|
||||
#include "nicklist.h"
|
||||
#include "server-redirect.h"
|
||||
#include "server-setup.h"
|
||||
|
||||
typedef struct {
|
||||
CHANNEL_REC *channel;
|
||||
char *ban;
|
||||
int timeleft;
|
||||
} KNOCKOUT_REC;
|
||||
|
||||
static GString *tmpstr;
|
||||
static int knockout_tag;
|
||||
|
||||
static IRC_SERVER_REC *connect_server(const char *data)
|
||||
{
|
||||
IRC_SERVER_CONNECT_REC *conn;
|
||||
IRC_SERVER_REC *server;
|
||||
char *params, *addr, *portstr, *password, *nick;
|
||||
int port;
|
||||
|
||||
g_return_val_if_fail(data != NULL, NULL);
|
||||
|
||||
params = cmd_get_params(data, 4, &addr, &portstr, &password, &nick);
|
||||
if (*addr == '\0') return NULL;
|
||||
|
||||
if (strcmp(password, "-") == 0)
|
||||
*password = '\0';
|
||||
|
||||
port = 6667;
|
||||
if (*portstr != '\0')
|
||||
sscanf(portstr, "%d", &port);
|
||||
|
||||
/* connect to server */
|
||||
conn = irc_server_create_conn(addr, port, password, nick);
|
||||
server = irc_server_connect(conn);
|
||||
|
||||
g_free(params);
|
||||
return server;
|
||||
}
|
||||
|
||||
static void cmd_connect(const char *data)
|
||||
{
|
||||
if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
connect_server(data);
|
||||
}
|
||||
|
||||
static void cmd_disconnect(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
IRC_SERVER_REC *ircserver;
|
||||
char *params, *tag, *msg;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
if (g_strncasecmp(data, "RECON-", 6) == 0)
|
||||
return; /* remove reconnection, handle in server-reconnect.c */
|
||||
|
||||
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &tag, &msg);
|
||||
|
||||
if (*tag != '\0' && strcmp(tag, "*") != 0)
|
||||
server = (IRC_SERVER_REC *) server_find_tag(tag);
|
||||
if (server == NULL || !irc_server_check(server))
|
||||
cmd_param_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
ircserver = (IRC_SERVER_REC *) server;
|
||||
if (ircserver->handle != -1 && ircserver->buffer != NULL) {
|
||||
/* flush transmit queue */
|
||||
g_slist_foreach(ircserver->cmdqueue, (GFunc) g_free, NULL);
|
||||
g_slist_free(ircserver->cmdqueue);
|
||||
ircserver->cmdqueue = NULL;
|
||||
ircserver->cmdcount = 0;
|
||||
|
||||
/* then send quit message */
|
||||
if (*msg == '\0') msg = (char *) settings_get_str("default_quit_message");
|
||||
irc_send_cmdv(ircserver, "QUIT :%s", msg);
|
||||
}
|
||||
g_free(params);
|
||||
|
||||
server_disconnect((SERVER_REC *) server);
|
||||
}
|
||||
|
||||
static void cmd_server(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *channels, *away_reason, *usermode, *ircnet;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
if (*data == '+' || server == NULL) {
|
||||
channels = away_reason = usermode = ircnet = NULL;
|
||||
} else {
|
||||
ircnet = g_strdup(server->connrec->ircnet);
|
||||
channels = irc_server_get_channels((IRC_SERVER_REC *) server);
|
||||
if (*channels == '\0')
|
||||
g_free_and_null(channels);
|
||||
usermode = g_strdup(server->usermode);
|
||||
away_reason = !server->usermode_away ? NULL :
|
||||
g_strdup(server->away_reason);
|
||||
cmd_disconnect("* Changing server", server);
|
||||
}
|
||||
|
||||
server = connect_server(data + (*data == '+' ? 1 : 0));
|
||||
if (*data == '+' || server == NULL ||
|
||||
(ircnet != NULL && server->connrec->ircnet != NULL &&
|
||||
g_strcasecmp(ircnet, server->connrec->ircnet) != 0)) {
|
||||
g_free_not_null(channels);
|
||||
g_free_not_null(usermode);
|
||||
g_free_not_null(away_reason);
|
||||
} else if (server != NULL) {
|
||||
server->connrec->reconnection = TRUE;
|
||||
server->connrec->channels = channels;
|
||||
server->connrec->usermode = usermode;
|
||||
server->connrec->away_reason = away_reason;
|
||||
}
|
||||
g_free_not_null(ircnet);
|
||||
}
|
||||
|
||||
static void cmd_quit(const char *data)
|
||||
{
|
||||
GSList *tmp, *next;
|
||||
const char *quitmsg;
|
||||
char *str;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
quitmsg = *data != '\0' ? data :
|
||||
settings_get_str("default_quit_message");
|
||||
|
||||
/* disconnect from every server */
|
||||
for (tmp = servers; tmp != NULL; tmp = next) {
|
||||
next = tmp->next;
|
||||
|
||||
str = g_strdup_printf("* %s", quitmsg);
|
||||
cmd_disconnect(str, tmp->data);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
signal_emit("gui exit", 0);
|
||||
}
|
||||
|
||||
static void cmd_msg(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
char *params, *target, *msg;
|
||||
int free_ret;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg);
|
||||
if (*target == '\0' || *msg == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
if (*target == '=') {
|
||||
/* dcc msg - don't even try to handle here.. */
|
||||
g_free(params);
|
||||
return;
|
||||
}
|
||||
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_param_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
free_ret = FALSE;
|
||||
if (strcmp(target, ",") == 0 || strcmp(target, ".") == 0)
|
||||
target = parse_special(&target, server, item, NULL, &free_ret, NULL);
|
||||
else if (strcmp(target, "*") == 0 &&
|
||||
(irc_item_channel(item) || irc_item_query(item)))
|
||||
target = item->name;
|
||||
if (target != NULL) {
|
||||
g_string_sprintf(tmpstr, "PRIVMSG %s :%s", target, msg);
|
||||
irc_send_cmd_split(server, tmpstr->str, 2, server->max_msgs_in_cmd);
|
||||
}
|
||||
|
||||
if (free_ret && target != NULL) g_free(target);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void cmd_notice(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *target, *msg;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg);
|
||||
if (*target == '\0' || *msg == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
g_string_sprintf(tmpstr, "NOTICE %s :%s", target, msg);
|
||||
irc_send_cmd_split(server, tmpstr->str, 2, server->max_msgs_in_cmd);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void cmd_ctcp(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *target, *ctcpcmd, *ctcpdata;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
params = cmd_get_params(data, 3 | PARAM_FLAG_GETREST, &target, &ctcpcmd, &ctcpdata);
|
||||
if (*target == '\0' || *ctcpcmd == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
g_strup(ctcpcmd);
|
||||
if (*ctcpdata == '\0')
|
||||
g_string_sprintf(tmpstr, "PRIVMSG %s :\001%s\001", target, ctcpcmd);
|
||||
else
|
||||
g_string_sprintf(tmpstr, "PRIVMSG %s :\001%s %s\001", target, ctcpcmd, ctcpdata);
|
||||
irc_send_cmd_split(server, tmpstr->str, 2, server->max_msgs_in_cmd);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void cmd_nctcp(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *target, *ctcpcmd, *ctcpdata;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
params = cmd_get_params(data, 3 | PARAM_FLAG_GETREST, &target, &ctcpcmd, &ctcpdata);
|
||||
if (*target == '\0' || *ctcpcmd == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
g_strup(ctcpcmd);
|
||||
g_string_sprintf(tmpstr, "NOTICE %s :\001%s %s\001", target, ctcpcmd, ctcpdata);
|
||||
irc_send_cmd_split(server, tmpstr->str, 2, server->max_msgs_in_cmd);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void cmd_join(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
if (*data == '\0' || g_strncasecmp(data, "-invite", 7) == 0) {
|
||||
if (server->last_invite != NULL)
|
||||
channels_join(server, server->last_invite, FALSE);
|
||||
} else
|
||||
channels_join(server, data, FALSE);
|
||||
}
|
||||
|
||||
static void cmd_part(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
char *params, *channame, *msg;
|
||||
CHANNEL_REC *chanrec;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
params = cmd_get_params(data, 2 | PARAM_FLAG_OPTCHAN | PARAM_FLAG_GETREST, item, &channame, &msg);
|
||||
if (*channame == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
chanrec = channel_find(server, channame);
|
||||
if (chanrec == NULL) cmd_param_error(CMDERR_CHAN_NOT_FOUND);
|
||||
|
||||
irc_send_cmdv(server, *msg == '\0' ? "PART %s" : "PART %s %s",
|
||||
channame, msg);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void cmd_kick(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
char *params, *channame, *nicks, *reason;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
params = cmd_get_params(data, 3 | PARAM_FLAG_OPTCHAN | PARAM_FLAG_GETREST,
|
||||
item, &channame, &nicks, &reason);
|
||||
|
||||
if (*channame == '\0' || *nicks == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
if (!ischannel(*channame)) cmd_param_error(CMDERR_NOT_JOINED);
|
||||
|
||||
g_string_sprintf(tmpstr, "KICK %s %s :%s", channame, nicks, reason);
|
||||
irc_send_cmd_split(server, tmpstr->str, 3, server->max_kicks_in_cmd);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void cmd_topic(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
char *params, *channame, *topic;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
params = cmd_get_params(data, 2 | PARAM_FLAG_OPTCHAN | PARAM_FLAG_GETREST, item, &channame, &topic);
|
||||
|
||||
irc_send_cmdv(server, *topic == '\0' ? "TOPIC %s" : "TOPIC %s :%s",
|
||||
channame, topic);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void cmd_invite(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
char *params, *nick, *channame;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
params = cmd_get_params(data, 2, &nick, &channame);
|
||||
if (*nick == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
if (*channame == '\0' || strcmp(channame, "*") == 0) {
|
||||
if (!irc_item_channel(item))
|
||||
cmd_param_error(CMDERR_NOT_JOINED);
|
||||
|
||||
channame = item->name;
|
||||
}
|
||||
|
||||
irc_send_cmdv(server, "INVITE %s %s", nick, channame);
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void cmd_list(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
char *params, *args, *str;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
params = cmd_get_params(data, 2 | PARAM_FLAG_OPTARGS | PARAM_FLAG_GETREST, &args, &str);
|
||||
|
||||
if (*str == '\0' && stristr(args, "-yes") == NULL)
|
||||
cmd_param_error(CMDERR_NOT_GOOD_IDEA);
|
||||
|
||||
irc_send_cmdv(server, "LIST %s", str);
|
||||
g_free(params);
|
||||
|
||||
/* add default redirection */
|
||||
server_redirect_default((SERVER_REC *) server, "bogus command list");
|
||||
}
|
||||
|
||||
static void cmd_who(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
char *params, *channel, *args, *rest;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
params = cmd_get_params(data, 3 | PARAM_FLAG_OPTARGS | PARAM_FLAG_GETREST, &args, &channel, &rest);
|
||||
|
||||
if (strcmp(channel, "*") == 0 || *channel == '\0') {
|
||||
if (!irc_item_check(item))
|
||||
cmd_return_error(CMDERR_NOT_JOINED);
|
||||
|
||||
data = item->name;
|
||||
}
|
||||
if (strcmp(channel, "**") == 0) {
|
||||
/* ** displays all nicks.. */
|
||||
*channel = '\0';
|
||||
}
|
||||
|
||||
irc_send_cmdv(server, *rest == '\0' ? "WHO %s" : "WHO %s %s",
|
||||
channel, rest);
|
||||
g_free(params);
|
||||
|
||||
/* add default redirection */
|
||||
server_redirect_default((SERVER_REC *) server, "bogus command who");
|
||||
}
|
||||
|
||||
static void cmd_names(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
if (*data == '\0') cmd_return_error(CMDERR_NOT_GOOD_IDEA);
|
||||
|
||||
if (strcmp(data, "*") == 0) {
|
||||
if (!irc_item_channel(item))
|
||||
cmd_return_error(CMDERR_NOT_JOINED);
|
||||
|
||||
data = item->name;
|
||||
}
|
||||
|
||||
if (g_strcasecmp(data, "-YES") == 0)
|
||||
irc_send_cmd(server, "NAMES");
|
||||
else
|
||||
irc_send_cmdv(server, "NAMES %s", data);
|
||||
}
|
||||
|
||||
static void cmd_whois(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
while (*data == ' ') data++;
|
||||
if (*data == '\0') data = server->nick;
|
||||
|
||||
g_string_sprintf(tmpstr, "WHOIS %s", data);
|
||||
irc_send_cmd_split(server, tmpstr->str, 2, server->max_whois_in_cmd);
|
||||
}
|
||||
|
||||
static void cmd_whowas(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
while (*data == ' ') data++;
|
||||
if (*data == '\0') data = server->nick;
|
||||
|
||||
irc_send_cmdv(server, "WHOWAS %s", data);
|
||||
}
|
||||
|
||||
static void cmd_ping(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
GTimeVal tv;
|
||||
char *str;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
if (*data == '\0' || strcmp(data, "*") == 0) {
|
||||
if (!irc_item_check(item))
|
||||
cmd_return_error(CMDERR_NOT_JOINED);
|
||||
|
||||
data = item->name;
|
||||
}
|
||||
|
||||
g_get_current_time(&tv);
|
||||
|
||||
str = g_strdup_printf("%s PING %ld %ld", data, tv.tv_sec, tv.tv_usec);
|
||||
signal_emit("command ctcp", 3, str, server, item);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void server_send_away(IRC_SERVER_REC *server, const char *reason)
|
||||
{
|
||||
g_free_not_null(server->away_reason);
|
||||
server->away_reason = g_strdup(reason);
|
||||
|
||||
irc_send_cmdv(server, "AWAY :%s", reason);
|
||||
}
|
||||
|
||||
static void cmd_away(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *args, *reason;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
params = cmd_get_params(data, 2 | PARAM_FLAG_OPTARGS | PARAM_FLAG_GETREST, &args, &reason);
|
||||
|
||||
if (stristr(args, "-all") != NULL)
|
||||
g_slist_foreach(servers, (GFunc) server_send_away, reason);
|
||||
else
|
||||
server_send_away(server, reason);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void cmd_deop(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
if (*data == '\0')
|
||||
irc_send_cmdv(server, "MODE %s -o", server->nick);
|
||||
}
|
||||
|
||||
static void cmd_sconnect(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
irc_send_cmdv(server, "CONNECT %s", data);
|
||||
}
|
||||
|
||||
static void cmd_quote(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
irc_send_cmd(server, data);
|
||||
}
|
||||
|
||||
static void cmd_wall_hash(gpointer key, NICK_REC *nick, GSList **nicks)
|
||||
{
|
||||
if (nick->op) *nicks = g_slist_append(*nicks, nick);
|
||||
}
|
||||
|
||||
static void cmd_wall(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
char *params, *channame, *msg;
|
||||
CHANNEL_REC *chanrec;
|
||||
GSList *tmp, *nicks;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
params = cmd_get_params(data, 2 | PARAM_FLAG_OPTCHAN | PARAM_FLAG_GETREST, item, &channame, &msg);
|
||||
if (*msg == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
chanrec = channel_find(server, channame);
|
||||
if (chanrec == NULL) cmd_param_error(CMDERR_CHAN_NOT_FOUND);
|
||||
|
||||
/* send notice to all ops */
|
||||
nicks = NULL;
|
||||
g_hash_table_foreach(chanrec->nicks, (GHFunc) cmd_wall_hash, &nicks);
|
||||
|
||||
for (tmp = nicks; tmp != NULL; tmp = tmp->next) {
|
||||
NICK_REC *rec = tmp->data;
|
||||
|
||||
irc_send_cmdv(server, "NOTICE %s :%s", rec->nick, msg);
|
||||
}
|
||||
g_slist_free(nicks);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void cmd_cycle(gchar *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
char *params, *channame, *msg;
|
||||
CHANNEL_REC *chanrec;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
params = cmd_get_params(data, 2 | PARAM_FLAG_OPTCHAN, item, &channame, &msg);
|
||||
if (*channame == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
chanrec = channel_find(server, channame);
|
||||
if (chanrec == NULL) cmd_param_error(CMDERR_CHAN_NOT_FOUND);
|
||||
|
||||
irc_send_cmdv(server, *msg == '\0' ? "PART %s" : "PART %s %s",
|
||||
channame, msg);
|
||||
irc_send_cmdv(server, chanrec->key == NULL ? "JOIN %s" : "JOIN %s %s",
|
||||
channame, chanrec->key);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void cmd_kickban(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
char *params, *nick;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = cmd_get_params(data, 1, &nick);
|
||||
if (*nick == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
signal_emit("command ban", 3, nick, server, item);
|
||||
signal_emit("command kick", 3, data, server, item);
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void knockout_destroy(IRC_SERVER_REC *server, KNOCKOUT_REC *rec)
|
||||
{
|
||||
server->knockoutlist = g_slist_remove(server->knockoutlist, rec);
|
||||
g_free(rec->ban);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
/* timeout function: knockout */
|
||||
static void knockout_timeout_server(IRC_SERVER_REC *server)
|
||||
{
|
||||
GSList *tmp, *next;
|
||||
time_t t;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
t = server->knockout_lastcheck == 0 ? 0 :
|
||||
time(NULL)-server->knockout_lastcheck;
|
||||
server->knockout_lastcheck = time(NULL);
|
||||
|
||||
for (tmp = server->knockoutlist; tmp != NULL; tmp = next) {
|
||||
KNOCKOUT_REC *rec = tmp->data;
|
||||
|
||||
next = tmp->next;
|
||||
if (rec->timeleft > t)
|
||||
rec->timeleft -= t;
|
||||
else {
|
||||
/* timeout, unban. */
|
||||
ban_remove(rec->channel, rec->ban);
|
||||
knockout_destroy(server, rec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int knockout_timeout(void)
|
||||
{
|
||||
g_slist_foreach(servers, (GFunc) knockout_timeout_server, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void cmd_knockout(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
KNOCKOUT_REC *rec;
|
||||
CHANNEL_REC *channel;
|
||||
char *params, *nick, *reason, *timeoutstr, *str;
|
||||
int timeleft;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL) cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
channel = irc_item_channel(item);
|
||||
if (channel == NULL) cmd_return_error(CMDERR_NOT_JOINED);
|
||||
|
||||
if (is_numeric(data, ' ')) {
|
||||
/* first argument is the timeout */
|
||||
params = cmd_get_params(data, 3 | PARAM_FLAG_GETREST, &timeoutstr, &nick, &reason);
|
||||
timeleft = atol(timeoutstr);
|
||||
} else {
|
||||
timeleft = 0;
|
||||
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &nick, &reason);
|
||||
}
|
||||
|
||||
if (timeleft == 0) timeleft = settings_get_int("knockout_time");
|
||||
if (*nick == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
signal_emit("command ban", 3, nick, server, channel);
|
||||
|
||||
str = g_strdup_printf("%s %s", nick, reason);
|
||||
signal_emit("command kick", 3, str, server, channel);
|
||||
g_free(str);
|
||||
|
||||
/* create knockout record */
|
||||
rec = g_new(KNOCKOUT_REC, 1);
|
||||
rec->timeleft = timeleft;
|
||||
rec->channel = channel;
|
||||
rec->ban = ban_get_mask(channel, nick);
|
||||
|
||||
server->knockoutlist = g_slist_append(server->knockoutlist, rec);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
/* destroy all knockouts in server */
|
||||
static void sig_server_disconnected(IRC_SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
while (server->knockoutlist != NULL)
|
||||
knockout_destroy(server, server->knockoutlist->data);
|
||||
}
|
||||
|
||||
/* destroy all knockouts in channel */
|
||||
static void sig_channel_destroyed(CHANNEL_REC *channel)
|
||||
{
|
||||
GSList *tmp, *next;
|
||||
|
||||
g_return_if_fail(channel != NULL);
|
||||
if (channel->server == NULL) return;
|
||||
|
||||
for (tmp = channel->server->knockoutlist; tmp != NULL; tmp = next) {
|
||||
KNOCKOUT_REC *rec = tmp->data;
|
||||
|
||||
next = tmp->next;
|
||||
if (rec->channel == channel)
|
||||
knockout_destroy(channel->server, rec);
|
||||
}
|
||||
}
|
||||
|
||||
static void command_self(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
irc_send_cmdv(server, *data == '\0' ? "%s" : "%s %s", current_command, data);
|
||||
}
|
||||
|
||||
static void command_1self(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
irc_send_cmdv(server, "%s :%s", current_command, data);
|
||||
}
|
||||
|
||||
static void command_2self(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *target, *text;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &text);
|
||||
if (*target == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
irc_send_cmdv(server, "%s %s :%s", current_command, target, text);
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void sig_connected(IRC_SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
server_redirect_init((SERVER_REC *) server, "", 2, "event 318", "event 402", "event 401",
|
||||
"event 301", "event 311", "event 312", "event 313",
|
||||
"event 317", "event 319", NULL);
|
||||
|
||||
/* gui-gnome can use server_redirect_event() in who/list commands so
|
||||
we can't use "command who" or list here.. */
|
||||
server_redirect_init((SERVER_REC *) server, "bogus command who", 2, "event 401", "event 315", "event 352", NULL);
|
||||
server_redirect_init((SERVER_REC *) server, "bogus command list", 1, "event 321", "event 322", "event 323", NULL);
|
||||
}
|
||||
|
||||
void irc_commands_init(void)
|
||||
{
|
||||
tmpstr = g_string_new(NULL);
|
||||
|
||||
settings_add_str("misc", "default_quit_message", "leaving");
|
||||
settings_add_int("misc", "knockout_time", 300);
|
||||
|
||||
knockout_tag = g_timeout_add(KNOCKOUT_TIMECHECK, (GSourceFunc) knockout_timeout, NULL);
|
||||
|
||||
signal_add("server connected", (SIGNAL_FUNC) sig_connected);
|
||||
command_bind("server", NULL, (SIGNAL_FUNC) cmd_server);
|
||||
command_bind("connect", NULL, (SIGNAL_FUNC) cmd_connect);
|
||||
command_bind("disconnect", NULL, (SIGNAL_FUNC) cmd_disconnect);
|
||||
command_bind("msg", NULL, (SIGNAL_FUNC) cmd_msg);
|
||||
command_bind("notice", NULL, (SIGNAL_FUNC) cmd_notice);
|
||||
command_bind("ctcp", NULL, (SIGNAL_FUNC) cmd_ctcp);
|
||||
command_bind("nctcp", NULL, (SIGNAL_FUNC) cmd_nctcp);
|
||||
command_bind("quit", NULL, (SIGNAL_FUNC) cmd_quit);
|
||||
command_bind("join", NULL, (SIGNAL_FUNC) cmd_join);
|
||||
command_bind("part", NULL, (SIGNAL_FUNC) cmd_part);
|
||||
command_bind("kick", NULL, (SIGNAL_FUNC) cmd_kick);
|
||||
command_bind("topic", NULL, (SIGNAL_FUNC) cmd_topic);
|
||||
command_bind("invite", NULL, (SIGNAL_FUNC) cmd_invite);
|
||||
command_bind("list", NULL, (SIGNAL_FUNC) cmd_list);
|
||||
command_bind("who", NULL, (SIGNAL_FUNC) cmd_who);
|
||||
command_bind("names", NULL, (SIGNAL_FUNC) cmd_names);
|
||||
command_bind("nick", NULL, (SIGNAL_FUNC) command_self);
|
||||
command_bind("note", NULL, (SIGNAL_FUNC) command_self);
|
||||
command_bind("whois", NULL, (SIGNAL_FUNC) cmd_whois);
|
||||
command_bind("whowas", NULL, (SIGNAL_FUNC) cmd_whowas);
|
||||
command_bind("ping", NULL, (SIGNAL_FUNC) cmd_ping);
|
||||
command_bind("kill", NULL, (SIGNAL_FUNC) command_2self);
|
||||
command_bind("away", NULL, (SIGNAL_FUNC) cmd_away);
|
||||
command_bind("ison", NULL, (SIGNAL_FUNC) command_1self);
|
||||
command_bind("admin", NULL, (SIGNAL_FUNC) command_self);
|
||||
command_bind("info", NULL, (SIGNAL_FUNC) command_self);
|
||||
command_bind("links", NULL, (SIGNAL_FUNC) command_self);
|
||||
command_bind("lusers", NULL, (SIGNAL_FUNC) command_self);
|
||||
command_bind("map", NULL, (SIGNAL_FUNC) command_self);
|
||||
command_bind("motd", NULL, (SIGNAL_FUNC) command_self);
|
||||
command_bind("stats", NULL, (SIGNAL_FUNC) command_self);
|
||||
command_bind("time", NULL, (SIGNAL_FUNC) command_self);
|
||||
command_bind("trace", NULL, (SIGNAL_FUNC) command_self);
|
||||
command_bind("version", NULL, (SIGNAL_FUNC) command_self);
|
||||
command_bind("servlist", NULL, (SIGNAL_FUNC) command_self);
|
||||
command_bind("silence", NULL, (SIGNAL_FUNC) command_self);
|
||||
command_bind("sconnect", NULL, (SIGNAL_FUNC) cmd_sconnect);
|
||||
command_bind("squery", NULL, (SIGNAL_FUNC) command_2self);
|
||||
command_bind("deop", NULL, (SIGNAL_FUNC) cmd_deop);
|
||||
command_bind("die", NULL, (SIGNAL_FUNC) command_self);
|
||||
command_bind("hash", NULL, (SIGNAL_FUNC) command_self);
|
||||
command_bind("oper", NULL, (SIGNAL_FUNC) command_self);
|
||||
command_bind("restart", NULL, (SIGNAL_FUNC) command_self);
|
||||
command_bind("rping", NULL, (SIGNAL_FUNC) command_self);
|
||||
command_bind("squit", NULL, (SIGNAL_FUNC) command_2self);
|
||||
command_bind("uping", NULL, (SIGNAL_FUNC) command_self);
|
||||
command_bind("quote", NULL, (SIGNAL_FUNC) cmd_quote);
|
||||
command_bind("wall", NULL, (SIGNAL_FUNC) cmd_wall);
|
||||
command_bind("wallops", NULL, (SIGNAL_FUNC) command_1self);
|
||||
command_bind("wallchops", NULL, (SIGNAL_FUNC) command_2self);
|
||||
command_bind("cycle", NULL, (SIGNAL_FUNC) cmd_cycle);
|
||||
command_bind("kickban", NULL, (SIGNAL_FUNC) cmd_kickban);
|
||||
command_bind("knockout", NULL, (SIGNAL_FUNC) cmd_knockout);
|
||||
|
||||
signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
|
||||
signal_add("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
|
||||
}
|
||||
|
||||
void irc_commands_deinit(void)
|
||||
{
|
||||
g_source_remove(knockout_tag);
|
||||
|
||||
signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
|
||||
command_unbind("server", (SIGNAL_FUNC) cmd_server);
|
||||
command_unbind("connect", (SIGNAL_FUNC) cmd_connect);
|
||||
command_unbind("disconnect", (SIGNAL_FUNC) cmd_disconnect);
|
||||
command_unbind("msg", (SIGNAL_FUNC) cmd_msg);
|
||||
command_unbind("notice", (SIGNAL_FUNC) cmd_notice);
|
||||
command_unbind("ctcp", (SIGNAL_FUNC) cmd_ctcp);
|
||||
command_unbind("nctcp", (SIGNAL_FUNC) cmd_nctcp);
|
||||
command_unbind("quit", (SIGNAL_FUNC) cmd_quit);
|
||||
command_unbind("join", (SIGNAL_FUNC) cmd_join);
|
||||
command_unbind("part", (SIGNAL_FUNC) cmd_part);
|
||||
command_unbind("kick", (SIGNAL_FUNC) cmd_kick);
|
||||
command_unbind("topic", (SIGNAL_FUNC) cmd_topic);
|
||||
command_unbind("invite", (SIGNAL_FUNC) cmd_invite);
|
||||
command_unbind("list", (SIGNAL_FUNC) cmd_list);
|
||||
command_unbind("who", (SIGNAL_FUNC) cmd_who);
|
||||
command_unbind("names", (SIGNAL_FUNC) cmd_names);
|
||||
command_unbind("nick", (SIGNAL_FUNC) command_self);
|
||||
command_unbind("note", (SIGNAL_FUNC) command_self);
|
||||
command_unbind("whois", (SIGNAL_FUNC) cmd_whois);
|
||||
command_unbind("whowas", (SIGNAL_FUNC) cmd_whowas);
|
||||
command_unbind("ping", (SIGNAL_FUNC) cmd_ping);
|
||||
command_unbind("kill", (SIGNAL_FUNC) command_2self);
|
||||
command_unbind("away", (SIGNAL_FUNC) cmd_away);
|
||||
command_unbind("ison", (SIGNAL_FUNC) command_1self);
|
||||
command_unbind("admin", (SIGNAL_FUNC) command_self);
|
||||
command_unbind("info", (SIGNAL_FUNC) command_self);
|
||||
command_unbind("links", (SIGNAL_FUNC) command_self);
|
||||
command_unbind("lusers", (SIGNAL_FUNC) command_self);
|
||||
command_unbind("map", (SIGNAL_FUNC) command_self);
|
||||
command_unbind("motd", (SIGNAL_FUNC) command_self);
|
||||
command_unbind("stats", (SIGNAL_FUNC) command_self);
|
||||
command_unbind("time", (SIGNAL_FUNC) command_self);
|
||||
command_unbind("trace", (SIGNAL_FUNC) command_self);
|
||||
command_unbind("version", (SIGNAL_FUNC) command_self);
|
||||
command_unbind("servlist", (SIGNAL_FUNC) command_self);
|
||||
command_unbind("silence", (SIGNAL_FUNC) command_self);
|
||||
command_unbind("sconnect", (SIGNAL_FUNC) cmd_sconnect);
|
||||
command_unbind("squery", (SIGNAL_FUNC) command_2self);
|
||||
command_unbind("deop", (SIGNAL_FUNC) cmd_deop);
|
||||
command_unbind("die", (SIGNAL_FUNC) command_self);
|
||||
command_unbind("hash", (SIGNAL_FUNC) command_self);
|
||||
command_unbind("oper", (SIGNAL_FUNC) command_self);
|
||||
command_unbind("restart", (SIGNAL_FUNC) command_self);
|
||||
command_unbind("rping", (SIGNAL_FUNC) command_self);
|
||||
command_unbind("squit", (SIGNAL_FUNC) command_2self);
|
||||
command_unbind("uping", (SIGNAL_FUNC) command_self);
|
||||
command_unbind("quote", (SIGNAL_FUNC) cmd_quote);
|
||||
command_unbind("wall", (SIGNAL_FUNC) cmd_wall);
|
||||
command_unbind("wallops", (SIGNAL_FUNC) command_1self);
|
||||
command_unbind("wallchops", (SIGNAL_FUNC) command_2self);
|
||||
command_unbind("cycle", (SIGNAL_FUNC) cmd_cycle);
|
||||
command_unbind("kickban", (SIGNAL_FUNC) cmd_kickban);
|
||||
command_unbind("knockout", (SIGNAL_FUNC) cmd_knockout);
|
||||
signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
|
||||
signal_remove("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
|
||||
|
||||
g_string_free(tmpstr, TRUE);
|
||||
}
|
||||
7
src/irc/core/irc-commands.h
Normal file
7
src/irc/core/irc-commands.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef __IRC_COMMANDS_H
|
||||
#define __IRC_COMMANDS_H
|
||||
|
||||
void irc_commands_init(void);
|
||||
void irc_commands_deinit(void);
|
||||
|
||||
#endif
|
||||
63
src/irc/core/irc-core.c
Normal file
63
src/irc/core/irc-core.c
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
irc-core.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
|
||||
#include "irc-server.h"
|
||||
#include "channels.h"
|
||||
|
||||
#include "ctcp.h"
|
||||
#include "irc-commands.h"
|
||||
#include "irc-rawlog.h"
|
||||
#include "irc-special-vars.h"
|
||||
#include "ignore.h"
|
||||
#include "irc.h"
|
||||
#include "lag.h"
|
||||
#include "netsplit.h"
|
||||
|
||||
void irc_core_init(void)
|
||||
{
|
||||
irc_servers_init();
|
||||
channels_init();
|
||||
|
||||
ctcp_init();
|
||||
irc_commands_init();
|
||||
irc_irc_init();
|
||||
lag_init();
|
||||
netsplit_init();
|
||||
ignore_init();
|
||||
irc_rawlog_init();
|
||||
irc_special_vars_init();
|
||||
}
|
||||
|
||||
void irc_core_deinit(void)
|
||||
{
|
||||
irc_special_vars_deinit();
|
||||
irc_rawlog_deinit();
|
||||
ignore_deinit();
|
||||
netsplit_deinit();
|
||||
lag_deinit();
|
||||
irc_irc_deinit();
|
||||
irc_commands_deinit();
|
||||
ctcp_deinit();
|
||||
|
||||
channels_deinit();
|
||||
irc_servers_deinit();
|
||||
}
|
||||
7
src/irc/core/irc-core.h
Normal file
7
src/irc/core/irc-core.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef __IRC_CORE_H
|
||||
#define __IRC_CORE_H
|
||||
|
||||
void irc_core_init(void);
|
||||
void irc_core_deinit(void);
|
||||
|
||||
#endif
|
||||
70
src/irc/core/irc-log.c
Normal file
70
src/irc/core/irc-log.c
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
static void sig_log(SERVER_REC *server, const char *channel, gpointer level, const char *str)
|
||||
{
|
||||
gint loglevel;
|
||||
|
||||
g_return_if_fail(str != NULL);
|
||||
|
||||
loglevel = GPOINTER_TO_INT(level);
|
||||
if (loglevel == MSGLEVEL_NEVER || logs == NULL) return;
|
||||
|
||||
/* Check if line should be saved in logs */
|
||||
log_file_write(server, channel, loglevel, str);
|
||||
}
|
||||
|
||||
|
||||
static void event_away(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
LOG_REC *log;
|
||||
const char *fname, *level;
|
||||
|
||||
fname = settings_get_str("awaylog_file");
|
||||
level = settings_get_str("awaylog_level");
|
||||
if (*fname == '\0' || *level == '\0') return;
|
||||
|
||||
log = log_file_find(fname);
|
||||
if (log != NULL) {
|
||||
/* awaylog already created */
|
||||
if (log->handle == -1) {
|
||||
/* ..but not open, open it. */
|
||||
log_file_open(log);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
log = log_create(fname, level);
|
||||
if (log != NULL) log_file_open(log);
|
||||
}
|
||||
|
||||
static void event_unaway(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
LOG_REC *rec;
|
||||
const char *fname;
|
||||
|
||||
fname = settings_get_str("awaylog_file");
|
||||
if (*fname == '\0') return;
|
||||
|
||||
rec = log_file_find(fname);
|
||||
if (rec == NULL || rec->handle == -1) {
|
||||
/* awaylog not open */
|
||||
return;
|
||||
}
|
||||
|
||||
log_file_destroy(rec);
|
||||
}
|
||||
|
||||
void log_init(void)
|
||||
{
|
||||
settings_add_str("misc", "awaylog_file", "~/.irssi/away.log");
|
||||
settings_add_str("misc", "awaylog_level", "-all +msgs +hilight");
|
||||
|
||||
signal_add("print text stripped", (SIGNAL_FUNC) sig_log);
|
||||
signal_add("event 306", (SIGNAL_FUNC) event_away);
|
||||
signal_add("event 305", (SIGNAL_FUNC) event_unaway);
|
||||
}
|
||||
|
||||
void log_deinit(void)
|
||||
{
|
||||
signal_remove("print text stripped", (SIGNAL_FUNC) sig_log);
|
||||
signal_remove("event 306", (SIGNAL_FUNC) event_away);
|
||||
signal_remove("event 305", (SIGNAL_FUNC) event_unaway);
|
||||
}
|
||||
77
src/irc/core/irc-rawlog.c
Normal file
77
src/irc/core/irc-rawlog.c
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
irc-rawlog.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "rawlog.h"
|
||||
#include "modules.h"
|
||||
#include "signals.h"
|
||||
#include "misc.h"
|
||||
|
||||
#include "commands.h"
|
||||
#include "server.h"
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
static void cmd_rawlog(const char *data, SERVER_REC *server, void *item)
|
||||
{
|
||||
command_runsub("rawlog", data, server, item);
|
||||
}
|
||||
|
||||
static void cmd_rawlog_save(const char *data, SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected) cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
rawlog_save(server->rawlog, data);
|
||||
}
|
||||
|
||||
static void cmd_rawlog_open(const char *data, SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected) cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
rawlog_open(server->rawlog, data);
|
||||
}
|
||||
|
||||
static void cmd_rawlog_close(const char *data, SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected) cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
rawlog_close(server->rawlog);
|
||||
}
|
||||
|
||||
void irc_rawlog_init(void)
|
||||
{
|
||||
command_bind("rawlog", NULL, (SIGNAL_FUNC) cmd_rawlog);
|
||||
command_bind("rawlog save", NULL, (SIGNAL_FUNC) cmd_rawlog_save);
|
||||
command_bind("rawlog open", NULL, (SIGNAL_FUNC) cmd_rawlog_open);
|
||||
command_bind("rawlog close", NULL, (SIGNAL_FUNC) cmd_rawlog_close);
|
||||
}
|
||||
|
||||
void irc_rawlog_deinit(void)
|
||||
{
|
||||
command_unbind("rawlog", (SIGNAL_FUNC) cmd_rawlog);
|
||||
command_unbind("rawlog save", (SIGNAL_FUNC) cmd_rawlog_save);
|
||||
command_unbind("rawlog open", (SIGNAL_FUNC) cmd_rawlog_open);
|
||||
command_unbind("rawlog close", (SIGNAL_FUNC) cmd_rawlog_close);
|
||||
}
|
||||
7
src/irc/core/irc-rawlog.h
Normal file
7
src/irc/core/irc-rawlog.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef __IRC_RAWLOG_H
|
||||
#define __IRC_RAWLOG_H
|
||||
|
||||
void irc_rawlog_init(void);
|
||||
void irc_rawlog_deinit(void);
|
||||
|
||||
#endif
|
||||
457
src/irc/core/irc-server.c
Normal file
457
src/irc/core/irc-server.c
Normal file
|
|
@ -0,0 +1,457 @@
|
|||
/*
|
||||
irc-server.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
|
||||
#include "net-nonblock.h"
|
||||
#include "line-split.h"
|
||||
#include "signals.h"
|
||||
#include "modules.h"
|
||||
#include "rawlog.h"
|
||||
#include "misc.h"
|
||||
|
||||
#include "irc-server.h"
|
||||
#include "server-idle.h"
|
||||
#include "server-reconnect.h"
|
||||
#include "server-setup.h"
|
||||
#include "ircnet-setup.h"
|
||||
#include "channels.h"
|
||||
#include "modes.h"
|
||||
#include "irc.h"
|
||||
#include "query.h"
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#define DEFAULT_MAX_KICKS 1
|
||||
#define DEFAULT_MAX_MODES 3
|
||||
#define DEFAULT_MAX_WHOIS 4
|
||||
#define DEFAULT_MAX_MSGS 1
|
||||
|
||||
#define DEFAULT_USER_MODE "+i"
|
||||
#define DEFAULT_CMD_QUEUE_SPEED 2200
|
||||
#define DEFAULT_CMDS_MAX_AT_ONCE 5
|
||||
|
||||
static int cmd_tag;
|
||||
|
||||
void irc_server_connect_free(IRC_SERVER_CONNECT_REC *rec)
|
||||
{
|
||||
g_return_if_fail(rec != NULL);
|
||||
|
||||
g_free_not_null(rec->proxy);
|
||||
g_free_not_null(rec->proxy_string);
|
||||
g_free_not_null(rec->ircnet);
|
||||
g_free_not_null(rec->password);
|
||||
g_free_not_null(rec->nick);
|
||||
g_free_not_null(rec->alternate_nick);
|
||||
g_free_not_null(rec->username);
|
||||
g_free_not_null(rec->realname);
|
||||
g_free_not_null(rec->own_ip);
|
||||
g_free_not_null(rec->channels);
|
||||
g_free_not_null(rec->away_reason);
|
||||
g_free_not_null(rec->usermode);
|
||||
g_free(rec->address);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
static void server_init(IRC_SERVER_REC *server)
|
||||
{
|
||||
IRC_SERVER_CONNECT_REC *conn;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
conn = server->connrec;
|
||||
|
||||
if (conn->proxy_string != NULL)
|
||||
irc_send_cmdv(server, conn->proxy_string, conn->address, conn->port);
|
||||
|
||||
if (conn->password != NULL && *conn->password != '\0') {
|
||||
/* send password */
|
||||
server->cmdcount = 0;
|
||||
irc_send_cmdv(server, "PASS %s", conn->password);
|
||||
}
|
||||
|
||||
/* send nick */
|
||||
server->cmdcount = 0;
|
||||
irc_send_cmdv(server, "NICK %s", conn->nick);
|
||||
|
||||
/* send user/realname */
|
||||
server->cmdcount = 0;
|
||||
irc_send_cmdv(server, "USER %s - - :%s", conn->username, conn->realname);
|
||||
|
||||
server->cmdcount = 0;
|
||||
}
|
||||
|
||||
IRC_SERVER_REC *irc_server_connect(IRC_SERVER_CONNECT_REC *conn)
|
||||
{
|
||||
IRC_SERVER_REC *server;
|
||||
|
||||
g_return_val_if_fail(conn != NULL, NULL);
|
||||
if (conn->address == NULL || *conn->address == '\0') return NULL;
|
||||
if (conn->nick == NULL || *conn->nick == '\0') return NULL;
|
||||
|
||||
server = g_new0(IRC_SERVER_REC, 1);
|
||||
server->type = module_get_uniq_id("IRC SERVER", SERVER_TYPE_IRC);
|
||||
|
||||
server->connrec = conn;
|
||||
if (conn->port <= 0) conn->port = 6667;
|
||||
if (conn->username == NULL || *conn->username == '\0') {
|
||||
g_free_not_null(conn->username);
|
||||
|
||||
conn->username = g_get_user_name();
|
||||
if (*conn->username == '\0') conn->username = "-";
|
||||
conn->username = g_strdup(conn->username);
|
||||
}
|
||||
if (conn->realname == NULL || *conn->realname == '\0') {
|
||||
g_free_not_null(conn->realname);
|
||||
|
||||
conn->realname = g_get_real_name();
|
||||
if (*conn->realname == '\0') conn->realname = "-";
|
||||
conn->realname = g_strdup(conn->realname);
|
||||
}
|
||||
|
||||
server->nick = g_strdup(conn->nick);
|
||||
|
||||
server->cmd_queue_speed = conn->cmd_queue_speed > 0 ?
|
||||
conn->cmd_queue_speed : settings_get_int("cmd_queue_speed");
|
||||
server->max_cmds_at_once = conn->max_cmds_at_once > 0 ?
|
||||
conn->max_cmds_at_once : settings_get_int("cmds_max_at_once");
|
||||
|
||||
server->max_kicks_in_cmd = conn->max_kicks > 0 ?
|
||||
conn->max_kicks : DEFAULT_MAX_KICKS;
|
||||
server->max_modes_in_cmd = conn->max_modes > 0 ?
|
||||
conn->max_modes : DEFAULT_MAX_MODES;
|
||||
server->max_whois_in_cmd = conn->max_whois > 0 ?
|
||||
conn->max_whois : DEFAULT_MAX_WHOIS;
|
||||
server->max_msgs_in_cmd = conn->max_msgs > 0 ?
|
||||
conn->max_msgs : DEFAULT_MAX_MSGS;
|
||||
|
||||
if (!server_connect((SERVER_REC *) server)) {
|
||||
irc_server_connect_free(conn);
|
||||
g_free(server->nick);
|
||||
g_free(server);
|
||||
return NULL;
|
||||
}
|
||||
return server;
|
||||
}
|
||||
|
||||
static void sig_connected(IRC_SERVER_REC *server)
|
||||
{
|
||||
server->eventtable = g_hash_table_new((GHashFunc) g_istr_hash, (GCompareFunc) g_istr_equal);
|
||||
server->eventgrouptable = g_hash_table_new((GHashFunc) g_direct_hash, (GCompareFunc) g_direct_equal);
|
||||
server->cmdtable = g_hash_table_new((GHashFunc) g_istr_hash, (GCompareFunc) g_istr_equal);
|
||||
server->splits = g_hash_table_new((GHashFunc) g_istr_hash, (GCompareFunc) g_istr_equal);
|
||||
|
||||
server_init(server);
|
||||
}
|
||||
|
||||
static int server_remove_channels(IRC_SERVER_REC *server)
|
||||
{
|
||||
GSList *tmp;
|
||||
int found;
|
||||
|
||||
g_return_val_if_fail(server != NULL, FALSE);
|
||||
|
||||
found = FALSE;
|
||||
for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
|
||||
CHANNEL_REC *channel = tmp->data;
|
||||
|
||||
channel->server = NULL;
|
||||
channel_destroy(channel);
|
||||
found = TRUE;
|
||||
}
|
||||
|
||||
for (tmp = server->queries; tmp != NULL; tmp = tmp->next)
|
||||
query_change_server(tmp->data, NULL);
|
||||
|
||||
g_slist_free(server->channels);
|
||||
g_slist_free(server->queries);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static void sig_disconnected(IRC_SERVER_REC *server)
|
||||
{
|
||||
int chans;
|
||||
|
||||
/* close all channels */
|
||||
chans = server_remove_channels(server);
|
||||
|
||||
g_slist_foreach(server->cmdqueue, (GFunc) g_free, NULL);
|
||||
g_slist_free(server->cmdqueue);
|
||||
|
||||
if (server->handle != -1) {
|
||||
if (!chans || server->connection_lost)
|
||||
net_disconnect(server->handle);
|
||||
else {
|
||||
/* we were on some channels, try to let the server
|
||||
disconnect so that our quit message is guaranteed
|
||||
to get displayed */
|
||||
net_disconnect_later(server->handle);
|
||||
}
|
||||
server->handle = -1;
|
||||
}
|
||||
|
||||
irc_server_connect_free(server->connrec);
|
||||
g_free_not_null(server->real_address);
|
||||
g_free_not_null(server->version);
|
||||
g_free_not_null(server->usermode);
|
||||
g_free_not_null(server->userhost);
|
||||
g_free_not_null(server->last_invite);
|
||||
g_free_not_null(server->away_reason);
|
||||
}
|
||||
|
||||
static void sig_connect_failed(IRC_SERVER_REC *server)
|
||||
{
|
||||
server_remove_channels(server);
|
||||
irc_server_connect_free(server->connrec);
|
||||
}
|
||||
|
||||
static void server_cmd_timeout(IRC_SERVER_REC *server, GTimeVal *now)
|
||||
{
|
||||
long usecs;
|
||||
char *cmd;
|
||||
int len, ret, add_rawlog;
|
||||
|
||||
if (server->cmdcount == 0 && server->cmdqueue == NULL)
|
||||
return;
|
||||
|
||||
if (!server->cmd_last_split) {
|
||||
usecs = get_timeval_diff(now, &server->last_cmd);
|
||||
if (usecs < server->cmd_queue_speed)
|
||||
return;
|
||||
}
|
||||
|
||||
server->cmdcount--;
|
||||
if (server->cmdqueue == NULL) return;
|
||||
|
||||
/* send command */
|
||||
cmd = server->cmdqueue->data;
|
||||
len = strlen(cmd);
|
||||
|
||||
add_rawlog = !server->cmd_last_split;
|
||||
|
||||
ret = net_transmit(server->handle, cmd, len);
|
||||
if (ret != len) {
|
||||
/* we didn't transmit all data, try again a bit later.. */
|
||||
if (ret > 0) {
|
||||
cmd = g_strdup((char *) (server->cmdqueue->data) + ret);
|
||||
g_free(server->cmdqueue->data);
|
||||
server->cmdqueue->data = cmd;
|
||||
}
|
||||
server->cmd_last_split = TRUE;
|
||||
server->cmdcount++;
|
||||
} else {
|
||||
memcpy(&server->last_cmd, now, sizeof(GTimeVal));
|
||||
if (server->cmd_last_split)
|
||||
server->cmd_last_split = FALSE;
|
||||
}
|
||||
|
||||
if (add_rawlog) {
|
||||
/* add to rawlog without CR+LF */
|
||||
int slen;
|
||||
|
||||
slen = strlen(cmd);
|
||||
cmd[slen-2] = '\0';
|
||||
rawlog_output(server->rawlog, cmd);
|
||||
cmd[slen-2] = '\r';
|
||||
}
|
||||
|
||||
if (ret == len) {
|
||||
/* remove from queue */
|
||||
g_free(cmd);
|
||||
server->cmdqueue = g_slist_remove(server->cmdqueue, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
/* check every now and then if there's data to be sent in command buffer */
|
||||
static int servers_cmd_timeout(void)
|
||||
{
|
||||
GTimeVal now;
|
||||
|
||||
g_get_current_time(&now);
|
||||
g_slist_foreach(servers, (GFunc) server_cmd_timeout, &now);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return a string of all channels (and keys, if any have them) in server,
|
||||
like "#a,#b,#c,#d x,b_chan_key,x,x" or just "#e,#f,#g" */
|
||||
char *irc_server_get_channels(IRC_SERVER_REC *server)
|
||||
{
|
||||
GSList *tmp;
|
||||
GString *chans, *keys;
|
||||
char *ret;
|
||||
int use_keys;
|
||||
|
||||
g_return_val_if_fail(server != NULL, FALSE);
|
||||
|
||||
chans = g_string_new(NULL);
|
||||
keys = g_string_new(NULL);
|
||||
|
||||
use_keys = FALSE;
|
||||
for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
|
||||
CHANNEL_REC *channel = tmp->data;
|
||||
|
||||
g_string_sprintfa(chans, "%s,", channel->name);
|
||||
g_string_sprintfa(keys, "%s,", channel->key == NULL ? "x" : channel->key);
|
||||
if (channel->key != NULL)
|
||||
use_keys = TRUE;
|
||||
}
|
||||
|
||||
if (chans->len > 0) {
|
||||
g_string_truncate(chans, chans->len-1);
|
||||
g_string_truncate(keys, keys->len-1);
|
||||
if (use_keys) g_string_sprintfa(chans, " %s", keys->str);
|
||||
}
|
||||
|
||||
ret = chans->str;
|
||||
g_string_free(chans, FALSE);
|
||||
g_string_free(keys, TRUE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sig_set_user_mode(IRC_SERVER_REC *server)
|
||||
{
|
||||
const char *mode;
|
||||
char *newmode;
|
||||
|
||||
if (g_slist_find(servers, server) == NULL)
|
||||
return 0; /* got disconnected */
|
||||
|
||||
mode = settings_get_str("default_user_mode");
|
||||
newmode = modes_join(server->usermode, mode);
|
||||
if (strcmp(newmode, server->usermode) != 0)
|
||||
irc_send_cmdv(server, "MODE %s %s", server->nick, mode);
|
||||
g_free(newmode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void event_connected(const char *data, IRC_SERVER_REC *server, const char *from)
|
||||
{
|
||||
char *params, *nick;
|
||||
const char *mode;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
params = event_get_params(data, 1, &nick);
|
||||
|
||||
if (strcmp(server->nick, nick) != 0) {
|
||||
/* nick changed unexpectedly .. connected via proxy, etc. */
|
||||
g_free(server->nick);
|
||||
server->nick = g_strdup(nick);
|
||||
}
|
||||
|
||||
if (server->real_address == NULL) {
|
||||
/* set the server address */
|
||||
server->real_address = g_strdup(from);
|
||||
}
|
||||
|
||||
/* last welcome message found - commands can be sent to server now. */
|
||||
server->connected = 1;
|
||||
|
||||
if (!server->connrec->reconnection) {
|
||||
/* wait a second and then send the user mode */
|
||||
mode = settings_get_str("default_user_mode");
|
||||
if (*mode != '\0')
|
||||
g_timeout_add(1000, (GSourceFunc) sig_set_user_mode, server);
|
||||
}
|
||||
|
||||
signal_emit("event connected", 1, server);
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_server_info(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *ircd_version, *usermodes, *chanmodes;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
params = event_get_params(data, 5, NULL, NULL, &ircd_version, &usermodes, &chanmodes);
|
||||
|
||||
/* check if server understands I and e channel modes */
|
||||
if (strchr(chanmodes, 'I') && strchr(chanmodes, 'e'))
|
||||
server->emode_known = TRUE;
|
||||
|
||||
/* save server version */
|
||||
g_free_not_null(server->version);
|
||||
server->version = g_strdup(ircd_version);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_ping(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *str;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
str = g_strdup_printf("PONG %s", data);
|
||||
irc_send_cmd_now(server, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void event_empty(void)
|
||||
{
|
||||
}
|
||||
|
||||
void irc_servers_init(void)
|
||||
{
|
||||
settings_add_str("misc", "default_user_mode", DEFAULT_USER_MODE);
|
||||
settings_add_int("flood", "cmd_queue_speed", DEFAULT_CMD_QUEUE_SPEED);
|
||||
settings_add_int("flood", "cmds_max_at_once", DEFAULT_CMDS_MAX_AT_ONCE);
|
||||
|
||||
cmd_tag = g_timeout_add(500, (GSourceFunc) servers_cmd_timeout, NULL);
|
||||
|
||||
signal_add_first("server connected", (SIGNAL_FUNC) sig_connected);
|
||||
signal_add_last("server disconnected", (SIGNAL_FUNC) sig_disconnected);
|
||||
signal_add_last("server connect failed", (SIGNAL_FUNC) sig_connect_failed);
|
||||
signal_add("event 001", (SIGNAL_FUNC) event_connected);
|
||||
signal_add("event 004", (SIGNAL_FUNC) event_server_info);
|
||||
signal_add("event ping", (SIGNAL_FUNC) event_ping);
|
||||
signal_add("event empty", (SIGNAL_FUNC) event_empty);
|
||||
|
||||
servers_setup_init();
|
||||
ircnets_setup_init();
|
||||
servers_idle_init();
|
||||
servers_reconnect_init();
|
||||
}
|
||||
|
||||
void irc_servers_deinit(void)
|
||||
{
|
||||
while (servers != NULL)
|
||||
server_disconnect(servers->data);
|
||||
while (lookup_servers != NULL)
|
||||
server_disconnect(lookup_servers->data);
|
||||
|
||||
g_source_remove(cmd_tag);
|
||||
|
||||
signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
|
||||
signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
|
||||
signal_remove("server connect failed", (SIGNAL_FUNC) sig_connect_failed);
|
||||
signal_remove("event 001", (SIGNAL_FUNC) event_connected);
|
||||
signal_remove("event 004", (SIGNAL_FUNC) event_server_info);
|
||||
signal_remove("event ping", (SIGNAL_FUNC) event_ping);
|
||||
signal_remove("event empty", (SIGNAL_FUNC) event_empty);
|
||||
|
||||
servers_setup_deinit();
|
||||
ircnets_setup_deinit();
|
||||
servers_idle_deinit();
|
||||
servers_reconnect_deinit();
|
||||
}
|
||||
146
src/irc/core/irc-server.h
Normal file
146
src/irc/core/irc-server.h
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
#ifndef __IRC_SERVER_H
|
||||
#define __IRC_SERVER_H
|
||||
|
||||
#include "server.h"
|
||||
|
||||
enum {
|
||||
SERVER_TYPE_IRC
|
||||
};
|
||||
|
||||
/* return if `server' doesn't point to IRC server record. */
|
||||
#define irc_server_check(server) \
|
||||
((server) != NULL && module_find_id("IRC SERVER", (server)->type) != -1)
|
||||
|
||||
/* all strings should be either NULL or dynamically allocated */
|
||||
/* address and nick are mandatory, rest are optional */
|
||||
typedef struct {
|
||||
/* -- GENERIC SERVER_CONNECT_REC - don't change! -- */
|
||||
/* if we're connecting via proxy, or just NULLs */
|
||||
char *proxy;
|
||||
int proxy_port;
|
||||
char *proxy_string;
|
||||
|
||||
/* server where we want to connect */
|
||||
char *address;
|
||||
int port;
|
||||
char *ircnet;
|
||||
|
||||
IPADDR *own_ip;
|
||||
|
||||
/* -- IRC specific - change if you wish -- */
|
||||
char *password;
|
||||
char *nick, *alternate_nick;
|
||||
char *username;
|
||||
char *realname;
|
||||
|
||||
int max_cmds_at_once;
|
||||
int cmd_queue_speed;
|
||||
int max_kicks, max_msgs, max_modes, max_whois;
|
||||
|
||||
/* when reconnecting, the old server status */
|
||||
int reconnection:1; /* we're trying to reconnect */
|
||||
char *channels;
|
||||
char *away_reason;
|
||||
char *usermode;
|
||||
} IRC_SERVER_CONNECT_REC;
|
||||
|
||||
typedef struct {
|
||||
/* -- GENERIC SERVER_REC - don't change! -- */
|
||||
int type; /* server type */
|
||||
|
||||
IRC_SERVER_CONNECT_REC *connrec;
|
||||
time_t connect_time; /* connection time */
|
||||
|
||||
char *tag; /* tag name for addressing server */
|
||||
char *nick; /* current nick */
|
||||
|
||||
int connected:1; /* connected to server */
|
||||
int connection_lost:1; /* Connection lost unintentionally */
|
||||
|
||||
int handle; /* socket handle */
|
||||
int readtag; /* input tag */
|
||||
|
||||
/* for net_connect_nonblock() */
|
||||
int connect_pipe[2];
|
||||
int connect_tag;
|
||||
int connect_pid;
|
||||
|
||||
/* For deciding if event should be handled internally */
|
||||
GHashTable *eventtable; /* "event xxx" : GSList* of REDIRECT_RECs */
|
||||
GHashTable *eventgrouptable; /* event group : GSList* of REDIRECT_RECs */
|
||||
GHashTable *cmdtable; /* "command xxx" : REDIRECT_CMD_REC* */
|
||||
|
||||
void *rawlog;
|
||||
void *buffer; /* receive buffer */
|
||||
GHashTable *module_data;
|
||||
|
||||
/* -- IRC specific - change if you wish -- */
|
||||
char *real_address; /* address the irc server gives */
|
||||
char *version; /* server version - taken from 004 event */
|
||||
char *usermode; /* The whole mode string .. */
|
||||
char *userhost; /* /USERHOST <nick> - set when joined to first channel */
|
||||
char *last_invite; /* channel where you were last invited */
|
||||
char *away_reason;
|
||||
int usermode_away:1;
|
||||
int server_operator:1;
|
||||
|
||||
int whois_coming:1; /* Mostly just to display away message right.. */
|
||||
|
||||
int emode_known:1; /* Server understands ban exceptions and invite lists */
|
||||
int no_multi_mode:1; /* Server doesn't understand MODE #chan1,#chan2,... */
|
||||
int no_multi_who:1; /* Server doesn't understand WHO #chan1,#chan2,... */
|
||||
int one_endofwho:1; /* /WHO #a,#b,.. replies only with one End of WHO message */
|
||||
|
||||
int max_kicks_in_cmd; /* max. number of people to kick with one /KICK command */
|
||||
int max_modes_in_cmd; /* max. number of mode changes in one /MODE command */
|
||||
int max_whois_in_cmd; /* max. number of nicks in one /WHOIS command */
|
||||
int max_msgs_in_cmd; /* max. number of targets in one /MSG */
|
||||
|
||||
/* Command sending queue */
|
||||
int cmdcount; /* number of commands in `cmdqueue'. Can be more than
|
||||
there actually is, to make flood control remember
|
||||
how many messages can be sent before starting the
|
||||
flood control */
|
||||
int cmd_last_split; /* Last command wasn't sent entirely to server.
|
||||
First item in `cmdqueue' should be re-sent. */
|
||||
GSList *cmdqueue;
|
||||
GTimeVal last_cmd; /* last time command was sent to server */
|
||||
|
||||
int max_cmds_at_once; /* How many messages can be sent immediately before timeouting starts */
|
||||
int cmd_queue_speed; /* Timeout between sending commands */
|
||||
|
||||
GSList *idles; /* Idle queue - send these commands to server
|
||||
if there's nothing else to do */
|
||||
|
||||
GSList *ctcpqueue; /* CTCP flood protection - list of tags in idle queue */
|
||||
|
||||
/* /knockout ban list */
|
||||
GSList *knockoutlist;
|
||||
time_t knockout_lastcheck;
|
||||
|
||||
GSList *lastmsgs; /* List of nicks who last send you msg */
|
||||
GHashTable *splits; /* For keeping track of netsplits */
|
||||
|
||||
time_t lag_sent; /* 0 or time when last lag query was sent to server */
|
||||
time_t lag_last_check; /* last time we checked lag */
|
||||
int lag; /* server lag in milliseconds */
|
||||
|
||||
GSList *channels;
|
||||
GSList *queries;
|
||||
|
||||
gpointer chanqueries;
|
||||
} IRC_SERVER_REC;
|
||||
|
||||
IRC_SERVER_REC *irc_server_connect(IRC_SERVER_CONNECT_REC *conn);
|
||||
|
||||
/* Return a string of all channels (and keys, if any have them) in server,
|
||||
like "#a,#b,#c,#d x,b_chan_key,x,x" or just "#e,#f,#g" */
|
||||
char *irc_server_get_channels(IRC_SERVER_REC *server);
|
||||
|
||||
/* INTERNAL: Free memory used by connection record */
|
||||
void irc_server_connect_free(IRC_SERVER_CONNECT_REC *rec);
|
||||
|
||||
void irc_servers_init(void);
|
||||
void irc_servers_deinit(void);
|
||||
|
||||
#endif
|
||||
332
src/irc/core/irc-special-vars.c
Normal file
332
src/irc/core/irc-special-vars.c
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
/*
|
||||
irc-special-vars.c : irssi
|
||||
|
||||
Copyright (C) 2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "misc.h"
|
||||
#include "special-vars.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include "irc.h"
|
||||
#include "irc-server.h"
|
||||
#include "channels.h"
|
||||
#include "query.h"
|
||||
|
||||
static char *last_privmsg_from;
|
||||
static char *last_sent_msg, *last_sent_msg_body;
|
||||
static char *last_join, *last_public_from;
|
||||
|
||||
/* last person who sent you a MSG */
|
||||
static char *expando_lastmsg(void *server, void *item, int *free_ret)
|
||||
{
|
||||
return last_privmsg_from;
|
||||
}
|
||||
|
||||
/* last person to whom you sent a MSG */
|
||||
static char *expando_lastmymsg(void *server, void *item, int *free_ret)
|
||||
{
|
||||
return last_sent_msg;
|
||||
}
|
||||
|
||||
/* last person to join a channel you are on */
|
||||
static char *expando_lastjoin(void *server, void *item, int *free_ret)
|
||||
{
|
||||
return last_join;
|
||||
}
|
||||
|
||||
/* last person to send a public message to a channel you are on */
|
||||
static char *expando_lastpublic(void *server, void *item, int *free_ret)
|
||||
{
|
||||
return last_public_from;
|
||||
}
|
||||
|
||||
/* text of your AWAY message, if any */
|
||||
static char *expando_awaymsg(void *server, void *item, int *free_ret)
|
||||
{
|
||||
IRC_SERVER_REC *ircserver = server;
|
||||
|
||||
return ircserver == NULL ? "" : ircserver->away_reason;
|
||||
}
|
||||
|
||||
/* body of last MSG you sent */
|
||||
static char *expando_lastmymsg_body(void *server, void *item, int *free_ret)
|
||||
{
|
||||
return last_sent_msg_body;
|
||||
}
|
||||
|
||||
/* current channel */
|
||||
static char *expando_channel(void *server, void *item, int *free_ret)
|
||||
{
|
||||
CHANNEL_REC *channel;
|
||||
|
||||
channel = irc_item_channel(item);
|
||||
return channel == NULL ? NULL : channel->name;
|
||||
}
|
||||
|
||||
/* current server numeric being processed */
|
||||
static char *expando_server_numeric(void *server, void *item, int *free_ret)
|
||||
{
|
||||
return current_server_event == NULL ||
|
||||
!is_numeric(current_server_event, 0) ? NULL :
|
||||
current_server_event;
|
||||
}
|
||||
|
||||
/* channel you were last INVITEd to */
|
||||
static char *expando_last_invite(void *server, void *item, int *free_ret)
|
||||
{
|
||||
IRC_SERVER_REC *ircserver = server;
|
||||
|
||||
return ircserver == NULL ? "" : ircserver->last_invite;
|
||||
}
|
||||
|
||||
/* modes of current channel, if any */
|
||||
static char *expando_chanmode(void *server, void *item, int *free_ret)
|
||||
{
|
||||
CHANNEL_REC *channel;
|
||||
|
||||
channel = irc_item_channel(item);
|
||||
if (channel == NULL) return NULL;
|
||||
|
||||
*free_ret = TRUE;
|
||||
return channel_get_mode(channel);
|
||||
}
|
||||
|
||||
/* current nickname */
|
||||
static char *expando_nick(void *server, void *item, int *free_ret)
|
||||
{
|
||||
IRC_SERVER_REC *ircserver = server;
|
||||
|
||||
return ircserver == NULL ? "" : ircserver->nick;
|
||||
}
|
||||
|
||||
/* value of STATUS_OPER if you are an irc operator */
|
||||
static char *expando_statusoper(void *server, void *item, int *free_ret)
|
||||
{
|
||||
IRC_SERVER_REC *ircserver = server;
|
||||
|
||||
return ircserver == NULL || !ircserver->server_operator ? "" :
|
||||
(char *) settings_get_str("STATUS_OPER");
|
||||
}
|
||||
|
||||
/* if you are a channel operator in $C, expands to a '@' */
|
||||
static char *expando_chanop(void *server, void *item, int *free_ret)
|
||||
{
|
||||
CHANNEL_REC *channel;
|
||||
|
||||
channel = irc_item_channel(item);
|
||||
if (channel == NULL) return NULL;
|
||||
|
||||
return channel->chanop ? "@" : "";
|
||||
}
|
||||
|
||||
/* nickname of whomever you are QUERYing */
|
||||
static char *expando_query(void *server, void *item, int *free_ret)
|
||||
{
|
||||
QUERY_REC *query;
|
||||
|
||||
query = irc_item_query(item);
|
||||
return query == NULL ? NULL : query->nick;
|
||||
}
|
||||
|
||||
/* version of current server */
|
||||
static char *expando_serverversion(void *server, void *item, int *free_ret)
|
||||
{
|
||||
IRC_SERVER_REC *ircserver = server;
|
||||
|
||||
return ircserver == NULL ? "" : ircserver->version;
|
||||
}
|
||||
|
||||
/* current server name */
|
||||
static char *expando_servername(void *server, void *item, int *free_ret)
|
||||
{
|
||||
IRC_SERVER_REC *ircserver = server;
|
||||
|
||||
return ircserver == NULL ? "" : ircserver->real_address;
|
||||
}
|
||||
|
||||
/* target of current input (channel or QUERY nickname) */
|
||||
static char *expando_target(void *server, void *item, int *free_ret)
|
||||
{
|
||||
if (!irc_item_check(item))
|
||||
return NULL;
|
||||
|
||||
return ((WI_IRC_REC *) item)->name;
|
||||
}
|
||||
/* your /userhost $N address (user@host) */
|
||||
static char *expando_userhost(void *server, void *item, int *free_ret)
|
||||
{
|
||||
IRC_SERVER_REC *ircserver = server;
|
||||
const char *username;
|
||||
char hostname[100];
|
||||
|
||||
/* prefer the _real_ /userhost reply */
|
||||
if (ircserver != NULL && ircserver->userhost != NULL)
|
||||
return ircserver->userhost;
|
||||
|
||||
/* haven't received userhost reply yet. guess something */
|
||||
*free_ret = TRUE;
|
||||
if (server == NULL)
|
||||
username = settings_get_str("user_name");
|
||||
else
|
||||
username = ircserver->connrec->username;
|
||||
|
||||
if (gethostname(hostname, sizeof(hostname)) != 0 || *hostname == '\0')
|
||||
strcpy(hostname, "??");
|
||||
return g_strconcat(username, "@", hostname, NULL);;
|
||||
}
|
||||
|
||||
/* value of REALNAME */
|
||||
static char *expando_realname(void *server, void *item, int *free_ret)
|
||||
{
|
||||
IRC_SERVER_REC *ircserver = server;
|
||||
|
||||
return ircserver == NULL ? "" : ircserver->connrec->realname;
|
||||
}
|
||||
|
||||
/* Server tag */
|
||||
static char *expando_servertag(void *server, void *item, int *free_ret)
|
||||
{
|
||||
IRC_SERVER_REC *ircserver = server;
|
||||
|
||||
return ircserver == NULL ? "" : ircserver->tag;
|
||||
}
|
||||
|
||||
/* Server ircnet */
|
||||
static char *expando_ircnet(void *server, void *item, int *free_ret)
|
||||
{
|
||||
IRC_SERVER_REC *ircserver = server;
|
||||
|
||||
return ircserver == NULL ? "" : ircserver->connrec->ircnet;
|
||||
}
|
||||
|
||||
static void event_privmsg(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr)
|
||||
{
|
||||
char *params, *target, *msg;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg);
|
||||
|
||||
if (*msg != 1) {
|
||||
if (!ischannel(*target)) {
|
||||
g_free_not_null(last_privmsg_from);
|
||||
last_privmsg_from = g_strdup(nick);
|
||||
} else {
|
||||
g_free_not_null(last_public_from);
|
||||
last_public_from = g_strdup(nick);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void cmd_msg(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *target, *msg;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg);
|
||||
if (*target != '\0' && *msg != '\0' && !ischannel(*target) && isalpha(*target)) {
|
||||
g_free_not_null(last_sent_msg);
|
||||
g_free_not_null(last_sent_msg_body);
|
||||
last_sent_msg = g_strdup(target);
|
||||
last_sent_msg_body = g_strdup(msg);
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_join(const char *data, IRC_SERVER_REC *server, const char *nick, const char *address)
|
||||
{
|
||||
g_return_if_fail(nick != NULL);
|
||||
|
||||
if (g_strcasecmp(nick, server->nick) != 0) {
|
||||
g_free_not_null(last_join);
|
||||
last_join = g_strdup(nick);
|
||||
}
|
||||
}
|
||||
|
||||
void irc_special_vars_init(void)
|
||||
{
|
||||
settings_add_str("misc", "STATUS_OPER", "*");
|
||||
|
||||
last_privmsg_from = NULL;
|
||||
last_sent_msg = NULL; last_sent_msg_body = NULL;
|
||||
last_join = NULL; last_public_from = NULL;
|
||||
|
||||
expando_create(",", expando_lastmsg);
|
||||
expando_create(".", expando_lastmymsg);
|
||||
expando_create(":", expando_lastjoin);
|
||||
expando_create(";", expando_lastpublic);
|
||||
expando_create("A", expando_awaymsg);
|
||||
expando_create("B", expando_lastmymsg_body);
|
||||
expando_create("C", expando_channel);
|
||||
expando_create("H", expando_server_numeric);
|
||||
expando_create("I", expando_last_invite);
|
||||
expando_create("M", expando_chanmode);
|
||||
expando_create("N", expando_nick);
|
||||
expando_create("O", expando_statusoper);
|
||||
expando_create("P", expando_chanop);
|
||||
expando_create("Q", expando_query);
|
||||
expando_create("R", expando_serverversion);
|
||||
expando_create("S", expando_servername);
|
||||
expando_create("T", expando_target);
|
||||
expando_create("X", expando_userhost);
|
||||
expando_create("Y", expando_realname);
|
||||
expando_create("tag", expando_servertag);
|
||||
expando_create("ircnet", expando_ircnet);
|
||||
|
||||
signal_add("event privmsg", (SIGNAL_FUNC) event_privmsg);
|
||||
signal_add("event join", (SIGNAL_FUNC) event_join);
|
||||
signal_add("command msg", (SIGNAL_FUNC) cmd_msg);
|
||||
}
|
||||
|
||||
void irc_special_vars_deinit(void)
|
||||
{
|
||||
g_free_not_null(last_privmsg_from);
|
||||
g_free_not_null(last_sent_msg); g_free_not_null(last_sent_msg_body);
|
||||
g_free_not_null(last_join); g_free_not_null(last_public_from);
|
||||
|
||||
expando_destroy(",", expando_lastmsg);
|
||||
expando_destroy(".", expando_lastmymsg);
|
||||
expando_destroy(":", expando_lastjoin);
|
||||
expando_destroy(";", expando_lastpublic);
|
||||
expando_destroy("A", expando_awaymsg);
|
||||
expando_destroy("B", expando_lastmymsg_body);
|
||||
expando_destroy("C", expando_channel);
|
||||
expando_destroy("H", expando_server_numeric);
|
||||
expando_destroy("I", expando_last_invite);
|
||||
expando_destroy("M", expando_chanmode);
|
||||
expando_destroy("N", expando_nick);
|
||||
expando_destroy("O", expando_statusoper);
|
||||
expando_destroy("P", expando_chanop);
|
||||
expando_destroy("Q", expando_query);
|
||||
expando_destroy("R", expando_serverversion);
|
||||
expando_destroy("S", expando_servername);
|
||||
expando_destroy("T", expando_target);
|
||||
expando_destroy("X", expando_userhost);
|
||||
expando_destroy("Y", expando_realname);
|
||||
expando_destroy("tag", expando_servertag);
|
||||
expando_destroy("ircnet", expando_ircnet);
|
||||
|
||||
signal_remove("event privmsg", (SIGNAL_FUNC) event_privmsg);
|
||||
signal_remove("event join", (SIGNAL_FUNC) event_join);
|
||||
signal_remove("command msg", (SIGNAL_FUNC) cmd_msg);
|
||||
}
|
||||
7
src/irc/core/irc-special-vars.h
Normal file
7
src/irc/core/irc-special-vars.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef __IRC_SPECIAL_VARS_H
|
||||
#define __IRC_SPECIAL_VARS_H
|
||||
|
||||
void irc_special_vars_init(void);
|
||||
void irc_special_vars_deinit(void);
|
||||
|
||||
#endif
|
||||
440
src/irc/core/irc.c
Normal file
440
src/irc/core/irc.c
Normal file
|
|
@ -0,0 +1,440 @@
|
|||
/*
|
||||
irc.c : irssi
|
||||
|
||||
Copyright (C) 1999 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "modules.h"
|
||||
#include "network.h"
|
||||
#include "line-split.h"
|
||||
#include "rawlog.h"
|
||||
|
||||
#include "irc.h"
|
||||
#include "irc-server.h"
|
||||
#include "channels.h"
|
||||
#include "server-redirect.h"
|
||||
|
||||
char *current_server_event;
|
||||
static int signal_send_command;
|
||||
static int signal_default_event;
|
||||
static int signal_server_event;
|
||||
static int signal_server_incoming;
|
||||
|
||||
static void cmd_send(IRC_SERVER_REC *server, const char *cmd, int send_now, int immediate)
|
||||
{
|
||||
char str[513], *ptr;
|
||||
int len, ret;
|
||||
|
||||
server->cmdcount++;
|
||||
|
||||
if (send_now)
|
||||
rawlog_output(server->rawlog, cmd);
|
||||
|
||||
/* just check that we don't send any longer commands than 512 bytes.. */
|
||||
strncpy(str, cmd, 510);
|
||||
len = strlen(cmd);
|
||||
str[len++] = 13; str[len++] = 10; str[len] = '\0';
|
||||
|
||||
ptr = str;
|
||||
if (send_now) {
|
||||
ret = net_transmit(server->handle, str, len);
|
||||
if (ret == len) {
|
||||
g_get_current_time(&server->last_cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
/* we didn't transmit all data, try again a bit later.. */
|
||||
ptr += ret;
|
||||
server->cmd_last_split = TRUE;
|
||||
}
|
||||
|
||||
/* add to queue */
|
||||
ptr = g_strdup(ptr);
|
||||
if (!immediate)
|
||||
server->cmdqueue = g_slist_append(server->cmdqueue, ptr);
|
||||
else if (send_now)
|
||||
server->cmdqueue = g_slist_prepend(server->cmdqueue, ptr);
|
||||
else
|
||||
server->cmdqueue = g_slist_insert(server->cmdqueue, ptr, 1);
|
||||
}
|
||||
|
||||
/* Send command to IRC server */
|
||||
void irc_send_cmd(IRC_SERVER_REC *server, const char *cmd)
|
||||
{
|
||||
int send_now;
|
||||
|
||||
g_return_if_fail(cmd != NULL);
|
||||
if (server == NULL) return;
|
||||
|
||||
send_now = !server->cmd_last_split &&
|
||||
(server->cmdcount < server->max_cmds_at_once ||
|
||||
server->cmd_queue_speed <= 0);
|
||||
|
||||
cmd_send(server, cmd, send_now, FALSE);
|
||||
}
|
||||
|
||||
/* Send command to IRC server */
|
||||
void irc_send_cmdv(IRC_SERVER_REC *server, const char *cmd, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *str;
|
||||
|
||||
va_start(args, cmd);
|
||||
|
||||
str = g_strdup_vprintf(cmd, args);
|
||||
irc_send_cmd(server, str);
|
||||
g_free(str);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* Send command to server immediately bypassing all flood protections
|
||||
and queues. */
|
||||
void irc_send_cmd_now(IRC_SERVER_REC *server, const char *cmd)
|
||||
{
|
||||
g_return_if_fail(cmd != NULL);
|
||||
if (server == NULL) return;
|
||||
|
||||
cmd_send(server, cmd, !server->cmd_last_split, TRUE);
|
||||
}
|
||||
|
||||
static char *split_nicks(const char *cmd, char **pre, char **nicks, char **post, int arg)
|
||||
{
|
||||
char *p;
|
||||
|
||||
*pre = g_strdup(cmd);
|
||||
*post = *nicks = NULL;
|
||||
for (p = *pre; *p != '\0'; p++) {
|
||||
if (!isspace(*p))
|
||||
continue;
|
||||
|
||||
if (arg == 1) {
|
||||
/* text after nicks */
|
||||
*p++ = '\0';
|
||||
while (isspace(*p)) p++;
|
||||
*post = p;
|
||||
break;
|
||||
}
|
||||
|
||||
/* find nicks */
|
||||
while (isspace(p[1])) p++;
|
||||
if (--arg == 1) {
|
||||
*p = '\0';
|
||||
*nicks = p+1;
|
||||
}
|
||||
}
|
||||
|
||||
return *pre;
|
||||
}
|
||||
|
||||
void irc_send_cmd_split(IRC_SERVER_REC *server, const char *cmd,
|
||||
int nickarg, int max_nicks)
|
||||
{
|
||||
char *str, *pre, *post, *nicks;
|
||||
char **nicklist, **tmp;
|
||||
GString *nickstr;
|
||||
int count;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
g_return_if_fail(cmd != NULL);
|
||||
|
||||
str = split_nicks(cmd, &pre, &nicks, &post, nickarg);
|
||||
|
||||
/* split the nicks */
|
||||
nickstr = g_string_new(NULL);
|
||||
nicklist = g_strsplit(nicks, ",", -1); count = 0;
|
||||
|
||||
tmp = nicklist;
|
||||
for (;; tmp++) {
|
||||
if (*tmp != NULL) {
|
||||
g_string_sprintfa(nickstr, "%s,", *tmp);
|
||||
if (++count < max_nicks)
|
||||
continue;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
g_string_truncate(nickstr, nickstr->len-1);
|
||||
irc_send_cmdv(server, post == NULL ? "%s %s" : "%s %s %s",
|
||||
pre, nickstr->str, post);
|
||||
g_string_truncate(nickstr, 0);
|
||||
|
||||
if (*tmp == NULL || tmp[1] == NULL)
|
||||
break;
|
||||
}
|
||||
g_strfreev(nicklist);
|
||||
g_string_free(nickstr, TRUE);
|
||||
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
/* Nick can be in format "servertag/nick" - Update `nick' to
|
||||
position "nick" and return "servertag" which you need to free */
|
||||
char *irc_nick_get_server(char **nick)
|
||||
{
|
||||
char *ptr, *tag;
|
||||
|
||||
ptr = strchr(*nick, '/');
|
||||
if (ptr == NULL) return NULL;
|
||||
if (ptr == *nick) {
|
||||
(*nick)++;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tag = g_strndup(*nick, (int) (ptr-*nick));
|
||||
*nick = ptr+1;
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
/* Get next parameter */
|
||||
char *event_get_param(char **data)
|
||||
{
|
||||
char *pos;
|
||||
|
||||
g_return_val_if_fail(data != NULL, NULL);
|
||||
g_return_val_if_fail(*data != NULL, NULL);
|
||||
|
||||
if (**data == ':') {
|
||||
/* last parameter */
|
||||
pos = *data;
|
||||
*data += strlen(*data);
|
||||
return pos+1;
|
||||
}
|
||||
|
||||
pos = *data;
|
||||
while (**data != '\0' && **data != ' ') (*data)++;
|
||||
if (**data == ' ') *(*data)++ = '\0';
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
/* Get count parameters from data */
|
||||
char *event_get_params(const char *data, int count, ...)
|
||||
{
|
||||
char **str, *tmp, *duprec, *datad;
|
||||
gboolean rest;
|
||||
va_list args;
|
||||
|
||||
g_return_val_if_fail(data != NULL, NULL);
|
||||
|
||||
va_start(args, count);
|
||||
duprec = datad = g_strdup(data);
|
||||
|
||||
rest = count & PARAM_FLAG_GETREST;
|
||||
count = PARAM_WITHOUT_FLAGS(count);
|
||||
|
||||
while (count-- > 0) {
|
||||
str = (char **) va_arg(args, char **);
|
||||
if (count == 0 && rest) {
|
||||
/* put the rest to last parameter */
|
||||
tmp = *datad == ':' ? datad+1 : datad;
|
||||
} else {
|
||||
tmp = event_get_param(&datad);
|
||||
}
|
||||
if (str != NULL) *str = tmp;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return duprec;
|
||||
}
|
||||
|
||||
static void irc_server_event(const char *line, IRC_SERVER_REC *server, const char *nick, const char *address)
|
||||
{
|
||||
char *event, *args, *callcmd;
|
||||
GSList *list;
|
||||
|
||||
g_return_if_fail(line != NULL);
|
||||
|
||||
/* get command.. */
|
||||
event = g_strconcat("event ", line, NULL);
|
||||
args = strchr(event+6, ' ');
|
||||
if (args != NULL) *args++ = '\0'; else args = "";
|
||||
while (*args == ' ') args++;
|
||||
|
||||
list = server_redirect_getqueue((SERVER_REC *) server, event, args);
|
||||
if (list == NULL)
|
||||
callcmd = g_strdup(event);
|
||||
else {
|
||||
/* event is redirected somewhere else.. */
|
||||
REDIRECT_REC *rec;
|
||||
|
||||
rec = list->data;
|
||||
callcmd = g_strdup(rec->name);
|
||||
rawlog_redirect(server->rawlog, callcmd);
|
||||
server_redirect_remove_next((SERVER_REC *) server, event, list);
|
||||
}
|
||||
|
||||
current_server_event = event+6;
|
||||
g_strdown(callcmd);
|
||||
if (!signal_emit(callcmd, 4, args, server, nick, address))
|
||||
signal_emit_id(signal_default_event, 4, line, server, nick, address);
|
||||
current_server_event = NULL;
|
||||
|
||||
g_free(callcmd);
|
||||
g_free(event);
|
||||
}
|
||||
|
||||
/* Read line from server */
|
||||
static int irc_receive_line(SERVER_REC *server, char **str)
|
||||
{
|
||||
char tmpbuf[512];
|
||||
int recvlen, ret;
|
||||
|
||||
g_return_val_if_fail(server != NULL, -1);
|
||||
g_return_val_if_fail(str != NULL, -1);
|
||||
|
||||
recvlen = net_receive(server->handle, tmpbuf, sizeof(tmpbuf));
|
||||
|
||||
ret = line_split(tmpbuf, recvlen, str, (LINEBUF_REC **) &server->buffer);
|
||||
if (ret == -1) {
|
||||
/* connection lost */
|
||||
server->connection_lost = TRUE;
|
||||
server_disconnect(server);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *irc_parse_prefix(char *line, char **nick, char **address)
|
||||
{
|
||||
*nick = *address = NULL;
|
||||
|
||||
if (*line != ':')
|
||||
return line;
|
||||
|
||||
*nick = ++line;
|
||||
while (*line != '\0' && *line != ' ') {
|
||||
if (*line == '!') {
|
||||
*line = '\0';
|
||||
*address = line+1;
|
||||
}
|
||||
line++;
|
||||
}
|
||||
|
||||
if (*line == ' ') {
|
||||
*line++ = '\0';
|
||||
while (*line == ' ') line++;
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
/* Parse command line sent by server */
|
||||
static void irc_parse_incoming_line(IRC_SERVER_REC *server, char *line)
|
||||
{
|
||||
char *nick, *address;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
g_return_if_fail(line != NULL);
|
||||
|
||||
line = irc_parse_prefix(line, &nick, &address);
|
||||
if (*line != '\0')
|
||||
signal_emit_id(signal_server_event, 4, line, server, nick, address);
|
||||
}
|
||||
|
||||
/* input function: handle incoming server messages */
|
||||
static void irc_parse_incoming(SERVER_REC *server)
|
||||
{
|
||||
char *str;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
while (irc_receive_line(server, &str) > 0) {
|
||||
rawlog_input(server->rawlog, str);
|
||||
signal_emit_id(signal_server_incoming, 2, server, str);
|
||||
}
|
||||
}
|
||||
|
||||
static void irc_init_server(IRC_SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
server->readtag =
|
||||
g_input_add(server->handle, G_INPUT_READ,
|
||||
(GInputFunction) irc_parse_incoming, server);
|
||||
}
|
||||
|
||||
static void irc_deinit_server(IRC_SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
if (server->readtag > 0)
|
||||
g_source_remove(server->readtag);
|
||||
}
|
||||
|
||||
#define isoptchan(a) \
|
||||
(ischannel((a)[0]) || ((a)[0] == '*' && ((a)[1] == '\0' || (a)[1] == ' ')))
|
||||
|
||||
static char *irc_cmd_get_func(const char *data, int *count, va_list *vargs)
|
||||
{
|
||||
WI_IRC_REC *item;
|
||||
CHANNEL_REC *channel;
|
||||
char *ret, *args, *chan, *p;
|
||||
|
||||
if ((*count & PARAM_FLAG_OPTCHAN) == 0)
|
||||
return g_strdup(data);
|
||||
|
||||
*count &= ~PARAM_FLAG_OPTCHAN;
|
||||
item = (WI_IRC_REC *) va_arg(*vargs, WI_IRC_REC *);
|
||||
channel = irc_item_channel(item);
|
||||
|
||||
/* change first argument in data to full channel name. */
|
||||
p = args = g_strdup(data);
|
||||
|
||||
chan = isoptchan(args) ? cmd_get_param(&args) : NULL;
|
||||
if (chan != NULL && *chan == '!') {
|
||||
/* whenever trying to send something to !channel,
|
||||
change it to the real joined !XXXXXchannel */
|
||||
channel = channel_find(channel->server, chan);
|
||||
if (channel != NULL) chan = channel->name;
|
||||
}
|
||||
|
||||
if (chan == NULL || strcmp(chan, "*") == 0) {
|
||||
chan = channel == NULL ? "*" : channel->name;
|
||||
}
|
||||
|
||||
ret = g_strconcat(chan, " ", args, NULL);
|
||||
g_free(p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void irc_irc_init(void)
|
||||
{
|
||||
cmd_get_add_func(irc_cmd_get_func);
|
||||
|
||||
signal_add("server event", (SIGNAL_FUNC) irc_server_event);
|
||||
signal_add("server connected", (SIGNAL_FUNC) irc_init_server);
|
||||
signal_add_first("server disconnected", (SIGNAL_FUNC) irc_deinit_server);
|
||||
signal_add("server incoming", (SIGNAL_FUNC) irc_parse_incoming_line);
|
||||
|
||||
current_server_event = NULL;
|
||||
signal_send_command = module_get_uniq_id_str("signals", "send command");
|
||||
signal_default_event = module_get_uniq_id_str("signals", "default event");
|
||||
signal_server_event = module_get_uniq_id_str("signals", "server event");
|
||||
signal_server_incoming = module_get_uniq_id_str("signals", "server incoming");
|
||||
}
|
||||
|
||||
void irc_irc_deinit(void)
|
||||
{
|
||||
signal_remove("server event", (SIGNAL_FUNC) irc_server_event);
|
||||
signal_remove("server connected", (SIGNAL_FUNC) irc_init_server);
|
||||
signal_remove("server disconnected", (SIGNAL_FUNC) irc_deinit_server);
|
||||
signal_remove("server incoming", (SIGNAL_FUNC) irc_parse_incoming_line);
|
||||
|
||||
module_uniq_destroy("IRC");
|
||||
module_uniq_destroy("IRC SERVER");
|
||||
}
|
||||
90
src/irc/core/irc.h
Normal file
90
src/irc/core/irc.h
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
#ifndef __IRC_H
|
||||
#define __IRC_H
|
||||
|
||||
#include "modules.h"
|
||||
#include "irc-server.h"
|
||||
|
||||
/* From ircd 2.9.5:
|
||||
none I line with ident
|
||||
^ I line with OTHER type ident
|
||||
~ I line, no ident
|
||||
+ i line with ident
|
||||
= i line with OTHER type ident
|
||||
- i line, no ident
|
||||
*/
|
||||
#define ishostflag(a) ((a) == '^' || (a) == '~' || (a) == '+' || (a) == '=' || (a) == '-')
|
||||
#define isnickflag(a) ((a) == '@' || (a) == '+' || (a) == '-' || (a) == '~')
|
||||
#define ischannel(a) ((a) == '#' || (a) == '&' || (a) == '!' || (a) == '+')
|
||||
|
||||
/* values returned by module_category() */
|
||||
enum {
|
||||
WI_IRC_CHANNEL,
|
||||
WI_IRC_QUERY,
|
||||
WI_IRC_DCC_CHAT
|
||||
};
|
||||
|
||||
/* *MUST* have the same contents as WI_ITEM_REC in same order. */
|
||||
typedef struct {
|
||||
int type;
|
||||
GHashTable *module_data;
|
||||
|
||||
IRC_SERVER_REC *server;
|
||||
char *name;
|
||||
|
||||
int new_data;
|
||||
} WI_IRC_REC;
|
||||
|
||||
/* return TRUE if `item' is an IRC type. */
|
||||
#define irc_item_check(item) \
|
||||
(item != NULL && module_find_id("IRC", ((WI_IRC_REC *) (item))->type) != -1)
|
||||
|
||||
/* return `item' type, or -1 if it's not IRC type. */
|
||||
#define irc_item_get(item) \
|
||||
(item == NULL ? -1 : module_find_id("IRC", ((WI_IRC_REC *) (item))->type))
|
||||
|
||||
/* Return `item' if it's channel, NULL if it isn't. */
|
||||
#define irc_item_channel(item) \
|
||||
(item != NULL && module_find_id("IRC", ((WI_IRC_REC *) (item))->type) == WI_IRC_CHANNEL ? \
|
||||
(void *) (item) : NULL)
|
||||
|
||||
/* Return `item' if it's query, NULL if it isn't. */
|
||||
#define irc_item_query(item) \
|
||||
(item != NULL && module_find_id("IRC", ((WI_IRC_REC *) (item))->type) == WI_IRC_QUERY ? \
|
||||
(void *) (item) : NULL)
|
||||
|
||||
/* Return `item' if it's DCC chat, NULL if it isn't. */
|
||||
#define irc_item_dcc_chat(item) \
|
||||
(item != NULL && module_find_id("IRC", ((WI_IRC_REC *) (item))->type) == WI_IRC_DCC_CHAT ? \
|
||||
(void *) (item) : NULL)
|
||||
|
||||
extern char *current_server_event; /* current server event being processed */
|
||||
|
||||
/* Send command to IRC server */
|
||||
void irc_send_cmd(IRC_SERVER_REC *server, const char *cmd);
|
||||
void irc_send_cmdv(IRC_SERVER_REC *server, const char *cmd, ...) G_GNUC_PRINTF (2, 3);;
|
||||
/* Send command to IRC server, split to multiple commands if necessary so
|
||||
that command will never have more target nicks than `max_nicks'. Nicks
|
||||
are separated with commas. (works with /msg, /kick, ...) */
|
||||
void irc_send_cmd_split(IRC_SERVER_REC *server, const char *cmd,
|
||||
int nickarg, int max_nicks);
|
||||
/* Send command to server immediately bypassing all flood protections
|
||||
and queues. */
|
||||
void irc_send_cmd_now(IRC_SERVER_REC *server, const char *cmd);
|
||||
|
||||
/* Nick can be in format "servertag/nick" - Update `nick' to
|
||||
position "nick" and return "servertag" which you need to free */
|
||||
char *irc_nick_get_server(char **nick);
|
||||
|
||||
#include "commands.h" /* contains the generic PARAM_FLAG_xxx defines */
|
||||
|
||||
/* IRC specific: optional channel in first argument */
|
||||
#define PARAM_FLAG_OPTCHAN 0x10000000
|
||||
|
||||
/* Get count parameters from data */
|
||||
char *event_get_param(char **data);
|
||||
char *event_get_params(const char *data, int count, ...);
|
||||
|
||||
void irc_irc_init(void);
|
||||
void irc_irc_deinit(void);
|
||||
|
||||
#endif
|
||||
116
src/irc/core/ircnet-setup.c
Normal file
116
src/irc/core/ircnet-setup.c
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
ircnet-setup.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "network.h"
|
||||
#include "signals.h"
|
||||
#include "lib-config/iconfig.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include "irc-server.h"
|
||||
#include "ircnet-setup.h"
|
||||
|
||||
GSList *ircnets; /* list of available ircnets */
|
||||
|
||||
/* Find the irc network by name */
|
||||
IRCNET_REC *ircnet_find(const char *name)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
g_return_val_if_fail(name != NULL, NULL);
|
||||
|
||||
for (tmp = ircnets; tmp != NULL; tmp = tmp->next) {
|
||||
IRCNET_REC *rec = tmp->data;
|
||||
|
||||
if (g_strcasecmp(rec->name, name) == 0)
|
||||
return rec;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ircnet_destroy(IRCNET_REC *rec)
|
||||
{
|
||||
ircnets = g_slist_remove(ircnets, rec);
|
||||
|
||||
g_free(rec->name);
|
||||
if (rec->nick != NULL) g_free(rec->nick);
|
||||
if (rec->username != NULL) g_free(rec->username);
|
||||
if (rec->realname != NULL) g_free(rec->realname);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
static IRCNET_REC *ircnet_add(CONFIG_NODE *node)
|
||||
{
|
||||
IRCNET_REC *rec;
|
||||
char *name, *nick, *username, *realname;
|
||||
|
||||
g_return_val_if_fail(node != NULL, NULL);
|
||||
|
||||
name = config_node_get_str(node, "name", NULL);
|
||||
if (name == NULL) return NULL;
|
||||
|
||||
nick = config_node_get_str(node, "nick", NULL);
|
||||
username = config_node_get_str(node, "username", NULL);
|
||||
realname = config_node_get_str(node, "realname", NULL);
|
||||
|
||||
rec = g_new0(IRCNET_REC, 1);
|
||||
rec->max_kicks = config_node_get_int(node, "max_kicks", 0);
|
||||
rec->max_msgs = config_node_get_int(node, "max_msgs", 0);
|
||||
rec->max_modes = config_node_get_int(node, "max_modes", 0);
|
||||
rec->max_whois = config_node_get_int(node, "max_whois", 0);
|
||||
|
||||
rec->name = g_strdup(name);
|
||||
rec->nick = (nick == NULL || *nick == '\0') ? NULL : g_strdup(nick);
|
||||
rec->username = (username == NULL || *username == '\0') ? NULL : g_strdup(username);
|
||||
rec->realname = (realname == NULL || *realname == '\0') ? NULL : g_strdup(realname);
|
||||
|
||||
ircnets = g_slist_append(ircnets, rec);
|
||||
return rec;
|
||||
}
|
||||
|
||||
static void read_ircnets(void)
|
||||
{
|
||||
CONFIG_NODE *node;
|
||||
GSList *tmp;
|
||||
|
||||
while (ircnets != NULL)
|
||||
ircnet_destroy(ircnets->data);
|
||||
|
||||
/* read ircnets */
|
||||
node = iconfig_node_traverse("ircnets", FALSE);
|
||||
if (node != NULL) {
|
||||
for (tmp = node->value; tmp != NULL; tmp = tmp->next)
|
||||
ircnet_add(tmp->data);
|
||||
}
|
||||
}
|
||||
|
||||
void ircnets_setup_init(void)
|
||||
{
|
||||
signal_add("setup reread", (SIGNAL_FUNC) read_ircnets);
|
||||
}
|
||||
|
||||
void ircnets_setup_deinit(void)
|
||||
{
|
||||
while (ircnets != NULL)
|
||||
ircnet_destroy(ircnets->data);
|
||||
|
||||
signal_remove("setup reread", (SIGNAL_FUNC) read_ircnets);
|
||||
}
|
||||
23
src/irc/core/ircnet-setup.h
Normal file
23
src/irc/core/ircnet-setup.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef __IRCNET_SETUP_H
|
||||
#define __IRCNET_SETUP_H
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
|
||||
char *nick;
|
||||
char *username;
|
||||
char *realname;
|
||||
|
||||
/* max. number of kicks/msgs/mode/whois per command */
|
||||
int max_kicks, max_msgs, max_modes, max_whois;
|
||||
} IRCNET_REC;
|
||||
|
||||
extern GSList *ircnets; /* list of available ircnets */
|
||||
|
||||
/* Find the irc network by name */
|
||||
IRCNET_REC *ircnet_find(const char *name);
|
||||
|
||||
void ircnets_setup_init(void);
|
||||
void ircnets_setup_deinit(void);
|
||||
|
||||
#endif
|
||||
178
src/irc/core/lag.c
Normal file
178
src/irc/core/lag.c
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
lag.c : irssi
|
||||
|
||||
Copyright (C) 1999 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
#include "misc.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include "irc.h"
|
||||
#include "irc-server.h"
|
||||
|
||||
typedef struct {
|
||||
IRC_SERVER_REC *server;
|
||||
GTimeVal time;
|
||||
} LAG_REC;
|
||||
|
||||
static gint timeout_tag;
|
||||
static GSList *lags;
|
||||
|
||||
static LAG_REC *lag_find(IRC_SERVER_REC *server)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
for (tmp = lags; tmp != NULL; tmp = tmp->next) {
|
||||
LAG_REC *lag = tmp->data;
|
||||
|
||||
if (lag->server == server)
|
||||
return lag;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void lag_free(LAG_REC *rec)
|
||||
{
|
||||
lags = g_slist_remove(lags, rec);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
static void lag_get(IRC_SERVER_REC *server)
|
||||
{
|
||||
LAG_REC *lag;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
lag = g_new0(LAG_REC, 1);
|
||||
lags = g_slist_append(lags, lag);
|
||||
lag->server = server;
|
||||
|
||||
g_get_current_time(&lag->time);
|
||||
|
||||
if (server->lag_sent == 0)
|
||||
server->lag_sent = time(NULL);
|
||||
server->lag_last_check = time(NULL);
|
||||
|
||||
/* NOTE: this will fail if there's any nick changes in buffer -
|
||||
that's why this function should be called only when the buffer
|
||||
is empty */
|
||||
irc_send_cmdv(server, "NOTICE %s :\001IRSSILAG %ld %ld\001",
|
||||
server->nick, lag->time.tv_sec, lag->time.tv_usec);
|
||||
}
|
||||
|
||||
/* we use "ctcp reply" signal here, because "ctcp reply irssilag" can be
|
||||
ignored with /IGNORE * CTCPS */
|
||||
static void sig_irssilag(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr, const char *target)
|
||||
{
|
||||
GTimeVal now, sent;
|
||||
LAG_REC *lag;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
if (strncmp(data, "IRSSILAG ", 9) != 0)
|
||||
return;
|
||||
data += 9;
|
||||
|
||||
lag = lag_find(server);
|
||||
if (lag == NULL) {
|
||||
/* not expecting lag reply.. */
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_strcasecmp(nick, server->nick) != 0) {
|
||||
/* we didn't sent this - not a lag notice */
|
||||
return;
|
||||
}
|
||||
|
||||
/* OK, it is a lag notice. */
|
||||
server->lag_sent = 0;
|
||||
|
||||
if (sscanf(data, "%ld %ld", &sent.tv_sec, &sent.tv_usec) == 2) {
|
||||
g_get_current_time(&now);
|
||||
server->lag = (int) get_timeval_diff(&now, &sent);
|
||||
signal_emit("server lag", 1, server);
|
||||
}
|
||||
|
||||
lag_free(lag);
|
||||
}
|
||||
|
||||
static int sig_check_lag(void)
|
||||
{
|
||||
GSList *tmp, *next;
|
||||
time_t now;
|
||||
int lag_check_time, max_lag;
|
||||
|
||||
lag_check_time = settings_get_int("lag_check_time");
|
||||
max_lag = settings_get_int("lag_max_before_disconnect");
|
||||
|
||||
if (lag_check_time <= 0)
|
||||
return 1;
|
||||
|
||||
now = time(NULL);
|
||||
for (tmp = servers; tmp != NULL; tmp = next) {
|
||||
IRC_SERVER_REC *rec = tmp->data;
|
||||
|
||||
next = tmp->next;
|
||||
if (!irc_server_check(rec))
|
||||
continue;
|
||||
|
||||
if (rec->lag_sent != 0) {
|
||||
/* waiting for lag reply */
|
||||
if (max_lag > 1 && now-rec->lag_sent > max_lag) {
|
||||
/* too much lag, disconnect */
|
||||
signal_emit("server lag disconnect", 1, rec);
|
||||
rec->connection_lost = TRUE;
|
||||
server_disconnect((SERVER_REC *) rec);
|
||||
}
|
||||
}
|
||||
else if (rec->lag_last_check+lag_check_time < now &&
|
||||
rec->cmdcount == 0 && rec->connected) {
|
||||
/* no commands in buffer - get the lag */
|
||||
lag_get(rec);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void sig_empty(void)
|
||||
{
|
||||
/* don't print the "CTCP IRSSILAG reply .." text */
|
||||
}
|
||||
|
||||
void lag_init(void)
|
||||
{
|
||||
settings_add_int("misc", "lag_check_time", 30);
|
||||
settings_add_int("misc", "lag_max_before_disconnect", 300);
|
||||
|
||||
lags = NULL;
|
||||
timeout_tag = g_timeout_add(1000, (GSourceFunc) sig_check_lag, NULL);
|
||||
signal_add("ctcp reply", (SIGNAL_FUNC) sig_irssilag);
|
||||
signal_add("ctcp reply irssilag", (SIGNAL_FUNC) sig_empty);
|
||||
}
|
||||
|
||||
void lag_deinit(void)
|
||||
{
|
||||
g_source_remove(timeout_tag);
|
||||
while (lags != NULL)
|
||||
lag_free(lags->data);
|
||||
signal_remove("ctcp reply", (SIGNAL_FUNC) sig_irssilag);
|
||||
signal_remove("ctcp reply irssilag", (SIGNAL_FUNC) sig_empty);
|
||||
}
|
||||
7
src/irc/core/lag.h
Normal file
7
src/irc/core/lag.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef __LAG_H
|
||||
#define __LAG_H
|
||||
|
||||
void lag_init(void);
|
||||
void lag_deinit(void);
|
||||
|
||||
#endif
|
||||
170
src/irc/core/masks.c
Normal file
170
src/irc/core/masks.c
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
masks.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "network.h"
|
||||
#include "misc.h"
|
||||
|
||||
#include "irc.h"
|
||||
#include "masks.h"
|
||||
|
||||
static int check_mask(const char *mask, int *wildcards)
|
||||
{
|
||||
while (*mask != '\0') {
|
||||
if (*mask == '!')
|
||||
return TRUE;
|
||||
|
||||
if (*mask == '?' || *mask == '*')
|
||||
*wildcards = TRUE;
|
||||
mask++;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int irc_mask_match(const char *mask, const char *nick, const char *user, const char *host)
|
||||
{
|
||||
char *str;
|
||||
int ret, wildcards;
|
||||
|
||||
if (!check_mask(mask, &wildcards)) {
|
||||
return wildcards ?
|
||||
match_wildcards(mask, nick) :
|
||||
g_strcasecmp(mask, nick) == 0;
|
||||
}
|
||||
|
||||
str = g_strdup_printf("%s!%s@%s", nick, user, host);
|
||||
ret = match_wildcards(mask, str);
|
||||
g_free(str);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int irc_mask_match_address(const char *mask, const char *nick, const char *address)
|
||||
{
|
||||
char *str;
|
||||
int ret, wildcards;
|
||||
|
||||
g_return_val_if_fail(address != NULL, FALSE);
|
||||
|
||||
if (!check_mask(mask, &wildcards)) {
|
||||
return wildcards ?
|
||||
match_wildcards(mask, nick) :
|
||||
g_strcasecmp(mask, nick) == 0;
|
||||
}
|
||||
|
||||
str = g_strdup_printf("%s!%s", nick, address);
|
||||
ret = match_wildcards(mask, str);
|
||||
g_free(str);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int irc_masks_match(const char *masks, const char *nick, const char *address)
|
||||
{
|
||||
char **list, **tmp, *mask;
|
||||
|
||||
g_return_val_if_fail(masks != NULL, FALSE);
|
||||
|
||||
mask = g_strdup_printf("%s!%s", nick, address);
|
||||
list = g_strsplit(masks, " ", -1);
|
||||
for (tmp = list; *tmp != NULL; tmp++) {
|
||||
if (strchr(*tmp, '!') == NULL && g_strcasecmp(*tmp, nick) == 0)
|
||||
break;
|
||||
|
||||
if (match_wildcards(*tmp, mask))
|
||||
break;
|
||||
}
|
||||
g_strfreev(list);
|
||||
g_free(mask);
|
||||
|
||||
return *tmp != NULL;
|
||||
}
|
||||
|
||||
static char *get_domain_mask(char *host)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
if (strchr(host, '.') == NULL) {
|
||||
/* no dots - toplevel domain or IPv6 address */
|
||||
ptr = strrchr(host, ':');
|
||||
if (ptr != NULL) {
|
||||
/* IPv6 address, ban the last 64k addresses */
|
||||
if (ptr[1] != '\0') strcpy(ptr+1, "*");
|
||||
}
|
||||
|
||||
return host;
|
||||
}
|
||||
|
||||
if (is_ipv4_address(host)) {
|
||||
/* it's an IP address, change last digit to * */
|
||||
ptr = strrchr(host, '.');
|
||||
if (ptr != NULL && isdigit(ptr[1]))
|
||||
strcpy(ptr+1, "*");
|
||||
} else {
|
||||
/* if more than one dot, skip the first
|
||||
(dyn123.blah.net -> *.blah.net) */
|
||||
ptr = strchr(host, '.');
|
||||
if (ptr != NULL && strchr(ptr+1, '.') != NULL) {
|
||||
host = ptr-1;
|
||||
host[0] = '*';
|
||||
}
|
||||
}
|
||||
|
||||
return host;
|
||||
}
|
||||
|
||||
char *irc_get_mask(const char *nick, const char *address, int flags)
|
||||
{
|
||||
char *ret, *user, *host;
|
||||
|
||||
/* strip -, ^ or ~ from start.. */
|
||||
user = g_strconcat("*", ishostflag(*address) ? address+1 : address, NULL);
|
||||
|
||||
/* split user and host */
|
||||
host = strchr(user, '@');
|
||||
if (host == NULL) {
|
||||
g_free(user);
|
||||
return NULL;
|
||||
}
|
||||
*host++ = '\0';
|
||||
|
||||
switch (flags & (IRC_MASK_HOST|IRC_MASK_DOMAIN)) {
|
||||
case IRC_MASK_HOST:
|
||||
/* we already have the host */
|
||||
break;
|
||||
case IRC_MASK_DOMAIN:
|
||||
/* domain - *.blah.org */
|
||||
host = get_domain_mask(host);
|
||||
break;
|
||||
default:
|
||||
/* no domain/host */
|
||||
host = "*";
|
||||
break;
|
||||
}
|
||||
|
||||
ret = g_strdup_printf("%s!%s@%s",
|
||||
(flags & IRC_MASK_NICK) ? nick : "*",
|
||||
(flags & IRC_MASK_USER) ? user : "*",
|
||||
host);
|
||||
g_free(user);
|
||||
|
||||
return ret;
|
||||
}
|
||||
15
src/irc/core/masks.h
Normal file
15
src/irc/core/masks.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef __MASKS_H
|
||||
#define __MASKS_H
|
||||
|
||||
#define IRC_MASK_NICK 0x01
|
||||
#define IRC_MASK_USER 0x02
|
||||
#define IRC_MASK_HOST 0x04
|
||||
#define IRC_MASK_DOMAIN 0x08
|
||||
|
||||
int irc_mask_match(const char *mask, const char *nick, const char *user, const char *host);
|
||||
int irc_mask_match_address(const char *mask, const char *nick, const char *address);
|
||||
int irc_masks_match(const char *masks, const char *nick, const char *address);
|
||||
|
||||
char *irc_get_mask(const char *nick, const char *address, int flags);
|
||||
|
||||
#endif
|
||||
254
src/irc/core/massjoin.c
Normal file
254
src/irc/core/massjoin.c
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
massjoin.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
#include "common-setup.h"
|
||||
|
||||
#include "channels.h"
|
||||
#include "irc.h"
|
||||
#include "nicklist.h"
|
||||
#include "irc-server.h"
|
||||
|
||||
static int massjoin_tag;
|
||||
|
||||
/* Massjoin support - really useful when trying to do things (like op/deop)
|
||||
to people after netjoins. It sends
|
||||
"massjoin #channel nick!user@host nick2!user@host ..." signals */
|
||||
static void event_join(const char *data, IRC_SERVER_REC *server, const char *nick, const char *address)
|
||||
{
|
||||
char *params, *channel, *ptr;
|
||||
CHANNEL_REC *chanrec;
|
||||
NICK_REC *nickrec;
|
||||
GSList *nicks, *tmp;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
if (g_strcasecmp(nick, server->nick) == 0) {
|
||||
/* You joined, no need to do anything here */
|
||||
return;
|
||||
}
|
||||
|
||||
params = event_get_params(data, 1, &channel);
|
||||
ptr = strchr(channel, 7); /* ^G does something weird.. */
|
||||
if (ptr != NULL) *ptr = '\0';
|
||||
|
||||
/* find channel */
|
||||
chanrec = channel_find(server, channel);
|
||||
g_free(params);
|
||||
if (chanrec == NULL) return;
|
||||
|
||||
/* add user to nicklist */
|
||||
nickrec = nicklist_insert(chanrec, nick, FALSE, FALSE, TRUE);
|
||||
nickrec->host = g_strdup(address);
|
||||
|
||||
if (chanrec->massjoins == 0) {
|
||||
/* no nicks waiting in massjoin queue */
|
||||
chanrec->massjoin_start = time(NULL);
|
||||
chanrec->last_massjoins = 0;
|
||||
}
|
||||
|
||||
/* Check if user is already in some other channel,
|
||||
get the realname from there */
|
||||
nicks = nicklist_get_same(server, nick);
|
||||
for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
|
||||
NICK_REC *rec = tmp->next->data;
|
||||
|
||||
if (rec->realname != NULL) {
|
||||
nickrec->last_check = rec->last_check;
|
||||
nickrec->realname = g_strdup(rec->realname);
|
||||
nickrec->gone = rec->gone;
|
||||
}
|
||||
}
|
||||
g_slist_free(nicks);
|
||||
|
||||
chanrec->massjoins++;
|
||||
}
|
||||
|
||||
static void event_part(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr)
|
||||
{
|
||||
char *params, *channel, *reason;
|
||||
CHANNEL_REC *chanrec;
|
||||
NICK_REC *nickrec;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
if (g_strcasecmp(nick, server->nick) == 0) {
|
||||
/* you left channel, no need to do anything here */
|
||||
return;
|
||||
}
|
||||
|
||||
params = event_get_params(data, 2, &channel, &reason);
|
||||
|
||||
/* find channel */
|
||||
chanrec = channel_find(server, channel);
|
||||
if (chanrec == NULL) {
|
||||
g_free(params);
|
||||
return;
|
||||
}
|
||||
|
||||
/* remove user from nicklist */
|
||||
nickrec = nicklist_find(chanrec, nick);
|
||||
if (nickrec != NULL) {
|
||||
if (nickrec->send_massjoin) {
|
||||
/* quick join/part after which it's useless to send
|
||||
nick in massjoin */
|
||||
chanrec->massjoins--;
|
||||
}
|
||||
nicklist_remove(chanrec, nickrec);
|
||||
}
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_quit(const char *data, IRC_SERVER_REC *server, const char *nick)
|
||||
{
|
||||
CHANNEL_REC *channel;
|
||||
NICK_REC *nickrec;
|
||||
GSList *nicks, *tmp;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
if (g_strcasecmp(nick, server->nick) == 0) {
|
||||
/* you quit, don't do anything here */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Remove nick from all channels */
|
||||
nicks = nicklist_get_same(server, nick);
|
||||
for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
|
||||
channel = tmp->data;
|
||||
nickrec = tmp->next->data;
|
||||
|
||||
if (nickrec->send_massjoin) {
|
||||
/* quick join/quit after which it's useless to
|
||||
send nick in massjoin */
|
||||
channel->massjoins--;
|
||||
}
|
||||
nicklist_remove(channel, nickrec);
|
||||
}
|
||||
g_slist_free(nicks);
|
||||
}
|
||||
|
||||
static void event_kick(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *channel, *nick, *reason;
|
||||
CHANNEL_REC *chanrec;
|
||||
NICK_REC *nickrec;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 3, &channel, &nick, &reason);
|
||||
|
||||
if (g_strcasecmp(nick, server->nick) == 0) {
|
||||
/* you were kicked, no need to do anything */
|
||||
g_free(params);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Remove user from nicklist */
|
||||
chanrec = channel_find(server, channel);
|
||||
nickrec = chanrec == NULL ? NULL : nicklist_find(chanrec, nick);
|
||||
if (chanrec != NULL && nickrec != NULL) {
|
||||
if (nickrec->send_massjoin) {
|
||||
/* quick join/kick after which it's useless to
|
||||
send nick in massjoin */
|
||||
chanrec->massjoins--;
|
||||
}
|
||||
nicklist_remove(chanrec, nickrec);
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void massjoin_send_hash(gpointer key, NICK_REC *nick, GSList **list)
|
||||
{
|
||||
if (nick->send_massjoin) {
|
||||
nick->send_massjoin = FALSE;
|
||||
*list = g_slist_append(*list, nick);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send channel's massjoin list signal */
|
||||
static void massjoin_send(CHANNEL_REC *channel)
|
||||
{
|
||||
GSList *list;
|
||||
|
||||
list = NULL;
|
||||
g_hash_table_foreach(channel->nicks, (GHFunc) massjoin_send_hash, &list);
|
||||
|
||||
channel->massjoins = 0;
|
||||
signal_emit("massjoin", 2, channel, list);
|
||||
g_slist_free(list);
|
||||
}
|
||||
|
||||
static void server_check_massjoins(IRC_SERVER_REC *server, time_t max)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
/* Scan all channels through for massjoins */
|
||||
for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
|
||||
CHANNEL_REC *rec = tmp->data;
|
||||
|
||||
if (rec->massjoins <= 0)
|
||||
continue;
|
||||
|
||||
if (rec->massjoin_start < max || /* We've waited long enough */
|
||||
rec->massjoins-5 < rec->last_massjoins) { /* Less than 5 joins since last check */
|
||||
/* send them */
|
||||
massjoin_send(rec);
|
||||
} else {
|
||||
/* Wait for some more.. */
|
||||
rec->last_massjoins = rec->massjoins;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int sig_massjoin_timeout(void)
|
||||
{
|
||||
GSList *tmp;
|
||||
time_t max;
|
||||
|
||||
max = time(NULL)-MAX_MASSJOIN_WAIT;
|
||||
for (tmp = servers; tmp != NULL; tmp = tmp->next)
|
||||
server_check_massjoins(tmp->data, max);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void massjoin_init(void)
|
||||
{
|
||||
massjoin_tag = g_timeout_add(1000, (GSourceFunc) sig_massjoin_timeout, NULL);
|
||||
|
||||
signal_add("event join", (SIGNAL_FUNC) event_join);
|
||||
signal_add("event part", (SIGNAL_FUNC) event_part);
|
||||
signal_add("event kick", (SIGNAL_FUNC) event_kick);
|
||||
signal_add("event quit", (SIGNAL_FUNC) event_quit);
|
||||
}
|
||||
|
||||
void massjoin_deinit(void)
|
||||
{
|
||||
g_source_remove(massjoin_tag);
|
||||
|
||||
signal_remove("event join", (SIGNAL_FUNC) event_join);
|
||||
signal_remove("event part", (SIGNAL_FUNC) event_part);
|
||||
signal_remove("event kick", (SIGNAL_FUNC) event_kick);
|
||||
signal_remove("event quit", (SIGNAL_FUNC) event_quit);
|
||||
}
|
||||
7
src/irc/core/massjoin.h
Normal file
7
src/irc/core/massjoin.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef __MASSJOIN_H
|
||||
#define __MASSJOIN_H
|
||||
|
||||
void massjoin_init(void);
|
||||
void massjoin_deinit(void);
|
||||
|
||||
#endif
|
||||
234
src/irc/core/mode-lists.c
Normal file
234
src/irc/core/mode-lists.c
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
mode-lists.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "misc.h"
|
||||
#include "signals.h"
|
||||
|
||||
#include "irc.h"
|
||||
#include "mode-lists.h"
|
||||
|
||||
static void ban_free(GSList **list, BAN_REC *rec)
|
||||
{
|
||||
g_return_if_fail(list != NULL);
|
||||
g_return_if_fail(rec != NULL);
|
||||
|
||||
g_free(rec->ban);
|
||||
g_free_not_null(rec->setby);
|
||||
g_free(rec);
|
||||
|
||||
*list = g_slist_remove(*list, rec);
|
||||
}
|
||||
|
||||
void banlist_free(GSList *banlist)
|
||||
{
|
||||
while (banlist != NULL)
|
||||
ban_free(&banlist, banlist->data);
|
||||
}
|
||||
|
||||
BAN_REC *banlist_add(CHANNEL_REC *channel, const char *ban, const char *nick, time_t time)
|
||||
{
|
||||
BAN_REC *rec;
|
||||
|
||||
g_return_val_if_fail(channel != NULL, NULL);
|
||||
g_return_val_if_fail(ban != NULL, NULL);
|
||||
g_return_val_if_fail(nick != NULL, NULL);
|
||||
|
||||
rec = g_new(BAN_REC, 1);
|
||||
rec->ban = g_strdup(ban);
|
||||
rec->setby = g_strdup(nick);
|
||||
rec->time = time;
|
||||
|
||||
channel->banlist = g_slist_append(channel->banlist, rec);
|
||||
|
||||
signal_emit("ban new", 1, rec);
|
||||
return rec;
|
||||
}
|
||||
|
||||
void banlist_remove(CHANNEL_REC *channel, const char *ban)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
g_return_if_fail(ban != NULL);
|
||||
|
||||
for (tmp = channel->banlist; tmp != NULL; tmp = tmp->next)
|
||||
{
|
||||
BAN_REC *rec = tmp->data;
|
||||
|
||||
if (g_strcasecmp(rec->ban, ban) == 0)
|
||||
{
|
||||
signal_emit("ban remove", 1, rec);
|
||||
ban_free(&channel->banlist, rec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BAN_REC *banlist_exception_add(CHANNEL_REC *channel, const char *ban, const char *nick, time_t time)
|
||||
{
|
||||
BAN_REC *rec;
|
||||
|
||||
g_return_val_if_fail(channel != NULL, NULL);
|
||||
g_return_val_if_fail(ban != NULL, NULL);
|
||||
g_return_val_if_fail(nick != NULL, NULL);
|
||||
|
||||
rec = g_new(BAN_REC, 1);
|
||||
rec->ban = g_strdup(ban);
|
||||
rec->setby = g_strdup(nick);
|
||||
rec->time = time;
|
||||
|
||||
channel->ebanlist = g_slist_append(channel->ebanlist, rec);
|
||||
|
||||
signal_emit("ban exception new", 1, rec);
|
||||
return rec;
|
||||
}
|
||||
|
||||
void banlist_exception_remove(CHANNEL_REC *channel, const char *ban)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
g_return_if_fail(ban != NULL);
|
||||
|
||||
for (tmp = channel->ebanlist; tmp != NULL; tmp = tmp->next)
|
||||
{
|
||||
BAN_REC *rec = tmp->data;
|
||||
|
||||
if (g_strcasecmp(rec->ban, ban) == 0)
|
||||
{
|
||||
signal_emit("ban exception remove", 1, rec);
|
||||
ban_free(&channel->ebanlist, rec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void invitelist_free(CHANNEL_REC *channel)
|
||||
{
|
||||
g_return_if_fail(channel != NULL);
|
||||
|
||||
g_slist_foreach(channel->invitelist, (GFunc) g_free, NULL);
|
||||
g_slist_free(channel->invitelist);
|
||||
}
|
||||
|
||||
void invitelist_add(CHANNEL_REC *channel, const char *mask)
|
||||
{
|
||||
g_return_if_fail(channel != NULL);
|
||||
g_return_if_fail(mask != NULL);
|
||||
|
||||
channel->invitelist = g_slist_append(channel->invitelist, g_strdup(mask));
|
||||
|
||||
signal_emit("invitelist new", 2, channel, mask);
|
||||
}
|
||||
|
||||
void invitelist_remove(CHANNEL_REC *channel, const char *mask)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
g_return_if_fail(channel != NULL);
|
||||
g_return_if_fail(mask != NULL);
|
||||
|
||||
tmp = gslist_find_icase_string(channel->invitelist, mask);
|
||||
if (tmp == NULL) return;
|
||||
|
||||
signal_emit("invitelist remove", 2, channel, tmp->data);
|
||||
g_free(tmp->data);
|
||||
channel->invitelist = g_slist_remove(channel->invitelist, tmp->data);
|
||||
}
|
||||
|
||||
static void channel_destroyed(CHANNEL_REC *channel)
|
||||
{
|
||||
g_return_if_fail(channel != NULL);
|
||||
|
||||
banlist_free(channel->banlist);
|
||||
banlist_free(channel->ebanlist);
|
||||
invitelist_free(channel);
|
||||
}
|
||||
|
||||
static void event_banlist(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
CHANNEL_REC *chanrec;
|
||||
char *params, *channel, *ban, *setby, *tims;
|
||||
time_t tim;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 5, NULL, &channel, &ban, &setby, &tims);
|
||||
chanrec = channel_find(server, channel);
|
||||
if (chanrec != NULL) {
|
||||
if (sscanf(tims, "%ld", (long *) &tim) != 1)
|
||||
tim = time(NULL);
|
||||
|
||||
banlist_add(chanrec, ban, setby, tim);
|
||||
}
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_ebanlist(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
CHANNEL_REC *chanrec;
|
||||
char *params, *channel, *ban, *setby, *tims;
|
||||
time_t tim;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 5, NULL, &channel, &ban, &setby, &tims);
|
||||
chanrec = channel_find(server, channel);
|
||||
if (chanrec != NULL) {
|
||||
if (sscanf(tims, "%ld", (long *) &tim) != 1)
|
||||
tim = time(NULL);
|
||||
|
||||
banlist_exception_add(chanrec, ban, setby, tim);
|
||||
}
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_invite_list(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
CHANNEL_REC *chanrec;
|
||||
char *params, *channel, *invite;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 3, NULL, &channel, &invite);
|
||||
chanrec = channel_find(server, channel);
|
||||
|
||||
if (chanrec != NULL)
|
||||
invitelist_add(chanrec, invite);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
void mode_lists_init(void)
|
||||
{
|
||||
signal_add("channel destroyed", (SIGNAL_FUNC) channel_destroyed);
|
||||
|
||||
signal_add("chanquery ban", (SIGNAL_FUNC) event_banlist);
|
||||
signal_add("chanquery eban", (SIGNAL_FUNC) event_ebanlist);
|
||||
signal_add("chanquery ilist", (SIGNAL_FUNC) event_invite_list);
|
||||
}
|
||||
|
||||
void mode_lists_deinit(void)
|
||||
{
|
||||
signal_remove("channel destroyed", (SIGNAL_FUNC) channel_destroyed);
|
||||
|
||||
signal_remove("chanquery ban", (SIGNAL_FUNC) event_banlist);
|
||||
signal_remove("chanquery eban", (SIGNAL_FUNC) event_ebanlist);
|
||||
signal_remove("chanquery ilist", (SIGNAL_FUNC) event_invite_list);
|
||||
}
|
||||
24
src/irc/core/mode-lists.h
Normal file
24
src/irc/core/mode-lists.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef __MODE_LISTS_H
|
||||
#define __MODE_LISTS_H
|
||||
|
||||
#include "channels.h"
|
||||
|
||||
typedef struct {
|
||||
char *ban;
|
||||
char *setby;
|
||||
time_t time;
|
||||
} BAN_REC;
|
||||
|
||||
BAN_REC *banlist_add(CHANNEL_REC *channel, const char *ban, const char *nick, time_t time);
|
||||
void banlist_remove(CHANNEL_REC *channel, const char *ban);
|
||||
|
||||
BAN_REC *banlist_exception_add(CHANNEL_REC *channel, const char *ban, const char *nick, time_t time);
|
||||
void banlist_exception_remove(CHANNEL_REC *channel, const char *ban);
|
||||
|
||||
void invitelist_add(CHANNEL_REC *channel, const char *mask);
|
||||
void invitelist_remove(CHANNEL_REC *channel, const char *mask);
|
||||
|
||||
void mode_lists_init(void);
|
||||
void mode_lists_deinit(void);
|
||||
|
||||
#endif
|
||||
451
src/irc/core/modes.c
Normal file
451
src/irc/core/modes.c
Normal file
|
|
@ -0,0 +1,451 @@
|
|||
/*
|
||||
modes.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "commands.h"
|
||||
#include "signals.h"
|
||||
|
||||
#include "irc.h"
|
||||
#include "mode-lists.h"
|
||||
#include "nicklist.h"
|
||||
|
||||
/* Change nick's mode in channel */
|
||||
static void nick_mode_change(CHANNEL_REC *channel, const char *nick, const char mode, gboolean set)
|
||||
{
|
||||
NICK_REC *nickrec;
|
||||
|
||||
g_return_if_fail(channel != NULL);
|
||||
g_return_if_fail(nick != NULL);
|
||||
|
||||
nickrec = nicklist_find(channel, nick);
|
||||
if (nickrec == NULL) return; /* No /names list got yet */
|
||||
|
||||
if (mode == '@') nickrec->op = set;
|
||||
if (mode == '+') nickrec->voice = set;
|
||||
|
||||
signal_emit("nick mode changed", 2, channel, nickrec);
|
||||
}
|
||||
|
||||
/* Parse channel mode string */
|
||||
void parse_channel_modes(CHANNEL_REC *channel, const char *setby, const char *mode)
|
||||
{
|
||||
char *dup, *modestr, *ptr, *curmode, type;
|
||||
|
||||
g_return_if_fail(channel != NULL);
|
||||
g_return_if_fail(setby != NULL);
|
||||
g_return_if_fail(modestr != NULL);
|
||||
|
||||
type = '+';
|
||||
|
||||
dup = modestr = g_strdup(mode);
|
||||
curmode = cmd_get_param(&modestr);
|
||||
while (*curmode != '\0') {
|
||||
switch (*curmode) {
|
||||
case '+':
|
||||
case '-':
|
||||
type = *curmode;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
ptr = cmd_get_param(&modestr);
|
||||
if (*ptr == '\0') break;
|
||||
|
||||
if (type == '+')
|
||||
banlist_add(channel, ptr, setby, time(NULL));
|
||||
else
|
||||
banlist_remove(channel, ptr);
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
ptr = cmd_get_param(&modestr);
|
||||
if (*ptr == '\0') break;
|
||||
|
||||
if (type == '+')
|
||||
banlist_exception_add(channel, ptr, setby, time(NULL));
|
||||
else
|
||||
banlist_exception_remove(channel, ptr);
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
ptr = cmd_get_param(&modestr);
|
||||
if (*ptr == '\0') break;
|
||||
|
||||
if (type == '+')
|
||||
invitelist_add(channel, ptr);
|
||||
else
|
||||
invitelist_remove(channel, ptr);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
ptr = cmd_get_param(&modestr);
|
||||
if (*ptr != '\0')
|
||||
nick_mode_change(channel, ptr, '+', type == '+');
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
ptr = cmd_get_param(&modestr);
|
||||
if (*ptr == '\0') break;
|
||||
|
||||
if (strcmp(channel->server->nick, ptr) == 0)
|
||||
channel->chanop = type == '+' ? TRUE : FALSE;
|
||||
nick_mode_change(channel, ptr, '@', type == '+');
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
if (type == '-')
|
||||
channel->limit = 0;
|
||||
else {
|
||||
ptr = cmd_get_param(&modestr);
|
||||
sscanf(ptr, "%d", &channel->limit);
|
||||
}
|
||||
signal_emit("channel mode changed", 1, channel);
|
||||
break;
|
||||
case 'k':
|
||||
ptr = cmd_get_param(&modestr);
|
||||
if (*ptr != '\0' || type == '-') {
|
||||
g_free_and_null(channel->key);
|
||||
if (type == '+') {
|
||||
channel->key = g_strdup(ptr);
|
||||
channel->mode_key = TRUE;
|
||||
}
|
||||
}
|
||||
signal_emit("channel mode changed", 1, channel);
|
||||
break;
|
||||
|
||||
default:
|
||||
switch (*curmode) {
|
||||
case 'i':
|
||||
channel->mode_invite = type == '+';
|
||||
break;
|
||||
case 'm':
|
||||
channel->mode_moderate = type == '+';
|
||||
break;
|
||||
case 's':
|
||||
channel->mode_secret = type == '+';
|
||||
break;
|
||||
case 'p':
|
||||
channel->mode_private = type == '+';
|
||||
break;
|
||||
case 'n':
|
||||
channel->mode_nomsgs = type == '+';
|
||||
break;
|
||||
case 't':
|
||||
channel->mode_optopic = type == '+';
|
||||
break;
|
||||
case 'a':
|
||||
channel->mode_anonymous = type == '+';
|
||||
break;
|
||||
case 'r':
|
||||
channel->mode_reop = type == '+';
|
||||
break;
|
||||
}
|
||||
signal_emit("channel mode changed", 1, channel);
|
||||
break;
|
||||
}
|
||||
|
||||
curmode++;
|
||||
}
|
||||
g_free(dup);
|
||||
|
||||
if (!channel->mode_key && channel->key != NULL) {
|
||||
/* join was used with key but there's no key set
|
||||
in channel modes.. */
|
||||
g_free(channel->key);
|
||||
channel->key = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int compare_char(const void *p1, const void *p2)
|
||||
{
|
||||
const char *c1 = p1, *c2 = p2;
|
||||
|
||||
return *c1 < *c2 ? -1 :
|
||||
(*c1 > *c2 ? 1 : 0);
|
||||
}
|
||||
|
||||
/* add `mode' to `old' - return newly allocated mode. */
|
||||
char *modes_join(const char *old, const char *mode)
|
||||
{
|
||||
GString *newmode;
|
||||
char type, *p;
|
||||
|
||||
g_return_val_if_fail(mode != NULL, NULL);
|
||||
|
||||
type = '+';
|
||||
newmode = g_string_new(old);
|
||||
while (*mode != '\0' && *mode != ' ') {
|
||||
if (*mode == '+' || *mode == '-') {
|
||||
type = *mode;
|
||||
} else {
|
||||
p = strchr(newmode->str, *mode);
|
||||
|
||||
if (type == '+' && p == NULL)
|
||||
g_string_append_c(newmode, *mode);
|
||||
else if (type == '-' && p != NULL)
|
||||
g_string_erase(newmode, (int) (p-newmode->str), 1);
|
||||
}
|
||||
|
||||
mode++;
|
||||
}
|
||||
|
||||
qsort(newmode->str, sizeof(char), newmode->len, compare_char);
|
||||
|
||||
p = newmode->str;
|
||||
g_string_free(newmode, FALSE);
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Parse user mode string */
|
||||
static void parse_user_mode(IRC_SERVER_REC *server, const char *modestr)
|
||||
{
|
||||
char *newmode, *oldmode;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
g_return_if_fail(modestr != NULL);
|
||||
|
||||
newmode = modes_join(server->usermode, modestr);
|
||||
oldmode = server->usermode;
|
||||
server->usermode = newmode;
|
||||
server->server_operator = (strchr(newmode, 'o') != NULL);
|
||||
|
||||
signal_emit("user mode changed", 2, server, oldmode);
|
||||
g_free_not_null(oldmode);
|
||||
}
|
||||
|
||||
static void event_user_mode(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *nick, *mode;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 3, NULL, &nick, &mode);
|
||||
parse_user_mode(server, mode);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_mode(const char *data, IRC_SERVER_REC *server, const char *nick)
|
||||
{
|
||||
CHANNEL_REC *chanrec;
|
||||
char *params, *channel, *mode;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &channel, &mode);
|
||||
|
||||
if (!ischannel(*channel)) {
|
||||
/* user mode change */
|
||||
parse_user_mode(server, mode);
|
||||
} else {
|
||||
/* channel mode change */
|
||||
chanrec = channel_find(server, channel);
|
||||
if (chanrec != NULL)
|
||||
parse_channel_modes(chanrec, nick, mode);
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_away(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
server->usermode_away = TRUE;
|
||||
signal_emit("away mode changed", 1, server);
|
||||
}
|
||||
|
||||
static void event_unaway(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
server->usermode_away = FALSE;
|
||||
g_free_and_null(server->away_reason);
|
||||
signal_emit("away mode changed", 1, server);
|
||||
}
|
||||
|
||||
void channel_set_singlemode(IRC_SERVER_REC *server, const char *channel, const char *nicks, const char *mode)
|
||||
{
|
||||
GString *str;
|
||||
int num, modepos;
|
||||
char **nick, **nicklist;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
g_return_if_fail(channel != NULL);
|
||||
g_return_if_fail(nicks != NULL);
|
||||
g_return_if_fail(mode != NULL);
|
||||
if (*nicks == '\0') return;
|
||||
|
||||
num = modepos = 0;
|
||||
str = g_string_new(NULL);
|
||||
|
||||
nicklist = g_strsplit(nicks, " ", -1);
|
||||
for (nick = nicklist; *nick != NULL; nick++) {
|
||||
if (num == 0)
|
||||
{
|
||||
g_string_sprintf(str, "MODE %s %s", channel, mode);
|
||||
modepos = str->len;
|
||||
} else {
|
||||
/* insert the mode string */
|
||||
g_string_insert(str, modepos, mode);
|
||||
}
|
||||
|
||||
g_string_sprintfa(str, " %s", *nick);
|
||||
|
||||
if (++num == server->connrec->max_modes) {
|
||||
/* max. modes / command reached, send to server */
|
||||
irc_send_cmd(server, str->str);
|
||||
num = 0;
|
||||
}
|
||||
}
|
||||
if (num > 0) irc_send_cmd(server, str->str);
|
||||
|
||||
g_strfreev(nicklist);
|
||||
g_string_free(str, TRUE);
|
||||
}
|
||||
|
||||
#define MODE_HAS_ARG(c) ((c) == 'b' || (c) == 'e' || (c) == 'I' || \
|
||||
(c) == 'v' || (c) == 'o' || (c) == 'l' || (c) == 'k')
|
||||
|
||||
void channel_set_mode(IRC_SERVER_REC *server, const char *channel, const char *mode)
|
||||
{
|
||||
char *modestr, *curmode, type, *orig;
|
||||
GString *tmode, *targs;
|
||||
int count;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
g_return_if_fail(channel != NULL);
|
||||
g_return_if_fail(modestr != NULL);
|
||||
|
||||
tmode = g_string_new(NULL);
|
||||
targs = g_string_new(NULL);
|
||||
type = '+'; count = 0;
|
||||
|
||||
orig = modestr = g_strdup(mode);
|
||||
|
||||
curmode = cmd_get_param(&modestr);
|
||||
for (; *curmode != '\0'; curmode++) {
|
||||
if (*curmode == '+' || *curmode == '-') {
|
||||
type = *curmode;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (count == server->connrec->max_modes && MODE_HAS_ARG(*curmode)) {
|
||||
irc_send_cmdv(server, "MODE %s %s%s", channel, tmode->str, targs->str);
|
||||
|
||||
count = 0;
|
||||
g_string_truncate(tmode, 0);
|
||||
g_string_truncate(targs, 0);
|
||||
}
|
||||
|
||||
g_string_append_c(tmode, *curmode);
|
||||
|
||||
if (MODE_HAS_ARG(*curmode)) {
|
||||
char *arg;
|
||||
|
||||
count++;
|
||||
arg = cmd_get_param(&modestr);
|
||||
if (*arg != '\0') g_string_sprintfa(targs, " %s", arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (tmode->len > 0)
|
||||
irc_send_cmdv(server, "MODE %s %s%s", channel, tmode->str, targs->str);
|
||||
|
||||
g_string_free(tmode, TRUE);
|
||||
g_string_free(targs, TRUE);
|
||||
g_free(orig);
|
||||
}
|
||||
|
||||
static void cmd_op(gchar *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
if (!irc_item_channel(item)) return;
|
||||
channel_set_singlemode(server, item->name, data, "+o");
|
||||
}
|
||||
|
||||
static void cmd_deop(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
if (!irc_item_channel(item)) return;
|
||||
channel_set_singlemode(server, item->name, data, "-o");
|
||||
}
|
||||
|
||||
static void cmd_voice(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
if (!irc_item_channel(item)) return;
|
||||
channel_set_singlemode(server, item->name, data, "+v");
|
||||
}
|
||||
|
||||
static void cmd_devoice(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
if (!irc_item_channel(item)) return;
|
||||
channel_set_singlemode(server, item->name, data, "-v");
|
||||
}
|
||||
|
||||
static void cmd_mode(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
char *params, *target, *mode;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected || !irc_server_check(server))
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &mode);
|
||||
if (strcmp(target, "*") == 0) {
|
||||
if (!irc_item_channel(item))
|
||||
cmd_return_error(CMDERR_NOT_JOINED);
|
||||
|
||||
target = item->name;
|
||||
}
|
||||
if (*target == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
if (ischannel(*target))
|
||||
channel_set_mode(server, target, mode);
|
||||
else
|
||||
irc_send_cmdv(server, "MODE %s %s", target, mode);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
void modes_init(void)
|
||||
{
|
||||
signal_add("event 221", (SIGNAL_FUNC) event_user_mode);
|
||||
signal_add("event 305", (SIGNAL_FUNC) event_unaway);
|
||||
signal_add("event 306", (SIGNAL_FUNC) event_away);
|
||||
signal_add("event mode", (SIGNAL_FUNC) event_mode);
|
||||
|
||||
command_bind("op", NULL, (SIGNAL_FUNC) cmd_op);
|
||||
command_bind("deop", NULL, (SIGNAL_FUNC) cmd_deop);
|
||||
command_bind("voice", NULL, (SIGNAL_FUNC) cmd_voice);
|
||||
command_bind("devoice", NULL, (SIGNAL_FUNC) cmd_devoice);
|
||||
command_bind("mode", NULL, (SIGNAL_FUNC) cmd_mode);
|
||||
}
|
||||
|
||||
void modes_deinit(void)
|
||||
{
|
||||
signal_remove("event 221", (SIGNAL_FUNC) event_user_mode);
|
||||
signal_remove("event 305", (SIGNAL_FUNC) event_unaway);
|
||||
signal_remove("event 306", (SIGNAL_FUNC) event_away);
|
||||
signal_remove("event mode", (SIGNAL_FUNC) event_mode);
|
||||
|
||||
command_unbind("op", (SIGNAL_FUNC) cmd_op);
|
||||
command_unbind("deop", (SIGNAL_FUNC) cmd_deop);
|
||||
command_unbind("voice", (SIGNAL_FUNC) cmd_voice);
|
||||
command_unbind("devoice", (SIGNAL_FUNC) cmd_devoice);
|
||||
command_unbind("mode", (SIGNAL_FUNC) cmd_mode);
|
||||
}
|
||||
18
src/irc/core/modes.h
Normal file
18
src/irc/core/modes.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef __MODES_H
|
||||
#define __MODES_H
|
||||
|
||||
#include "server.h"
|
||||
#include "channels.h"
|
||||
|
||||
void modes_init(void);
|
||||
void modes_deinit(void);
|
||||
|
||||
/* add `mode' to `old' - return newly allocated mode. */
|
||||
char *modes_join(const char *old, const char *mode);
|
||||
|
||||
void parse_channel_modes(CHANNEL_REC *channel, const char *setby, const char *modestr);
|
||||
|
||||
void channel_set_singlemode(IRC_SERVER_REC *server, const char *channel, const char *nicks, const char *mode);
|
||||
void channel_set_mode(IRC_SERVER_REC *server, const char *channel, const char *mode);
|
||||
|
||||
#endif
|
||||
4
src/irc/core/module.h
Normal file
4
src/irc/core/module.h
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#include "common.h"
|
||||
|
||||
#define MODULE_NAME "irc/core"
|
||||
|
||||
270
src/irc/core/netsplit.c
Normal file
270
src/irc/core/netsplit.c
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
netsplit.c : irssi
|
||||
|
||||
Copyright (C) 1999 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
#include "commands.h"
|
||||
#include "misc.h"
|
||||
#include "common-setup.h"
|
||||
|
||||
#include "irc-server.h"
|
||||
#include "netsplit.h"
|
||||
|
||||
static int split_tag;
|
||||
|
||||
static NETSPLIT_REC *netsplit_add(IRC_SERVER_REC *server, const char *nick, const char *address, const char *servers)
|
||||
{
|
||||
NETSPLIT_REC *rec;
|
||||
NETSPLIT_CHAN_REC *splitchan;
|
||||
NICK_REC *nickrec;
|
||||
GSList *tmp;
|
||||
char *p, *dupservers;
|
||||
|
||||
g_return_val_if_fail(server != NULL, NULL);
|
||||
g_return_val_if_fail(nick != NULL, NULL);
|
||||
g_return_val_if_fail(address != NULL, NULL);
|
||||
|
||||
dupservers = g_strdup(servers);
|
||||
p = strchr(dupservers, ' ');
|
||||
if (p == NULL) {
|
||||
g_free(dupservers);
|
||||
g_return_val_if_fail(p != NULL, NULL);
|
||||
}
|
||||
*p++ = '\0';
|
||||
|
||||
rec = g_new0(NETSPLIT_REC, 1);
|
||||
rec->nick = g_strdup(nick);
|
||||
rec->address = g_strdup(address);
|
||||
rec->destroy = time(NULL)+NETSPLIT_MAX_REMEMBER;
|
||||
|
||||
/* get splitted servers */
|
||||
rec->server = g_strdup(dupservers);
|
||||
rec->destserver = g_strdup(p);
|
||||
g_free(dupservers);
|
||||
|
||||
/* copy the channel nick records.. */
|
||||
for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
|
||||
CHANNEL_REC *channel = tmp->data;
|
||||
|
||||
nickrec = nicklist_find(channel, nick);
|
||||
if (nickrec == NULL)
|
||||
continue;
|
||||
|
||||
splitchan = g_new0(NETSPLIT_CHAN_REC, 1);
|
||||
splitchan->name = g_strdup(channel->name);
|
||||
memcpy(&splitchan->nick, nickrec, sizeof(NICK_REC));
|
||||
|
||||
rec->channels = g_slist_append(rec->channels, splitchan);
|
||||
}
|
||||
|
||||
g_hash_table_insert(server->splits, rec->nick, rec);
|
||||
signal_emit("netsplit add", 1, rec);
|
||||
return rec;
|
||||
}
|
||||
|
||||
static void netsplit_destroy(NETSPLIT_REC *rec)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
g_return_if_fail(rec != NULL);
|
||||
|
||||
signal_emit("netsplit remove", 1, rec);
|
||||
for (tmp = rec->channels; tmp != NULL; tmp = tmp->next) {
|
||||
NETSPLIT_CHAN_REC *rec = tmp->data;
|
||||
|
||||
g_free(rec->name);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
g_free(rec->server);
|
||||
g_free(rec->destserver);
|
||||
g_free(rec->nick);
|
||||
g_free(rec->address);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
static void netsplit_destroy_hash(gpointer key, NETSPLIT_REC *rec)
|
||||
{
|
||||
netsplit_destroy(rec);
|
||||
}
|
||||
|
||||
NETSPLIT_REC *netsplit_find(IRC_SERVER_REC *server, const char *nick, const char *address)
|
||||
{
|
||||
NETSPLIT_REC *rec;
|
||||
|
||||
g_return_val_if_fail(server != NULL, NULL);
|
||||
g_return_val_if_fail(nick != NULL, NULL);
|
||||
|
||||
rec = g_hash_table_lookup(server->splits, nick);
|
||||
if (rec == NULL) return NULL;
|
||||
|
||||
return (address == NULL || g_strcasecmp(rec->address, address) == 0) ? rec : NULL;
|
||||
}
|
||||
|
||||
NICK_REC *netsplit_find_channel(IRC_SERVER_REC *server, const char *nick, const char *address, const char *channel)
|
||||
{
|
||||
NETSPLIT_REC *rec;
|
||||
GSList *tmp;
|
||||
|
||||
rec = netsplit_find(server, nick, address);
|
||||
if (rec == NULL) return NULL;
|
||||
|
||||
for (tmp = rec->channels; tmp != NULL; tmp = tmp->next) {
|
||||
NETSPLIT_CHAN_REC *rec = tmp->data;
|
||||
|
||||
if (g_strcasecmp(rec->name, channel) == 0)
|
||||
return &rec->nick;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int is_split(const char *msg)
|
||||
{
|
||||
char *params, *host1, *host2, *p;
|
||||
int ok;
|
||||
|
||||
g_return_val_if_fail(msg != NULL, FALSE);
|
||||
|
||||
/* must have only two words */
|
||||
p = strchr(msg, ' ');
|
||||
if (p == NULL || strchr(p+1, ' ') != NULL) return FALSE;
|
||||
|
||||
/* check that it looks ok.. */
|
||||
if (!match_wildcards("*.* *.*", msg) ||
|
||||
match_wildcards("*..*", msg) || strstr(msg, "))") != NULL)
|
||||
return FALSE;
|
||||
|
||||
/* get the two hosts */
|
||||
ok = FALSE;
|
||||
params = cmd_get_params(msg, 2, &host1, &host2);
|
||||
if (g_strcasecmp(host1, host2) != 0) { /* hosts can't be same.. */
|
||||
/* check that domain length is 2 or 3 */
|
||||
p = strrchr(host1, '.');
|
||||
if (p != NULL && (strlen(p+1) == 2 || strlen(p+1) == 3)) {
|
||||
p = strrchr(host2, '.');
|
||||
if (p != NULL && (strlen(p+1) == 2 || strlen(p+1) == 3)) {
|
||||
/* it looks just like a netsplit to me. */
|
||||
ok = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
g_free(params);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void split_set_timeout(gpointer key, NETSPLIT_REC *rec, NETSPLIT_REC *orig)
|
||||
{
|
||||
if (rec == orig) {
|
||||
/* original nick, destroy it in a few seconds.. */
|
||||
rec->destroy = time(NULL)+4;
|
||||
} else if (g_strcasecmp(rec->server, orig->server) == 0 &&
|
||||
g_strcasecmp(rec->destserver, orig->destserver) == 0) {
|
||||
/* same servers -> split over -> destroy old records sooner.. */
|
||||
rec->destroy = time(NULL)+60;
|
||||
}
|
||||
}
|
||||
|
||||
static void event_join(gchar *data, IRC_SERVER_REC *server, gchar *nick, gchar *address)
|
||||
{
|
||||
NETSPLIT_REC *rec;
|
||||
|
||||
/* check if split is over */
|
||||
rec = g_hash_table_lookup(server->splits, nick);
|
||||
if (rec == NULL) return;
|
||||
|
||||
if (g_strcasecmp(rec->address, address) == 0) {
|
||||
/* yep, looks like it is. for same people that had the same
|
||||
splitted servers set the timeout to one minute.
|
||||
|
||||
.. if the user just changed server, he/she can't use the
|
||||
same nick (unless the server is broken) so don't bother
|
||||
checking that the nick's server matches the split. */
|
||||
g_hash_table_foreach(server->splits, (GHFunc) split_set_timeout, rec);
|
||||
} else {
|
||||
/* back from different address.. just destroy it. */
|
||||
g_hash_table_remove(server->splits, rec->nick);
|
||||
netsplit_destroy(rec);
|
||||
}
|
||||
}
|
||||
|
||||
static void event_quit(const char *data, IRC_SERVER_REC *server, const char *nick, const char *address)
|
||||
{
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
if (*data == ':') data++;
|
||||
if (g_strcasecmp(nick, server->nick) != 0 && is_split(data)) {
|
||||
/* netsplit! */
|
||||
netsplit_add(server, nick, address, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void sig_disconnected(IRC_SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
g_hash_table_foreach(server->splits, (GHFunc) netsplit_destroy_hash, NULL);
|
||||
g_hash_table_destroy(server->splits);
|
||||
}
|
||||
|
||||
static int split_server_check(gpointer key, NETSPLIT_REC *rec, IRC_SERVER_REC *server)
|
||||
{
|
||||
/* Check if this split record is too old.. */
|
||||
if (rec->destroy > time(NULL))
|
||||
return FALSE;
|
||||
|
||||
netsplit_destroy(rec);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int split_check_old(void)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
for (tmp = servers; tmp != NULL; tmp = tmp->next) {
|
||||
IRC_SERVER_REC *server = tmp->data;
|
||||
|
||||
g_hash_table_foreach_remove(server->splits, (GHRFunc) split_server_check, server);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void netsplit_init(void)
|
||||
{
|
||||
split_tag = g_timeout_add(1000, (GSourceFunc) split_check_old, NULL);
|
||||
signal_add_first("event join", (SIGNAL_FUNC) event_join);
|
||||
signal_add_first("event quit", (SIGNAL_FUNC) event_quit);
|
||||
signal_add("server disconnected", (SIGNAL_FUNC) sig_disconnected);
|
||||
}
|
||||
|
||||
void netsplit_deinit(void)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
for (tmp = servers; tmp != NULL; tmp = tmp->next)
|
||||
sig_disconnected(tmp->data);
|
||||
|
||||
g_source_remove(split_tag);
|
||||
signal_remove("event join", (SIGNAL_FUNC) event_join);
|
||||
signal_remove("event quit", (SIGNAL_FUNC) event_quit);
|
||||
signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
|
||||
}
|
||||
27
src/irc/core/netsplit.h
Normal file
27
src/irc/core/netsplit.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef __NETSPLIT_H
|
||||
#define __NETSPLIT_H
|
||||
|
||||
#include "nicklist.h"
|
||||
|
||||
typedef struct {
|
||||
char *nick;
|
||||
char *address;
|
||||
char *server;
|
||||
char *destserver;
|
||||
GSList *channels;
|
||||
|
||||
time_t destroy;
|
||||
} NETSPLIT_REC;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
NICK_REC nick;
|
||||
} NETSPLIT_CHAN_REC;
|
||||
|
||||
void netsplit_init(void);
|
||||
void netsplit_deinit(void);
|
||||
|
||||
NETSPLIT_REC *netsplit_find(IRC_SERVER_REC *server, const char *nick, const char *address);
|
||||
NICK_REC *netsplit_find_channel(IRC_SERVER_REC *server, const char *nick, const char *address, const char *channel);
|
||||
|
||||
#endif
|
||||
566
src/irc/core/nicklist.c
Normal file
566
src/irc/core/nicklist.c
Normal file
|
|
@ -0,0 +1,566 @@
|
|||
/*
|
||||
nicklist.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
#include "misc.h"
|
||||
|
||||
#include "channels.h"
|
||||
#include "irc.h"
|
||||
#include "masks.h"
|
||||
#include "nicklist.h"
|
||||
#include "irc-server.h"
|
||||
|
||||
/* Add new nick to list */
|
||||
NICK_REC *nicklist_insert(CHANNEL_REC *channel, const char *nick, int op, int voice, int send_massjoin)
|
||||
{
|
||||
NICK_REC *rec;
|
||||
|
||||
g_return_val_if_fail(channel != NULL, NULL);
|
||||
g_return_val_if_fail(nick != NULL, NULL);
|
||||
|
||||
rec = g_new0(NICK_REC, 1);
|
||||
|
||||
if (op) rec->op = TRUE;
|
||||
if (voice) rec->voice = TRUE;
|
||||
|
||||
rec->send_massjoin = send_massjoin;
|
||||
rec->nick = g_strdup(nick);
|
||||
rec->host = NULL;
|
||||
|
||||
g_hash_table_insert(channel->nicks, rec->nick, rec);
|
||||
signal_emit("nicklist new", 2, channel, rec);
|
||||
return rec;
|
||||
}
|
||||
|
||||
static void nicklist_destroy(CHANNEL_REC *channel, NICK_REC *nick)
|
||||
{
|
||||
signal_emit("nicklist remove", 2, channel, nick);
|
||||
|
||||
g_free(nick->nick);
|
||||
g_free_not_null(nick->realname);
|
||||
g_free_not_null(nick->host);
|
||||
g_free(nick);
|
||||
}
|
||||
|
||||
/* remove nick from list */
|
||||
void nicklist_remove(CHANNEL_REC *channel, NICK_REC *nick)
|
||||
{
|
||||
g_return_if_fail(channel != NULL);
|
||||
g_return_if_fail(nick != NULL);
|
||||
|
||||
g_hash_table_remove(channel->nicks, nick->nick);
|
||||
nicklist_destroy(channel, nick);
|
||||
}
|
||||
|
||||
static NICK_REC *nicklist_find_wildcards(CHANNEL_REC *channel, const char *mask)
|
||||
{
|
||||
GSList *nicks, *tmp;
|
||||
NICK_REC *nick;
|
||||
|
||||
nicks = nicklist_getnicks(channel);
|
||||
nick = NULL;
|
||||
for (tmp = nicks; tmp != NULL; tmp = tmp->next) {
|
||||
nick = tmp->data;
|
||||
|
||||
if (irc_mask_match_address(mask, nick->nick, nick->host == NULL ? "" : nick->host))
|
||||
break;
|
||||
}
|
||||
g_slist_free(nicks);
|
||||
return tmp == NULL ? NULL : nick;
|
||||
}
|
||||
|
||||
/* Find nick record from list */
|
||||
NICK_REC *nicklist_find(CHANNEL_REC *channel, const char *mask)
|
||||
{
|
||||
NICK_REC *nickrec;
|
||||
char *nick, *host;
|
||||
|
||||
g_return_val_if_fail(channel != NULL, NULL);
|
||||
g_return_val_if_fail(mask != NULL, NULL);
|
||||
|
||||
nick = g_strdup(mask);
|
||||
host = strchr(nick, '!');
|
||||
if (host != NULL) *host++ = '\0';
|
||||
|
||||
if (strchr(nick, '*') || strchr(nick, '?')) {
|
||||
g_free(nick);
|
||||
return nicklist_find_wildcards(channel, mask);
|
||||
}
|
||||
|
||||
nickrec = g_hash_table_lookup(channel->nicks, nick);
|
||||
|
||||
if (nickrec != NULL && host != NULL &&
|
||||
(nickrec->host == NULL || !match_wildcards(host, nickrec->host))) {
|
||||
/* hosts didn't match */
|
||||
nickrec = NULL;
|
||||
}
|
||||
g_free(nick);
|
||||
return nickrec;
|
||||
}
|
||||
|
||||
static void get_nicks_hash(gpointer key, NICK_REC *rec, GSList **list)
|
||||
{
|
||||
*list = g_slist_append(*list, rec);
|
||||
}
|
||||
|
||||
/* Get list of nicks */
|
||||
GSList *nicklist_getnicks(CHANNEL_REC *channel)
|
||||
{
|
||||
GSList *list;
|
||||
|
||||
list = NULL;
|
||||
g_hash_table_foreach(channel->nicks, (GHFunc) get_nicks_hash, &list);
|
||||
return list;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
CHANNEL_REC *channel;
|
||||
const char *nick;
|
||||
GSList *list;
|
||||
} NICKLIST_GET_SAME_REC;
|
||||
|
||||
static void get_nicks_same_hash(gpointer key, NICK_REC *nick, NICKLIST_GET_SAME_REC *rec)
|
||||
{
|
||||
if (g_strcasecmp(nick->nick, rec->nick) == 0) {
|
||||
rec->list = g_slist_append(rec->list, rec->channel);
|
||||
rec->list = g_slist_append(rec->list, nick);
|
||||
}
|
||||
}
|
||||
|
||||
GSList *nicklist_get_same(IRC_SERVER_REC *server, const char *nick)
|
||||
{
|
||||
NICKLIST_GET_SAME_REC rec;
|
||||
GSList *tmp;
|
||||
|
||||
rec.nick = nick;
|
||||
rec.list = NULL;
|
||||
for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
|
||||
rec.channel = tmp->data;
|
||||
g_hash_table_foreach(rec.channel->nicks, (GHFunc) get_nicks_same_hash, &rec);
|
||||
}
|
||||
return rec.list;
|
||||
}
|
||||
|
||||
/* nick record comparision for sort functions */
|
||||
int nicklist_compare(NICK_REC *p1, NICK_REC *p2)
|
||||
{
|
||||
if (p1 == NULL) return -1;
|
||||
if (p2 == NULL) return 1;
|
||||
|
||||
if (p1->op && !p2->op) return -1;
|
||||
if (!p1->op && p2->op) return 1;
|
||||
|
||||
if (!p1->op) {
|
||||
if (p1->voice && !p2->voice) return -1;
|
||||
if (!p1->voice && p2->voice) return 1;
|
||||
}
|
||||
|
||||
return g_strcasecmp(p1->nick, p2->nick);
|
||||
}
|
||||
|
||||
#define isnickchar(a) \
|
||||
(isalnum(a) || (a) == '`' || (a) == '-' || (a) == '_' || \
|
||||
(a) == '[' || (a) == ']' || (a) == '{' || (a) == '}' || \
|
||||
(a) == '|' || (a) == '\\' || (a) == '^')
|
||||
|
||||
char *nick_strip(const char *nick)
|
||||
{
|
||||
char *stripped, *spos;
|
||||
|
||||
g_return_val_if_fail(nick != NULL, NULL);
|
||||
|
||||
spos = stripped = g_strdup(nick);
|
||||
while (isnickchar(*nick)) {
|
||||
if (isalnum((gint) *nick)) *spos++ = *nick;
|
||||
nick++;
|
||||
}
|
||||
if ((unsigned char) *nick >= 128)
|
||||
*spos++ = *nick; /* just add it so that nicks won't match.. */
|
||||
*spos = '\0';
|
||||
return stripped;
|
||||
}
|
||||
|
||||
static void event_names_list(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
CHANNEL_REC *chanrec;
|
||||
char *params, *type, *channel, *names, *ptr;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 4, NULL, &type, &channel, &names);
|
||||
|
||||
chanrec = channel_find(server, channel);
|
||||
if (chanrec == NULL || chanrec->names_got) {
|
||||
/* unknown channel / names list already read */
|
||||
g_free(params);
|
||||
return;
|
||||
}
|
||||
|
||||
/* type = '=' = public, '*' = private, '@' = secret.
|
||||
|
||||
This is actually pretty useless to check here, but at least we
|
||||
get to know if the channel is +p or +s a few seconds before
|
||||
we receive the MODE reply... */
|
||||
if (*type == '*')
|
||||
chanrec->mode_private = TRUE;
|
||||
else if (*type == '@')
|
||||
chanrec->mode_secret = TRUE;
|
||||
|
||||
while (*names != '\0') {
|
||||
while (*names == ' ') names++;
|
||||
ptr = names;
|
||||
while (*names != '\0' && *names != ' ') names++;
|
||||
if (*names != '\0') *names++ = '\0';
|
||||
|
||||
if (*ptr == '@' && strcmp(server->nick, ptr+1) == 0)
|
||||
chanrec->chanop = TRUE;
|
||||
|
||||
nicklist_insert(chanrec, ptr+isnickflag(*ptr), *ptr == '@', *ptr == '+', FALSE);
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_end_of_names(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *channel;
|
||||
CHANNEL_REC *chanrec;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
params = event_get_params(data, 2, NULL, &channel);
|
||||
|
||||
chanrec = channel_find(server, channel);
|
||||
if (chanrec != NULL && !chanrec->names_got) {
|
||||
chanrec->names_got = TRUE;
|
||||
signal_emit("channel query", 1, chanrec);
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void nicklist_update_flags(IRC_SERVER_REC *server, const char *nick, int gone, int ircop)
|
||||
{
|
||||
GSList *nicks, *tmp;
|
||||
CHANNEL_REC *channel;
|
||||
NICK_REC *rec;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
g_return_if_fail(nick != NULL);
|
||||
|
||||
nicks = nicklist_get_same(server, nick);
|
||||
for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
|
||||
channel = tmp->data;
|
||||
rec = tmp->next->data;
|
||||
|
||||
rec->last_check = time(NULL);
|
||||
|
||||
if (gone != -1 && rec->gone != gone) {
|
||||
rec->gone = gone;
|
||||
signal_emit("nick gone changed", 2, channel, rec);
|
||||
}
|
||||
|
||||
if (ircop != -1 && rec->ircop != ircop) {
|
||||
rec->ircop = ircop;
|
||||
signal_emit("nick ircop changed", 2, channel, rec);
|
||||
}
|
||||
}
|
||||
g_slist_free(nicks);
|
||||
}
|
||||
|
||||
static void event_who(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *nick, *channel, *user, *host, *stat, *realname, *hops;
|
||||
CHANNEL_REC *chanrec;
|
||||
NICK_REC *nickrec;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 8, NULL, &channel, &user, &host, NULL, &nick, &stat, &realname);
|
||||
|
||||
/* get hop count */
|
||||
hops = realname;
|
||||
while (*realname != '\0' && *realname != ' ') realname++;
|
||||
*realname++ = '\0';
|
||||
while (*realname == ' ') realname++;
|
||||
|
||||
/* update host, realname, hopcount */
|
||||
chanrec = channel_find(server, channel);
|
||||
nickrec = chanrec == NULL ? NULL : nicklist_find(chanrec, nick);
|
||||
if (nickrec != NULL) {
|
||||
if (nickrec->host == NULL)
|
||||
nickrec->host = g_strdup_printf("%s@%s", user, host);
|
||||
if (nickrec->realname == NULL)
|
||||
nickrec->realname = g_strdup(realname);
|
||||
sscanf(hops, "%d", &nickrec->hops);
|
||||
}
|
||||
|
||||
nicklist_update_flags(server, nick,
|
||||
strchr(stat, 'G') != NULL, /* gone */
|
||||
strchr(stat, '*') != NULL); /* ircop */
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_whois(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *nick, *realname;
|
||||
GSList *nicks, *tmp;
|
||||
NICK_REC *rec;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
server->whois_coming = TRUE;
|
||||
|
||||
/* first remove the gone-flag, if user is gone it will be set later.. */
|
||||
params = event_get_params(data, 6, NULL, &nick, NULL, NULL, NULL, &realname);
|
||||
|
||||
nicks = nicklist_get_same(server, nick);
|
||||
for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
|
||||
rec = tmp->next->data;
|
||||
|
||||
if (rec->realname == NULL)
|
||||
rec->realname = g_strdup(realname);
|
||||
}
|
||||
g_slist_free(nicks);
|
||||
|
||||
/* reset gone and ircop status, we'll handle them in the following
|
||||
WHOIS replies */
|
||||
nicklist_update_flags(server, nick, FALSE, FALSE);
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_whois_away(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *nick, *awaymsg;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
/* set user's gone flag.. */
|
||||
params = event_get_params(data, 3, NULL, &nick, &awaymsg);
|
||||
nicklist_update_flags(server, nick, TRUE, -1);
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_whois_ircop(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *nick, *awaymsg;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
/* set user's gone flag.. */
|
||||
params = event_get_params(data, 3, NULL, &nick, &awaymsg);
|
||||
nicklist_update_flags(server, nick, -1, TRUE);
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_end_of_whois(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
server->whois_coming = FALSE;
|
||||
}
|
||||
|
||||
static void event_nick_in_use(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *str;
|
||||
int n;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
if (server->connected) {
|
||||
/* Already connected, no need to handle this anymore. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* nick already in use - need to change it .. */
|
||||
if (strcmp(server->nick, server->connrec->nick) == 0) {
|
||||
/* first try, so try the alternative nick.. */
|
||||
g_free(server->nick);
|
||||
server->nick = g_strdup(server->connrec->alternate_nick);
|
||||
}
|
||||
else if (strlen(server->nick) < 9) {
|
||||
/* keep adding '_' to end of nick.. */
|
||||
str = g_strdup_printf("%s_", server->nick);
|
||||
g_free(server->nick);
|
||||
server->nick = str;
|
||||
} else {
|
||||
/* nick full, keep adding number at the end */
|
||||
for (n = 8; n > 0; n--) {
|
||||
if (server->nick[n] < '0' || server->nick[n] > '9') {
|
||||
server->nick[n] = '1';
|
||||
break;
|
||||
}
|
||||
|
||||
if (server->nick[n] < '9') {
|
||||
server->nick[n]++;
|
||||
break;
|
||||
}
|
||||
server->nick[n] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
irc_send_cmdv(server, "NICK %s", server->nick);
|
||||
}
|
||||
|
||||
static void event_target_unavailable(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *channel;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 2, NULL, &channel);
|
||||
if (!ischannel(*channel)) {
|
||||
/* nick is unavailable. */
|
||||
event_nick_in_use(data, server);
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_nick(const char *data, IRC_SERVER_REC *server, const char *orignick)
|
||||
{
|
||||
CHANNEL_REC *channel;
|
||||
NICK_REC *nickrec;
|
||||
GSList *nicks, *tmp;
|
||||
char *params, *nick;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 1, &nick);
|
||||
|
||||
if (g_strcasecmp(orignick, server->nick) == 0) {
|
||||
/* You changed your nick */
|
||||
g_free(server->connrec->nick);
|
||||
g_free(server->nick);
|
||||
server->connrec->nick = g_strdup(nick);
|
||||
server->nick = g_strdup(nick);
|
||||
signal_emit("server nick changed", 1, server);
|
||||
}
|
||||
|
||||
nicks = nicklist_get_same(server, nick);
|
||||
for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
|
||||
channel = tmp->data;
|
||||
nickrec = tmp->next->data;
|
||||
|
||||
/* remove old nick from hash table */
|
||||
g_hash_table_remove(channel->nicks, nickrec->nick);
|
||||
|
||||
g_free(nickrec->nick);
|
||||
nickrec->nick = g_strdup(nick);
|
||||
|
||||
/* add new nick to hash table */
|
||||
g_hash_table_insert(channel->nicks, nickrec->nick, nickrec);
|
||||
|
||||
signal_emit("nicklist changed", 3, channel, nickrec, orignick);
|
||||
}
|
||||
g_slist_free(nicks);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_userhost(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *hosts, **phosts, **pos, *ptr;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
/* set user's gone flag.. */
|
||||
params = event_get_params(data, 2, NULL, &hosts);
|
||||
|
||||
phosts = g_strsplit(hosts, " ", -1);
|
||||
for (pos = phosts; pos != NULL; pos++) {
|
||||
ptr = strchr(*pos, '=');
|
||||
if (ptr == NULL) continue;
|
||||
*ptr++ = '\0';
|
||||
|
||||
nicklist_update_flags(server, *pos, *ptr == '-', -1);
|
||||
}
|
||||
g_strfreev(phosts);
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void sig_usermode(IRC_SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
nicklist_update_flags(server, server->nick, server->usermode_away, -1);
|
||||
}
|
||||
|
||||
static void sig_channel_created(CHANNEL_REC *channel)
|
||||
{
|
||||
g_return_if_fail(channel != NULL);
|
||||
|
||||
channel->nicks = g_hash_table_new((GHashFunc) g_istr_hash, (GCompareFunc) g_istr_equal);
|
||||
}
|
||||
|
||||
static void nicklist_remove_hash(gpointer key, NICK_REC *nick, CHANNEL_REC *channel)
|
||||
{
|
||||
nicklist_destroy(channel, nick);
|
||||
}
|
||||
|
||||
static void sig_channel_destroyed(CHANNEL_REC *channel)
|
||||
{
|
||||
g_return_if_fail(channel != NULL);
|
||||
|
||||
g_hash_table_foreach(channel->nicks, (GHFunc) nicklist_remove_hash, channel);
|
||||
g_hash_table_destroy(channel->nicks);
|
||||
}
|
||||
|
||||
void nicklist_init(void)
|
||||
{
|
||||
signal_add("event nick", (SIGNAL_FUNC) event_nick);
|
||||
signal_add_first("event 352", (SIGNAL_FUNC) event_who);
|
||||
signal_add("silent event who", (SIGNAL_FUNC) event_who);
|
||||
signal_add("silent event whois", (SIGNAL_FUNC) event_whois);
|
||||
signal_add_first("event 311", (SIGNAL_FUNC) event_whois);
|
||||
signal_add_first("event 301", (SIGNAL_FUNC) event_whois_away);
|
||||
signal_add_first("event 313", (SIGNAL_FUNC) event_whois_ircop);
|
||||
signal_add("event 318", (SIGNAL_FUNC) event_end_of_whois);
|
||||
signal_add("event 353", (SIGNAL_FUNC) event_names_list);
|
||||
signal_add("event 366", (SIGNAL_FUNC) event_end_of_names);
|
||||
signal_add("event 433", (SIGNAL_FUNC) event_nick_in_use);
|
||||
signal_add("event 437", (SIGNAL_FUNC) event_target_unavailable);
|
||||
signal_add("event 302", (SIGNAL_FUNC) event_userhost);
|
||||
signal_add("userhost event", (SIGNAL_FUNC) event_userhost);
|
||||
signal_add("user mode changed", (SIGNAL_FUNC) sig_usermode);
|
||||
signal_add_first("channel created", (SIGNAL_FUNC) sig_channel_created);
|
||||
signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
|
||||
}
|
||||
|
||||
void nicklist_deinit(void)
|
||||
{
|
||||
signal_remove("event nick", (SIGNAL_FUNC) event_nick);
|
||||
signal_remove("event 352", (SIGNAL_FUNC) event_who);
|
||||
signal_remove("silent event who", (SIGNAL_FUNC) event_who);
|
||||
signal_remove("silent event whois", (SIGNAL_FUNC) event_whois);
|
||||
signal_remove("event 311", (SIGNAL_FUNC) event_whois);
|
||||
signal_remove("event 301", (SIGNAL_FUNC) event_whois_away);
|
||||
signal_remove("event 313", (SIGNAL_FUNC) event_whois_ircop);
|
||||
signal_remove("event 318", (SIGNAL_FUNC) event_end_of_whois);
|
||||
signal_remove("event 353", (SIGNAL_FUNC) event_names_list);
|
||||
signal_remove("event 366", (SIGNAL_FUNC) event_end_of_names);
|
||||
signal_remove("event 433", (SIGNAL_FUNC) event_nick_in_use);
|
||||
signal_remove("event 437", (SIGNAL_FUNC) event_target_unavailable);
|
||||
signal_remove("event 302", (SIGNAL_FUNC) event_userhost);
|
||||
signal_remove("userhost event", (SIGNAL_FUNC) event_userhost);
|
||||
signal_remove("user mode changed", (SIGNAL_FUNC) sig_usermode);
|
||||
signal_remove("channel created", (SIGNAL_FUNC) sig_channel_created);
|
||||
signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
|
||||
}
|
||||
41
src/irc/core/nicklist.h
Normal file
41
src/irc/core/nicklist.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef __NICKLIST_H
|
||||
#define __NICKLIST_H
|
||||
|
||||
#include "channels.h"
|
||||
|
||||
typedef struct {
|
||||
time_t last_check; /* last time gone was checked */
|
||||
int send_massjoin; /* Waiting to be sent in massjoin signal */
|
||||
|
||||
char *nick;
|
||||
char *host;
|
||||
char *realname;
|
||||
|
||||
int hops;
|
||||
|
||||
int op:1;
|
||||
int voice:1;
|
||||
int gone:1;
|
||||
int ircop:1;
|
||||
} NICK_REC;
|
||||
|
||||
/* Add new nick to list */
|
||||
NICK_REC *nicklist_insert(CHANNEL_REC *channel, const char *nick, int op, int voice, int send_massjoin);
|
||||
/* remove nick from list */
|
||||
void nicklist_remove(CHANNEL_REC *channel, NICK_REC *nick);
|
||||
/* Find nick record from list */
|
||||
NICK_REC *nicklist_find(CHANNEL_REC *channel, const char *mask);
|
||||
/* Get list of nicks */
|
||||
GSList *nicklist_getnicks(CHANNEL_REC *channel);
|
||||
/* Get all the nick records of `nick'. Returns channel, nick, channel, ... */
|
||||
GSList *nicklist_get_same(IRC_SERVER_REC *server, const char *nick);
|
||||
|
||||
/* nick record comparision for sort functions */
|
||||
int nicklist_compare(NICK_REC *p1, NICK_REC *p2);
|
||||
|
||||
char *nick_strip(const char *nick);
|
||||
|
||||
void nicklist_init(void);
|
||||
void nicklist_deinit(void);
|
||||
|
||||
#endif
|
||||
158
src/irc/core/query.c
Normal file
158
src/irc/core/query.c
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
query.c : irssi
|
||||
|
||||
Copyright (C) 1999 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
|
||||
#include "misc.h"
|
||||
#include "signals.h"
|
||||
#include "modules.h"
|
||||
|
||||
#include "irc.h"
|
||||
#include "query.h"
|
||||
|
||||
GSList *queries;
|
||||
|
||||
QUERY_REC *query_create(IRC_SERVER_REC *server, const char *nick, int automatic)
|
||||
{
|
||||
QUERY_REC *rec;
|
||||
|
||||
g_return_val_if_fail(server != NULL, NULL);
|
||||
g_return_val_if_fail(nick != NULL, NULL);
|
||||
|
||||
rec = g_new0(QUERY_REC, 1);
|
||||
queries = g_slist_append(queries, rec);
|
||||
server->queries = g_slist_append(server->queries, rec);
|
||||
|
||||
MODULE_DATA_INIT(rec);
|
||||
rec->type = module_get_uniq_id("IRC", WI_IRC_QUERY);
|
||||
rec->nick = g_strdup(nick);
|
||||
rec->server_tag = g_strdup(server->tag);
|
||||
rec->server = server;
|
||||
|
||||
signal_emit("query created", 2, rec, GINT_TO_POINTER(automatic));
|
||||
return rec;
|
||||
}
|
||||
|
||||
void query_destroy(QUERY_REC *query)
|
||||
{
|
||||
g_return_if_fail(query != NULL);
|
||||
|
||||
if (query->destroying) return;
|
||||
query->destroying = TRUE;
|
||||
|
||||
queries = g_slist_remove(queries, query);
|
||||
if (query->server != NULL)
|
||||
query->server->queries = g_slist_remove(query->server->queries, query);
|
||||
signal_emit("query destroyed", 1, query);
|
||||
|
||||
MODULE_DATA_DEINIT(query);
|
||||
g_free(query->nick);
|
||||
g_free(query->server_tag);
|
||||
g_free(query);
|
||||
}
|
||||
|
||||
|
||||
static QUERY_REC *query_find_server(IRC_SERVER_REC *server, const char *nick)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
for (tmp = server->queries; tmp != NULL; tmp = tmp->next) {
|
||||
QUERY_REC *rec = tmp->data;
|
||||
|
||||
if (g_strcasecmp(nick, rec->nick) == 0)
|
||||
return rec;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QUERY_REC *query_find(IRC_SERVER_REC *server, const char *nick)
|
||||
{
|
||||
g_return_val_if_fail(nick != NULL, NULL);
|
||||
|
||||
if (server != NULL)
|
||||
return query_find_server(server, nick);
|
||||
|
||||
/* find from any server */
|
||||
return gslist_foreach_find(servers, (FOREACH_FIND_FUNC) query_find_server, (void *) nick);
|
||||
}
|
||||
|
||||
void query_change_server(QUERY_REC *query, IRC_SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(query != NULL);
|
||||
|
||||
query->server = server;
|
||||
signal_emit("query server changed", 2, query, server);
|
||||
}
|
||||
|
||||
static void event_privmsg(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr)
|
||||
{
|
||||
char *params, *target, *msg;
|
||||
QUERY_REC *query;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg);
|
||||
|
||||
if (addr != NULL && *msg != 1 && !ischannel(*target)) {
|
||||
/* save nick's address to query */
|
||||
query = query_find(server, nick);
|
||||
if (query != NULL && (query->address == NULL || strcmp(query->address, addr) != 0)) {
|
||||
g_free_not_null(query->address);
|
||||
query->address = g_strdup(addr);
|
||||
|
||||
signal_emit("query address changed", 1, query);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_nick(const char *data, IRC_SERVER_REC *server, const char *orignick)
|
||||
{
|
||||
char *params, *nick;
|
||||
GSList *tmp;
|
||||
|
||||
params = event_get_params(data, 1, &nick);
|
||||
|
||||
for (tmp = server->queries; tmp != NULL; tmp = tmp->next) {
|
||||
QUERY_REC *rec = tmp->data;
|
||||
|
||||
if (g_strcasecmp(rec->nick, orignick) == 0) {
|
||||
g_free(rec->nick);
|
||||
rec->nick = g_strdup(nick);
|
||||
signal_emit("query nick changed", 1, rec);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
void query_init(void)
|
||||
{
|
||||
signal_add_last("event privmsg", (SIGNAL_FUNC) event_privmsg);
|
||||
signal_add("event nick", (SIGNAL_FUNC) event_nick);
|
||||
}
|
||||
|
||||
void query_deinit(void)
|
||||
{
|
||||
signal_remove("event privmsg", (SIGNAL_FUNC) event_privmsg);
|
||||
signal_remove("event nick", (SIGNAL_FUNC) event_nick);
|
||||
}
|
||||
30
src/irc/core/query.h
Normal file
30
src/irc/core/query.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef __QUERY_H
|
||||
#define __QUERY_H
|
||||
|
||||
#include "server.h"
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
GHashTable *module_data;
|
||||
|
||||
IRC_SERVER_REC *server;
|
||||
char *nick;
|
||||
|
||||
int new_data;
|
||||
|
||||
char *address;
|
||||
char *server_tag;
|
||||
int destroying:1;
|
||||
} QUERY_REC;
|
||||
|
||||
extern GSList *queries;
|
||||
|
||||
QUERY_REC *query_create(IRC_SERVER_REC *server, const char *nick, int automatic);
|
||||
void query_destroy(QUERY_REC *query);
|
||||
|
||||
/* Find query by name, if `server' is NULL, search from all servers */
|
||||
QUERY_REC *query_find(IRC_SERVER_REC *server, const char *nick);
|
||||
|
||||
void query_change_server(QUERY_REC *query, IRC_SERVER_REC *server);
|
||||
|
||||
#endif
|
||||
252
src/irc/core/server-idle.c
Normal file
252
src/irc/core/server-idle.c
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
server-idle.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
|
||||
#include "irc-server.h"
|
||||
#include "server-idle.h"
|
||||
#include "server-redirect.h"
|
||||
#include "irc.h"
|
||||
|
||||
typedef struct {
|
||||
char *event;
|
||||
char *signal;
|
||||
int argpos;
|
||||
} REDIRECT_IDLE_REC;
|
||||
|
||||
typedef struct {
|
||||
char *cmd;
|
||||
char *arg;
|
||||
int tag;
|
||||
|
||||
int last;
|
||||
GSList *redirects;
|
||||
} SERVER_IDLE_REC;
|
||||
|
||||
static int idle_tag, idlepos;
|
||||
|
||||
/* Add new idle command to queue */
|
||||
static SERVER_IDLE_REC *server_idle_create(const char *cmd, const char *arg, int last, va_list args)
|
||||
{
|
||||
REDIRECT_IDLE_REC *rrec;
|
||||
SERVER_IDLE_REC *rec;
|
||||
char *event;
|
||||
|
||||
g_return_val_if_fail(cmd != NULL, FALSE);
|
||||
|
||||
rec = g_new0(SERVER_IDLE_REC, 1);
|
||||
|
||||
rec->tag = ++idlepos;
|
||||
rec->arg = arg == NULL ? NULL : g_strdup(arg);
|
||||
rec->cmd = g_strdup(cmd);
|
||||
rec->last = last;
|
||||
|
||||
while ((event = va_arg(args, char *)) != NULL) {
|
||||
rrec = g_new(REDIRECT_IDLE_REC, 1);
|
||||
rec->redirects = g_slist_append(rec->redirects, rrec);
|
||||
|
||||
rrec->event = g_strdup(event);
|
||||
rrec->signal = g_strdup(va_arg(args, char *));
|
||||
rrec->argpos = va_arg(args, int);
|
||||
}
|
||||
|
||||
return rec;
|
||||
}
|
||||
|
||||
static SERVER_IDLE_REC *server_idle_find_rec(IRC_SERVER_REC *server, int tag)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
g_return_val_if_fail(server != NULL, FALSE);
|
||||
|
||||
for (tmp = server->idles; tmp != NULL; tmp = tmp->next) {
|
||||
SERVER_IDLE_REC *rec = tmp->data;
|
||||
|
||||
if (rec->tag == tag)
|
||||
return rec;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Add new idle command to queue */
|
||||
int server_idle_add(IRC_SERVER_REC *server, const char *cmd, const char *arg, int last, ...)
|
||||
{
|
||||
va_list args;
|
||||
SERVER_IDLE_REC *rec;
|
||||
|
||||
g_return_val_if_fail(server != NULL, -1);
|
||||
|
||||
va_start(args, last);
|
||||
rec = server_idle_create(cmd, arg, last, args);
|
||||
server->idles = g_slist_append(server->idles, rec);
|
||||
va_end(args);
|
||||
|
||||
return rec->tag;
|
||||
}
|
||||
|
||||
/* Add new idle command to first of queue */
|
||||
int server_idle_add_first(IRC_SERVER_REC *server, const char *cmd, const char *arg, int last, ...)
|
||||
{
|
||||
va_list args;
|
||||
SERVER_IDLE_REC *rec;
|
||||
|
||||
g_return_val_if_fail(server != NULL, -1);
|
||||
|
||||
va_start(args, last);
|
||||
rec = server_idle_create(cmd, arg, last, args);
|
||||
server->idles = g_slist_prepend(server->idles, rec);
|
||||
va_end(args);
|
||||
|
||||
return rec->tag;
|
||||
}
|
||||
|
||||
/* Add new idle command to specified position of queue */
|
||||
int server_idle_insert(IRC_SERVER_REC *server, const char *cmd, const char *arg, int tag, int last, ...)
|
||||
{
|
||||
va_list args;
|
||||
SERVER_IDLE_REC *rec;
|
||||
int pos;
|
||||
|
||||
g_return_val_if_fail(server != NULL, -1);
|
||||
|
||||
va_start(args, last);
|
||||
|
||||
/* find the position of tag in idle list */
|
||||
rec = server_idle_find_rec(server, tag);
|
||||
pos = g_slist_index(server->idles, rec);
|
||||
|
||||
rec = server_idle_create(cmd, arg, last, args);
|
||||
server->idles = pos < 0 ?
|
||||
g_slist_append(server->idles, rec) :
|
||||
g_slist_insert(server->idles, rec, pos);
|
||||
va_end(args);
|
||||
return rec->tag;
|
||||
}
|
||||
|
||||
static void server_idle_destroy(IRC_SERVER_REC *server, SERVER_IDLE_REC *rec)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
server->idles = g_slist_remove(server->idles, rec);
|
||||
|
||||
for (tmp = rec->redirects; tmp != NULL; tmp = tmp->next) {
|
||||
REDIRECT_IDLE_REC *rec = tmp->data;
|
||||
|
||||
g_free(rec->event);
|
||||
g_free(rec->signal);
|
||||
g_free(rec);
|
||||
}
|
||||
g_slist_free(rec->redirects);
|
||||
|
||||
g_free_not_null(rec->arg);
|
||||
g_free(rec->cmd);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
/* Check if record is still in queue */
|
||||
int server_idle_find(IRC_SERVER_REC *server, int tag)
|
||||
{
|
||||
return server_idle_find_rec(server, tag) != NULL;
|
||||
}
|
||||
|
||||
/* Remove record from idle queue */
|
||||
int server_idle_remove(IRC_SERVER_REC *server, int tag)
|
||||
{
|
||||
SERVER_IDLE_REC *rec;
|
||||
|
||||
g_return_val_if_fail(server != NULL, FALSE);
|
||||
|
||||
rec = server_idle_find_rec(server, tag);
|
||||
if (rec == NULL)
|
||||
return FALSE;
|
||||
|
||||
server_idle_destroy(server, rec);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Execute next idle command */
|
||||
static void server_idle_next(IRC_SERVER_REC *server)
|
||||
{
|
||||
SERVER_IDLE_REC *rec;
|
||||
GSList *tmp;
|
||||
int group;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
if (server->idles == NULL) return;
|
||||
rec = server->idles->data;
|
||||
|
||||
/* Send command */
|
||||
irc_send_cmd(server, rec->cmd);
|
||||
|
||||
/* Add server redirections */
|
||||
group = 0;
|
||||
for (tmp = rec->redirects; tmp != NULL; tmp = tmp->next) {
|
||||
REDIRECT_IDLE_REC *rrec = tmp->data;
|
||||
|
||||
group = server_redirect_single_event((SERVER_REC *) server, rec->arg, rec->last > 0,
|
||||
group, rrec->event, rrec->signal, rrec->argpos);
|
||||
if (rec->last > 0) rec->last--;
|
||||
}
|
||||
|
||||
server_idle_destroy(server, rec);
|
||||
}
|
||||
|
||||
static void sig_disconnected(IRC_SERVER_REC *server)
|
||||
{
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
while (server->idles != NULL)
|
||||
server_idle_destroy(server, server->idles->data);
|
||||
}
|
||||
|
||||
static int sig_idle_timeout(void)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
/* Scan through every server */
|
||||
for (tmp = servers; tmp != NULL; tmp = tmp->next) {
|
||||
IRC_SERVER_REC *rec = tmp->data;
|
||||
|
||||
if (rec->idles != NULL && rec->cmdcount == 0) {
|
||||
/* We're idling and we have idle commands to run! */
|
||||
server_idle_next(rec);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void servers_idle_init(void)
|
||||
{
|
||||
idlepos = 0;
|
||||
idle_tag = g_timeout_add(1000, (GSourceFunc) sig_idle_timeout, NULL);
|
||||
|
||||
signal_add("server disconnected", (SIGNAL_FUNC) sig_disconnected);
|
||||
}
|
||||
|
||||
void servers_idle_deinit(void)
|
||||
{
|
||||
g_source_remove(idle_tag);
|
||||
signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
|
||||
}
|
||||
24
src/irc/core/server-idle.h
Normal file
24
src/irc/core/server-idle.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef __SERVER_IDLE_H
|
||||
#define __SERVER_IDLE_H
|
||||
|
||||
#include "irc-server.h"
|
||||
|
||||
/* Add new idle command to queue */
|
||||
int server_idle_add(IRC_SERVER_REC *server, const char *cmd, const char *arg, int last, ...);
|
||||
|
||||
/* Add new idle command to first of queue */
|
||||
int server_idle_add_first(IRC_SERVER_REC *server, const char *cmd, const char *arg, int last, ...);
|
||||
|
||||
/* Add new idle command to specified position of queue */
|
||||
int server_idle_insert(IRC_SERVER_REC *server, const char *cmd, const char *arg, int tag, int last, ...);
|
||||
|
||||
/* Check if record is still in queue */
|
||||
int server_idle_find(IRC_SERVER_REC *server, int tag);
|
||||
|
||||
/* Remove record from idle queue */
|
||||
int server_idle_remove(IRC_SERVER_REC *server, int tag);
|
||||
|
||||
void servers_idle_init(void);
|
||||
void servers_idle_deinit(void);
|
||||
|
||||
#endif
|
||||
398
src/irc/core/server-reconnect.c
Normal file
398
src/irc/core/server-reconnect.c
Normal file
|
|
@ -0,0 +1,398 @@
|
|||
/*
|
||||
server-reconnect.c : irssi
|
||||
|
||||
Copyright (C) 1999 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "modules.h"
|
||||
#include "commands.h"
|
||||
#include "network.h"
|
||||
#include "signals.h"
|
||||
|
||||
#include "irc.h"
|
||||
#include "modes.h"
|
||||
#include "irc-server.h"
|
||||
#include "server-setup.h"
|
||||
#include "server-reconnect.h"
|
||||
|
||||
#include "settings.h"
|
||||
#include "common-setup.h"
|
||||
|
||||
GSList *reconnects;
|
||||
static int last_reconnect_tag;
|
||||
static int reconnect_timeout_tag;
|
||||
static int reconnect_time;
|
||||
|
||||
static void server_reconnect_add(IRC_SERVER_CONNECT_REC *conn, time_t next_connect)
|
||||
{
|
||||
RECONNECT_REC *rec;
|
||||
|
||||
rec = g_new(RECONNECT_REC, 1);
|
||||
rec->tag = ++last_reconnect_tag;
|
||||
rec->conn = conn;
|
||||
rec->next_connect = next_connect;
|
||||
|
||||
reconnects = g_slist_append(reconnects, rec);
|
||||
}
|
||||
|
||||
static void server_reconnect_destroy(RECONNECT_REC *rec, int free_conn)
|
||||
{
|
||||
reconnects = g_slist_remove(reconnects, rec);
|
||||
|
||||
signal_emit("server reconnect remove", 1, rec);
|
||||
if (free_conn) irc_server_connect_free(rec->conn);
|
||||
g_free(rec);
|
||||
|
||||
if (reconnects == NULL)
|
||||
last_reconnect_tag = 0;
|
||||
}
|
||||
|
||||
static int server_reconnect_timeout(void)
|
||||
{
|
||||
IRC_SERVER_CONNECT_REC *conn;
|
||||
GSList *tmp, *next;
|
||||
time_t now;
|
||||
|
||||
now = time(NULL);
|
||||
for (tmp = reconnects; tmp != NULL; tmp = next) {
|
||||
RECONNECT_REC *rec = tmp->data;
|
||||
|
||||
next = tmp->next;
|
||||
if (rec->next_connect <= now) {
|
||||
conn = rec->conn;
|
||||
server_reconnect_destroy(rec, FALSE);
|
||||
irc_server_connect(conn);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void sserver_connect(SETUP_SERVER_REC *rec, IRC_SERVER_CONNECT_REC *conn)
|
||||
{
|
||||
conn->address = g_strdup(rec->server);
|
||||
conn->port = rec->port;
|
||||
conn->password = rec->password == NULL ? NULL :
|
||||
g_strdup(rec->password);
|
||||
if (rec->cmd_queue_speed > 0)
|
||||
conn->cmd_queue_speed = rec->cmd_queue_speed;
|
||||
|
||||
if (rec->last_connect > time(NULL)-reconnect_time) {
|
||||
/* can't reconnect this fast, wait.. */
|
||||
server_reconnect_add(conn, rec->last_connect+reconnect_time);
|
||||
} else {
|
||||
/* connect to server.. */
|
||||
irc_server_connect(conn);
|
||||
}
|
||||
}
|
||||
|
||||
static void server_connect_copy_skeleton(IRC_SERVER_CONNECT_REC *dest, IRC_SERVER_CONNECT_REC *src)
|
||||
{
|
||||
dest->proxy = src->proxy == NULL ? NULL :
|
||||
g_strdup(src->proxy);
|
||||
dest->proxy_port = src->proxy_port;
|
||||
dest->proxy_string = src->proxy_string == NULL ? NULL :
|
||||
g_strdup(src->proxy_string);
|
||||
|
||||
dest->ircnet = src->ircnet == NULL ? NULL :
|
||||
g_strdup(src->ircnet);
|
||||
dest->nick = src->nick == NULL ? NULL :
|
||||
g_strdup(src->nick);
|
||||
dest->username = src->username == NULL ? NULL :
|
||||
g_strdup(src->username);
|
||||
dest->realname = src->realname == NULL ? NULL :
|
||||
g_strdup(src->realname);
|
||||
|
||||
if (src->own_ip != NULL) {
|
||||
dest->own_ip = g_new(IPADDR, 1);
|
||||
memcpy(dest->own_ip, src->own_ip, sizeof(IPADDR));
|
||||
}
|
||||
|
||||
dest->cmd_queue_speed = src->cmd_queue_speed;
|
||||
dest->max_kicks = src->max_kicks;
|
||||
dest->max_modes = src->max_modes;
|
||||
dest->max_msgs = src->max_msgs;
|
||||
}
|
||||
|
||||
static void sig_reconnect(IRC_SERVER_REC *server)
|
||||
{
|
||||
IRC_SERVER_CONNECT_REC *conn;
|
||||
SETUP_SERVER_REC *sserver;
|
||||
GSList *tmp;
|
||||
int found, through;
|
||||
time_t now;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
if (reconnect_time == -1 || !server->connection_lost || !irc_server_check(server))
|
||||
return;
|
||||
|
||||
conn = g_new0(IRC_SERVER_CONNECT_REC, 1);
|
||||
conn->reconnection = TRUE;
|
||||
server_connect_copy_skeleton(conn, server->connrec);
|
||||
|
||||
/* save the server status */
|
||||
if (!server->connected) {
|
||||
conn->channels = g_strdup(server->connrec->channels);
|
||||
conn->away_reason = g_strdup(server->connrec->away_reason);
|
||||
conn->usermode = g_strdup(server->connrec->usermode);
|
||||
} else {
|
||||
conn->channels = irc_server_get_channels(server);
|
||||
conn->away_reason = !server->usermode_away ? NULL :
|
||||
g_strdup(server->away_reason);
|
||||
conn->usermode = g_strdup(server->usermode);
|
||||
}
|
||||
|
||||
sserver = server_setup_find(server->connrec->address, server->connrec->port);
|
||||
if (sserver == NULL) {
|
||||
/* port specific record not found, try without port.. */
|
||||
sserver = server_setup_find(server->connrec->address, -1);
|
||||
}
|
||||
|
||||
if (sserver != NULL) {
|
||||
/* save the last connection time/status */
|
||||
sserver->last_connect = server->connect_time == 0 ?
|
||||
time(NULL) : server->connect_time;
|
||||
sserver->last_failed = !server->connected;
|
||||
}
|
||||
|
||||
if (sserver == NULL || conn->ircnet == NULL) {
|
||||
/* not in any ircnet, just reconnect back to same server */
|
||||
conn->address = g_strdup(server->connrec->address);
|
||||
conn->port = server->connrec->port;
|
||||
conn->password = server->connrec->password == NULL ? NULL :
|
||||
g_strdup(server->connrec->password);
|
||||
|
||||
if (server->connect_time != 0 &&
|
||||
time(NULL)-server->connect_time > reconnect_time) {
|
||||
/* there's been enough time since last connection,
|
||||
reconnect back immediately */
|
||||
irc_server_connect(conn);
|
||||
} else {
|
||||
/* reconnect later.. */
|
||||
server_reconnect_add(conn, (server->connect_time == 0 ? time(NULL) :
|
||||
server->connect_time) + reconnect_time);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* always try to first connect to the first on the list where we
|
||||
haven't got unsuccessful connection attempts for the last half
|
||||
an hour. */
|
||||
|
||||
now = time(NULL);
|
||||
for (tmp = setupservers; tmp != NULL; tmp = tmp->next) {
|
||||
SETUP_SERVER_REC *rec = tmp->data;
|
||||
|
||||
if (rec->ircnet == NULL || g_strcasecmp(conn->ircnet, rec->ircnet) != 0)
|
||||
continue;
|
||||
|
||||
if (!rec->last_connect || !rec->last_failed || rec->last_connect < now-FAILED_RECONNECT_WAIT) {
|
||||
sserver_connect(rec, conn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* just try the next server in list */
|
||||
found = through = FALSE;
|
||||
for (tmp = setupservers; tmp != NULL; ) {
|
||||
SETUP_SERVER_REC *rec = tmp->data;
|
||||
|
||||
if (!found && g_strcasecmp(rec->server, server->connrec->address) == 0 &&
|
||||
server->connrec->port == rec->port)
|
||||
found = TRUE;
|
||||
else if (found && rec->ircnet != NULL && g_strcasecmp(conn->ircnet, rec->ircnet) == 0) {
|
||||
sserver_connect(rec, conn);
|
||||
break;
|
||||
}
|
||||
|
||||
if (tmp->next != NULL) {
|
||||
tmp = tmp->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (through) {
|
||||
/* shouldn't happen unless there's no servers in
|
||||
this ircnet in setup.. */
|
||||
break;
|
||||
}
|
||||
|
||||
tmp = setupservers;
|
||||
found = through = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void sig_server_looking(IRC_SERVER_REC *server)
|
||||
{
|
||||
IRC_SERVER_CONNECT_REC *conn;
|
||||
GSList *tmp, *next;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
if (!irc_server_check(server))
|
||||
return;
|
||||
|
||||
/* trying to connect somewhere, check if there's anything in reconnect
|
||||
queue waiting to connect to same ircnet or same server+port.. */
|
||||
conn = server->connrec;
|
||||
for (tmp = reconnects; tmp != NULL; tmp = next) {
|
||||
RECONNECT_REC *rec = tmp->data;
|
||||
|
||||
next = tmp->next;
|
||||
if (g_strcasecmp(conn->address, rec->conn->address) == 0 &&
|
||||
conn->port == rec->conn->port) {
|
||||
server_reconnect_destroy(rec, TRUE);
|
||||
}
|
||||
else if (conn->ircnet != NULL && rec->conn->ircnet != NULL &&
|
||||
g_strcasecmp(conn->ircnet, rec->conn->ircnet) == 0) {
|
||||
server_reconnect_destroy(rec, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove all servers from reconnect list */
|
||||
static void cmd_rmreconns(void)
|
||||
{
|
||||
while (reconnects != NULL)
|
||||
server_reconnect_destroy(reconnects->data, TRUE);
|
||||
}
|
||||
|
||||
static RECONNECT_REC *reconnect_find_tag(int tag)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
for (tmp = reconnects; tmp != NULL; tmp = tmp->next) {
|
||||
RECONNECT_REC *rec = tmp->data;
|
||||
|
||||
if (rec->tag == tag)
|
||||
return rec;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Try to reconnect immediately */
|
||||
static void cmd_reconnect(const char *data)
|
||||
{
|
||||
IRC_SERVER_CONNECT_REC *conn;
|
||||
RECONNECT_REC *rec;
|
||||
int tag;
|
||||
|
||||
if (g_strncasecmp(data, "RECON-", 6) == 0)
|
||||
data += 6;
|
||||
|
||||
rec = sscanf(data, "%d", &tag) == 1 && tag > 0 ?
|
||||
reconnect_find_tag(tag) : NULL;
|
||||
|
||||
if (rec == NULL)
|
||||
signal_emit("server reconnect not found", 1, data);
|
||||
else {
|
||||
conn = rec->conn;
|
||||
server_reconnect_destroy(rec, FALSE);
|
||||
irc_server_connect(rec->conn);
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_disconnect(const char *data, SERVER_REC *server)
|
||||
{
|
||||
RECONNECT_REC *rec;
|
||||
int tag;
|
||||
|
||||
if (g_strncasecmp(data, "RECON-", 6) != 0)
|
||||
return; /* handle only reconnection removing */
|
||||
|
||||
rec = sscanf(data+6, "%d", &tag) == 1 && tag > 0 ?
|
||||
reconnect_find_tag(tag) : NULL;
|
||||
|
||||
if (rec == NULL)
|
||||
signal_emit("server reconnect not found", 1, data);
|
||||
else
|
||||
server_reconnect_destroy(rec, TRUE);
|
||||
}
|
||||
|
||||
static int sig_set_user_mode(IRC_SERVER_REC *server)
|
||||
{
|
||||
const char *mode;
|
||||
char *newmode;
|
||||
|
||||
if (g_slist_find(servers, server) == NULL)
|
||||
return 0; /* got disconnected */
|
||||
|
||||
mode = server->connrec->usermode;
|
||||
if (mode == NULL) return 0;
|
||||
|
||||
newmode = modes_join(server->usermode, mode);
|
||||
if (strcmp(newmode, server->usermode) != 0)
|
||||
irc_send_cmdv(server, "MODE %s -%s+%s", server->nick, server->usermode, mode);
|
||||
g_free(newmode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sig_connected(IRC_SERVER_REC *server)
|
||||
{
|
||||
if (!server->connrec->reconnection)
|
||||
return;
|
||||
|
||||
if (server->connrec->channels != NULL)
|
||||
channels_join(server, server->connrec->channels, TRUE);
|
||||
if (server->connrec->away_reason != NULL)
|
||||
signal_emit("command away", 2, server->connrec->away_reason, server, NULL);
|
||||
if (server->connrec->usermode != NULL) {
|
||||
/* wait a second and then send the user mode */
|
||||
g_timeout_add(1000, (GSourceFunc) sig_set_user_mode, server);
|
||||
}
|
||||
}
|
||||
|
||||
static void read_settings(void)
|
||||
{
|
||||
reconnect_time = settings_get_int("server_reconnect_time");
|
||||
}
|
||||
|
||||
void servers_reconnect_init(void)
|
||||
{
|
||||
reconnects = NULL;
|
||||
last_reconnect_tag = 0;
|
||||
|
||||
reconnect_timeout_tag = g_timeout_add(1000, (GSourceFunc) server_reconnect_timeout, NULL);
|
||||
read_settings();
|
||||
|
||||
signal_add("server looking", (SIGNAL_FUNC) sig_server_looking);
|
||||
signal_add("server connect failed", (SIGNAL_FUNC) sig_reconnect);
|
||||
signal_add("server disconnected", (SIGNAL_FUNC) sig_reconnect);
|
||||
signal_add("event connected", (SIGNAL_FUNC) sig_connected);
|
||||
command_bind("rmreconns", NULL, (SIGNAL_FUNC) cmd_rmreconns);
|
||||
command_bind("reconnect", NULL, (SIGNAL_FUNC) cmd_reconnect);
|
||||
command_bind("disconnect", NULL, (SIGNAL_FUNC) cmd_disconnect);
|
||||
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
|
||||
}
|
||||
|
||||
void servers_reconnect_deinit(void)
|
||||
{
|
||||
g_source_remove(reconnect_timeout_tag);
|
||||
|
||||
while (reconnects != NULL)
|
||||
server_reconnect_destroy(reconnects->data, TRUE);
|
||||
|
||||
signal_remove("server looking", (SIGNAL_FUNC) sig_server_looking);
|
||||
signal_remove("server connect failed", (SIGNAL_FUNC) sig_reconnect);
|
||||
signal_remove("server disconnected", (SIGNAL_FUNC) sig_reconnect);
|
||||
signal_remove("event connected", (SIGNAL_FUNC) sig_connected);
|
||||
command_unbind("rmreconns", (SIGNAL_FUNC) cmd_rmreconns);
|
||||
command_unbind("reconnect", (SIGNAL_FUNC) cmd_reconnect);
|
||||
command_unbind("disconnect", (SIGNAL_FUNC) cmd_disconnect);
|
||||
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
|
||||
}
|
||||
16
src/irc/core/server-reconnect.h
Normal file
16
src/irc/core/server-reconnect.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef __SERVER_RECONNECT_H
|
||||
#define __SERVER_RECONNECT_H
|
||||
|
||||
typedef struct {
|
||||
int tag;
|
||||
time_t next_connect;
|
||||
|
||||
IRC_SERVER_CONNECT_REC *conn;
|
||||
} RECONNECT_REC;
|
||||
|
||||
extern GSList *reconnects;
|
||||
|
||||
void servers_reconnect_init(void);
|
||||
void servers_reconnect_deinit(void);
|
||||
|
||||
#endif
|
||||
317
src/irc/core/server-setup.c
Normal file
317
src/irc/core/server-setup.c
Normal file
|
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
server-setup.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
#include "network.h"
|
||||
#include "lib-config/iconfig.h"
|
||||
#include "settings.h"
|
||||
#include "common-setup.h"
|
||||
|
||||
#include "irc-server.h"
|
||||
#include "server-setup.h"
|
||||
#include "ircnet-setup.h"
|
||||
|
||||
GSList *setupservers; /* list of irc servers */
|
||||
|
||||
int source_host_ok; /* Use source_host_ip .. */
|
||||
IPADDR *source_host_ip; /* Resolved address */
|
||||
|
||||
static void get_source_host_ip(void)
|
||||
{
|
||||
IPADDR ip;
|
||||
|
||||
/* FIXME: This will block! */
|
||||
if (!source_host_ok) {
|
||||
source_host_ok = *settings_get_str("hostname") != '\0' &&
|
||||
net_gethostname(settings_get_str("hostname"), &ip) == 0;
|
||||
if (source_host_ok) {
|
||||
source_host_ip = g_new(IPADDR, 1);
|
||||
memcpy(source_host_ip, &ip, sizeof(IPADDR));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create server connection record. `address' is required, rest can be NULL */
|
||||
static IRC_SERVER_CONNECT_REC *
|
||||
create_addr_conn(const char *address, int port, const char *password,
|
||||
const char *nick)
|
||||
{
|
||||
IRC_SERVER_CONNECT_REC *conn;
|
||||
SETUP_SERVER_REC *sserver;
|
||||
IRCNET_REC *ircnet;
|
||||
|
||||
g_return_val_if_fail(address != NULL, NULL);
|
||||
|
||||
conn = g_new0(IRC_SERVER_CONNECT_REC, 1);
|
||||
|
||||
conn->address = g_strdup(address);
|
||||
conn->port = port > 0 ? port : 6667;
|
||||
|
||||
if (password && *password) conn->password = g_strdup(password);
|
||||
if (nick && *nick) conn->nick = g_strdup(nick);
|
||||
|
||||
if (!conn->nick) conn->nick = g_strdup(settings_get_str("default_nick"));
|
||||
conn->alternate_nick = g_strdup(settings_get_str("alternate_nick"));
|
||||
conn->username = g_strdup(settings_get_str("user_name"));
|
||||
conn->realname = g_strdup(settings_get_str("real_name"));
|
||||
|
||||
/* proxy settings */
|
||||
if (settings_get_bool("toggle_use_ircproxy")) {
|
||||
conn->proxy = g_strdup(settings_get_str("proxy_address"));
|
||||
conn->proxy_port = settings_get_int("proxy_port");
|
||||
conn->proxy_string = g_strdup(settings_get_str("proxy_string"));
|
||||
}
|
||||
|
||||
/* source IP */
|
||||
get_source_host_ip();
|
||||
if (source_host_ok) {
|
||||
conn->own_ip = g_new(IPADDR, 1);
|
||||
memcpy(conn->own_ip, source_host_ip, sizeof(IPADDR));
|
||||
}
|
||||
|
||||
/* fill the information from setup */
|
||||
sserver = server_setup_find(address, -1);
|
||||
if (sserver == NULL) return conn;
|
||||
|
||||
sserver->last_connect = time(NULL);
|
||||
|
||||
if (sserver->ircnet) conn->ircnet = g_strdup(sserver->ircnet);
|
||||
if (sserver->password && !conn->password)
|
||||
conn->password = g_strdup(sserver->password);
|
||||
if (sserver->cmd_queue_speed > 0)
|
||||
conn->cmd_queue_speed = sserver->cmd_queue_speed;
|
||||
if (sserver->max_cmds_at_once > 0)
|
||||
conn->max_cmds_at_once = sserver->max_cmds_at_once;
|
||||
|
||||
/* fill the rest from IRC network settings */
|
||||
ircnet = sserver->ircnet == NULL ? NULL : ircnet_find(sserver->ircnet);
|
||||
if (ircnet == NULL) return conn;
|
||||
|
||||
if (ircnet->nick && !nick) {
|
||||
g_free(conn->nick);
|
||||
conn->nick = g_strdup(ircnet->nick);;
|
||||
}
|
||||
if (ircnet->username) {
|
||||
g_free(conn->username);
|
||||
conn->username = g_strdup(ircnet->username);;
|
||||
}
|
||||
if (ircnet->realname) {
|
||||
g_free(conn->realname);
|
||||
conn->realname = g_strdup(ircnet->realname);;
|
||||
}
|
||||
if (ircnet->max_kicks > 0) conn->max_kicks = ircnet->max_kicks;
|
||||
if (ircnet->max_msgs > 0) conn->max_msgs = ircnet->max_msgs;
|
||||
if (ircnet->max_modes > 0) conn->max_modes = ircnet->max_modes;
|
||||
if (ircnet->max_whois > 0) conn->max_whois = ircnet->max_whois;
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
/* Create server connection record. `dest' is required, rest can be NULL.
|
||||
`dest' is either a server address or irc network */
|
||||
IRC_SERVER_CONNECT_REC *
|
||||
irc_server_create_conn(const char *dest, int port, const char *password, const char *nick)
|
||||
{
|
||||
GSList *tmp;
|
||||
time_t now;
|
||||
int n;
|
||||
|
||||
g_return_val_if_fail(dest != NULL, NULL);
|
||||
|
||||
/* check if `dest' is IRC network */
|
||||
if (ircnet_find(dest) == NULL)
|
||||
return create_addr_conn(dest, port, password, nick);
|
||||
|
||||
/* first try to find a server that hasn't had any connection failures
|
||||
for the past half an hour. If that isn't found, try any server. */
|
||||
now = time(NULL);
|
||||
for (n = 0; n < 2; n++) {
|
||||
for (tmp = setupservers; tmp != NULL; tmp = tmp->next) {
|
||||
SETUP_SERVER_REC *rec = tmp->data;
|
||||
|
||||
if (rec->ircnet == NULL || g_strcasecmp(rec->ircnet, dest) != 0)
|
||||
continue;
|
||||
|
||||
if (n == 1 || !rec->last_failed || rec->last_connect < now-FAILED_RECONNECT_WAIT)
|
||||
return create_addr_conn(rec->server, port, password, nick);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find matching server from setup. Set port to -1 if you don't care about it */
|
||||
SETUP_SERVER_REC *server_setup_find(const char *address, int port)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
g_return_val_if_fail(address != NULL, NULL);
|
||||
|
||||
for (tmp = setupservers; tmp != NULL; tmp = tmp->next) {
|
||||
SETUP_SERVER_REC *rec = tmp->data;
|
||||
|
||||
if (g_strcasecmp(rec->server, address) == 0 &&
|
||||
(port == -1 || rec->port == port)) return rec;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void init_userinfo(void)
|
||||
{
|
||||
const char *set, *default_nick, *user_name;
|
||||
char *str;
|
||||
|
||||
/* check if nick/username/realname wasn't read from setup.. */
|
||||
set = settings_get_str("real_name");
|
||||
if (set == NULL || *set == '\0') {
|
||||
str = g_getenv("IRCNAME");
|
||||
iconfig_set_str("settings", "real_name",
|
||||
str != NULL ? str : g_get_real_name());
|
||||
g_free_not_null(str);
|
||||
}
|
||||
|
||||
/* username */
|
||||
user_name = settings_get_str("user_name");
|
||||
if (user_name == NULL || *user_name == '\0') {
|
||||
str = g_getenv("IRCUSER");
|
||||
iconfig_set_str("settings", "user_name",
|
||||
str != NULL ? str : g_get_user_name());
|
||||
g_free_not_null(str);
|
||||
|
||||
user_name = settings_get_str("user_name");
|
||||
}
|
||||
|
||||
/* nick */
|
||||
default_nick = settings_get_str("default_nick");
|
||||
if (default_nick == NULL || *default_nick == '\0') {
|
||||
str = g_getenv("IRCNICK");
|
||||
iconfig_set_str("settings", "default_nick",
|
||||
str != NULL ? str : user_name);
|
||||
g_free_not_null(str);
|
||||
|
||||
default_nick = settings_get_str("default_nick");
|
||||
}
|
||||
|
||||
/* alternate nick */
|
||||
set = settings_get_str("alternate_nick");
|
||||
if (set == NULL || *set == '\0') {
|
||||
if (strlen(default_nick) < 9)
|
||||
str = g_strconcat(default_nick, "_", NULL);
|
||||
else {
|
||||
str = g_strdup(default_nick);
|
||||
str[strlen(str)-1] = '_';
|
||||
}
|
||||
iconfig_set_str("settings", "alternate_nick", str);
|
||||
g_free(str);
|
||||
}
|
||||
}
|
||||
|
||||
static SETUP_SERVER_REC *setupserver_add(CONFIG_NODE *node)
|
||||
{
|
||||
SETUP_SERVER_REC *rec;
|
||||
char *ircnet, *server;
|
||||
int port;
|
||||
|
||||
g_return_val_if_fail(node != NULL, NULL);
|
||||
|
||||
ircnet = config_node_get_str(node, "ircnet", NULL);
|
||||
server = config_node_get_str(node, "server", NULL);
|
||||
if (ircnet == NULL || server == NULL) return NULL;
|
||||
|
||||
port = config_node_get_int(node, "port", 6667);
|
||||
if (server_setup_find(server, port) != NULL) {
|
||||
/* already exists - don't let it get there twice or
|
||||
server reconnects will screw up! */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rec = g_new0(SETUP_SERVER_REC, 1);
|
||||
rec->ircnet = g_strdup(ircnet);
|
||||
rec->server = g_strdup(server);
|
||||
rec->password = g_strdup(config_node_get_str(node, "password", ""));
|
||||
rec->port = port;
|
||||
rec->autoconnect = config_node_get_bool(node, "autoconnect", FALSE);
|
||||
rec->max_cmds_at_once = config_node_get_int(node, "cmds_max_at_once", 0);
|
||||
rec->cmd_queue_speed = config_node_get_int(node, "cmd_queue_speed", 0);
|
||||
|
||||
setupservers = g_slist_append(setupservers, rec);
|
||||
return rec;
|
||||
}
|
||||
|
||||
static void setupserver_destroy(SETUP_SERVER_REC *rec)
|
||||
{
|
||||
setupservers = g_slist_remove(setupservers, rec);
|
||||
|
||||
g_free(rec->ircnet);
|
||||
g_free(rec->server);
|
||||
g_free(rec->password);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
static void read_servers(void)
|
||||
{
|
||||
CONFIG_NODE *node;
|
||||
GSList *tmp;
|
||||
|
||||
while (setupservers != NULL)
|
||||
setupserver_destroy(setupservers->data);
|
||||
|
||||
/* Read servers */
|
||||
node = iconfig_node_traverse("(setupservers", FALSE);
|
||||
if (node != NULL) {
|
||||
for (tmp = node->value; tmp != NULL; tmp = tmp->next)
|
||||
setupserver_add(tmp->data);
|
||||
}
|
||||
}
|
||||
|
||||
void servers_setup_init(void)
|
||||
{
|
||||
source_host_ok = FALSE;
|
||||
source_host_ip = NULL;
|
||||
|
||||
settings_add_int("server", "server_reconnect_time", 300);
|
||||
settings_add_str("server", "hostname", "");
|
||||
settings_add_bool("server", "toggle_skip_motd", FALSE);
|
||||
|
||||
settings_add_str("server", "default_nick", NULL);
|
||||
settings_add_str("server", "alternate_nick", NULL);
|
||||
settings_add_str("server", "user_name", NULL);
|
||||
settings_add_str("server", "real_name", NULL);
|
||||
|
||||
settings_add_bool("ircproxy", "toggle_use_ircproxy", FALSE);
|
||||
settings_add_str("ircproxy", "proxy_address", "");
|
||||
settings_add_int("ircproxy", "proxy_port", 6667);
|
||||
settings_add_str("ircproxy", "proxy_string", "CONNECT %s %d");
|
||||
|
||||
init_userinfo();
|
||||
|
||||
read_servers();
|
||||
signal_add("setup reread", (SIGNAL_FUNC) read_servers);
|
||||
}
|
||||
|
||||
void servers_setup_deinit(void)
|
||||
{
|
||||
while (setupservers != NULL)
|
||||
setupserver_destroy(setupservers->data);
|
||||
|
||||
signal_remove("setup reread", (SIGNAL_FUNC) read_servers);
|
||||
}
|
||||
40
src/irc/core/server-setup.h
Normal file
40
src/irc/core/server-setup.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef __SERVER_SETUP_H
|
||||
#define __SERVER_SETUP_H
|
||||
|
||||
#include "irc-server.h"
|
||||
|
||||
/* servers */
|
||||
typedef struct {
|
||||
char *server;
|
||||
int port;
|
||||
|
||||
char *ircnet;
|
||||
char *password;
|
||||
int autoconnect;
|
||||
int max_cmds_at_once; /* override the default if > 0 */
|
||||
int cmd_queue_speed; /* override the default if > 0 */
|
||||
|
||||
char *own_address; /* address to use when connecting this server */
|
||||
IPADDR *own_ip; /* resolved own_address or full of zeros */
|
||||
|
||||
time_t last_connect; /* to avoid reconnecting too fast.. */
|
||||
int last_failed; /* if last connection attempt failed */
|
||||
} SETUP_SERVER_REC;
|
||||
|
||||
extern GSList *setupservers; /* list of irc servers */
|
||||
|
||||
extern IPADDR *source_host_ip; /* Resolved address */
|
||||
extern gboolean source_host_ok; /* Use source_host_ip .. */
|
||||
|
||||
/* Create server connection record. `dest' is required, rest can be NULL.
|
||||
`dest' is either a server address or irc network */
|
||||
IRC_SERVER_CONNECT_REC *
|
||||
irc_server_create_conn(const char *dest, int port, const char *password, const char *nick);
|
||||
|
||||
/* Find matching server from setup. Set port to -1 if you don't care about it */
|
||||
SETUP_SERVER_REC *server_setup_find(const char *address, int port);
|
||||
|
||||
void servers_setup_init(void);
|
||||
void servers_setup_deinit(void);
|
||||
|
||||
#endif
|
||||
14
src/irc/dcc/Makefile.am
Normal file
14
src/irc/dcc/Makefile.am
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
noinst_LTLIBRARIES = libirc_dcc.la
|
||||
|
||||
INCLUDES = $(GLIB_CFLAGS) \
|
||||
-I$(top_srcdir)/src -I$(top_srcdir)/src/core/ -I$(top_srcdir)/src/irc/core/
|
||||
|
||||
libirc_dcc_la_SOURCES = \
|
||||
dcc.c \
|
||||
dcc-chat.c \
|
||||
dcc-files.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
dcc.h \
|
||||
dcc-chat.h \
|
||||
dcc-files.h
|
||||
371
src/irc/dcc/dcc-chat.c
Normal file
371
src/irc/dcc/dcc-chat.c
Normal file
|
|
@ -0,0 +1,371 @@
|
|||
/*
|
||||
dcc-chat.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
#include "commands.h"
|
||||
#include "network.h"
|
||||
#include "net-nonblock.h"
|
||||
#include "line-split.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include "masks.h"
|
||||
#include "irc.h"
|
||||
#include "server-setup.h"
|
||||
|
||||
#include "dcc.h"
|
||||
|
||||
/* Send text to DCC chat */
|
||||
static void dcc_chat_write(gchar *data)
|
||||
{
|
||||
DCC_REC *dcc;
|
||||
gchar *params, *text, *target;
|
||||
gint len;
|
||||
|
||||
g_return_if_fail(text != NULL);
|
||||
|
||||
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &text);
|
||||
|
||||
if (*target == '=')
|
||||
{
|
||||
/* dcc msg */
|
||||
dcc = dcc_find_item(DCC_TYPE_CHAT, ++target, NULL);
|
||||
if (dcc != NULL)
|
||||
{
|
||||
len = strlen(text);
|
||||
/* FIXME: we need output queue! */
|
||||
if (net_transmit(dcc->handle, text, len) != len)
|
||||
g_warning("dcc_chat_write() : could not send all data!");
|
||||
net_transmit(dcc->handle, "\n", 1);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void dcc_chat_me(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
DCC_REC *dcc;
|
||||
char *str;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
dcc = irc_item_dcc_chat(item);
|
||||
if (dcc == NULL) return;
|
||||
|
||||
str = g_strdup_printf("ACTION %s", data);
|
||||
dcc_ctcp_message(dcc->nick, NULL, dcc, FALSE, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void dcc_chat_action(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *target, *text;
|
||||
DCC_REC *dcc;
|
||||
char *str;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
if (*data != '=') {
|
||||
/* handle only DCC actions */
|
||||
return;
|
||||
}
|
||||
|
||||
params = cmd_get_params(data, 3 | PARAM_FLAG_GETREST, &target, &text);
|
||||
if (*target == '\0' || *text == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
dcc = dcc_find_item(DCC_TYPE_CHAT, target+1, NULL);
|
||||
if (dcc != NULL) {
|
||||
str = g_strdup_printf("ACTION %s", data);
|
||||
dcc_ctcp_message(dcc->nick, NULL, dcc, FALSE, str);
|
||||
g_free(str);
|
||||
}
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void dcc_chat_ctcp(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *target, *ctcpcmd, *ctcpdata;
|
||||
DCC_REC *dcc;
|
||||
char *str;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (server == NULL || !server->connected) cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
params = cmd_get_params(data, 3 | PARAM_FLAG_GETREST, &target, &ctcpcmd, &ctcpdata);
|
||||
if (*target == '\0' || *ctcpcmd == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
if (*target != '=') {
|
||||
/* handle only DCC CTCPs */
|
||||
g_free(params);
|
||||
return;
|
||||
}
|
||||
|
||||
dcc = dcc_find_item(DCC_TYPE_CHAT, target+1, NULL);
|
||||
if (dcc != NULL) {
|
||||
g_strup(ctcpcmd);
|
||||
|
||||
str = g_strdup_printf("%s %s", ctcpcmd, ctcpdata);
|
||||
dcc_ctcp_message(dcc->nick, NULL, dcc, FALSE, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
/* DCC CHAT: text received */
|
||||
static void dcc_chat_msg(DCC_REC *dcc, gchar *msg)
|
||||
{
|
||||
gchar *cmd, *ptr;
|
||||
gboolean reply;
|
||||
|
||||
g_return_if_fail(dcc != NULL);
|
||||
g_return_if_fail(msg != NULL);
|
||||
|
||||
reply = FALSE;
|
||||
if (g_strncasecmp(msg, "CTCP_MESSAGE ", 13) != 0)
|
||||
{
|
||||
if (g_strncasecmp(msg, "CTCP_REPLY ", 11) != 0)
|
||||
{
|
||||
/* Use the mirc style CTCPing from now on.. */
|
||||
dcc->mirc_ctcp = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* bitchx (and ircii?) sends this */
|
||||
msg += 11;
|
||||
reply = TRUE;
|
||||
dcc->mirc_ctcp = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* bitchx (and ircii?) sends this */
|
||||
msg += 13;
|
||||
dcc->mirc_ctcp = FALSE;
|
||||
}
|
||||
|
||||
/* Handle only DCC CTCPs */
|
||||
if (*msg != 1)
|
||||
return;
|
||||
|
||||
msg = g_strdup(msg+1);
|
||||
/* remove the later \001 */
|
||||
ptr = strrchr(msg, 1);
|
||||
if (ptr != NULL) *ptr = '\0';
|
||||
|
||||
/* get ctcp command */
|
||||
cmd = g_strconcat(reply ? "dcc reply " : "dcc ctcp ", msg, NULL);
|
||||
ptr = strchr(cmd+9, ' ');
|
||||
if (ptr != NULL) *ptr++ = '\0'; else ptr = "";
|
||||
|
||||
g_strdown(cmd+9);
|
||||
if (!signal_emit(cmd, 2, ptr, dcc))
|
||||
signal_emit(reply ? "default dcc reply" : "default dcc ctcp", 2, msg, dcc);
|
||||
|
||||
g_free(cmd);
|
||||
g_free(msg);
|
||||
|
||||
signal_stop();
|
||||
}
|
||||
|
||||
/* input function: DCC CHAT received some data.. */
|
||||
static void dcc_chat_input(DCC_REC *dcc)
|
||||
{
|
||||
char tmpbuf[512], *str;
|
||||
int recvlen, ret;
|
||||
|
||||
g_return_if_fail(dcc != NULL);
|
||||
|
||||
do {
|
||||
recvlen = net_receive(dcc->handle, tmpbuf, sizeof(tmpbuf));
|
||||
|
||||
ret = line_split(tmpbuf, recvlen, &str, (LINEBUF_REC **) &dcc->databuf);
|
||||
if (ret == -1) {
|
||||
/* connection lost */
|
||||
dcc->destroyed = TRUE;
|
||||
signal_emit("dcc closed", 1, dcc);
|
||||
dcc_destroy(dcc);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
dcc->transfd += ret;
|
||||
signal_emit("dcc chat message", 2, dcc, str);
|
||||
}
|
||||
} while (ret > 0);
|
||||
}
|
||||
|
||||
/* input function: DCC CHAT - someone tried to connect to our socket */
|
||||
static void dcc_chat_listen(DCC_REC *dcc)
|
||||
{
|
||||
IPADDR ip;
|
||||
gint handle, port;
|
||||
|
||||
g_return_if_fail(dcc != NULL);
|
||||
|
||||
/* accept connection */
|
||||
handle = net_accept(dcc->handle, &ip, &port);
|
||||
if (handle == -1)
|
||||
return;
|
||||
|
||||
/* FIXME: add paranoia checking, check if host ip is the same as to who
|
||||
we sent the DCC CHAT request.. */
|
||||
|
||||
g_source_remove(dcc->tagread);
|
||||
close(dcc->handle);
|
||||
|
||||
dcc->starttime = time(NULL);
|
||||
dcc->handle = handle;
|
||||
memcpy(&dcc->addr, &ip, sizeof(IPADDR));
|
||||
net_ip2host(&dcc->addr, dcc->addrstr);
|
||||
dcc->port = port;
|
||||
dcc->tagread = g_input_add(handle, G_INPUT_READ,
|
||||
(GInputFunction) dcc_chat_input, dcc);
|
||||
|
||||
signal_emit("dcc connected", 1, dcc);
|
||||
}
|
||||
|
||||
/* callback: DCC CHAT - net_connect_nonblock() finished */
|
||||
static void dcc_chat_connect(DCC_REC *dcc)
|
||||
{
|
||||
g_return_if_fail(dcc != NULL);
|
||||
|
||||
g_source_remove(dcc->tagread);
|
||||
if (net_geterror(dcc->handle) != 0)
|
||||
{
|
||||
/* error connecting */
|
||||
signal_emit("dcc error connect", 1, dcc);
|
||||
dcc_destroy(dcc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* connect ok. */
|
||||
dcc->starttime = time(NULL);
|
||||
dcc->tagread = g_input_add(dcc->handle, G_INPUT_READ,
|
||||
(GInputFunction) dcc_chat_input, dcc);
|
||||
|
||||
signal_emit("dcc connected", 1, dcc);
|
||||
}
|
||||
|
||||
/* command: DCC CHAT */
|
||||
static void cmd_dcc_chat(gchar *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
DCC_REC *dcc;
|
||||
IPADDR addr;
|
||||
gchar *str;
|
||||
gint port, handle;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
dcc = dcc_find_item(DCC_TYPE_CHAT, data, NULL);
|
||||
if (dcc != NULL)
|
||||
{
|
||||
if (dcc->addrstr[0] == '\0' || dcc->starttime != 0)
|
||||
{
|
||||
/* already sent a chat request / already chatting */
|
||||
return;
|
||||
}
|
||||
|
||||
/* found from dcc list - so we're the connecting side.. */
|
||||
dcc->handle = net_connect_ip(&dcc->addr, dcc->port,
|
||||
source_host_ok ? source_host_ip : NULL);
|
||||
if (dcc->handle != -1)
|
||||
{
|
||||
dcc->tagread = g_input_add(dcc->handle, G_INPUT_WRITE,
|
||||
(GInputFunction) dcc_chat_connect, dcc);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* error connecting */
|
||||
signal_emit("dcc error connect", 1, dcc);
|
||||
dcc_destroy(dcc);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* send dcc chat request */
|
||||
if (server == NULL || !server->connected)
|
||||
cmd_return_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
if (!net_getsockname(server->handle, &addr, NULL))
|
||||
cmd_return_error(CMDERR_GETSOCKNAME);
|
||||
|
||||
port = settings_get_int("dcc_port");
|
||||
handle = net_listen(&addr, &port);
|
||||
if (handle == -1)
|
||||
cmd_return_error(CMDERR_LISTEN);
|
||||
|
||||
dcc = dcc_create(DCC_TYPE_CHAT, handle, data, "chat", server, NULL);
|
||||
dcc->tagread = g_input_add(dcc->handle, G_INPUT_READ,
|
||||
(GInputFunction) dcc_chat_listen, dcc);
|
||||
|
||||
/* send the request */
|
||||
str = g_strdup_printf("PRIVMSG %s :\001DCC CHAT CHAT %s %d\001",
|
||||
data, dcc_make_address(&addr), port);
|
||||
irc_send_cmd(server, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void cmd_mircdcc(gchar *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
DCC_REC *dcc;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
dcc = irc_item_dcc_chat(item);
|
||||
if (dcc == NULL) return;
|
||||
|
||||
dcc->mirc_ctcp = toupper(*data) == 'N' ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
static void dcc_ctcp_redirect(gchar *msg, DCC_REC *dcc)
|
||||
{
|
||||
g_return_if_fail(msg != NULL);
|
||||
g_return_if_fail(dcc != NULL);
|
||||
|
||||
signal_emit("ctcp msg dcc", 6, msg, dcc->server, dcc->nick, "dcc", dcc->mynick, dcc);
|
||||
}
|
||||
|
||||
void dcc_chat_init(void)
|
||||
{
|
||||
command_bind("msg", NULL, (SIGNAL_FUNC) dcc_chat_write);
|
||||
command_bind("me", NULL, (SIGNAL_FUNC) dcc_chat_me);
|
||||
command_bind("action", NULL, (SIGNAL_FUNC) dcc_chat_action);
|
||||
command_bind("ctcp", NULL, (SIGNAL_FUNC) dcc_chat_ctcp);
|
||||
command_bind("dcc chat", NULL, (SIGNAL_FUNC) cmd_dcc_chat);
|
||||
signal_add_first("dcc chat message", (SIGNAL_FUNC) dcc_chat_msg);
|
||||
command_bind("mircdcc", NULL, (SIGNAL_FUNC) cmd_mircdcc);
|
||||
signal_add("dcc ctcp dcc", (SIGNAL_FUNC) dcc_ctcp_redirect);
|
||||
}
|
||||
|
||||
void dcc_chat_deinit(void)
|
||||
{
|
||||
command_unbind("msg", (SIGNAL_FUNC) dcc_chat_write);
|
||||
command_unbind("me", (SIGNAL_FUNC) dcc_chat_me);
|
||||
command_unbind("action", (SIGNAL_FUNC) dcc_chat_action);
|
||||
command_unbind("ctcp", (SIGNAL_FUNC) dcc_chat_ctcp);
|
||||
command_unbind("dcc chat", (SIGNAL_FUNC) cmd_dcc_chat);
|
||||
signal_remove("dcc chat message", (SIGNAL_FUNC) dcc_chat_msg);
|
||||
command_unbind("mircdcc", (SIGNAL_FUNC) cmd_mircdcc);
|
||||
signal_remove("dcc ctcp dcc", (SIGNAL_FUNC) dcc_ctcp_redirect);
|
||||
}
|
||||
7
src/irc/dcc/dcc-chat.h
Normal file
7
src/irc/dcc/dcc-chat.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef __DCC_CHAT_H
|
||||
#define __DCC_CHAT_H
|
||||
|
||||
void dcc_chat_init(void);
|
||||
void dcc_chat_deinit(void);
|
||||
|
||||
#endif
|
||||
577
src/irc/dcc/dcc-files.c
Normal file
577
src/irc/dcc/dcc-files.c
Normal file
|
|
@ -0,0 +1,577 @@
|
|||
/*
|
||||
dcc-files.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
#include "commands.h"
|
||||
#include "network.h"
|
||||
#include "line-split.h"
|
||||
#include "misc.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include "masks.h"
|
||||
#include "irc.h"
|
||||
#include "server-setup.h"
|
||||
|
||||
#include "dcc.h"
|
||||
|
||||
static gint dcc_file_create_mode;
|
||||
|
||||
static gchar *dcc_prepare_path(gchar *fname)
|
||||
{
|
||||
gchar *str, *ptr, *downpath;
|
||||
|
||||
/* strip all paths from file. */
|
||||
ptr = strrchr(fname, '/');
|
||||
if (ptr == NULL) ptr = fname; else ptr++;
|
||||
|
||||
downpath = convert_home(settings_get_str("dcc_download_path"));
|
||||
str = g_strdup_printf("%s/%s", downpath, ptr);
|
||||
g_free(downpath);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/* input function: DCC GET received data */
|
||||
static void dcc_receive(DCC_REC *dcc)
|
||||
{
|
||||
guint32 recd;
|
||||
gint len, ret;
|
||||
|
||||
g_return_if_fail(dcc != NULL);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
len = net_receive(dcc->handle, dcc->databuf, dcc->databufsize);
|
||||
if (len == 0) break;
|
||||
if (len < 0)
|
||||
{
|
||||
/* socket closed - transmit complete (or other side died..) */
|
||||
signal_emit("dcc closed", 1, dcc);
|
||||
dcc_destroy(dcc);
|
||||
return;
|
||||
}
|
||||
|
||||
write(dcc->fhandle, dcc->databuf, len);
|
||||
dcc->transfd += len;
|
||||
}
|
||||
|
||||
/* send number of total bytes received - if for some reason we couldn't
|
||||
send the 4 characters last time, try to somehow fix it this time by
|
||||
sending missing amount of 0 characters.. */
|
||||
if (dcc->trans_bytes != 0)
|
||||
{
|
||||
recd = (guint32) htonl(0);
|
||||
dcc->trans_bytes += net_transmit(dcc->handle, ((gchar *) &recd)+dcc->trans_bytes, 4-dcc->trans_bytes);
|
||||
if (dcc->trans_bytes == 4) dcc->trans_bytes = 0;
|
||||
}
|
||||
|
||||
if (dcc->trans_bytes == 0)
|
||||
{
|
||||
recd = (guint32) htonl(dcc->transfd);
|
||||
ret = net_transmit(dcc->handle, ((gchar *) &recd), 4);
|
||||
if (ret > 0 && ret < 4) dcc->trans_bytes = ret;
|
||||
}
|
||||
signal_emit("dcc transfer update", 1, dcc);
|
||||
}
|
||||
|
||||
/* callback: net_connect() finished for DCC GET */
|
||||
static void dcc_get_connect(DCC_REC *dcc)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
g_return_if_fail(dcc != NULL);
|
||||
|
||||
g_source_remove(dcc->tagread);
|
||||
if (net_geterror(dcc->handle) != 0)
|
||||
{
|
||||
/* error connecting */
|
||||
signal_emit("dcc error connect", 1, dcc);
|
||||
dcc_destroy(dcc);
|
||||
return;
|
||||
}
|
||||
dcc->file = dcc_prepare_path(dcc->arg);
|
||||
|
||||
/* if some plugin wants to change the file name/path here.. */
|
||||
signal_emit("dcc get receive", 1, dcc);
|
||||
|
||||
if (stat(dcc->file, &statbuf) == 0 &&
|
||||
(dcc->get_type == DCC_GET_RENAME || dcc->get_type == DCC_GET_DEFAULT))
|
||||
{
|
||||
/* file exists, rename.. */
|
||||
GString *newname;
|
||||
gint num;
|
||||
|
||||
newname = g_string_new(NULL);
|
||||
for (num = 1; ; num++)
|
||||
{
|
||||
g_string_sprintf(newname, "%s.%d", dcc->file, num);
|
||||
if (stat(newname->str, &statbuf) != 0) break;
|
||||
}
|
||||
g_free(dcc->file);
|
||||
dcc->file = newname->str;
|
||||
g_string_free(newname, FALSE);
|
||||
}
|
||||
|
||||
if (dcc->get_type != DCC_GET_RESUME)
|
||||
{
|
||||
dcc->fhandle = open(dcc->file, O_WRONLY | O_TRUNC | O_CREAT, dcc_file_create_mode);
|
||||
if (dcc->fhandle == -1)
|
||||
{
|
||||
signal_emit("dcc error file create", 2, dcc, dcc->file);
|
||||
dcc_destroy(dcc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dcc->databufsize = settings_get_int("dcc_block_size") > 0 ? settings_get_int("dcc_block_size") : 2048;
|
||||
dcc->databuf = g_malloc(dcc->databufsize);
|
||||
|
||||
dcc->starttime = time(NULL);
|
||||
dcc->tagread = g_input_add(dcc->handle, G_INPUT_READ,
|
||||
(GInputFunction) dcc_receive, dcc);
|
||||
signal_emit("dcc connected", 1, dcc);
|
||||
}
|
||||
|
||||
/* command: DCC GET */
|
||||
static void cmd_dcc_get(gchar *data)
|
||||
{
|
||||
DCC_REC *dcc;
|
||||
GSList *tmp, *next;
|
||||
gchar *params, *nick, *fname;
|
||||
gboolean found;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &nick, &fname);
|
||||
if (*nick == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
dcc = NULL; found = FALSE;
|
||||
for (tmp = dcc_conns; tmp != NULL; tmp = next)
|
||||
{
|
||||
dcc = tmp->data;
|
||||
next = tmp->next;
|
||||
|
||||
if (dcc->dcc_type == DCC_TYPE_GET && dcc->handle == -1 && g_strcasecmp(dcc->nick, nick) == 0 &&
|
||||
(*fname == '\0' || strcmp(dcc->arg, fname) == 0))
|
||||
{
|
||||
/* found! */
|
||||
found = TRUE;
|
||||
dcc->handle = net_connect_ip(&dcc->addr, dcc->port,
|
||||
source_host_ok ? source_host_ip : NULL);
|
||||
if (dcc->handle != -1)
|
||||
{
|
||||
dcc->tagread = g_input_add(dcc->handle, G_INPUT_WRITE,
|
||||
(GInputFunction) dcc_get_connect, dcc);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* error connecting */
|
||||
signal_emit("dcc error connect", 1, dcc);
|
||||
dcc_destroy(dcc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
signal_emit("dcc error get not found", 1, nick);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
/* resume setup: DCC SEND - we either said resume on get, or when we sent,
|
||||
someone chose resume */
|
||||
static void dcc_resume_setup(DCC_REC *dcc, gint port)
|
||||
{
|
||||
gchar *str;
|
||||
|
||||
/* Check for DCC_SEND_RESUME */
|
||||
if (dcc->dcc_type == DCC_TYPE_SEND)
|
||||
{
|
||||
if (lseek(dcc->fhandle, dcc->transfd, SEEK_SET) == -1)
|
||||
{
|
||||
signal_emit("dcc closed", 1, dcc);
|
||||
dcc_destroy(dcc);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
str = g_strdup_printf("DCC ACCEPT %s %d %lu",
|
||||
dcc->arg, port, dcc->transfd);
|
||||
dcc_ctcp_message(dcc->nick, dcc->server, dcc->chat, FALSE, str);
|
||||
g_free(str);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for DCC_GET_RESUME */
|
||||
if (dcc->dcc_type == DCC_TYPE_GET && dcc->get_type == DCC_GET_RESUME)
|
||||
{
|
||||
dcc->handle = net_connect_ip(&dcc->addr, dcc->port,
|
||||
source_host_ok ? source_host_ip : NULL);
|
||||
if (dcc->handle != -1)
|
||||
{
|
||||
dcc->tagread = g_input_add(dcc->handle, G_INPUT_WRITE,
|
||||
(GInputFunction) dcc_get_connect, dcc);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* error connecting */
|
||||
signal_emit("dcc error connect", 1, dcc);
|
||||
dcc_destroy(dcc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dcc_ctcp_msg(gchar *data, IRC_SERVER_REC *server, gchar *sender, gchar *sendaddr, gchar *target, DCC_REC *chat)
|
||||
{
|
||||
gchar *params, *type, *arg, *portstr, *sizestr;
|
||||
gulong size;
|
||||
gint port;
|
||||
DCC_REC *dcc;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
g_return_if_fail(sender != NULL);
|
||||
|
||||
params = cmd_get_params(data, 4, &type, &arg, &portstr, &sizestr);
|
||||
if (g_strcasecmp(type, "RESUME") == 0 || g_strcasecmp(type, "ACCEPT") == 0)
|
||||
{
|
||||
if (sscanf(portstr, "%d", &port) != 1) port = 0;
|
||||
if (sscanf(sizestr, "%lu", &size) != 1) size = 0;
|
||||
|
||||
dcc = dcc_find_by_port(sender, port);
|
||||
if (dcc != NULL && (dcc->dcc_type == DCC_TYPE_GET || dcc->transfd == 0))
|
||||
{
|
||||
dcc->transfd = size;
|
||||
dcc->skipped = size;
|
||||
dcc_resume_setup(dcc, port);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void dcc_resume_rec(DCC_REC *dcc)
|
||||
{
|
||||
gchar *str;
|
||||
|
||||
dcc->file = dcc_prepare_path(dcc->arg);
|
||||
|
||||
dcc->fhandle = open(dcc->file, O_WRONLY, dcc_file_create_mode);
|
||||
if (dcc->fhandle == -1)
|
||||
{
|
||||
signal_emit("dcc error file not found", 2, dcc, dcc->file);
|
||||
dcc_destroy(dcc);
|
||||
}
|
||||
else
|
||||
{
|
||||
dcc->transfd = lseek(dcc->fhandle, 0, SEEK_END);
|
||||
if (dcc->transfd < 0) dcc->transfd = 0;
|
||||
dcc->skipped = dcc->transfd;
|
||||
|
||||
str = g_strdup_printf("DCC RESUME %s %d %lu",
|
||||
dcc->arg, dcc->port, dcc->transfd);
|
||||
dcc_ctcp_message(dcc->nick, dcc->server, dcc->chat, FALSE, str);
|
||||
g_free(str);
|
||||
}
|
||||
}
|
||||
|
||||
/* command: DCC RESUME */
|
||||
static void cmd_dcc_resume(gchar *data)
|
||||
{
|
||||
DCC_REC *dcc;
|
||||
GSList *tmp;
|
||||
gchar *params, *nick, *fname;
|
||||
gboolean found;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &nick, &fname);
|
||||
if (*nick == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
dcc = NULL; found = FALSE;
|
||||
for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next)
|
||||
{
|
||||
dcc = tmp->data;
|
||||
|
||||
if (dcc->dcc_type == DCC_TYPE_GET && dcc->handle == -1 && g_strcasecmp(dcc->nick, nick) == 0 &&
|
||||
(*fname == '\0' || strcmp(dcc->arg, fname) == 0))
|
||||
{
|
||||
/* found! */
|
||||
dcc->get_type = DCC_GET_RESUME;
|
||||
dcc_resume_rec(dcc);
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
signal_emit("dcc error get not found", 1, nick);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
/* input function: DCC SEND send more data */
|
||||
static void dcc_send_data(DCC_REC *dcc)
|
||||
{
|
||||
gint n;
|
||||
|
||||
g_return_if_fail(dcc != NULL);
|
||||
|
||||
if (!dcc->fastsend && !dcc->gotalldata)
|
||||
{
|
||||
/* haven't received everything we've send there yet.. */
|
||||
return;
|
||||
}
|
||||
|
||||
n = read(dcc->fhandle, dcc->databuf, dcc->databufsize);
|
||||
if (n <= 0)
|
||||
{
|
||||
/* end of file .. or some error .. */
|
||||
if (dcc->fastsend)
|
||||
{
|
||||
/* no need to call this function anymore.. in fact it just eats
|
||||
all the cpu.. */
|
||||
dcc->waitforend = TRUE;
|
||||
g_source_remove(dcc->tagwrite);
|
||||
dcc->tagwrite = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
signal_emit("dcc closed", 1, dcc);
|
||||
dcc_destroy(dcc);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
dcc->transfd += net_transmit(dcc->handle, dcc->databuf, n);
|
||||
dcc->gotalldata = FALSE;
|
||||
|
||||
lseek(dcc->fhandle, dcc->transfd, SEEK_SET);
|
||||
|
||||
signal_emit("dcc transfer update", 1, dcc);
|
||||
}
|
||||
|
||||
/* input function: DCC SEND received some data */
|
||||
static void dcc_send_read_size(DCC_REC *dcc)
|
||||
{
|
||||
guint32 bytes;
|
||||
gint ret;
|
||||
|
||||
g_return_if_fail(dcc != NULL);
|
||||
|
||||
if (dcc->read_pos == 4)
|
||||
return;
|
||||
|
||||
/* we need to get 4 bytes.. */
|
||||
ret = net_receive(dcc->handle, dcc->read_buf+dcc->read_pos, 4-dcc->read_pos);
|
||||
if (ret == -1)
|
||||
{
|
||||
signal_emit("dcc closed", 1, dcc);
|
||||
dcc_destroy(dcc);
|
||||
return;
|
||||
}
|
||||
|
||||
dcc->read_pos += ret;
|
||||
|
||||
if (dcc->read_pos == 4)
|
||||
{
|
||||
bytes = 0; memcpy(&bytes, dcc->read_buf, 4);
|
||||
bytes = (guint32) ntohl(bytes);
|
||||
|
||||
dcc->gotalldata = bytes == dcc->transfd;
|
||||
dcc->read_pos = 0;
|
||||
|
||||
if (!dcc->fastsend)
|
||||
{
|
||||
/* send more data.. */
|
||||
dcc_send_data(dcc);
|
||||
}
|
||||
|
||||
if (dcc->waitforend && dcc->gotalldata)
|
||||
{
|
||||
/* file is sent */
|
||||
signal_emit("dcc closed", 1, dcc);
|
||||
dcc_destroy(dcc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* input function: DCC SEND - someone tried to connect to our socket */
|
||||
static void dcc_send_init(DCC_REC *dcc)
|
||||
{
|
||||
gint handle, port;
|
||||
IPADDR addr;
|
||||
|
||||
g_return_if_fail(dcc != NULL);
|
||||
|
||||
/* accept connection */
|
||||
handle = net_accept(dcc->handle, &addr, &port);
|
||||
if (handle == -1)
|
||||
return;
|
||||
|
||||
/* FIXME: add paranoia checking, check if host ip is the same as to who
|
||||
we sent the DCC SEND request.. */
|
||||
|
||||
g_source_remove(dcc->tagread);
|
||||
close(dcc->handle);
|
||||
|
||||
dcc->fastsend = settings_get_bool("toggle_dcc_fast_send");
|
||||
dcc->handle = handle;
|
||||
memcpy(&dcc->addr, &addr, sizeof(IPADDR));
|
||||
net_ip2host(&dcc->addr, dcc->addrstr);
|
||||
dcc->port = port;
|
||||
dcc->databufsize = settings_get_int("dcc_block_size") > 0 ? settings_get_int("dcc_block_size") : 2048;
|
||||
dcc->databuf = g_malloc(dcc->databufsize);
|
||||
dcc->starttime = time(NULL);
|
||||
dcc->tagread = g_input_add(handle, G_INPUT_READ,
|
||||
(GInputFunction) dcc_send_read_size, dcc);
|
||||
dcc->tagwrite = !dcc->fastsend ? -1 :
|
||||
g_input_add(handle, G_INPUT_WRITE, (GInputFunction) dcc_send_data, dcc);
|
||||
|
||||
signal_emit("dcc connected", 1, dcc);
|
||||
|
||||
if (!dcc->fastsend)
|
||||
{
|
||||
/* send first block */
|
||||
dcc->gotalldata = TRUE;
|
||||
dcc_send_data(dcc);
|
||||
}
|
||||
}
|
||||
|
||||
/* command: DCC SEND */
|
||||
static void cmd_dcc_send(gchar *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
gchar *params, *target, *fname, *str, *ptr;
|
||||
gint fh, h, port;
|
||||
glong fsize;
|
||||
DCC_REC *dcc, *chat;
|
||||
IPADDR addr;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &fname);
|
||||
|
||||
/* if we're in dcc chat, send the request via it. */
|
||||
chat = irc_item_dcc_chat(item);
|
||||
|
||||
if (chat != NULL && (chat->mirc_ctcp || g_strcasecmp(target, chat->nick) != 0))
|
||||
chat = NULL;
|
||||
|
||||
if ((server == NULL || !server->connected) && chat == NULL)
|
||||
cmd_param_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
if (*target == '\0' || *fname == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
if (dcc_find_item(DCC_TYPE_SEND, target, fname))
|
||||
{
|
||||
signal_emit("dcc error send exists", 2, target, fname);
|
||||
g_free(params);
|
||||
return;
|
||||
}
|
||||
|
||||
str = convert_home(fname);
|
||||
if (*str != '/')
|
||||
{
|
||||
gchar *path;
|
||||
|
||||
g_free(str);
|
||||
path = convert_home(settings_get_str("dcc_upload_path"));
|
||||
str = g_strconcat(path, "/", fname, NULL);
|
||||
g_free(path);
|
||||
}
|
||||
|
||||
fh = open(str, O_RDONLY);
|
||||
g_free(str);
|
||||
|
||||
if (fh == -1)
|
||||
{
|
||||
signal_emit("dcc error file not found", 2, target, fname);
|
||||
g_free(params);
|
||||
return;
|
||||
}
|
||||
fsize = lseek(fh, 0, SEEK_END);
|
||||
lseek(fh, 0, SEEK_SET);
|
||||
|
||||
/* get the IP address we use with IRC server */
|
||||
if (!net_getsockname(chat != NULL ? chat->handle : server->handle, &addr, NULL))
|
||||
{
|
||||
close(fh);
|
||||
cmd_param_error(CMDERR_GETSOCKNAME);
|
||||
}
|
||||
|
||||
/* start listening */
|
||||
port = settings_get_int("dcc_port");
|
||||
h = net_listen(&addr, &port);
|
||||
if (h == -1)
|
||||
{
|
||||
close(fh);
|
||||
cmd_param_error(CMDERR_LISTEN);
|
||||
}
|
||||
|
||||
/* skip path */
|
||||
ptr = strrchr(fname, '/');
|
||||
if (ptr != NULL) fname = ptr+1;
|
||||
|
||||
/* change all spaces to _ */
|
||||
fname = g_strdup(fname);
|
||||
for (ptr = fname; *ptr != '\0'; ptr++)
|
||||
if (*ptr == ' ') *ptr = '_';
|
||||
|
||||
dcc = dcc_create(DCC_TYPE_SEND, h, target, fname, server, chat);
|
||||
dcc->port = port;
|
||||
dcc->size = fsize;
|
||||
dcc->fhandle = fh;
|
||||
dcc->tagread = g_input_add(h, G_INPUT_READ,
|
||||
(GInputFunction) dcc_send_init, dcc);
|
||||
|
||||
/* send DCC request */
|
||||
str = g_strdup_printf("DCC SEND %s %s %d %lu",
|
||||
fname, dcc_make_address(&addr), port, fsize);
|
||||
dcc_ctcp_message(target, server, chat, FALSE, str);
|
||||
g_free(str);
|
||||
|
||||
g_free(fname);
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void read_settings(void)
|
||||
{
|
||||
dcc_file_create_mode = octal2dec(settings_get_int("dcc_file_create_mode"));
|
||||
}
|
||||
|
||||
void dcc_files_init(void)
|
||||
{
|
||||
signal_add("ctcp msg dcc", (SIGNAL_FUNC) dcc_ctcp_msg);
|
||||
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
|
||||
signal_add("irssi init finished", (SIGNAL_FUNC) read_settings);
|
||||
command_bind("dcc send", NULL, (SIGNAL_FUNC) cmd_dcc_send);
|
||||
command_bind("dcc get", NULL, (SIGNAL_FUNC) cmd_dcc_get);
|
||||
command_bind("dcc resume", NULL, (SIGNAL_FUNC) cmd_dcc_resume);
|
||||
}
|
||||
|
||||
void dcc_files_deinit(void)
|
||||
{
|
||||
signal_remove("ctcp msg dcc", (SIGNAL_FUNC) dcc_ctcp_msg);
|
||||
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
|
||||
signal_remove("irssi init finished", (SIGNAL_FUNC) read_settings);
|
||||
command_unbind("dcc send", (SIGNAL_FUNC) cmd_dcc_send);
|
||||
command_unbind("dcc get", (SIGNAL_FUNC) cmd_dcc_get);
|
||||
command_unbind("dcc resume", (SIGNAL_FUNC) cmd_dcc_resume);
|
||||
}
|
||||
7
src/irc/dcc/dcc-files.h
Normal file
7
src/irc/dcc/dcc-files.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef __DCC_FILES_H
|
||||
#define __DCC_FILES_H
|
||||
|
||||
void dcc_files_init(void);
|
||||
void dcc_files_deinit(void);
|
||||
|
||||
#endif
|
||||
550
src/irc/dcc/dcc.c
Normal file
550
src/irc/dcc/dcc.c
Normal file
|
|
@ -0,0 +1,550 @@
|
|||
/*
|
||||
dcc.c : irssi
|
||||
|
||||
Copyright (C) 1999 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
#include "commands.h"
|
||||
#include "network.h"
|
||||
#include "line-split.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include "masks.h"
|
||||
#include "irc.h"
|
||||
|
||||
#include "dcc.h"
|
||||
|
||||
#define DCC_TYPES 5
|
||||
|
||||
static gchar *dcc_types[] =
|
||||
{
|
||||
"CHAT",
|
||||
"SEND",
|
||||
"GET",
|
||||
"RESUME",
|
||||
"ACCEPT"
|
||||
};
|
||||
|
||||
GSList *dcc_conns;
|
||||
|
||||
static gint dcc_timeouttag;
|
||||
|
||||
/* Create new DCC record */
|
||||
DCC_REC *dcc_create(gint type, gint handle, gchar *nick, gchar *arg, IRC_SERVER_REC *server, DCC_REC *chat)
|
||||
{
|
||||
DCC_REC *dcc;
|
||||
|
||||
g_return_val_if_fail(nick != NULL, NULL);
|
||||
g_return_val_if_fail(arg != NULL, NULL);
|
||||
|
||||
dcc = g_new0(DCC_REC, 1);
|
||||
dcc->type = type == DCC_TYPE_CHAT ? module_get_uniq_id("IRC", WI_IRC_DCC_CHAT) : -1;
|
||||
dcc->mirc_ctcp = settings_get_bool("toggle_dcc_mirc_ctcp");
|
||||
dcc->created = time(NULL);
|
||||
dcc->chat = chat;
|
||||
dcc->dcc_type = type;
|
||||
dcc->arg = g_strdup(arg);
|
||||
dcc->nick = g_strdup(nick);
|
||||
dcc->handle = handle;
|
||||
dcc->fhandle = -1;
|
||||
dcc->tagread = dcc->tagwrite = -1;
|
||||
dcc->server = server;
|
||||
dcc->mynick = g_strdup(server != NULL ? server->nick :
|
||||
chat != NULL ? chat->nick : "??");
|
||||
dcc->ircnet = server == NULL ?
|
||||
chat == NULL || chat->ircnet == NULL ? NULL : g_strdup(chat->ircnet) :
|
||||
server->connrec->ircnet == NULL ? NULL : g_strdup(server->connrec->ircnet);
|
||||
dcc_conns = g_slist_append(dcc_conns, dcc);
|
||||
|
||||
signal_emit("dcc created", 1, dcc);
|
||||
return dcc;
|
||||
}
|
||||
|
||||
/* Destroy DCC record */
|
||||
void dcc_destroy(DCC_REC *dcc)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
g_return_if_fail(dcc != NULL);
|
||||
|
||||
dcc_conns = g_slist_remove(dcc_conns, dcc);
|
||||
|
||||
/* remove dcc chat references.. */
|
||||
for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next)
|
||||
{
|
||||
DCC_REC *rec = tmp->data;
|
||||
|
||||
if (rec->chat == dcc)
|
||||
rec->chat = NULL;
|
||||
}
|
||||
|
||||
signal_emit("dcc destroyed", 1, dcc);
|
||||
|
||||
if (dcc->fhandle != -1) close(dcc->fhandle);
|
||||
if (dcc->handle != -1) net_disconnect(dcc->handle);
|
||||
if (dcc->tagread != -1) g_source_remove(dcc->tagread);
|
||||
if (dcc->tagwrite != -1) g_source_remove(dcc->tagwrite);
|
||||
|
||||
if (dcc->dcc_type == DCC_TYPE_CHAT)
|
||||
line_split_free((LINEBUF_REC *) dcc->databuf);
|
||||
else if (dcc->databuf != NULL) g_free(dcc->databuf);
|
||||
if (dcc->file != NULL) g_free(dcc->file);
|
||||
if (dcc->ircnet != NULL) g_free(dcc->ircnet);
|
||||
g_free(dcc->mynick);
|
||||
g_free(dcc->nick);
|
||||
g_free(dcc->arg);
|
||||
g_free(dcc);
|
||||
}
|
||||
|
||||
gchar *dcc_make_address(IPADDR *ip)
|
||||
{
|
||||
static gchar str[MAX_IP_LEN];
|
||||
gulong addr;
|
||||
|
||||
if (is_ipv6_addr(ip))
|
||||
{
|
||||
/* IPv6 */
|
||||
net_ip2host(ip, str);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(&addr, &ip->addr, 4);
|
||||
sprintf(str, "%lu", (unsigned long) htonl(addr));
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/* Find DCC record, arg can be NULL */
|
||||
DCC_REC *dcc_find_item(gint type, gchar *nick, gchar *arg)
|
||||
{
|
||||
DCC_REC *dcc;
|
||||
GSList *tmp;
|
||||
|
||||
g_return_val_if_fail(nick != NULL, NULL);
|
||||
|
||||
for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next)
|
||||
{
|
||||
dcc = tmp->data;
|
||||
|
||||
if (dcc->dcc_type == type && g_strcasecmp(dcc->nick, nick) == 0 &&
|
||||
(arg == NULL || strcmp(dcc->arg, arg) == 0))
|
||||
return dcc;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find DCC record by port # */
|
||||
DCC_REC *dcc_find_by_port(gchar *nick, gint port)
|
||||
{
|
||||
DCC_REC *dcc;
|
||||
GSList *tmp;
|
||||
|
||||
for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next)
|
||||
{
|
||||
dcc = tmp->data;
|
||||
|
||||
if (dcc->port == port && ((dcc->dcc_type == DCC_TYPE_GET || dcc->dcc_type == DCC_TYPE_SEND) && g_strcasecmp(dcc->nick, nick) == 0))
|
||||
{
|
||||
/* found! */
|
||||
return dcc;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gchar *dcc_type2str(gint type)
|
||||
{
|
||||
g_return_val_if_fail(type >= 1 && type <= DCC_TYPES, NULL);
|
||||
return dcc_types[type-1];
|
||||
}
|
||||
|
||||
gint dcc_str2type(gchar *type)
|
||||
{
|
||||
gint num;
|
||||
|
||||
for (num = 0; num < DCC_TYPES; num++)
|
||||
if (g_strcasecmp(dcc_types[num], type) == 0) return num+1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dcc_ctcp_message(gchar *target, IRC_SERVER_REC *server, DCC_REC *chat, gboolean notice, gchar *msg)
|
||||
{
|
||||
gchar *str;
|
||||
|
||||
if (chat != NULL)
|
||||
{
|
||||
/* send it via open DCC chat */
|
||||
/* FIXME: we need output queue! */
|
||||
str = g_strdup_printf("%s\001%s\001\n", chat->mirc_ctcp ? "" :
|
||||
notice ? "CTCP_REPLY " : "CTCP_MESSAGE ", msg);
|
||||
net_transmit(chat->handle, str, strlen(str));
|
||||
}
|
||||
else
|
||||
{
|
||||
str = g_strdup_printf("%s %s :\001%s\001",
|
||||
notice ? "NOTICE" : "PRIVMSG", target, msg);
|
||||
irc_send_cmd(server, str);
|
||||
}
|
||||
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
/* Server connected, check if there's any open dcc sessions for this ircnet.. */
|
||||
static void dcc_server_connected(IRC_SERVER_REC *server)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
if (server->connrec->ircnet == NULL)
|
||||
return;
|
||||
|
||||
for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next) {
|
||||
DCC_REC *dcc = tmp->data;
|
||||
|
||||
if (dcc->server == NULL && dcc->ircnet != NULL &&
|
||||
g_strcasecmp(dcc->ircnet, server->connrec->ircnet) == 0) {
|
||||
dcc->server = server;
|
||||
g_free(dcc->mynick);
|
||||
dcc->mynick = g_strdup(server->nick);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Server disconnected, remove it from all dcc records */
|
||||
static void dcc_server_disconnected(IRC_SERVER_REC *server)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next)
|
||||
{
|
||||
DCC_REC *dcc = tmp->data;
|
||||
|
||||
if (dcc->server == server)
|
||||
{
|
||||
if (dcc->ircnet == NULL)
|
||||
dcc->server = NULL;
|
||||
else
|
||||
{
|
||||
dcc->server = (IRC_SERVER_REC *) server_find_ircnet(dcc->ircnet);
|
||||
if (dcc->server != NULL)
|
||||
{
|
||||
g_free(dcc->mynick);
|
||||
dcc->mynick = g_strdup(dcc->server->nick);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dcc_get_address(gchar *str, IPADDR *ip)
|
||||
{
|
||||
gulong addr;
|
||||
|
||||
if (strchr(str, ':') == NULL)
|
||||
{
|
||||
/* normal IPv4 address */
|
||||
if (sscanf(str, "%lu", &addr)!=1)
|
||||
addr = 0;
|
||||
ip->family = AF_INET;
|
||||
addr = (gulong) ntohl(addr);
|
||||
memcpy(&ip->addr, &addr, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* IPv6 */
|
||||
net_host2ip(str, ip);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle incoming DCC CTCP messages */
|
||||
static void dcc_ctcp_msg(gchar *data, IRC_SERVER_REC *server, gchar *sender, gchar *sendaddr, gchar *target, DCC_REC *chat)
|
||||
{
|
||||
gchar *params, *type, *arg, *addrstr, *portstr, *sizestr, *str;
|
||||
const char *cstr;
|
||||
DCC_REC *dcc;
|
||||
gulong size;
|
||||
gint port;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
g_return_if_fail(sender != NULL);
|
||||
|
||||
params = cmd_get_params(data, 5, &type, &arg, &addrstr, &portstr, &sizestr);
|
||||
|
||||
if (sscanf(portstr, "%d", &port) != 1) port = 0;
|
||||
if (sscanf(sizestr, "%lu", &size) != 1) size = 0;
|
||||
|
||||
dcc = dcc_create(SWAP_SENDGET(dcc_str2type(type)), -1, sender, arg, server, chat);
|
||||
dcc_get_address(addrstr, &dcc->addr);
|
||||
net_ip2host(&dcc->addr, dcc->addrstr);
|
||||
dcc->port = port;
|
||||
dcc->size = size;
|
||||
|
||||
switch (dcc->dcc_type)
|
||||
{
|
||||
case DCC_TYPE_GET:
|
||||
cstr = settings_get_str("dcc_autoget_masks");
|
||||
/* check that autoget masks match */
|
||||
if (settings_get_bool("toggle_dcc_autoget") && (*cstr == '\0' || irc_masks_match(cstr, sender, sendaddr)) &&
|
||||
/* check file size limit, FIXME: it's possible to send a bogus file size and then just send what ever sized file.. */
|
||||
(settings_get_int("dcc_max_autoget_size") <= 0 || (settings_get_int("dcc_max_autoget_size") > 0 && size <= settings_get_int("dcc_max_autoget_size")*1024)))
|
||||
{
|
||||
/* automatically get */
|
||||
str = g_strdup_printf("GET %s %s", dcc->nick, dcc->arg);
|
||||
signal_emit("command dcc", 2, str, server);
|
||||
g_free(str);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* send request */
|
||||
signal_emit("dcc request", 1, dcc);
|
||||
}
|
||||
break;
|
||||
|
||||
case DCC_TYPE_CHAT:
|
||||
cstr = settings_get_str("dcc_autochat_masks");
|
||||
if (*cstr != '\0' && irc_masks_match(cstr, sender, sendaddr))
|
||||
{
|
||||
/* automatically accept chat */
|
||||
str = g_strdup_printf("CHAT %s", dcc->nick);
|
||||
signal_emit("command dcc", 2, str, server);
|
||||
g_free(str);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* send request */
|
||||
signal_emit("dcc request", 1, dcc);
|
||||
}
|
||||
break;
|
||||
|
||||
case DCC_TYPE_RESUME:
|
||||
case DCC_TYPE_ACCEPT:
|
||||
/* handle this in dcc-files.c */
|
||||
dcc_destroy(dcc);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* unknown DCC command */
|
||||
signal_emit("dcc unknown ctcp", 3, data, sender, sendaddr);
|
||||
dcc_destroy(dcc);
|
||||
break;
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
/* Handle incoming DCC CTCP replies */
|
||||
static void dcc_ctcp_reply(gchar *data, IRC_SERVER_REC *server, gchar *sender, gchar *sendaddr)
|
||||
{
|
||||
gchar *params, *cmd, *subcmd, *args;
|
||||
gint type;
|
||||
DCC_REC *dcc;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
g_return_if_fail(sender != NULL);
|
||||
|
||||
params = cmd_get_params(data, 3 | PARAM_FLAG_GETREST, &cmd, &subcmd, &args);
|
||||
|
||||
if (g_strcasecmp(cmd, "REJECT") == 0)
|
||||
{
|
||||
type = dcc_str2type(subcmd);
|
||||
dcc = dcc_find_item(type, sender, type == DCC_TYPE_CHAT ? NULL : args);
|
||||
if (dcc != NULL)
|
||||
{
|
||||
dcc->destroyed = TRUE;
|
||||
signal_emit("dcc closed", 1, dcc);
|
||||
dcc_destroy(dcc);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unknown dcc ctcp reply */
|
||||
signal_emit("dcc unknown reply", 3, data, sender, sendaddr);
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void dcc_reject(DCC_REC *dcc, IRC_SERVER_REC *server)
|
||||
{
|
||||
gchar *str;
|
||||
|
||||
g_return_if_fail(dcc != NULL);
|
||||
|
||||
if (dcc->server != NULL) server = dcc->server;
|
||||
if (server != NULL && (dcc->dcc_type != DCC_TYPE_CHAT || dcc->starttime == 0))
|
||||
{
|
||||
signal_emit("dcc rejected", 1, dcc);
|
||||
str = g_strdup_printf("NOTICE %s :\001DCC REJECT %s %s\001",
|
||||
dcc->nick, dcc_type2str(SWAP_SENDGET(dcc->dcc_type)), dcc->arg);
|
||||
|
||||
irc_send_cmd(server, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
dcc->destroyed = TRUE;
|
||||
signal_emit("dcc closed", 1, dcc);
|
||||
dcc_destroy(dcc);
|
||||
}
|
||||
|
||||
/* command: DCC CLOSE */
|
||||
static void cmd_dcc_close(gchar *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
DCC_REC *dcc;
|
||||
GSList *tmp, *next;
|
||||
gchar *params, *type, *nick, *arg;
|
||||
gboolean found;
|
||||
gint itype;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = cmd_get_params(data, 3, &type, &nick, &arg);
|
||||
|
||||
g_strup(type);
|
||||
itype = dcc_str2type(type);
|
||||
if (itype == 0)
|
||||
{
|
||||
signal_emit("dcc error unknown type", 1, type);
|
||||
g_free(params);
|
||||
return;
|
||||
}
|
||||
|
||||
dcc = NULL; found = FALSE;
|
||||
for (tmp = dcc_conns; tmp != NULL; tmp = next)
|
||||
{
|
||||
dcc = tmp->data;
|
||||
next = tmp->next;
|
||||
|
||||
if (dcc->dcc_type == itype && g_strcasecmp(nick, dcc->nick) == 0)
|
||||
{
|
||||
dcc_reject(dcc, server);
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
signal_emit("dcc error close not found", 3, type, nick, arg);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void cmd_dcc(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
|
||||
{
|
||||
command_runsub("dcc", data, server, item);
|
||||
}
|
||||
|
||||
static int dcc_timeout_func(void)
|
||||
{
|
||||
GSList *tmp, *next;
|
||||
time_t now;
|
||||
|
||||
now = time(NULL)-settings_get_int("dcc_timeout");
|
||||
for (tmp = dcc_conns; tmp != NULL; tmp = next)
|
||||
{
|
||||
DCC_REC *rec = tmp->data;
|
||||
|
||||
next = tmp->next;
|
||||
if (rec->tagread == -1 && now > rec->created)
|
||||
{
|
||||
/* timed out. */
|
||||
dcc_reject(rec, NULL);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void event_no_such_nick(gchar *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
gchar *params, *nick;
|
||||
GSList *tmp, *next;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 2, NULL, &nick);
|
||||
|
||||
/* check if we've send any dcc requests to this nick.. */
|
||||
for (tmp = dcc_conns; tmp != NULL; tmp = next)
|
||||
{
|
||||
DCC_REC *rec = tmp->data;
|
||||
|
||||
next = tmp->next;
|
||||
if (g_strcasecmp(rec->nick, nick) == 0 && rec->starttime == 0)
|
||||
{
|
||||
/* timed out. */
|
||||
rec->destroyed = TRUE;
|
||||
signal_emit("dcc closed", 1, rec);
|
||||
dcc_destroy(rec);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
void dcc_init(void)
|
||||
{
|
||||
dcc_conns = NULL;
|
||||
dcc_timeouttag = g_timeout_add(1000, (GSourceFunc) dcc_timeout_func, NULL);
|
||||
|
||||
settings_add_bool("dcc", "toggle_dcc_autorename", FALSE);
|
||||
settings_add_bool("dcc", "toggle_dcc_autogete", FALSE);
|
||||
settings_add_int("dcc", "dcc_max_autoget_size", 1000);
|
||||
settings_add_str("dcc", "dcc_download_path", "~");
|
||||
settings_add_int("dcc", "dcc_file_create_mode", 644);
|
||||
settings_add_str("dcc", "dcc_autoget_masks", "");
|
||||
settings_add_str("dcc", "dcc_autochat_masks", "");
|
||||
|
||||
settings_add_bool("dcc", "toggle_dcc_fast_send", TRUE);
|
||||
settings_add_str("dcc", "dcc_upload_path", "~");
|
||||
|
||||
settings_add_bool("dcc", "toggle_dcc_mirc_ctcp", FALSE);
|
||||
settings_add_bool("dcc", "toggle_dcc_autodisplay_dialog", TRUE);
|
||||
settings_add_int("dcc", "dcc_block_size", 2048);
|
||||
settings_add_int("dcc", "dcc_port", 0);
|
||||
settings_add_int("dcc", "dcc_timeout", 300);
|
||||
|
||||
signal_add("server connected", (SIGNAL_FUNC) dcc_server_connected);
|
||||
signal_add("server disconnected", (SIGNAL_FUNC) dcc_server_disconnected);
|
||||
signal_add("ctcp reply dcc", (SIGNAL_FUNC) dcc_ctcp_reply);
|
||||
signal_add("ctcp msg dcc", (SIGNAL_FUNC) dcc_ctcp_msg);
|
||||
command_bind("dcc", NULL, (SIGNAL_FUNC) cmd_dcc);
|
||||
command_bind("dcc close", NULL, (SIGNAL_FUNC) cmd_dcc_close);
|
||||
signal_add("event 401", (SIGNAL_FUNC) event_no_such_nick);
|
||||
}
|
||||
|
||||
void dcc_deinit(void)
|
||||
{
|
||||
signal_remove("server connected", (SIGNAL_FUNC) dcc_server_connected);
|
||||
signal_remove("server disconnected", (SIGNAL_FUNC) dcc_server_disconnected);
|
||||
signal_remove("ctcp reply dcc", (SIGNAL_FUNC) dcc_ctcp_reply);
|
||||
signal_remove("ctcp msg dcc", (SIGNAL_FUNC) dcc_ctcp_msg);
|
||||
command_unbind("dcc", (SIGNAL_FUNC) cmd_dcc);
|
||||
command_unbind("dcc close", (SIGNAL_FUNC) cmd_dcc_close);
|
||||
signal_remove("event 401", (SIGNAL_FUNC) event_no_such_nick);
|
||||
|
||||
g_source_remove(dcc_timeouttag);
|
||||
|
||||
while (dcc_conns != NULL)
|
||||
dcc_destroy(dcc_conns->data);
|
||||
}
|
||||
91
src/irc/dcc/dcc.h
Normal file
91
src/irc/dcc/dcc.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#ifndef __DCC_H
|
||||
#define __DCC_H
|
||||
|
||||
#include "network.h"
|
||||
|
||||
enum
|
||||
{
|
||||
DCC_TYPE_CHAT = 1,
|
||||
DCC_TYPE_SEND,
|
||||
DCC_TYPE_GET,
|
||||
DCC_TYPE_RESUME,
|
||||
DCC_TYPE_ACCEPT
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DCC_GET_DEFAULT = 0,
|
||||
DCC_GET_OVERWRITE,
|
||||
DCC_GET_RENAME,
|
||||
DCC_GET_RESUME
|
||||
};
|
||||
|
||||
#define SWAP_SENDGET(a) ((a) == DCC_TYPE_SEND ? DCC_TYPE_GET : \
|
||||
(a) == DCC_TYPE_GET ? DCC_TYPE_SEND : (a))
|
||||
|
||||
typedef struct DCC_REC
|
||||
{
|
||||
int type;
|
||||
GHashTable *module_data;
|
||||
|
||||
IRC_SERVER_REC *server;
|
||||
gchar *nick;
|
||||
|
||||
struct DCC_REC *chat; /* if the request came through DCC chat */
|
||||
|
||||
gchar *ircnet;
|
||||
gchar *mynick;
|
||||
|
||||
gchar *arg;
|
||||
gchar *file; /* file name we're really moving, arg is just the reference.. */
|
||||
|
||||
time_t created;
|
||||
gint dcc_type;
|
||||
|
||||
IPADDR addr; /* address we're connected in */
|
||||
gchar addrstr[MAX_IP_LEN]; /* in readable form */
|
||||
gint port; /* port we're connected in */
|
||||
|
||||
glong size, transfd, skipped; /* file size / bytes transferred / skipped at start */
|
||||
gint handle; /* socket handle */
|
||||
gint tagread, tagwrite;
|
||||
gint fhandle; /* file handle */
|
||||
time_t starttime; /* transfer start time */
|
||||
gint trans_bytes;
|
||||
|
||||
gboolean fastsend; /* fastsending (just in case that global fastsend toggle changes while transferring..) */
|
||||
gboolean waitforend; /* DCC fast send: file is sent, just wait for the replies from the other side */
|
||||
gboolean gotalldata; /* DCC fast send: got all acks from the other end (needed to make sure the end of transfer works right) */
|
||||
gint get_type; /* DCC get: what to do if file exists? */
|
||||
|
||||
gboolean mirc_ctcp; /* DCC chat: Send CTCPs without the CTCP_MESSAGE prefix */
|
||||
gboolean destroyed; /* We're about to destroy this DCC recond */
|
||||
|
||||
/* read counter buffer */
|
||||
gchar read_buf[4];
|
||||
gint read_pos;
|
||||
|
||||
gchar *databuf; /* buffer for receiving/transmitting data */
|
||||
gint databufsize;
|
||||
}
|
||||
DCC_REC;
|
||||
|
||||
extern GSList *dcc_conns;
|
||||
|
||||
void dcc_init(void);
|
||||
void dcc_deinit(void);
|
||||
|
||||
/* Find DCC record, arg can be NULL */
|
||||
DCC_REC *dcc_find_item(gint type, gchar *nick, gchar *arg);
|
||||
DCC_REC *dcc_find_by_port(gchar *nick, gint port);
|
||||
|
||||
gchar *dcc_type2str(gint type);
|
||||
gint dcc_str2type(gchar *type);
|
||||
gchar *dcc_make_address(IPADDR *ip);
|
||||
|
||||
DCC_REC *dcc_create(gint type, gint handle, gchar *nick, gchar *arg, IRC_SERVER_REC *server, DCC_REC *chat);
|
||||
void dcc_destroy(DCC_REC *dcc);
|
||||
|
||||
void dcc_ctcp_message(gchar *target, IRC_SERVER_REC *server, DCC_REC *chat, gboolean notice, gchar *msg);
|
||||
|
||||
#endif
|
||||
3
src/irc/dcc/module.h
Normal file
3
src/irc/dcc/module.h
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#include "common.h"
|
||||
|
||||
#define MODULE_NAME "irc/dcc"
|
||||
12
src/irc/flood/Makefile.am
Normal file
12
src/irc/flood/Makefile.am
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
noinst_LTLIBRARIES = libirc_flood.la
|
||||
|
||||
INCLUDES = $(GLIB_CFLAGS) \
|
||||
-I$(top_srcdir)/src -I$(top_srcdir)/src/core/ -I$(top_srcdir)/src/irc/core/
|
||||
|
||||
libirc_flood_la_SOURCES = \
|
||||
autoignore.c \
|
||||
flood.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
autoignore.h \
|
||||
flood.h
|
||||
250
src/irc/flood/autoignore.c
Normal file
250
src/irc/flood/autoignore.c
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
autoignore.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "modules.h"
|
||||
#include "signals.h"
|
||||
#include "commands.h"
|
||||
#include "levels.h"
|
||||
#include "misc.h"
|
||||
#include "settings.h"
|
||||
#include "common-setup.h"
|
||||
|
||||
#include "irc-server.h"
|
||||
#include "ignore.h"
|
||||
|
||||
#include "autoignore.h"
|
||||
|
||||
static int ignore_tag;
|
||||
|
||||
GSList *server_autoignores(IRC_SERVER_REC *server)
|
||||
{
|
||||
MODULE_SERVER_REC *rec;
|
||||
|
||||
g_return_val_if_fail(server != NULL, NULL);
|
||||
|
||||
rec = MODULE_DATA(server);
|
||||
return rec->ignorelist;
|
||||
}
|
||||
|
||||
static void autoignore_remove_rec(IRC_SERVER_REC *server, AUTOIGNORE_REC *rec)
|
||||
{
|
||||
MODULE_SERVER_REC *mserver;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
g_return_if_fail(rec != NULL);
|
||||
|
||||
signal_emit("autoignore remove", 2, server, rec);
|
||||
|
||||
g_free(rec->nick);
|
||||
g_free(rec);
|
||||
|
||||
mserver = MODULE_DATA(server);
|
||||
mserver->ignorelist = g_slist_remove(mserver->ignorelist, rec);
|
||||
}
|
||||
|
||||
static AUTOIGNORE_REC *autoignore_find(IRC_SERVER_REC *server, const char *mask)
|
||||
{
|
||||
MODULE_SERVER_REC *mserver;
|
||||
GSList *tmp;
|
||||
|
||||
g_return_val_if_fail(server != NULL, NULL);
|
||||
g_return_val_if_fail(mask != NULL, NULL);
|
||||
|
||||
mserver = MODULE_DATA(server);
|
||||
for (tmp = mserver->ignorelist; tmp != NULL; tmp = tmp->next) {
|
||||
AUTOIGNORE_REC *rec = tmp->data;
|
||||
|
||||
if (g_strcasecmp(rec->nick, mask) == 0)
|
||||
return rec;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* timeout function: unignore old ignores.. */
|
||||
static void autoignore_timeout_server(IRC_SERVER_REC *server)
|
||||
{
|
||||
MODULE_SERVER_REC *mserver;
|
||||
GSList *tmp, *next;
|
||||
time_t t;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
mserver = MODULE_DATA(server);
|
||||
t = time(NULL);
|
||||
t -= mserver->ignore_lastcheck;
|
||||
|
||||
for (tmp = mserver->ignorelist; tmp != NULL; tmp = next) {
|
||||
AUTOIGNORE_REC *rec = tmp->data;
|
||||
|
||||
next = tmp->next;
|
||||
if (rec->timeleft > t)
|
||||
rec->timeleft -= t;
|
||||
else
|
||||
autoignore_remove_rec(server, rec);
|
||||
}
|
||||
|
||||
mserver->ignore_lastcheck = time(NULL);
|
||||
}
|
||||
|
||||
static int autoignore_timeout(void)
|
||||
{
|
||||
g_slist_foreach(servers, (GFunc) autoignore_timeout_server, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void autoignore_init_server(IRC_SERVER_REC *server)
|
||||
{
|
||||
MODULE_SERVER_REC *mserver;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
mserver = MODULE_DATA(server);
|
||||
mserver->ignorelist = NULL;
|
||||
mserver->ignore_lastcheck = time(NULL)-AUTOIGNORE_TIMECHECK;
|
||||
}
|
||||
|
||||
static void autoignore_deinit_server(IRC_SERVER_REC *server)
|
||||
{
|
||||
MODULE_SERVER_REC *mserver;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
mserver = MODULE_DATA(server);
|
||||
while (mserver->ignorelist != NULL)
|
||||
autoignore_remove_rec(server, (AUTOIGNORE_REC *) mserver->ignorelist->data);
|
||||
}
|
||||
|
||||
IGNORE_REC *ignore_find_server(IRC_SERVER_REC *server, const char *mask)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
for (tmp = ignores; tmp != NULL; tmp = tmp->next) {
|
||||
IGNORE_REC *rec = tmp->data;
|
||||
|
||||
if (rec->servertag != NULL &&
|
||||
g_strcasecmp(rec->mask, mask) == 0 &&
|
||||
g_strcasecmp(rec->servertag, server->tag) == 0)
|
||||
return rec;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void autoignore_add(IRC_SERVER_REC *server, const char *nick, int level)
|
||||
{
|
||||
MODULE_SERVER_REC *mserver;
|
||||
AUTOIGNORE_REC *rec;
|
||||
IGNORE_REC *irec;
|
||||
int igtime;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
g_return_if_fail(nick != NULL);
|
||||
if (level == 0) return;
|
||||
|
||||
igtime = settings_get_int("autoignore_time");
|
||||
if (igtime <= 0) return;
|
||||
|
||||
irec = ignore_find_server(server, nick);
|
||||
if (irec == NULL) {
|
||||
irec = g_new0(IGNORE_REC, 1);
|
||||
irec->servertag = g_strdup(server->tag);
|
||||
irec->mask = g_strdup(nick);
|
||||
irec->level = level;
|
||||
ignore_add_rec(irec);
|
||||
} else {
|
||||
irec->level |= level;
|
||||
ignore_update_rec(irec);
|
||||
}
|
||||
|
||||
rec = autoignore_find(server, nick);
|
||||
if (rec != NULL) {
|
||||
/* already being ignored */
|
||||
rec->timeleft = igtime;
|
||||
return;
|
||||
}
|
||||
|
||||
rec = g_new(AUTOIGNORE_REC, 1);
|
||||
rec->nick = g_strdup(nick);
|
||||
rec->timeleft = igtime;
|
||||
rec->level = level;
|
||||
|
||||
mserver = MODULE_DATA(server);
|
||||
mserver->ignorelist = g_slist_append(mserver->ignorelist, rec);
|
||||
|
||||
signal_emit("autoignore new", 2, server, rec);
|
||||
}
|
||||
|
||||
int autoignore_remove(IRC_SERVER_REC *server, const char *mask, int level)
|
||||
{
|
||||
AUTOIGNORE_REC *rec;
|
||||
IGNORE_REC *irec;
|
||||
|
||||
g_return_val_if_fail(server != NULL, FALSE);
|
||||
g_return_val_if_fail(mask != NULL, FALSE);
|
||||
|
||||
irec = ignore_find_server(server, mask);
|
||||
if (irec != NULL) {
|
||||
irec->level &= ~level;
|
||||
ignore_update_rec(irec);
|
||||
}
|
||||
|
||||
rec = autoignore_find(server, mask);
|
||||
if (rec != NULL && (level & rec->level)) {
|
||||
rec->level &= ~level;
|
||||
if (rec->level == 0) autoignore_remove_rec(server, rec);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void sig_flood(IRC_SERVER_REC *server, const char *nick, const char *host, const char *levelstr)
|
||||
{
|
||||
int level, check_level;
|
||||
|
||||
level = level2bits(levelstr);
|
||||
check_level = level2bits(settings_get_str("autoignore_levels"));
|
||||
|
||||
if (level & check_level)
|
||||
autoignore_add(server, nick, level);
|
||||
}
|
||||
|
||||
void autoignore_init(void)
|
||||
{
|
||||
settings_add_int("flood", "autoignore_time", 300);
|
||||
settings_add_str("flood", "autoignore_levels", "ctcps");
|
||||
|
||||
ignore_tag = g_timeout_add(AUTOIGNORE_TIMECHECK, (GSourceFunc) autoignore_timeout, NULL);
|
||||
|
||||
signal_add("server connected", (SIGNAL_FUNC) autoignore_init_server);
|
||||
signal_add("server disconnected", (SIGNAL_FUNC) autoignore_deinit_server);
|
||||
signal_add("flood", (SIGNAL_FUNC) sig_flood);
|
||||
}
|
||||
|
||||
void autoignore_deinit(void)
|
||||
{
|
||||
g_source_remove(ignore_tag);
|
||||
|
||||
signal_remove("server connected", (SIGNAL_FUNC) autoignore_init_server);
|
||||
signal_remove("server disconnected", (SIGNAL_FUNC) autoignore_deinit_server);
|
||||
signal_remove("flood", (SIGNAL_FUNC) sig_flood);
|
||||
}
|
||||
18
src/irc/flood/autoignore.h
Normal file
18
src/irc/flood/autoignore.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef __AUTOIGNORE_H
|
||||
#define __AUTOIGNORE_H
|
||||
|
||||
typedef struct {
|
||||
char *nick;
|
||||
int timeleft;
|
||||
int level;
|
||||
} AUTOIGNORE_REC;
|
||||
|
||||
GSList *server_autoignores(IRC_SERVER_REC *server);
|
||||
|
||||
void autoignore_add(IRC_SERVER_REC *server, const char *nick, int level);
|
||||
int autoignore_remove(IRC_SERVER_REC *server, const char *mask, int level);
|
||||
|
||||
void autoignore_init(void);
|
||||
void autoignore_deinit(void);
|
||||
|
||||
#endif
|
||||
212
src/irc/flood/flood.c
Normal file
212
src/irc/flood/flood.c
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
|
||||
flood.c : Flood protection (see also ctcp.c)
|
||||
|
||||
Copyright (C) 1999 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "modules.h"
|
||||
#include "signals.h"
|
||||
#include "levels.h"
|
||||
#include "misc.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include "irc.h"
|
||||
#include "irc-server.h"
|
||||
#include "autoignore.h"
|
||||
#include "ignore.h"
|
||||
|
||||
typedef struct {
|
||||
char *nick;
|
||||
int level;
|
||||
int msgcount;
|
||||
} FLOOD_REC;
|
||||
|
||||
static int flood_tag;
|
||||
static int flood_max_msgs;
|
||||
|
||||
static int flood_hash_deinit(const char *key, FLOOD_REC *rec)
|
||||
{
|
||||
g_return_val_if_fail(key != NULL, FALSE);
|
||||
g_return_val_if_fail(rec != NULL, FALSE);
|
||||
|
||||
g_free(rec->nick);
|
||||
g_free(rec);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* timeout function: flood protection */
|
||||
static int flood_timeout(void)
|
||||
{
|
||||
MODULE_SERVER_REC *mserver;
|
||||
GSList *tmp;
|
||||
|
||||
/* remove everyone from flood list */
|
||||
for (tmp = servers; tmp != NULL; tmp = tmp->next) {
|
||||
IRC_SERVER_REC *rec = tmp->data;
|
||||
|
||||
mserver = MODULE_DATA(rec);
|
||||
g_hash_table_foreach_remove(mserver->floodlist, (GHRFunc) flood_hash_deinit, NULL);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initialize flood protection */
|
||||
static void flood_init_server(IRC_SERVER_REC *server)
|
||||
{
|
||||
MODULE_SERVER_REC *rec;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
rec = g_new0(MODULE_SERVER_REC, 1);
|
||||
MODULE_DATA_SET(server, rec);
|
||||
|
||||
rec->floodlist = g_hash_table_new((GHashFunc) g_istr_hash, (GCompareFunc) g_istr_equal);
|
||||
}
|
||||
|
||||
/* Deinitialize flood protection */
|
||||
static void flood_deinit_server(IRC_SERVER_REC *server)
|
||||
{
|
||||
MODULE_SERVER_REC *mserver;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
mserver = MODULE_DATA(server);
|
||||
if (mserver != NULL && mserver->floodlist != NULL) {
|
||||
g_hash_table_freeze(mserver->floodlist);
|
||||
g_hash_table_foreach(mserver->floodlist, (GHFunc) flood_hash_deinit, NULL);
|
||||
g_hash_table_thaw(mserver->floodlist);
|
||||
g_hash_table_destroy(mserver->floodlist);
|
||||
}
|
||||
g_free(mserver);
|
||||
}
|
||||
|
||||
/* All messages should go through here.. */
|
||||
static void flood_newmsg(IRC_SERVER_REC *server, int level, const char *nick, const char *host, const char *target)
|
||||
{
|
||||
MODULE_SERVER_REC *mserver;
|
||||
FLOOD_REC *rec;
|
||||
char *levelstr;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
g_return_if_fail(nick != NULL);
|
||||
|
||||
mserver = MODULE_DATA(server);
|
||||
rec = g_hash_table_lookup(mserver->floodlist, nick);
|
||||
if (rec != NULL) {
|
||||
if (++rec->msgcount > flood_max_msgs) {
|
||||
/* flooding! */
|
||||
levelstr = bits2level(rec->level);
|
||||
signal_emit("flood", 5, server, nick, host, levelstr, target);
|
||||
g_free(levelstr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
rec = g_new(FLOOD_REC, 1);
|
||||
rec->level = level;
|
||||
rec->msgcount = 1;
|
||||
rec->nick = g_strdup(nick);
|
||||
|
||||
g_hash_table_insert(mserver->floodlist, rec->nick, rec);
|
||||
}
|
||||
|
||||
static void flood_privmsg(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr)
|
||||
{
|
||||
int publiclevel;
|
||||
char *params, *target, *text;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
if (nick == NULL) {
|
||||
/* don't try to ignore server messages.. */
|
||||
return;
|
||||
}
|
||||
|
||||
params = event_get_params(data, 2, &target, &text);
|
||||
|
||||
if (*text == 1) {
|
||||
/* CTCP */
|
||||
if (!ignore_check(server, nick, addr, target, text, MSGLEVEL_CTCPS))
|
||||
flood_newmsg(server, MSGLEVEL_CTCPS, nick, addr, target);
|
||||
} else {
|
||||
publiclevel = ischannel(*target) ? MSGLEVEL_PUBLIC : MSGLEVEL_MSGS;
|
||||
|
||||
if (addr != NULL && !ignore_check(server, nick, addr, target, text, publiclevel))
|
||||
flood_newmsg(server, publiclevel, nick, addr, target);
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void flood_notice(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr)
|
||||
{
|
||||
char *params, *target, *text;
|
||||
|
||||
g_return_if_fail(text != NULL);
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
if (nick == NULL) {
|
||||
/* don't try to ignore server messages.. */
|
||||
return;
|
||||
}
|
||||
|
||||
params = event_get_params(data, 2, &target, &text);
|
||||
if (addr != NULL && !ignore_check(server, nick, addr, target, text, MSGLEVEL_NOTICES))
|
||||
flood_newmsg(server, MSGLEVEL_NOTICES | ischannel(*target) ? MSGLEVEL_PUBLIC : MSGLEVEL_MSGS, nick, addr, target);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void read_settings(void)
|
||||
{
|
||||
if (flood_tag != -1) g_source_remove(flood_tag);
|
||||
flood_tag = g_timeout_add(settings_get_int("flood_timecheck"), (GSourceFunc) flood_timeout, NULL);
|
||||
|
||||
flood_max_msgs = settings_get_int("flood_max_msgs");
|
||||
}
|
||||
|
||||
void flood_init(void)
|
||||
{
|
||||
settings_add_int("flood", "flood_timecheck", 1000);
|
||||
settings_add_int("flood", "flood_max_msgs", 5);
|
||||
|
||||
flood_tag = -1;
|
||||
read_settings();
|
||||
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
|
||||
signal_add_first("server connected", (SIGNAL_FUNC) flood_init_server);
|
||||
signal_add("server disconnected", (SIGNAL_FUNC) flood_deinit_server);
|
||||
signal_add("event privmsg", (SIGNAL_FUNC) flood_privmsg);
|
||||
signal_add("event notice", (SIGNAL_FUNC) flood_notice);
|
||||
|
||||
autoignore_init();
|
||||
}
|
||||
|
||||
void flood_deinit(void)
|
||||
{
|
||||
autoignore_deinit();
|
||||
|
||||
if (flood_tag != -1) g_source_remove(flood_tag);
|
||||
|
||||
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
|
||||
signal_remove("server connected", (SIGNAL_FUNC) flood_init_server);
|
||||
signal_remove("server disconnected", (SIGNAL_FUNC) flood_deinit_server);
|
||||
signal_remove("event privmsg", (SIGNAL_FUNC) flood_privmsg);
|
||||
signal_remove("event notice", (SIGNAL_FUNC) flood_notice);
|
||||
}
|
||||
7
src/irc/flood/flood.h
Normal file
7
src/irc/flood/flood.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef __FLOOD_H
|
||||
#define __FLOOD_H
|
||||
|
||||
void flood_init(void);
|
||||
void flood_deinit(void);
|
||||
|
||||
#endif
|
||||
12
src/irc/flood/module.h
Normal file
12
src/irc/flood/module.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#include "common.h"
|
||||
|
||||
typedef struct {
|
||||
/* Flood protection */
|
||||
GHashTable *floodlist;
|
||||
|
||||
/* Auto ignore list */
|
||||
GSList *ignorelist;
|
||||
time_t ignore_lastcheck;
|
||||
} MODULE_SERVER_REC;
|
||||
|
||||
#define MODULE_NAME "irc/flood"
|
||||
27
src/irc/irc.c
Normal file
27
src/irc/irc.c
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
void irc_core_init(void);
|
||||
void irc_core_deinit(void);
|
||||
|
||||
void dcc_init(void);
|
||||
void dcc_deinit(void);
|
||||
|
||||
void flood_init(void);
|
||||
void flood_deinit(void);
|
||||
|
||||
void notifylist_init(void);
|
||||
void notifylist_deinit(void);
|
||||
|
||||
void irc_init(void)
|
||||
{
|
||||
irc_core_init();
|
||||
dcc_init();
|
||||
flood_init();
|
||||
notifylist_init();
|
||||
}
|
||||
|
||||
void irc_deinit(void)
|
||||
{
|
||||
notifylist_deinit();
|
||||
flood_deinit();
|
||||
dcc_deinit();
|
||||
irc_core_deinit();
|
||||
}
|
||||
15
src/irc/notifylist/Makefile.am
Normal file
15
src/irc/notifylist/Makefile.am
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
noinst_LTLIBRARIES = libirc_notifylist.la
|
||||
|
||||
INCLUDES = $(GLIB_CFLAGS) \
|
||||
-I$(top_srcdir)/src -I$(top_srcdir)/src/core/ -I$(top_srcdir)/src/irc/core/
|
||||
|
||||
libirc_notifylist_la_SOURCES = \
|
||||
notifylist.c \
|
||||
notify-commands.c \
|
||||
notify-ison.c \
|
||||
notify-setup.c \
|
||||
notify-whois.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
notifylist.h \
|
||||
notify-setup.h
|
||||
44
src/irc/notifylist/module.h
Normal file
44
src/irc/notifylist/module.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#include "common.h"
|
||||
|
||||
#define MODULE_NAME "irc/notifylist"
|
||||
|
||||
#define ISON_EVENT "event 303"
|
||||
|
||||
typedef struct {
|
||||
char *nick;
|
||||
char *user, *host, *realname, *awaymsg;
|
||||
time_t idle_time;
|
||||
|
||||
int host_ok:1; /* host matches the one in notifylist = this is the right person*/
|
||||
int away_ok:1; /* not away, or we don't care about it */
|
||||
int idle_ok:1; /* idle time is low enough, or we don't care about it */
|
||||
|
||||
int away:1; /* nick is away */
|
||||
int join_announced:1; /* join to IRC has been announced */
|
||||
int idle_changed:1; /* idle time is lower than in last check */
|
||||
|
||||
time_t last_whois;
|
||||
} NOTIFY_NICK_REC;
|
||||
|
||||
typedef struct {
|
||||
GSList *notify_users; /* NOTIFY_NICK_REC's of notifylist people who are in IRC */
|
||||
GSList *ison_tempusers; /* Temporary list for saving /ISON events.. */
|
||||
} MODULE_SERVER_REC;
|
||||
|
||||
#include "irc-server.h"
|
||||
|
||||
NOTIFY_NICK_REC *notify_nick_create(IRC_SERVER_REC *server, const char *nick);
|
||||
void notify_nick_destroy(NOTIFY_NICK_REC *rec);
|
||||
NOTIFY_NICK_REC *notify_nick_find(IRC_SERVER_REC *server, const char *nick);
|
||||
|
||||
void notifylist_left(IRC_SERVER_REC *server, NOTIFY_NICK_REC *rec);
|
||||
void notifylist_destroy_all(void);
|
||||
|
||||
void notifylist_commands_init(void);
|
||||
void notifylist_commands_deinit(void);
|
||||
|
||||
void notifylist_whois_init(void);
|
||||
void notifylist_whois_deinit(void);
|
||||
|
||||
void notifylist_ison_init(void);
|
||||
void notifylist_ison_deinit(void);
|
||||
81
src/irc/notifylist/notify-commands.c
Normal file
81
src/irc/notifylist/notify-commands.c
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
notify-commands.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
#include "commands.h"
|
||||
#include "misc.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include "notifylist.h"
|
||||
|
||||
#define DEFAULT_NOTIFY_IDLE_TIME 60
|
||||
|
||||
static void cmd_notify(gchar *data)
|
||||
{
|
||||
char *params, *mask, *ircnets, *args, *idletime;
|
||||
int away_check, idle_check_time;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
args = "@idle";
|
||||
params = cmd_get_params(data, 4 | PARAM_FLAG_MULTIARGS | PARAM_FLAG_GETREST, &args, &idletime, &mask, &ircnets);
|
||||
if (*mask == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
if (stristr(args, "-idle") == NULL)
|
||||
idle_check_time = 0;
|
||||
else {
|
||||
idle_check_time = is_numeric(idletime, 0) ? (atol(idletime)*60) :
|
||||
(settings_get_int("notify_idle_time")*60);
|
||||
}
|
||||
|
||||
away_check = stristr(args, "-away") != NULL;
|
||||
notifylist_remove(mask);
|
||||
notifylist_add(mask, ircnets, away_check, idle_check_time);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void cmd_unnotify(const char *data)
|
||||
{
|
||||
char *params, *mask;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = cmd_get_params(data, 1, &mask);
|
||||
if (*mask == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
notifylist_remove(mask);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
void notifylist_commands_init(void)
|
||||
{
|
||||
settings_add_int("misc", "notify_idle_time", DEFAULT_NOTIFY_IDLE_TIME);
|
||||
command_bind("notify", NULL, (SIGNAL_FUNC) cmd_notify);
|
||||
command_bind("unnotify", NULL, (SIGNAL_FUNC) cmd_unnotify);
|
||||
}
|
||||
|
||||
void notifylist_commands_deinit(void)
|
||||
{
|
||||
command_unbind("notify", (SIGNAL_FUNC) cmd_notify);
|
||||
command_unbind("unnotify", (SIGNAL_FUNC) cmd_unnotify);
|
||||
}
|
||||
354
src/irc/notifylist/notify-ison.c
Normal file
354
src/irc/notifylist/notify-ison.c
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
/*
|
||||
notify-ison.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
#include "misc.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include "irc.h"
|
||||
#include "irc-server.h"
|
||||
#include "server-redirect.h"
|
||||
|
||||
#include "notifylist.h"
|
||||
|
||||
#define DEFAULT_NOTIFY_CHECK_TIME 60
|
||||
#define DEFAULT_NOTIFY_WHOIS_TIME (60*5)
|
||||
|
||||
typedef struct {
|
||||
char *nick;
|
||||
int hostok;
|
||||
} ISON_REC;
|
||||
|
||||
static int notify_tag;
|
||||
static int notify_whois_time;
|
||||
|
||||
NOTIFY_NICK_REC *notify_nick_create(IRC_SERVER_REC *server, const char *nick)
|
||||
{
|
||||
MODULE_SERVER_REC *mserver;
|
||||
NOTIFY_NICK_REC *rec;
|
||||
|
||||
mserver = MODULE_DATA(server);
|
||||
|
||||
rec = g_new0(NOTIFY_NICK_REC, 1);
|
||||
rec->nick = g_strdup(nick);
|
||||
|
||||
mserver->notify_users = g_slist_append(mserver->notify_users, rec);
|
||||
return rec;
|
||||
}
|
||||
|
||||
void notify_nick_destroy(NOTIFY_NICK_REC *rec)
|
||||
{
|
||||
g_free(rec->nick);
|
||||
g_free_not_null(rec->user);
|
||||
g_free_not_null(rec->host);
|
||||
g_free_not_null(rec->realname);
|
||||
g_free_not_null(rec->awaymsg);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
NOTIFY_NICK_REC *notify_nick_find(IRC_SERVER_REC *server, const char *nick)
|
||||
{
|
||||
MODULE_SERVER_REC *mserver;
|
||||
NOTIFY_NICK_REC *rec;
|
||||
GSList *tmp;
|
||||
|
||||
mserver = MODULE_DATA(server);
|
||||
for (tmp = mserver->notify_users; tmp != NULL; tmp = tmp->next) {
|
||||
rec = tmp->data;
|
||||
|
||||
if (g_strcasecmp(rec->nick, nick) == 0)
|
||||
return rec;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int is_ison_queue_empty(IRC_SERVER_REC *server)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
tmp = server_redirect_getqueue((SERVER_REC *) server, ISON_EVENT, NULL);
|
||||
for (; tmp != NULL; tmp = tmp->next) {
|
||||
REDIRECT_REC *rec = tmp->data;
|
||||
|
||||
if (strcmp(rec->name, "notifylist event") == 0)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void ison_send(IRC_SERVER_REC *server, GString *cmd)
|
||||
{
|
||||
g_string_truncate(cmd, cmd->len-1);
|
||||
g_string_prepend(cmd, "ISON :");
|
||||
|
||||
irc_send_cmd(server, cmd->str);
|
||||
server_redirect_event((SERVER_REC *) server, NULL, 1, ISON_EVENT, "notifylist event", -1, NULL);
|
||||
|
||||
g_string_truncate(cmd, 0);
|
||||
}
|
||||
|
||||
/* timeout function: send /ISON commands to server to check if someone in
|
||||
notify list is in IRC */
|
||||
static void notifylist_timeout_server(IRC_SERVER_REC *server)
|
||||
{
|
||||
GSList *tmp;
|
||||
GString *cmd;
|
||||
char *nick, *ptr;
|
||||
int len;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
if (!is_ison_queue_empty(server)) {
|
||||
/* still not received all replies to previous /ISON commands.. */
|
||||
return;
|
||||
}
|
||||
|
||||
cmd = g_string_new(NULL);
|
||||
for (tmp = notifies; tmp != NULL; tmp = tmp->next) {
|
||||
NOTIFYLIST_REC *rec = tmp->data;
|
||||
|
||||
if (!notify_ircnets_match(rec, server->connrec->ircnet))
|
||||
continue;
|
||||
|
||||
nick = g_strdup(rec->mask);
|
||||
ptr = strchr(nick, '!');
|
||||
if (ptr != NULL) *ptr = '\0';
|
||||
|
||||
len = strlen(nick);
|
||||
|
||||
if (cmd->len+len+1 > 510)
|
||||
ison_send(server, cmd);
|
||||
|
||||
g_string_sprintfa(cmd, "%s ", nick);
|
||||
g_free(nick);
|
||||
}
|
||||
|
||||
if (cmd->len > 0)
|
||||
ison_send(server, cmd);
|
||||
g_string_free(cmd, TRUE);
|
||||
}
|
||||
|
||||
static int notifylist_timeout_func(void)
|
||||
{
|
||||
g_slist_foreach(servers, (GFunc) notifylist_timeout_server, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void ison_save_users(MODULE_SERVER_REC *mserver, char *online)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
while (online != NULL && *online != '\0') {
|
||||
ptr = strchr(online, ' ');
|
||||
if (ptr != NULL) *ptr++ = '\0';
|
||||
|
||||
mserver->ison_tempusers =
|
||||
g_slist_append(mserver->ison_tempusers, g_strdup(online));
|
||||
online = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void whois_send(IRC_SERVER_REC *server, char *nicks)
|
||||
{
|
||||
char *p, *str;
|
||||
|
||||
irc_send_cmdv(server, "WHOIS %s", nicks);
|
||||
|
||||
/* "nick1,nick2" -> "nick1,nick2 nick1 nick2" because
|
||||
End of WHOIS give nick1,nick2 while other whois events give
|
||||
nick1 or nick2 */
|
||||
str = g_strconcat(nicks, " ", nicks, NULL);
|
||||
for (p = str+strlen(nicks)+1; *p != '\0'; p++)
|
||||
if (*p == ',') *p = ' ';
|
||||
|
||||
server_redirect_event((SERVER_REC *) server, str, 2,
|
||||
"event 318", "notifylist event whois end", 1,
|
||||
"event 402", "event empty", -1,
|
||||
"event 401", "event empty", 1,
|
||||
"event 311", "notifylist event whois", 1,
|
||||
"event 301", "notifylist event whois away", 1,
|
||||
"event 312", "event empty", 1,
|
||||
"event 313", "event empty", 1,
|
||||
"event 317", "notifylist event whois idle", 1,
|
||||
"event 319", "event empty", 1, NULL);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void whois_send_server(IRC_SERVER_REC *server, char *nick)
|
||||
{
|
||||
char *str;
|
||||
|
||||
str = g_strdup_printf("%s %s", nick, nick);
|
||||
whois_send(server, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
/* try to send as many nicks in one WHOIS as possible */
|
||||
static void whois_list_send(IRC_SERVER_REC *server, GSList *nicks)
|
||||
{
|
||||
GSList *tmp;
|
||||
GString *str;
|
||||
char *nick;
|
||||
int count;
|
||||
|
||||
str = g_string_new(NULL);
|
||||
count = 0;
|
||||
|
||||
for (tmp = nicks; tmp != NULL; tmp = tmp->next) {
|
||||
nick = tmp->data;
|
||||
|
||||
count++;
|
||||
g_string_sprintfa(str, "%s,", nick);
|
||||
|
||||
if (count >= server->max_whois_in_cmd) {
|
||||
g_string_truncate(str, str->len-1);
|
||||
whois_send(server, str->str);
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (str->len > 0) {
|
||||
g_string_truncate(str, str->len-1);
|
||||
whois_send(server, str->str);
|
||||
}
|
||||
|
||||
g_string_free(str, TRUE);
|
||||
}
|
||||
|
||||
static void ison_check_joins(IRC_SERVER_REC *server)
|
||||
{
|
||||
MODULE_SERVER_REC *mserver;
|
||||
NOTIFYLIST_REC *notify;
|
||||
NOTIFY_NICK_REC *rec;
|
||||
GSList *tmp, *newnicks;
|
||||
int send_whois;
|
||||
time_t now;
|
||||
|
||||
mserver = MODULE_DATA(server);
|
||||
|
||||
now = time(NULL);
|
||||
newnicks = NULL;
|
||||
for (tmp = mserver->ison_tempusers; tmp != NULL; tmp = tmp->next) {
|
||||
char *nick = tmp->data;
|
||||
|
||||
notify = notifylist_find(nick, server->connrec->ircnet);
|
||||
send_whois = notify != NULL &&
|
||||
(notify->away_check || notify->idle_check_time > 0);
|
||||
|
||||
rec = notify_nick_find(server, nick);
|
||||
if (rec != NULL) {
|
||||
/* check if we want to send WHOIS yet.. */
|
||||
if (now-rec->last_whois < notify_whois_time)
|
||||
continue;
|
||||
} else {
|
||||
rec = notify_nick_create(server, nick);
|
||||
if (!send_whois) newnicks = g_slist_append(newnicks, nick);
|
||||
}
|
||||
|
||||
if (send_whois) {
|
||||
/* we need away message or idle time -
|
||||
send the WHOIS reply to the nick's server */
|
||||
rec->last_whois = now;
|
||||
whois_send_server(server, nick);
|
||||
}
|
||||
}
|
||||
|
||||
whois_list_send(server, newnicks);
|
||||
g_slist_free(newnicks);
|
||||
}
|
||||
|
||||
static void ison_check_parts(IRC_SERVER_REC *server)
|
||||
{
|
||||
MODULE_SERVER_REC *mserver;
|
||||
GSList *tmp, *next;
|
||||
|
||||
mserver = MODULE_DATA(server);
|
||||
for (tmp = mserver->notify_users; tmp != NULL; tmp = next) {
|
||||
NOTIFY_NICK_REC *rec = tmp->data;
|
||||
next = tmp->next;
|
||||
|
||||
if (gslist_find_icase_string(mserver->ison_tempusers, rec->nick) != NULL)
|
||||
continue;
|
||||
|
||||
notifylist_left(server, rec);
|
||||
notify_nick_destroy(rec);
|
||||
}
|
||||
}
|
||||
|
||||
static void event_ison(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
MODULE_SERVER_REC *mserver;
|
||||
char *params, *online;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
params = event_get_params(data, 2, NULL, &online);
|
||||
|
||||
mserver = MODULE_DATA(server);
|
||||
ison_save_users(mserver, online);
|
||||
|
||||
if (!is_ison_queue_empty(server)) {
|
||||
/* wait for the rest of the /ISON replies */
|
||||
g_free(params);
|
||||
return;
|
||||
}
|
||||
|
||||
ison_check_joins(server);
|
||||
ison_check_parts(server);
|
||||
|
||||
/* free memory used by temp list */
|
||||
g_slist_foreach(mserver->ison_tempusers, (GFunc) g_free, NULL);
|
||||
g_slist_free(mserver->ison_tempusers);
|
||||
mserver->ison_tempusers = NULL;
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void read_settings(void)
|
||||
{
|
||||
if (notify_tag != -1) g_source_remove(notify_tag);
|
||||
notify_tag = g_timeout_add(1000*settings_get_int("notify_check_time"), (GSourceFunc) notifylist_timeout_func, NULL);
|
||||
|
||||
notify_whois_time = settings_get_int("notify_whois_time");
|
||||
}
|
||||
|
||||
void notifylist_ison_init(void)
|
||||
{
|
||||
settings_add_int("misc", "notify_check_time", DEFAULT_NOTIFY_CHECK_TIME);
|
||||
settings_add_int("misc", "notify_whois_time", DEFAULT_NOTIFY_WHOIS_TIME);
|
||||
|
||||
notify_tag = -1;
|
||||
read_settings();
|
||||
|
||||
signal_add("notifylist event", (SIGNAL_FUNC) event_ison);
|
||||
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
|
||||
}
|
||||
|
||||
void notifylist_ison_deinit(void)
|
||||
{
|
||||
g_source_remove(notify_tag);
|
||||
|
||||
signal_remove("notifylist event", (SIGNAL_FUNC) event_ison);
|
||||
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
|
||||
}
|
||||
84
src/irc/notifylist/notify-setup.c
Normal file
84
src/irc/notifylist/notify-setup.c
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
notify-setup.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "lib-config/iconfig.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include "irc-server.h"
|
||||
#include "notifylist.h"
|
||||
|
||||
void notifylist_add_config(NOTIFYLIST_REC *rec)
|
||||
{
|
||||
CONFIG_NODE *node;
|
||||
|
||||
node = iconfig_node_traverse("notifies", TRUE);
|
||||
node = config_node_section(node, rec->mask, NODE_TYPE_BLOCK);
|
||||
|
||||
if (rec->away_check)
|
||||
config_node_set_bool(node, "away_check", TRUE);
|
||||
else
|
||||
config_node_set_str(node, "away_check", NULL);
|
||||
|
||||
if (rec->idle_check_time > 0)
|
||||
config_node_set_int(node, "idle_check_time", rec->idle_check_time/60);
|
||||
else
|
||||
config_node_set_str(node, "idle_check_time", NULL);
|
||||
|
||||
config_node_set_str(node, "ircnets", NULL);
|
||||
if (rec->ircnets != NULL && *rec->ircnets != NULL) {
|
||||
node = config_node_section(node, "ircnets", NODE_TYPE_LIST);
|
||||
config_node_add_list(node, rec->ircnets);
|
||||
}
|
||||
}
|
||||
|
||||
void notifylist_remove_config(NOTIFYLIST_REC *rec)
|
||||
{
|
||||
iconfig_set_str("notifies", rec->mask, NULL);
|
||||
}
|
||||
|
||||
void notifylist_read_config(void)
|
||||
{
|
||||
CONFIG_NODE *node;
|
||||
NOTIFYLIST_REC *rec;
|
||||
GSList *tmp;
|
||||
|
||||
notifylist_destroy_all();
|
||||
|
||||
node = iconfig_node_traverse("notifies", FALSE);
|
||||
if (node == NULL) return;
|
||||
|
||||
for (tmp = node->value; tmp != NULL; tmp = tmp->next) {
|
||||
node = tmp->data;
|
||||
|
||||
if (node->type != NODE_TYPE_BLOCK)
|
||||
continue;
|
||||
|
||||
rec = g_new0(NOTIFYLIST_REC, 1);
|
||||
notifies = g_slist_append(notifies, rec);
|
||||
|
||||
rec->mask = g_strdup(node->key);
|
||||
rec->away_check = config_node_get_bool(node, "away_check", FALSE);
|
||||
rec->idle_check_time = config_node_get_int(node, "idle_check_time", 0)*60;
|
||||
|
||||
node = config_node_section(node, "ircnets", -1);
|
||||
if (node != NULL) rec->ircnets = config_node_get_list(node);
|
||||
}
|
||||
}
|
||||
9
src/irc/notifylist/notify-setup.h
Normal file
9
src/irc/notifylist/notify-setup.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef __NOTIFY_SETUP_H
|
||||
#define __NOTIFY_SETUP_H
|
||||
|
||||
void notifylist_add_config(NOTIFYLIST_REC *rec);
|
||||
void notifylist_remove_config(NOTIFYLIST_REC *rec);
|
||||
|
||||
void notifylist_read_config(void);
|
||||
|
||||
#endif
|
||||
186
src/irc/notifylist/notify-whois.c
Normal file
186
src/irc/notifylist/notify-whois.c
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
notify-whois.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
#include "special-vars.h"
|
||||
|
||||
#include "irc.h"
|
||||
#include "irc-server.h"
|
||||
#include "masks.h"
|
||||
|
||||
#include "notifylist.h"
|
||||
|
||||
static char *last_notify_nick;
|
||||
|
||||
static void event_whois(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
char *params, *nick, *user, *host, *realname;
|
||||
NOTIFY_NICK_REC *nickrec;
|
||||
NOTIFYLIST_REC *notify;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
params = event_get_params(data, 6, NULL, &nick, &user, &host, NULL, &realname);
|
||||
|
||||
notify = notifylist_find(nick, server->connrec->ircnet);
|
||||
if (notify != NULL && !irc_mask_match(notify->mask, nick, user, host)) {
|
||||
/* user or host didn't match */
|
||||
g_free(params);
|
||||
return;
|
||||
}
|
||||
|
||||
nickrec = notify_nick_find(server, nick);
|
||||
if (nickrec != NULL) {
|
||||
g_free_not_null(last_notify_nick);
|
||||
last_notify_nick = g_strdup(nick);
|
||||
|
||||
g_free_not_null(nickrec->user);
|
||||
g_free_not_null(nickrec->host);
|
||||
g_free_not_null(nickrec->realname);
|
||||
g_free_and_null(nickrec->awaymsg);
|
||||
nickrec->user = g_strdup(user);
|
||||
nickrec->host = g_strdup(host);
|
||||
nickrec->realname = g_strdup(realname);
|
||||
|
||||
nickrec->away = FALSE;
|
||||
nickrec->host_ok = TRUE;
|
||||
nickrec->idle_ok = TRUE;
|
||||
}
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_whois_idle(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
NOTIFY_NICK_REC *nickrec;
|
||||
NOTIFYLIST_REC *notify;
|
||||
char *params, *nick, *secstr;
|
||||
long secs;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 3, NULL, &nick, &secstr);
|
||||
secs = atol(secstr);
|
||||
|
||||
notify = notifylist_find(nick, server->connrec->ircnet);
|
||||
nickrec = notify_nick_find(server, nick);
|
||||
if (notify != NULL && nickrec != NULL) {
|
||||
time_t now = time(NULL);
|
||||
nickrec->idle_changed = secs < now-nickrec->idle_time &&
|
||||
now-nickrec->idle_time > notify->idle_check_time;
|
||||
|
||||
nickrec->idle_time = now-secs;
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void event_whois_away(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
NOTIFY_NICK_REC *nickrec;
|
||||
char *params, *nick, *awaymsg;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 3, NULL, &nick, &awaymsg);
|
||||
|
||||
nickrec = notify_nick_find(server, nick);
|
||||
if (nickrec != NULL) {
|
||||
nickrec->awaymsg = g_strdup(awaymsg);
|
||||
nickrec->away = TRUE;
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
/* All WHOIS replies got, now announce all the changes at once. */
|
||||
static void event_whois_end(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
MODULE_SERVER_REC *mserver;
|
||||
NOTIFYLIST_REC *notify;
|
||||
NOTIFY_NICK_REC *rec;
|
||||
GSList *tmp;
|
||||
const char *event;
|
||||
int away_ok;
|
||||
time_t now;
|
||||
|
||||
now = time(NULL);
|
||||
mserver = MODULE_DATA(server);
|
||||
for (tmp = mserver->notify_users; tmp != NULL; tmp = tmp->next) {
|
||||
rec = tmp->data;
|
||||
|
||||
if (rec->realname == NULL)
|
||||
continue;
|
||||
|
||||
notify = notifylist_find(rec->nick, server->connrec->ircnet);
|
||||
if (notify == NULL) continue;
|
||||
|
||||
away_ok = !notify->away_check || !rec->away;
|
||||
|
||||
event = NULL;
|
||||
if (!rec->join_announced) {
|
||||
rec->join_announced = TRUE;
|
||||
rec->idle_time = now;
|
||||
if (away_ok) event = "notifylist joined";
|
||||
} else if (notify->away_check && rec->away_ok == rec->away)
|
||||
event = "notifylist away changed";
|
||||
else if (notify->idle_check_time > 0 && rec->idle_changed)
|
||||
event = "notifylist unidle";
|
||||
|
||||
if (event != NULL) {
|
||||
signal_emit(event, 6, server, rec->nick,
|
||||
rec->user, rec->host,
|
||||
rec->realname, rec->awaymsg);
|
||||
}
|
||||
rec->idle_ok = notify->idle_check_time <= 0 ||
|
||||
now-rec->idle_time <= notify->idle_check_time;
|
||||
rec->idle_changed = FALSE;
|
||||
rec->away_ok = away_ok;
|
||||
}
|
||||
}
|
||||
|
||||
/* last person that NOTIFY detected a signon for */
|
||||
static char *expando_lastnotify(void *server, void *item, int *free_ret)
|
||||
{
|
||||
return last_notify_nick;
|
||||
}
|
||||
|
||||
void notifylist_whois_init(void)
|
||||
{
|
||||
last_notify_nick = NULL;
|
||||
|
||||
signal_add("notifylist event whois", (SIGNAL_FUNC) event_whois);
|
||||
signal_add("notifylist event whois away", (SIGNAL_FUNC) event_whois_away);
|
||||
signal_add("notifylist event whois idle", (SIGNAL_FUNC) event_whois_idle);
|
||||
signal_add("notifylist event whois end", (SIGNAL_FUNC) event_whois_end);
|
||||
expando_create("D", expando_lastnotify);
|
||||
}
|
||||
|
||||
void notifylist_whois_deinit(void)
|
||||
{
|
||||
g_free_not_null(last_notify_nick);
|
||||
|
||||
signal_remove("notifylist event whois", (SIGNAL_FUNC) event_whois);
|
||||
signal_remove("notifylist event whois away", (SIGNAL_FUNC) event_whois_away);
|
||||
signal_remove("notifylist event whois idle", (SIGNAL_FUNC) event_whois_idle);
|
||||
signal_remove("notifylist event whois end", (SIGNAL_FUNC) event_whois_end);
|
||||
expando_destroy("D", expando_lastnotify);
|
||||
}
|
||||
356
src/irc/notifylist/notifylist.c
Normal file
356
src/irc/notifylist/notifylist.c
Normal file
|
|
@ -0,0 +1,356 @@
|
|||
/*
|
||||
notifylist.c : irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "modules.h"
|
||||
#include "signals.h"
|
||||
|
||||
#include "irc.h"
|
||||
#include "irc-server.h"
|
||||
#include "server-redirect.h"
|
||||
#include "masks.h"
|
||||
#include "nicklist.h"
|
||||
|
||||
#include "notifylist.h"
|
||||
#include "notify-setup.h"
|
||||
|
||||
GSList *notifies;
|
||||
|
||||
NOTIFYLIST_REC *notifylist_add(const char *mask, const char *ircnets,
|
||||
int away_check, int idle_check_time)
|
||||
{
|
||||
NOTIFYLIST_REC *rec;
|
||||
|
||||
g_return_val_if_fail(mask != NULL, NULL);
|
||||
|
||||
rec = g_new0(NOTIFYLIST_REC, 1);
|
||||
rec->mask = g_strdup(mask);
|
||||
rec->ircnets = ircnets == NULL || *ircnets == '\0' ? NULL :
|
||||
g_strsplit(ircnets, " ", -1);
|
||||
rec->away_check = away_check;
|
||||
rec->idle_check_time = idle_check_time;
|
||||
|
||||
notifylist_add_config(rec);
|
||||
|
||||
notifies = g_slist_append(notifies, rec);
|
||||
signal_emit("notifylist new", 1, rec);
|
||||
return rec;
|
||||
}
|
||||
|
||||
static void notify_destroy(NOTIFYLIST_REC *rec)
|
||||
{
|
||||
if (rec->ircnets != NULL) g_strfreev(rec->ircnets);
|
||||
g_free(rec->mask);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
void notifylist_destroy_all(void)
|
||||
{
|
||||
g_slist_foreach(notifies, (GFunc) notify_destroy, NULL);
|
||||
g_slist_free(notifies);
|
||||
|
||||
notifies = NULL;
|
||||
}
|
||||
|
||||
void notifylist_remove(const char *mask)
|
||||
{
|
||||
NOTIFYLIST_REC *rec;
|
||||
|
||||
g_return_if_fail(mask != NULL);
|
||||
|
||||
rec = notifylist_find(mask, "*");
|
||||
if (rec == NULL) return;
|
||||
|
||||
notifylist_remove_config(rec);
|
||||
notifies = g_slist_remove(notifies, rec);
|
||||
signal_emit("notifylist remove", 1, rec);
|
||||
|
||||
notify_destroy(rec);
|
||||
}
|
||||
|
||||
int notify_ircnets_match(NOTIFYLIST_REC *rec, const char *ircnet)
|
||||
{
|
||||
char **tmp;
|
||||
|
||||
if (rec->ircnets == NULL) return TRUE;
|
||||
if (ircnet == NULL) return FALSE;
|
||||
if (strcmp(ircnet, "*") == 0) return TRUE;
|
||||
|
||||
for (tmp = rec->ircnets; *tmp != NULL; tmp++) {
|
||||
if (g_strcasecmp(*tmp, ircnet) == 0)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
NOTIFYLIST_REC *notifylist_find(const char *mask, const char *ircnet)
|
||||
{
|
||||
NOTIFYLIST_REC *best;
|
||||
GSList *tmp;
|
||||
int len;
|
||||
|
||||
best = NULL;
|
||||
len = strlen(mask);
|
||||
for (tmp = notifies; tmp != NULL; tmp = tmp->next) {
|
||||
NOTIFYLIST_REC *rec = tmp->data;
|
||||
|
||||
/* check mask */
|
||||
if (g_strncasecmp(rec->mask, mask, len) != 0 ||
|
||||
(rec->mask[len] != '\0' && rec->mask[len] != '!')) continue;
|
||||
|
||||
/* check ircnet */
|
||||
if (rec->ircnets == NULL) {
|
||||
best = rec;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (notify_ircnets_match(rec, ircnet))
|
||||
return rec;
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
int notifylist_ison_server(IRC_SERVER_REC *server, const char *nick)
|
||||
{
|
||||
NOTIFY_NICK_REC *rec;
|
||||
|
||||
g_return_val_if_fail(nick != NULL, FALSE);
|
||||
g_return_val_if_fail(server != NULL, FALSE);
|
||||
|
||||
rec = notify_nick_find(server, nick);
|
||||
return rec != NULL && rec->host_ok && rec->away_ok && rec->idle_ok;
|
||||
}
|
||||
|
||||
static IRC_SERVER_REC *notifylist_ison_serverlist(const char *nick, const char *taglist)
|
||||
{
|
||||
IRC_SERVER_REC *server;
|
||||
char **list, **tmp;
|
||||
|
||||
list = g_strsplit(taglist, " ", -1);
|
||||
|
||||
server = NULL;
|
||||
for (tmp = list; *tmp != NULL; tmp++) {
|
||||
server = (IRC_SERVER_REC *) server_find_ircnet(*tmp);
|
||||
|
||||
if (server != NULL && notifylist_ison_server(server, nick))
|
||||
break;
|
||||
}
|
||||
g_strfreev(list);
|
||||
|
||||
return tmp == NULL ? NULL : server;
|
||||
}
|
||||
|
||||
IRC_SERVER_REC *notifylist_ison(const char *nick, const char *serverlist)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
g_return_val_if_fail(nick != NULL, FALSE);
|
||||
g_return_val_if_fail(serverlist != NULL, FALSE);
|
||||
|
||||
if (*serverlist != '\0')
|
||||
return notifylist_ison_serverlist(nick, serverlist);
|
||||
|
||||
/* any server.. */
|
||||
for (tmp = servers; tmp != NULL; tmp = tmp->next) {
|
||||
if (notifylist_ison_server(tmp->data, nick))
|
||||
return tmp->data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void notifylist_init_server(IRC_SERVER_REC *server)
|
||||
{
|
||||
MODULE_SERVER_REC *rec;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
rec = g_new0(MODULE_SERVER_REC,1 );
|
||||
MODULE_DATA_SET(server, rec);
|
||||
|
||||
server_redirect_init((SERVER_REC *) server, "command ison", 1, ISON_EVENT, NULL);
|
||||
}
|
||||
|
||||
static void notifylist_deinit_server(IRC_SERVER_REC *server)
|
||||
{
|
||||
MODULE_SERVER_REC *mserver;
|
||||
NOTIFY_NICK_REC *rec;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
mserver = MODULE_DATA(server);
|
||||
while (mserver->notify_users != NULL) {
|
||||
rec = mserver->notify_users->data;
|
||||
|
||||
mserver->notify_users = g_slist_remove(mserver->notify_users, rec);
|
||||
notify_nick_destroy(rec);
|
||||
}
|
||||
g_free(mserver);
|
||||
}
|
||||
|
||||
void notifylist_left(IRC_SERVER_REC *server, NOTIFY_NICK_REC *rec)
|
||||
{
|
||||
MODULE_SERVER_REC *mserver;
|
||||
|
||||
mserver = MODULE_DATA(server);
|
||||
mserver->notify_users = g_slist_remove(mserver->notify_users, rec);
|
||||
|
||||
if (rec->host_ok && rec->away_ok) {
|
||||
signal_emit("notifylist left", 6,
|
||||
server, rec->nick,
|
||||
rec->user, rec->host,
|
||||
rec->realname, rec->awaymsg);
|
||||
}
|
||||
}
|
||||
|
||||
static void notifylist_idle_reset(IRC_SERVER_REC *server, const char *nick)
|
||||
{
|
||||
NOTIFY_NICK_REC *rec;
|
||||
NOTIFYLIST_REC *notify;
|
||||
|
||||
notify = notifylist_find(nick, server->connrec->ircnet);
|
||||
rec = notify_nick_find(server, nick);
|
||||
|
||||
if (notify != NULL && rec != NULL && notify->idle_check_time > 0 &&
|
||||
time(NULL)-rec->idle_time > notify->idle_check_time) {
|
||||
rec->idle_time = time(NULL);
|
||||
signal_emit("notifylist unidle", 6,
|
||||
server, rec->nick,
|
||||
rec->user, rec->host,
|
||||
rec->realname, rec->awaymsg);
|
||||
}
|
||||
}
|
||||
|
||||
static void event_quit(const char *data, IRC_SERVER_REC *server, const char *nick)
|
||||
{
|
||||
NOTIFY_NICK_REC *rec;
|
||||
|
||||
if (*data == ':') data++; /* quit message */
|
||||
|
||||
rec = notify_nick_find(server, nick);
|
||||
if (rec != NULL) notifylist_left(server, rec);
|
||||
}
|
||||
|
||||
static void notifylist_check_join(IRC_SERVER_REC *server, const char *nick,
|
||||
const char *userhost, const char *realname, int away)
|
||||
{
|
||||
NOTIFYLIST_REC *notify;
|
||||
NOTIFY_NICK_REC *rec;
|
||||
char *user, *host;
|
||||
|
||||
notify = notifylist_find(nick, server->connrec->ircnet);
|
||||
if (notify == NULL) return;
|
||||
|
||||
rec = notify_nick_find(server, nick);
|
||||
if (rec != NULL && rec->join_announced) return;
|
||||
if (rec == NULL) rec = notify_nick_create(server, nick);
|
||||
|
||||
user = g_strdup(userhost);
|
||||
host = strchr(user, '@');
|
||||
if (host != NULL) *host++ = '\0'; else host = "";
|
||||
|
||||
if (!irc_mask_match(notify->mask, nick, user, host)) {
|
||||
g_free(user);
|
||||
return;
|
||||
}
|
||||
|
||||
if (notify->away_check && away == -1) {
|
||||
/* we need to know if the nick is away */
|
||||
g_free(user);
|
||||
return;
|
||||
}
|
||||
|
||||
g_free_not_null(rec->user);
|
||||
g_free_not_null(rec->host);
|
||||
g_free_not_null(rec->realname);
|
||||
rec->user = g_strdup(user);
|
||||
rec->host = g_strdup(host);
|
||||
rec->realname = *realname == '\0' ? NULL : g_strdup(realname);
|
||||
|
||||
if (away != -1) rec->away = away;
|
||||
rec->host_ok = TRUE;
|
||||
rec->join_announced = TRUE;
|
||||
rec->idle_time = time(NULL);
|
||||
|
||||
signal_emit("notifylist joined", 6,
|
||||
server, rec->nick, rec->user, rec->host, realname, NULL);
|
||||
g_free(user);
|
||||
}
|
||||
|
||||
static void event_privmsg(const char *data, IRC_SERVER_REC *server, const char *nick, const char *address)
|
||||
{
|
||||
if (nick != NULL) {
|
||||
notifylist_check_join(server, nick, address, "", -1);
|
||||
notifylist_idle_reset(server, nick);
|
||||
}
|
||||
}
|
||||
|
||||
static void event_join(const char *data, IRC_SERVER_REC *server, const char *nick, const char *address)
|
||||
{
|
||||
notifylist_check_join(server, nick, address, "", -1);
|
||||
}
|
||||
|
||||
static void sig_channel_wholist(CHANNEL_REC *channel)
|
||||
{
|
||||
GSList *nicks, *tmp;
|
||||
|
||||
nicks = nicklist_getnicks(channel);
|
||||
for (tmp = nicks; tmp != NULL; tmp = tmp->next) {
|
||||
NICK_REC *rec = tmp->data;
|
||||
|
||||
notifylist_check_join(channel->server, rec->nick, rec->host, rec->realname, rec->gone);
|
||||
}
|
||||
g_slist_free(nicks);
|
||||
}
|
||||
|
||||
void notifylist_init(void)
|
||||
{
|
||||
notifylist_read_config();
|
||||
|
||||
notifylist_commands_init();
|
||||
notifylist_ison_init();
|
||||
notifylist_whois_init();
|
||||
signal_add("server connected", (SIGNAL_FUNC) notifylist_init_server);
|
||||
signal_add("server disconnected", (SIGNAL_FUNC) notifylist_deinit_server);
|
||||
signal_add("event quit", (SIGNAL_FUNC) event_quit);
|
||||
signal_add("event privmsg", (SIGNAL_FUNC) event_privmsg);
|
||||
signal_add("event join", (SIGNAL_FUNC) event_join);
|
||||
signal_add("channel wholist", (SIGNAL_FUNC) sig_channel_wholist);
|
||||
signal_add("setup reread", (SIGNAL_FUNC) notifylist_read_config);
|
||||
}
|
||||
|
||||
void notifylist_deinit(void)
|
||||
{
|
||||
notifylist_commands_deinit();
|
||||
notifylist_ison_deinit();
|
||||
notifylist_whois_deinit();
|
||||
|
||||
signal_remove("server connected", (SIGNAL_FUNC) notifylist_init_server);
|
||||
signal_remove("server disconnected", (SIGNAL_FUNC) notifylist_deinit_server);
|
||||
signal_remove("event quit", (SIGNAL_FUNC) event_quit);
|
||||
signal_remove("event privmsg", (SIGNAL_FUNC) event_privmsg);
|
||||
signal_remove("event join", (SIGNAL_FUNC) event_join);
|
||||
signal_remove("channel wholist", (SIGNAL_FUNC) sig_channel_wholist);
|
||||
signal_remove("setup reread", (SIGNAL_FUNC) notifylist_read_config);
|
||||
|
||||
notifylist_destroy_all();
|
||||
}
|
||||
32
src/irc/notifylist/notifylist.h
Normal file
32
src/irc/notifylist/notifylist.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef __NOTIFYLIST_H
|
||||
#define __NOTIFYLIST_H
|
||||
|
||||
typedef struct {
|
||||
char *mask; /* nick part must not contain wildcards */
|
||||
char **ircnets; /* if non-NULL, check only from these irc networks */
|
||||
|
||||
/* notify when AWAY status changes (uses /USERHOST) */
|
||||
int away_check:1;
|
||||
/* notify when idle time is reset and it was bigger than this
|
||||
(uses /WHOIS and PRIVMSG events) */
|
||||
int idle_check_time;
|
||||
} NOTIFYLIST_REC;
|
||||
|
||||
extern GSList *notifies;
|
||||
|
||||
void notifylist_init(void);
|
||||
void notifylist_deinit(void);
|
||||
|
||||
NOTIFYLIST_REC *notifylist_add(const char *mask, const char *ircnets,
|
||||
int away_check, int idle_check_time);
|
||||
void notifylist_remove(const char *mask);
|
||||
|
||||
IRC_SERVER_REC *notifylist_ison(const char *nick, const char *serverlist);
|
||||
int notifylist_ison_server(IRC_SERVER_REC *server, const char *nick);
|
||||
|
||||
/* If `ircnet' is "*", it doesn't matter at all. */
|
||||
NOTIFYLIST_REC *notifylist_find(const char *mask, const char *ircnet);
|
||||
|
||||
int notify_ircnets_match(NOTIFYLIST_REC *rec, const char *ircnet);
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue