diff options
Diffstat (limited to 'src/core/servers-redirect.c')
-rw-r--r-- | src/core/servers-redirect.c | 359 |
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); +} |