summaryrefslogtreecommitdiff
path: root/src/fe-common/irc/fe-netjoin.c
diff options
context:
space:
mode:
authorTimo Sirainen <cras@irssi.org>2000-07-02 16:19:26 +0000
committercras <cras@dbcabf3a-b0e7-0310-adc4-f8d773084564>2000-07-02 16:19:26 +0000
commitbb76eec0ffc836eaaccd35c2979fc092f1a9c520 (patch)
tree66b8de0e26e86b419d76729cb86ab50a2324883d /src/fe-common/irc/fe-netjoin.c
parentcf7d6915f5cfff985cee06643644e1f176a0d28d (diff)
downloadirssi-bb76eec0ffc836eaaccd35c2979fc092f1a9c520.zip
When netsplit is over, irssi prints "Netsplit over, joins: (nicks)" and
hides all the real JOIN messages. Fixed also some netsplit bugs. git-svn-id: http://svn.irssi.org/repos/irssi/trunk@414 dbcabf3a-b0e7-0310-adc4-f8d773084564
Diffstat (limited to 'src/fe-common/irc/fe-netjoin.c')
-rw-r--r--src/fe-common/irc/fe-netjoin.c307
1 files changed, 307 insertions, 0 deletions
diff --git a/src/fe-common/irc/fe-netjoin.c b/src/fe-common/irc/fe-netjoin.c
new file mode 100644
index 00000000..ffb1d93e
--- /dev/null
+++ b/src/fe-common/irc/fe-netjoin.c
@@ -0,0 +1,307 @@
+/*
+ fe-netjoin.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 "module-formats.h"
+#include "signals.h"
+#include "levels.h"
+#include "misc.h"
+#include "settings.h"
+
+#include "irc.h"
+#include "irc-server.h"
+#include "ignore.h"
+#include "netsplit.h"
+
+#define NETJOIN_WAIT_TIME 2 /* how many seconds to wait for the netsplitted JOIN messages to stop */
+#define NETJOIN_MAX_WAIT 30 /* how many seconds to wait for nick to join to the rest of the channels she was before the netsplit */
+
+typedef struct {
+ char *nick;
+ GSList *old_channels;
+ GSList *now_channels;
+} NETJOIN_REC;
+
+typedef struct {
+ IRC_SERVER_REC *server;
+ time_t last_netjoin;
+
+ GSList *netjoins;
+} NETJOIN_SERVER_REC;
+
+typedef struct {
+ int count;
+ GString *nicks;
+} TEMP_PRINT_REC;
+
+static int join_tag;
+static int netjoin_max_nicks, hide_netsplit_quits;
+static GSList *joinservers;
+
+static NETJOIN_SERVER_REC *netjoin_find_server(IRC_SERVER_REC *server)
+{
+ GSList *tmp;
+
+ g_return_val_if_fail(server != NULL, NULL);
+
+ for (tmp = joinservers; tmp != NULL; tmp = tmp->next) {
+ NETJOIN_SERVER_REC *rec = tmp->data;
+
+ if (rec->server == server)
+ return rec;
+ }
+
+ return NULL;
+}
+
+static NETJOIN_REC *netjoin_add(IRC_SERVER_REC *server, const char *nick, GSList *channels)
+{
+ NETJOIN_REC *rec;
+ NETJOIN_SERVER_REC *srec;
+
+ g_return_val_if_fail(server != NULL, NULL);
+ g_return_val_if_fail(nick != NULL, NULL);
+ g_return_val_if_fail(channels != NULL, NULL);
+
+ rec = g_new0(NETJOIN_REC, 1);
+ rec->nick = g_strdup(nick);
+ while (channels != NULL) {
+ NETSPLIT_CHAN_REC *channel = channels->data;
+
+ rec->old_channels = g_slist_append(rec->old_channels, g_strdup(channel->name));
+ channels = channels->next;
+ }
+
+ srec = netjoin_find_server(server);
+ if (srec == NULL) {
+ srec = g_new0(NETJOIN_SERVER_REC, 1);
+ srec->server = server;
+ joinservers = g_slist_append(joinservers, srec);
+ }
+
+ srec->last_netjoin = time(NULL);
+ srec->netjoins = g_slist_append(srec->netjoins, rec);
+ return rec;
+}
+
+static NETJOIN_REC *netjoin_find(IRC_SERVER_REC *server, const char *nick)
+{
+ NETJOIN_SERVER_REC *srec;
+ GSList *tmp;
+
+ g_return_val_if_fail(server != NULL, NULL);
+ g_return_val_if_fail(nick != NULL, NULL);
+
+ srec = netjoin_find_server(server);
+ if (srec == NULL) return NULL;
+
+ for (tmp = srec->netjoins; tmp != NULL; tmp = tmp->next) {
+ NETJOIN_REC *rec = tmp->data;
+
+ if (g_strcasecmp(rec->nick, nick) == 0)
+ return rec;
+ }
+
+ return NULL;
+}
+
+int netsplit_is_join(IRC_SERVER_REC *server, const char *nick, const char *address)
+{
+ return netsplit_find(server, nick, address) ||
+ netjoin_find(server, nick);
+}
+
+static void netjoin_remove(NETJOIN_SERVER_REC *server, NETJOIN_REC *rec)
+{
+ server->netjoins = g_slist_remove(server->netjoins, rec);
+
+ g_slist_foreach(rec->old_channels, (GFunc) g_free, NULL);
+ g_slist_foreach(rec->now_channels, (GFunc) g_free, NULL);
+ g_slist_free(rec->old_channels);
+ g_slist_free(rec->now_channels);
+
+ g_free(rec->nick);
+ g_free(rec);
+}
+
+static void netjoin_server_remove(NETJOIN_SERVER_REC *server)
+{
+ joinservers = g_slist_remove(joinservers, server);
+
+ while (server->netjoins != NULL)
+ netjoin_remove(server, server->netjoins->data);
+ g_free(server);
+}
+
+static void print_channel_netjoins(char *channel, TEMP_PRINT_REC *rec, NETJOIN_SERVER_REC *server)
+{
+ if (rec->nicks->len > 0)
+ g_string_truncate(rec->nicks, rec->nicks->len-2);
+
+ printformat(server->server, channel, MSGLEVEL_JOINS,
+ rec->count > netjoin_max_nicks ? IRCTXT_NETSPLIT_JOIN_MORE : IRCTXT_NETSPLIT_JOIN,
+ rec->nicks->str, rec->count-netjoin_max_nicks);
+
+ g_string_free(rec->nicks, TRUE);
+ g_free(rec);
+ g_free(channel);
+}
+
+static void print_netjoins(NETJOIN_SERVER_REC *server)
+{
+ TEMP_PRINT_REC *temp;
+ GHashTable *channels;
+ GSList *tmp, *next, *old;
+
+ g_return_if_fail(server != NULL);
+
+ /* save nicks to string, clear now_channels and remove the same
+ channels from old_channels list */
+ channels = g_hash_table_new((GHashFunc) g_istr_hash, (GCompareFunc) g_istr_equal);
+ for (tmp = server->netjoins; tmp != NULL; tmp = next) {
+ NETJOIN_REC *rec = tmp->data;
+
+ next = tmp->next;
+ while (rec->now_channels != NULL) {
+ char *channel = rec->now_channels->data;
+
+ temp = g_hash_table_lookup(channels, channel);
+ if (temp == NULL) {
+ temp = g_new0(TEMP_PRINT_REC, 1);
+ temp->nicks = g_string_new(NULL);
+ g_hash_table_insert(channels, g_strdup(channel), temp);
+ }
+
+ temp->count++;
+ if (temp->count <= netjoin_max_nicks)
+ g_string_sprintfa(temp->nicks, "%s, ", rec->nick);
+
+ /* remove the channel from old_channels too */
+ old = gslist_find_icase_string(rec->old_channels, channel);
+ if (old != NULL) {
+ g_free(old->data);
+ rec->old_channels = g_slist_remove(rec->old_channels, old->data);
+ }
+
+ g_free(channel);
+ rec->now_channels = g_slist_remove(rec->now_channels, channel);
+ }
+
+ if (rec->old_channels == NULL)
+ netjoin_remove(server, rec);
+ }
+
+ g_hash_table_foreach(channels, (GHFunc) print_channel_netjoins, server);
+ g_hash_table_destroy(channels);
+
+ if (server->netjoins == NULL)
+ netjoin_server_remove(server);
+}
+
+static int sig_check_netjoins(void)
+{
+ GSList *tmp, *next;
+ int diff;
+
+ for (tmp = joinservers; tmp != NULL; tmp = next) {
+ NETJOIN_SERVER_REC *server = tmp->data;
+
+ next = tmp->next;
+ diff = time(NULL)-server->last_netjoin;
+ if (diff <= NETJOIN_WAIT_TIME) {
+ /* wait for more JOINs */
+ continue;
+ }
+
+ if (server->netjoins != NULL)
+ print_netjoins(server);
+ else if (diff >= NETJOIN_MAX_WAIT) {
+ /* waited long enough, remove the netjoin */
+ netjoin_server_remove(server);
+ }
+ }
+
+ if (joinservers == NULL) {
+ g_source_remove(join_tag);
+ join_tag = -1;
+ }
+ return 1;
+}
+
+static void event_join(const char *data, IRC_SERVER_REC *server, const char *nick, const char *address)
+{
+ NETSPLIT_REC *split;
+ NETJOIN_REC *netjoin;
+ char *params, *channel, *tmp;
+
+ g_return_if_fail(data != NULL);
+
+ split = netsplit_find(server, nick, address);
+ netjoin = netjoin_find(server, nick);
+ if (split == NULL && netjoin == NULL)
+ return;
+
+ params = event_get_params(data, 1, &channel);
+ tmp = strchr(channel, 7); /* ^G does something weird.. */
+ if (tmp != NULL) *tmp = '\0';
+
+ if (!ignore_check(server, nick, address, channel, NULL, MSGLEVEL_JOINS)) {
+ if (join_tag == -1)
+ join_tag = g_timeout_add(1000, (GSourceFunc) sig_check_netjoins, NULL);
+
+ if (netjoin == NULL)
+ netjoin = netjoin_add(server, nick, split->channels);
+
+ netjoin->now_channels = g_slist_append(netjoin->now_channels, g_strdup(channel));
+ }
+ g_free(params);
+}
+
+static void read_settings(void)
+{
+ int old_hide;
+
+ old_hide = hide_netsplit_quits;
+ hide_netsplit_quits = settings_get_bool("hide_netsplit_quits");
+ netjoin_max_nicks = settings_get_int("netjoin_max_nicks");
+
+ if (old_hide && !hide_netsplit_quits)
+ signal_remove("event join", (SIGNAL_FUNC) event_join);
+ else if (!old_hide && hide_netsplit_quits)
+ signal_add("event join", (SIGNAL_FUNC) event_join);
+}
+
+void fe_netjoin_init(void)
+{
+ settings_add_int("misc", "netjoin_max_nicks", 10);
+ join_tag = -1;
+
+ read_settings();
+ signal_add("setup changed", (SIGNAL_FUNC) read_settings);
+}
+
+void fe_netjoin_deinit(void)
+{
+ while (joinservers != NULL)
+ netjoin_server_remove(joinservers->data);
+ if (join_tag != -1) g_source_remove(join_tag);
+
+ signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
+}