addition of silc.css
[crypto.git] / apps / irssi / src / core / servers-redirect.c
1 /*
2  server-redirect.c : irssi
3
4     Copyright (C) 1999-2000 Timo Sirainen
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "module.h"
22 #include "signals.h"
23 #include "misc.h"
24
25 #include "servers.h"
26 #include "servers-redirect.h"
27
28 static int redirect_group;
29
30 static void server_eventtable_destroy(char *key, GSList *value)
31 {
32         GSList *tmp;
33
34         g_free(key);
35
36         for (tmp = value; tmp != NULL; tmp = tmp->next) {
37                 REDIRECT_REC *rec = tmp->data;
38
39                 g_free_not_null(rec->arg);
40                 g_free(rec->name);
41                 g_free(rec);
42         }
43         g_slist_free(value);
44 }
45
46 static void server_eventgrouptable_destroy(gpointer key, GSList *value)
47 {
48         g_slist_foreach(value, (GFunc) g_free, NULL);
49         g_slist_free(value);
50 }
51
52 static void server_cmdtable_destroy(char *key, REDIRECT_CMD_REC *value)
53 {
54         g_free(key);
55
56         g_slist_foreach(value->events, (GFunc) g_free, NULL);
57         g_slist_free(value->events);
58         g_free(value);
59 }
60
61 static void sig_disconnected(SERVER_REC *server)
62 {
63         g_return_if_fail(IS_SERVER(server));
64
65         if (server->eventtable != NULL) {
66                 g_hash_table_foreach(server->eventtable,
67                                      (GHFunc) server_eventtable_destroy, NULL);
68                 g_hash_table_destroy(server->eventtable);
69         }
70
71         g_hash_table_foreach(server->eventgrouptable,
72                              (GHFunc) server_eventgrouptable_destroy, NULL);
73         g_hash_table_destroy(server->eventgrouptable);
74
75         if (server->cmdtable != NULL) {
76                 g_hash_table_foreach(server->cmdtable,
77                                      (GHFunc) server_cmdtable_destroy, NULL);
78                 g_hash_table_destroy(server->cmdtable);
79         }
80 }
81
82 void server_redirect_initv(SERVER_REC *server, const char *command,
83                            int last, GSList *list)
84 {
85         REDIRECT_CMD_REC *rec;
86
87         g_return_if_fail(IS_SERVER(server));
88         g_return_if_fail(command != NULL);
89         g_return_if_fail(last > 0);
90
91         if (g_hash_table_lookup(server->cmdtable, command) != NULL) {
92                 /* already in hash table. list of events SHOULD be the same. */
93                 g_slist_foreach(list, (GFunc) g_free, NULL);
94                 g_slist_free(list);
95                 return;
96         }
97
98         rec = g_new(REDIRECT_CMD_REC, 1);
99         rec->last = last;
100         rec->events = list;
101         g_hash_table_insert(server->cmdtable, g_strdup(command), rec);
102 }
103
104 void server_redirect_init(SERVER_REC *server, const char *command,
105                           int last, ...)
106 {
107         va_list args;
108         GSList *list;
109         char *event;
110
111         va_start(args, last);
112         list = NULL;
113         while ((event = va_arg(args, gchar *)) != NULL)
114                 list = g_slist_append(list, g_strdup(event));
115         va_end(args);
116
117         server_redirect_initv(server, command, last, list);
118 }
119
120 int server_redirect_single_event(SERVER_REC *server, const char *arg,
121                                  int last, int group, const char *event,
122                                  const char *signal, int argpos)
123 {
124         REDIRECT_REC *rec;
125         GSList *list, *grouplist;
126         char *origkey;
127
128         g_return_val_if_fail(IS_SERVER(server), 0);
129         g_return_val_if_fail(event != NULL, 0);
130         g_return_val_if_fail(signal != NULL, 0);
131         g_return_val_if_fail(arg != NULL || argpos == -1, 0);
132
133         if (group == 0) group = ++redirect_group;
134
135         rec = g_new0(REDIRECT_REC, 1);
136         rec->arg = arg == NULL ? NULL : g_strdup(arg);
137         rec->argpos = argpos;
138         rec->name = g_strdup(signal);
139         rec->group = group;
140         rec->last = last;
141
142         if (g_hash_table_lookup_extended(server->eventtable, event,
143                                          (gpointer *) &origkey,
144                                          (gpointer *) &list)) {
145                 g_hash_table_remove(server->eventtable, origkey);
146         } else {
147                 list = NULL;
148                 origkey = g_strdup(event);
149         }
150
151         grouplist = g_hash_table_lookup(server->eventgrouptable,
152                                         GINT_TO_POINTER(group));
153         if (grouplist != NULL) {
154                 g_hash_table_remove(server->eventgrouptable,
155                                     GINT_TO_POINTER(group));
156         }
157
158         list = g_slist_append(list, rec);
159         grouplist = g_slist_append(grouplist, g_strdup(event));
160
161         g_hash_table_insert(server->eventtable, origkey, list);
162         g_hash_table_insert(server->eventgrouptable,
163                             GINT_TO_POINTER(group), grouplist);
164
165         return group;
166 }
167
168 void server_redirect_event(SERVER_REC *server, const char *arg, int last, ...)
169 {
170         va_list args;
171         char *event, *signal;
172         int argpos, group;
173
174         g_return_if_fail(IS_SERVER(server));
175
176         va_start(args, last);
177
178         group = 0;
179         while ((event = va_arg(args, gchar *)) != NULL) {
180                 signal = va_arg(args, gchar *);
181                 argpos = va_arg(args, gint);
182
183                 group = server_redirect_single_event(server, arg, last > 0,
184                                                      group, event, signal,
185                                                      argpos);
186                 last--;
187         }
188
189         va_end(args);
190 }
191
192 void server_redirect_default(SERVER_REC *server, const char *command)
193 {
194         REDIRECT_CMD_REC *cmdrec;
195         REDIRECT_REC *rec;
196         GSList *events, *list, *grouplist;
197         char *event, *origkey;
198         int last;
199
200         g_return_if_fail(IS_SERVER(server));
201         g_return_if_fail(command != NULL);
202
203         if (server->cmdtable == NULL)
204                 return; /* not connected yet */
205
206         cmdrec = g_hash_table_lookup(server->cmdtable, command);
207         if (cmdrec == NULL) return;
208
209         /* add all events used by command to eventtable and eventgrouptable */
210         redirect_group++; grouplist = NULL; last = cmdrec->last;
211         for (events = cmdrec->events; events != NULL; events = events->next) {
212                 event = events->data;
213
214                 if (g_hash_table_lookup_extended(server->eventtable, event,
215                                                  (gpointer *) &origkey,
216                                                  (gpointer *) &list)) {
217                         g_hash_table_remove(server->eventtable, origkey);
218                 } else {
219                         list = NULL;
220                         origkey = g_strdup(event);
221                 }
222
223                 rec = g_new0(REDIRECT_REC, 1);
224                 rec->argpos = -1;
225                 rec->name = g_strdup(event);
226                 rec->group = redirect_group;
227                 rec->last = last > 0;
228
229                 grouplist = g_slist_append(grouplist, g_strdup(event));
230                 list = g_slist_append(list, rec);
231                 g_hash_table_insert(server->eventtable, origkey, list);
232
233                 last--;
234         }
235
236         g_hash_table_insert(server->eventgrouptable,
237                             GINT_TO_POINTER(redirect_group), grouplist);
238 }
239
240 void server_redirect_remove_next(SERVER_REC *server, const char *event,
241                                  GSList *item)
242 {
243         REDIRECT_REC *rec;
244         GSList *grouplist, *list, *events, *tmp;
245         char *origkey;
246         int group;
247
248         g_return_if_fail(IS_SERVER(server));
249         g_return_if_fail(event != NULL);
250
251         if (!g_hash_table_lookup_extended(server->eventtable, event,
252                                           (gpointer *) &origkey,
253                                           (gpointer *) &list))
254                 return;
255
256         rec = item == NULL ? list->data : item->data;
257         if (!rec->last) {
258                 /* this wasn't last expected event */
259                 return;
260         }
261         group = rec->group;
262
263         /* get list of events from this group */
264         grouplist = g_hash_table_lookup(server->eventgrouptable,
265                                         GINT_TO_POINTER(group));
266
267         /* remove all of them */
268         for (list = grouplist; list != NULL; list = list->next) {
269                 char *event = list->data;
270
271                 if (!g_hash_table_lookup_extended(server->eventtable, event,
272                                                   (gpointer *) &origkey,
273                                                   (gpointer *) &events)) {
274                         g_warning("server_redirect_remove_next() : "
275                                   "event in eventgrouptable but not in "
276                                   "eventtable");
277                         continue;
278                 }
279
280                 /* remove the right group */
281                 for (tmp = events; tmp != NULL; tmp = tmp->next) {
282                         rec = tmp->data;
283
284                         if (rec->group == group)
285                                 break;
286                 }
287
288                 if (rec == NULL) {
289                         g_warning("server_redirect_remove_next() : "
290                                   "event in eventgrouptable but not in "
291                                   "eventtable (group)");
292                         continue;
293                 }
294
295                 g_free(event);
296
297                 events = g_slist_remove(events, rec);
298                 g_free_not_null(rec->arg);
299                 g_free(rec->name);
300                 g_free(rec);
301
302                 /* update hash table */
303                 g_hash_table_remove(server->eventtable, origkey);
304                 if (events == NULL)
305                         g_free(origkey);
306                 else {
307                         g_hash_table_insert(server->eventtable,
308                                             origkey, events);
309                 }
310         }
311
312         g_hash_table_remove(server->eventgrouptable, GINT_TO_POINTER(group));
313         g_slist_free(grouplist);
314 }
315
316 GSList *server_redirect_getqueue(SERVER_REC *server, const char *event,
317                                  const char *args)
318 {
319         REDIRECT_REC *rec;
320         GSList *list;
321         char **arglist;
322         int found;
323
324         g_return_val_if_fail(IS_SERVER(server), NULL);
325         g_return_val_if_fail(event != NULL, NULL);
326
327         list = g_hash_table_lookup(server->eventtable, event);
328
329         for (; list != NULL; list = list->next) {
330                 rec = list->data;
331                 if (rec->argpos == -1)
332                         break;
333
334                 if (rec->arg == NULL || args == NULL)
335                         continue;
336
337                 /* we need to check that the argument is right.. */
338                 arglist = g_strsplit(args, " ", -1);
339                 found = (strarray_length(arglist) > rec->argpos &&
340                          find_substr(rec->arg, arglist[rec->argpos]));
341                 g_strfreev(arglist);
342
343                 if (found) break;
344         }
345
346         return list;
347 }
348
349 void servers_redirect_init(void)
350 {
351         redirect_group = 0;
352
353         signal_add("server disconnected", (SIGNAL_FUNC) sig_disconnected);
354 }
355
356 void servers_redirect_deinit(void)
357 {
358         signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
359 }