summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTimo Sirainen <cras@irssi.org>2000-10-14 00:45:16 +0000
committercras <cras@dbcabf3a-b0e7-0310-adc4-f8d773084564>2000-10-14 00:45:16 +0000
commit6a3efe49ab7b41062650da894eccc2d4be0b8f45 (patch)
treee60a8f2eaaef04f87d9c8752f2742acc4f5e41bb /src
parentf850204479e84c3112b6353da48a5a1ec81bb1fe (diff)
downloadirssi-6a3efe49ab7b41062650da894eccc2d4be0b8f45.zip
Autorejoin when join temporarily fails because of netsplit is handled
better now. Irssi prints a nice message about it only once and you can abort it with /RMREJOINS command. "channel query" -> "channel joined" channels_join() must not use cmd_return|param_error() commands since we don't necessarily call it from command handler and signal_stop() could cause some damage. git-svn-id: http://svn.irssi.org/repos/irssi/trunk@739 dbcabf3a-b0e7-0310-adc4-f8d773084564
Diffstat (limited to 'src')
-rw-r--r--src/core/chat-commands.c3
-rw-r--r--src/fe-common/irc/fe-irc-channels.c13
-rw-r--r--src/fe-common/irc/module-formats.c1
-rw-r--r--src/fe-common/irc/module-formats.h1
-rw-r--r--src/irc/core/channel-rejoin.c146
-rw-r--r--src/irc/core/channels-query.c13
-rw-r--r--src/irc/core/irc-channels.c22
-rw-r--r--src/irc/core/irc-nicklist.c2
8 files changed, 169 insertions, 32 deletions
diff --git a/src/core/chat-commands.c b/src/core/chat-commands.c
index 58b83f7c..f2cae1ab 100644
--- a/src/core/chat-commands.c
+++ b/src/core/chat-commands.c
@@ -46,6 +46,9 @@ static void cmd_join(const char *data, SERVER_REC *server)
if (g_hash_table_lookup(optlist, "invite"))
channels = server->last_invite;
else {
+ if (*channels == '\0')
+ cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+
/* -<server tag> */
server = cmd_options_get_server("join", optlist, server);
}
diff --git a/src/fe-common/irc/fe-irc-channels.c b/src/fe-common/irc/fe-irc-channels.c
index bb22e54d..8a7de92d 100644
--- a/src/fe-common/irc/fe-irc-channels.c
+++ b/src/fe-common/irc/fe-irc-channels.c
@@ -19,11 +19,22 @@
*/
#include "module.h"
+#include "module-formats.h"
#include "signals.h"
#include "commands.h"
+#include "levels.h"
#include "servers.h"
#include "irc.h"
+#include "channel-rejoin.h"
+
+static void sig_channel_rejoin(IRC_SERVER_REC *server, REJOIN_REC *rec)
+{
+ g_return_if_fail(rec != NULL);
+
+ printformat(server, NULL, MSGLEVEL_CLIENTNOTICE,
+ IRCTXT_CHANNEL_REJOIN, rec->channel);
+}
static void cmd_channel(const char *data, SERVER_REC *server)
{
@@ -35,10 +46,12 @@ static void cmd_channel(const char *data, SERVER_REC *server)
void fe_irc_channels_init(void)
{
+ signal_add("channel rejoin new", (SIGNAL_FUNC) sig_channel_rejoin);
command_bind("channel", NULL, (SIGNAL_FUNC) cmd_channel);
}
void fe_irc_channels_deinit(void)
{
+ signal_remove("channel rejoin new", (SIGNAL_FUNC) sig_channel_rejoin);
command_unbind("channel", (SIGNAL_FUNC) cmd_channel);
}
diff --git a/src/fe-common/irc/module-formats.c b/src/fe-common/irc/module-formats.c
index d71152f9..4b193840 100644
--- a/src/fe-common/irc/module-formats.c
+++ b/src/fe-common/irc/module-formats.c
@@ -55,6 +55,7 @@ FORMAT_REC fecommon_irc_formats[] = {
{ "joinerror_bad_key", "Cannot join to channel %_$0%_ %K(%nBad channel key%K)", 1, { 0 } },
{ "joinerror_bad_mask", "Cannot join to channel %_$0%_ %K(%nBad channel mask%K)", 1, { 0 } },
{ "joinerror_unavail", "Cannot join to channel %_$0%_ %K(%nChannel is temporarily unavailable%K)", 1, { 0 } },
+ { "channel_rejoin", "Channel %_$0%_ is temporarily unavailable, this is normally because of netsplits. Irssi will now automatically try to rejoin to this channel until the join is successfull. Use /RMREJOINS command if you wish to abort this.", 1, { 0 } },
{ "inviting", "Inviting $0 to %_$1", 2, { 0, 0 } },
{ "not_invited", "You have not been invited to a channel!", 0 },
{ "names", "%K[%g%_Users%_%K(%g$0%K)]%n $1", 2, { 0, 0 } },
diff --git a/src/fe-common/irc/module-formats.h b/src/fe-common/irc/module-formats.h
index 46e91322..75e84a4b 100644
--- a/src/fe-common/irc/module-formats.h
+++ b/src/fe-common/irc/module-formats.h
@@ -32,6 +32,7 @@ enum {
IRCTXT_JOINERROR_BAD_KEY,
IRCTXT_JOINERROR_BAD_MASK,
IRCTXT_JOINERROR_UNAVAIL,
+ IRCTXT_CHANNEL_REJOIN,
IRCTXT_INVITING,
IRCTXT_NOT_INVITED,
IRCTXT_NAMES,
diff --git a/src/irc/core/channel-rejoin.c b/src/irc/core/channel-rejoin.c
index 9efed72c..32070a79 100644
--- a/src/irc/core/channel-rejoin.c
+++ b/src/irc/core/channel-rejoin.c
@@ -25,25 +25,79 @@
#include "irc.h"
#include "irc-channels.h"
+#include "channel-rejoin.h"
-#define REJOIN_TIMEOUT (1000*60*5) /* try to rejoin every 5 minutes */
+//#define REJOIN_TIMEOUT (1000*60*5) /* try to rejoin every 5 minutes */
+#define REJOIN_TIMEOUT (1000*10) /* FIXME: test */
static int rejoin_tag;
+static void rejoin_destroy(IRC_SERVER_REC *server, REJOIN_REC *rec)
+{
+ g_return_if_fail(IS_IRC_SERVER(server));
+ g_return_if_fail(rec != NULL);
+
+ server->rejoin_channels =
+ g_slist_remove(server->rejoin_channels, rec);
+
+ signal_emit("channel rejoin remove", 2, server, rec);
+
+ g_free(rec->channel);
+ g_free_not_null(rec->key);
+ g_free(rec);
+}
+
+static REJOIN_REC *rejoin_find(IRC_SERVER_REC *server, const char *channel)
+{
+ GSList *tmp;
+
+ g_return_val_if_fail(IS_IRC_SERVER(server), NULL);
+ g_return_val_if_fail(channel != NULL, NULL);
+
+ for (tmp = server->rejoin_channels; tmp != NULL; tmp = tmp->next) {
+ REJOIN_REC *rec = tmp->data;
+
+ if (g_strcasecmp(rec->channel, channel) == 0)
+ return rec;
+ }
+
+ return NULL;
+}
+
#define channel_have_key(chan) \
((chan) != NULL && (chan)->key != NULL && (chan)->key[0] != '\0')
static void channel_rejoin(IRC_SERVER_REC *server, const char *channel)
{
IRC_CHANNEL_REC *chanrec;
- char *str;
+ REJOIN_REC *rec;
+
+ g_return_if_fail(IS_IRC_SERVER(server));
+ g_return_if_fail(channel != NULL);
chanrec = irc_channel_find(server, channel);
- str = channel_have_key(chanrec) ? g_strdup(channel) :
- g_strdup_printf("%s %s", channel, chanrec->key);
+
+ rec = rejoin_find(server, channel);
+ if (rec != NULL) {
+ /* already exists */
+ rec->joining = FALSE;
+
+ /* update channel key */
+ g_free_and_null(rec->key);
+ if (channel_have_key(chanrec))
+ rec->key = g_strdup(chanrec->key);
+ return;
+ }
+
+ /* new rejoin */
+ rec = g_new0(REJOIN_REC, 1);
+ rec->channel = g_strdup(channel);
+ if (channel_have_key(chanrec))
+ rec->key = g_strdup(chanrec->key);
server->rejoin_channels =
- g_slist_append(server->rejoin_channels, str);
+ g_slist_append(server->rejoin_channels, rec);
+ signal_emit("channel rejoin new", 2, server, rec);
}
static void event_target_unavailable(const char *data, IRC_SERVER_REC *server)
@@ -56,29 +110,80 @@ static void event_target_unavailable(const char *data, IRC_SERVER_REC *server)
if (ischannel(*channel)) {
/* channel is unavailable - try to join again a bit later */
channel_rejoin(server, channel);
+ signal_stop();
}
g_free(params);
}
+/* join ok/failed - remove from rejoins list. this happens always after join
+ except if the "target unavailable" error happens again */
+static void sig_remove_rejoin(IRC_CHANNEL_REC *channel)
+{
+ REJOIN_REC *rec;
+
+ if (!IS_IRC_CHANNEL(channel) && channel->server != NULL)
+ return;
+
+ rec = rejoin_find(channel->server, channel->name);
+ if (rec != NULL && rec->joining) {
+ /* join failed, remove the rejoin */
+ rejoin_destroy(channel->server, rec);
+ }
+}
+
static void sig_disconnected(IRC_SERVER_REC *server)
{
if (!IS_IRC_SERVER(server))
return;
- g_slist_foreach(server->rejoin_channels, (GFunc) g_free, NULL);
- g_slist_free(server->rejoin_channels);
+ while (server->rejoin_channels != NULL)
+ rejoin_destroy(server, server->rejoin_channels->data);
}
static void server_rejoin_channels(IRC_SERVER_REC *server)
{
- while (server->rejoin_channels != NULL) {
- char *channel = server->rejoin_channels->data;
+ GSList *tmp, *next;
+ GString *channels, *keys;
+ int use_keys;
+
+ g_return_if_fail(IS_IRC_SERVER(server));
+
+ channels = g_string_new(NULL);
+ keys = g_string_new(NULL);
+
+ use_keys = FALSE;
+ for (tmp = server->rejoin_channels; tmp != NULL; tmp = next) {
+ REJOIN_REC *rec = tmp->data;
+ next = tmp->next;
+
+ if (rec->joining) {
+ /* we missed the join (failed) message,
+ remove from rejoins.. */
+ rejoin_destroy(server, rec);
+ continue;
+ }
+
+ rec->joining = TRUE;
+ g_string_sprintfa(channels, "%s,", rec->channel);
+ if (rec->key == NULL)
+ g_string_append(keys, "x,");
+ else {
+ g_string_sprintfa(keys, "%s,", rec->key);
+ use_keys = TRUE;
+ }
+ }
- server->channels_join(server, channel, TRUE);
- server->rejoin_channels =
- g_slist_remove(server->rejoin_channels, channel);
+ if (channels->len > 0) {
+ g_string_truncate(channels, channels->len-1);
+ g_string_truncate(keys, keys->len-1);
+
+ if (use_keys) g_string_sprintfa(channels, " %s", keys->str);
+ server->channels_join(server, channels->str, TRUE);
}
+
+ g_string_free(channels, TRUE);
+ g_string_free(keys, TRUE);
}
static int sig_rejoin(void)
@@ -88,19 +193,31 @@ static int sig_rejoin(void)
for (tmp = servers; tmp != NULL; tmp = tmp->next) {
IRC_SERVER_REC *rec = tmp->data;
- if (IS_IRC_SERVER(rec))
+ if (IS_IRC_SERVER(rec) && rec->rejoin_channels != NULL)
server_rejoin_channels(rec);
}
return TRUE;
}
+static void cmd_rmrejoins(const char *data, IRC_SERVER_REC *server)
+{
+ if (!IS_IRC_SERVER(server) || !server->connected)
+ cmd_return_error(CMDERR_NOT_CONNECTED);
+
+ while (server->rejoin_channels != NULL)
+ rejoin_destroy(server, server->rejoin_channels->data);
+}
+
void channel_rejoin_init(void)
{
rejoin_tag = g_timeout_add(REJOIN_TIMEOUT,
(GSourceFunc) sig_rejoin, NULL);
+ command_bind("rmrejoins", NULL, (SIGNAL_FUNC) cmd_rmrejoins);
signal_add_first("event 437", (SIGNAL_FUNC) event_target_unavailable);
+ signal_add_first("channel joined", (SIGNAL_FUNC) sig_remove_rejoin);
+ signal_add_first("channel destroyed", (SIGNAL_FUNC) sig_remove_rejoin);
signal_add("server disconnected", (SIGNAL_FUNC) sig_disconnected);
}
@@ -108,6 +225,9 @@ void channel_rejoin_deinit(void)
{
g_source_remove(rejoin_tag);
+ command_unbind("rmrejoins", (SIGNAL_FUNC) cmd_rmrejoins);
signal_remove("event 437", (SIGNAL_FUNC) event_target_unavailable);
+ signal_remove("channel joined", (SIGNAL_FUNC) sig_remove_rejoin);
+ signal_remove("channel destroyed", (SIGNAL_FUNC) sig_remove_rejoin);
signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
}
diff --git a/src/irc/core/channels-query.c b/src/irc/core/channels-query.c
index 96f17f4d..bb48ef9f 100644
--- a/src/irc/core/channels-query.c
+++ b/src/irc/core/channels-query.c
@@ -22,8 +22,8 @@
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
+ - After channel is joined and NAMES list is got, send "channel joined" signal
+ - "channel joined" : add channel to server->queries lists
loop:
- Wait for NAMES list from all channels before doing anything else..
@@ -304,11 +304,12 @@ static void channels_query_check(IRC_SERVER_REC *server)
channel_send_query(server, query);
}
-static void sig_channel_query(IRC_CHANNEL_REC *channel)
+static void sig_channel_joined(IRC_CHANNEL_REC *channel)
{
SERVER_QUERY_REC *rec;
- g_return_if_fail(channel != NULL);
+ if (!IS_IRC_CHANNEL(channel))
+ return;
/* Add channel to query lists */
if (!channel->no_modes)
@@ -567,7 +568,7 @@ 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 joined", (SIGNAL_FUNC) sig_channel_joined);
signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
signal_add("chanquery mode", (SIGNAL_FUNC) event_channel_mode);
@@ -584,7 +585,7 @@ 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 joined", (SIGNAL_FUNC) sig_channel_joined);
signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
signal_remove("chanquery mode", (SIGNAL_FUNC) event_channel_mode);
diff --git a/src/irc/core/irc-channels.c b/src/irc/core/irc-channels.c
index fffd2445..7daba896 100644
--- a/src/irc/core/irc-channels.c
+++ b/src/irc/core/irc-channels.c
@@ -21,15 +21,16 @@
#include "module.h"
#include "signals.h"
#include "misc.h"
-
-#include "bans.h"
-#include "irc-channels.h"
+#include "levels.h"
#include "channels-setup.h"
+
#include "irc.h"
+#include "bans.h"
#include "modes.h"
-#include "levels.h"
#include "mode-lists.h"
+#include "irc-channels.h"
#include "irc-nicklist.h"
+#include "channel-rejoin.h"
void channels_query_init(void);
void channels_query_deinit(void);
@@ -37,9 +38,6 @@ void channels_query_deinit(void);
void channel_events_init(void);
void channel_events_deinit(void);
-void channel_rejoin_init(void);
-void channel_rejoin_deinit(void);
-
void massjoin_init(void);
void massjoin_deinit(void);
@@ -104,12 +102,12 @@ static void irc_channels_join(IRC_SERVER_REC *server, const char *data,
int use_keys;
g_return_if_fail(data != NULL);
- if (!IS_IRC_SERVER(server) || !server->connected)
- cmd_return_error(CMDERR_NOT_CONNECTED);
+ g_return_if_fail(IS_IRC_SERVER(server) && server->connected);
+ if (*data == '\0') return;
- if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST, &channels, &keys))
+ if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST,
+ &channels, &keys))
return;
- if (*channels == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
chanlist = g_strsplit(channels, ",", -1);
keylist = g_strsplit(keys, ",", -1);
@@ -202,7 +200,7 @@ void irc_channels_init(void)
signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
channel_events_init();
- channel_rejoin_init();
+ channel_rejoin_init(); /* after channel_events_init() */
channels_query_init();
channels_setup_init();
diff --git a/src/irc/core/irc-nicklist.c b/src/irc/core/irc-nicklist.c
index 420b3834..a107d15a 100644
--- a/src/irc/core/irc-nicklist.c
+++ b/src/irc/core/irc-nicklist.c
@@ -107,7 +107,7 @@ static void event_end_of_names(const char *data, SERVER_REC *server)
chanrec = irc_channel_find(server, channel);
if (chanrec != NULL && !chanrec->names_got) {
chanrec->names_got = TRUE;
- signal_emit("channel query", 1, chanrec);
+ signal_emit("channel joined", 1, chanrec);
}
g_free(params);