summaryrefslogtreecommitdiff
path: root/src/core/servers-redirect.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/servers-redirect.c')
-rw-r--r--src/core/servers-redirect.c359
1 files changed, 359 insertions, 0 deletions
diff --git a/src/core/servers-redirect.c b/src/core/servers-redirect.c
new file mode 100644
index 00000000..ca340fc6
--- /dev/null
+++ b/src/core/servers-redirect.c
@@ -0,0 +1,359 @@
+/*
+ server-redirect.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 "servers.h"
+#include "servers-redirect.h"
+
+static int redirect_group;
+
+static void server_eventtable_destroy(char *key, GSList *value)
+{
+ GSList *tmp;
+
+ g_free(key);
+
+ for (tmp = value; tmp != NULL; tmp = tmp->next) {
+ REDIRECT_REC *rec = tmp->data;
+
+ g_free_not_null(rec->arg);
+ g_free(rec->name);
+ g_free(rec);
+ }
+ g_slist_free(value);
+}
+
+static void server_eventgrouptable_destroy(gpointer key, GSList *value)
+{
+ g_slist_foreach(value, (GFunc) g_free, NULL);
+ g_slist_free(value);
+}
+
+static void server_cmdtable_destroy(char *key, REDIRECT_CMD_REC *value)
+{
+ g_free(key);
+
+ g_slist_foreach(value->events, (GFunc) g_free, NULL);
+ g_slist_free(value->events);
+ g_free(value);
+}
+
+static void sig_disconnected(SERVER_REC *server)
+{
+ g_return_if_fail(IS_SERVER(server));
+
+ if (server->eventtable != NULL) {
+ g_hash_table_foreach(server->eventtable,
+ (GHFunc) server_eventtable_destroy, NULL);
+ g_hash_table_destroy(server->eventtable);
+ }
+
+ g_hash_table_foreach(server->eventgrouptable,
+ (GHFunc) server_eventgrouptable_destroy, NULL);
+ g_hash_table_destroy(server->eventgrouptable);
+
+ if (server->cmdtable != NULL) {
+ g_hash_table_foreach(server->cmdtable,
+ (GHFunc) server_cmdtable_destroy, NULL);
+ g_hash_table_destroy(server->cmdtable);
+ }
+}
+
+void server_redirect_initv(SERVER_REC *server, const char *command,
+ int last, GSList *list)
+{
+ REDIRECT_CMD_REC *rec;
+
+ g_return_if_fail(IS_SERVER(server));
+ g_return_if_fail(command != NULL);
+ g_return_if_fail(last > 0);
+
+ if (g_hash_table_lookup(server->cmdtable, command) != NULL) {
+ /* already in hash table. list of events SHOULD be the same. */
+ g_slist_foreach(list, (GFunc) g_free, NULL);
+ g_slist_free(list);
+ return;
+ }
+
+ rec = g_new(REDIRECT_CMD_REC, 1);
+ rec->last = last;
+ rec->events = list;
+ g_hash_table_insert(server->cmdtable, g_strdup(command), rec);
+}
+
+void server_redirect_init(SERVER_REC *server, const char *command,
+ int last, ...)
+{
+ va_list args;
+ GSList *list;
+ char *event;
+
+ va_start(args, last);
+ list = NULL;
+ while ((event = va_arg(args, gchar *)) != NULL)
+ list = g_slist_append(list, g_strdup(event));
+ va_end(args);
+
+ server_redirect_initv(server, command, last, list);
+}
+
+int server_redirect_single_event(SERVER_REC *server, const char *arg,
+ int last, int group, const char *event,
+ const char *signal, int argpos)
+{
+ REDIRECT_REC *rec;
+ GSList *list, *grouplist;
+ char *origkey;
+
+ g_return_val_if_fail(IS_SERVER(server), 0);
+ g_return_val_if_fail(event != NULL, 0);
+ g_return_val_if_fail(signal != NULL, 0);
+ g_return_val_if_fail(arg != NULL || argpos == -1, 0);
+
+ if (group == 0) group = ++redirect_group;
+
+ rec = g_new0(REDIRECT_REC, 1);
+ rec->arg = arg == NULL ? NULL : g_strdup(arg);
+ rec->argpos = argpos;
+ rec->name = g_strdup(signal);
+ rec->group = group;
+ rec->last = last;
+
+ if (g_hash_table_lookup_extended(server->eventtable, event,
+ (gpointer *) &origkey,
+ (gpointer *) &list)) {
+ g_hash_table_remove(server->eventtable, origkey);
+ } else {
+ list = NULL;
+ origkey = g_strdup(event);
+ }
+
+ grouplist = g_hash_table_lookup(server->eventgrouptable,
+ GINT_TO_POINTER(group));
+ if (grouplist != NULL) {
+ g_hash_table_remove(server->eventgrouptable,
+ GINT_TO_POINTER(group));
+ }
+
+ list = g_slist_append(list, rec);
+ grouplist = g_slist_append(grouplist, g_strdup(event));
+
+ g_hash_table_insert(server->eventtable, origkey, list);
+ g_hash_table_insert(server->eventgrouptable,
+ GINT_TO_POINTER(group), grouplist);
+
+ return group;
+}
+
+void server_redirect_event(SERVER_REC *server, const char *arg, int last, ...)
+{
+ va_list args;
+ char *event, *signal;
+ int argpos, group;
+
+ g_return_if_fail(IS_SERVER(server));
+
+ va_start(args, last);
+
+ group = 0;
+ while ((event = va_arg(args, gchar *)) != NULL) {
+ signal = va_arg(args, gchar *);
+ argpos = va_arg(args, gint);
+
+ group = server_redirect_single_event(server, arg, last > 0,
+ group, event, signal,
+ argpos);
+ last--;
+ }
+
+ va_end(args);
+}
+
+void server_redirect_default(SERVER_REC *server, const char *command)
+{
+ REDIRECT_CMD_REC *cmdrec;
+ REDIRECT_REC *rec;
+ GSList *events, *list, *grouplist;
+ char *event, *origkey;
+ int last;
+
+ g_return_if_fail(IS_SERVER(server));
+ g_return_if_fail(command != NULL);
+
+ if (server->cmdtable == NULL)
+ return; /* not connected yet */
+
+ cmdrec = g_hash_table_lookup(server->cmdtable, command);
+ if (cmdrec == NULL) return;
+
+ /* add all events used by command to eventtable and eventgrouptable */
+ redirect_group++; grouplist = NULL; last = cmdrec->last;
+ for (events = cmdrec->events; events != NULL; events = events->next) {
+ event = events->data;
+
+ if (g_hash_table_lookup_extended(server->eventtable, event,
+ (gpointer *) &origkey,
+ (gpointer *) &list)) {
+ g_hash_table_remove(server->eventtable, origkey);
+ } else {
+ list = NULL;
+ origkey = g_strdup(event);
+ }
+
+ rec = g_new0(REDIRECT_REC, 1);
+ rec->argpos = -1;
+ rec->name = g_strdup(event);
+ rec->group = redirect_group;
+ rec->last = last > 0;
+
+ grouplist = g_slist_append(grouplist, g_strdup(event));
+ list = g_slist_append(list, rec);
+ g_hash_table_insert(server->eventtable, origkey, list);
+
+ last--;
+ }
+
+ g_hash_table_insert(server->eventgrouptable,
+ GINT_TO_POINTER(redirect_group), grouplist);
+}
+
+void server_redirect_remove_next(SERVER_REC *server, const char *event,
+ GSList *item)
+{
+ REDIRECT_REC *rec;
+ GSList *grouplist, *list, *events, *tmp;
+ char *origkey;
+ int group;
+
+ g_return_if_fail(IS_SERVER(server));
+ g_return_if_fail(event != NULL);
+
+ if (!g_hash_table_lookup_extended(server->eventtable, event,
+ (gpointer *) &origkey,
+ (gpointer *) &list))
+ return;
+
+ rec = item == NULL ? list->data : item->data;
+ if (!rec->last) {
+ /* this wasn't last expected event */
+ return;
+ }
+ group = rec->group;
+
+ /* get list of events from this group */
+ grouplist = g_hash_table_lookup(server->eventgrouptable,
+ GINT_TO_POINTER(group));
+
+ /* remove all of them */
+ for (list = grouplist; list != NULL; list = list->next) {
+ char *event = list->data;
+
+ if (!g_hash_table_lookup_extended(server->eventtable, event,
+ (gpointer *) &origkey,
+ (gpointer *) &events)) {
+ g_warning("server_redirect_remove_next() : "
+ "event in eventgrouptable but not in "
+ "eventtable");
+ continue;
+ }
+
+ /* remove the right group */
+ for (tmp = events; tmp != NULL; tmp = tmp->next) {
+ rec = tmp->data;
+
+ if (rec->group == group)
+ break;
+ }
+
+ if (rec == NULL) {
+ g_warning("server_redirect_remove_next() : "
+ "event in eventgrouptable but not in "
+ "eventtable (group)");
+ continue;
+ }
+
+ g_free(event);
+
+ events = g_slist_remove(events, rec);
+ g_free_not_null(rec->arg);
+ g_free(rec->name);
+ g_free(rec);
+
+ /* update hash table */
+ g_hash_table_remove(server->eventtable, origkey);
+ if (events == NULL)
+ g_free(origkey);
+ else {
+ g_hash_table_insert(server->eventtable,
+ origkey, events);
+ }
+ }
+
+ g_hash_table_remove(server->eventgrouptable, GINT_TO_POINTER(group));
+ g_slist_free(grouplist);
+}
+
+GSList *server_redirect_getqueue(SERVER_REC *server, const char *event,
+ const char *args)
+{
+ REDIRECT_REC *rec;
+ GSList *list;
+ char **arglist;
+ int found;
+
+ g_return_val_if_fail(IS_SERVER(server), NULL);
+ g_return_val_if_fail(event != NULL, NULL);
+
+ list = g_hash_table_lookup(server->eventtable, event);
+
+ for (; list != NULL; list = list->next) {
+ rec = list->data;
+ if (rec->argpos == -1)
+ break;
+
+ if (rec->arg == NULL || args == NULL)
+ continue;
+
+ /* we need to check that the argument is right.. */
+ arglist = g_strsplit(args, " ", -1);
+ found = (strarray_length(arglist) > rec->argpos &&
+ find_substr(rec->arg, arglist[rec->argpos]));
+ g_strfreev(arglist);
+
+ if (found) break;
+ }
+
+ return list;
+}
+
+void servers_redirect_init(void)
+{
+ redirect_group = 0;
+
+ signal_add("server disconnected", (SIGNAL_FUNC) sig_disconnected);
+}
+
+void servers_redirect_deinit(void)
+{
+ signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
+}