Bug Summary

File:irc/core/servers-redirect.c
Location:line 566, column 9
Description:Uninitialized or undefined return value returned to caller.

Annotated Source Code

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 along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20
21#include "module.h"
22#include "signals.h"
23#include "misc.h"
24#include "rawlog.h"
25
26#include "irc-servers.h"
27#include "servers-redirect.h"
28
29#define DEFAULT_REDIRECT_TIMEOUT60 60
30
31/* Allow one non-expected redirections to come before the expected one
32 before aborting it. Some IRC bouncers/proxies reply to eg. PINGs
33 immediately. */
34#define MAX_FAILURE_COUNT1 1
35
36typedef struct {
37 char *name;
38 int refcount;
39
40 int remote;
41 int timeout;
42 GSList *start, *stop, *opt; /* char *event, int argpos, ... */
43} REDIRECT_CMD_REC;
44
45struct _REDIRECT_REC {
46 REDIRECT_CMD_REC *cmd;
47 time_t created;
48 int failures;
49 char *prefix;
50
51 unsigned int destroyed:1;
52 unsigned int aborted:1;
53 unsigned int remote:1;
54 unsigned int first_signal_sent:1;
55
56 char *arg;
57 int count;
58 char *failure_signal, *default_signal, *first_signal, *last_signal;
59 GSList *signals; /* event, signal, ... */
60};
61
62static GHashTable *command_redirects; /* "command xxx" : REDIRECT_CMD_REC* */
63
64/* Find redirection command record for specified command line. */
65static REDIRECT_CMD_REC *redirect_cmd_find(const char *command)
66{
67 REDIRECT_CMD_REC *rec;
68 const char *p;
69 char *cmd;
70
71 p = strchr(command, ' ');
72 if (p == NULL((void *)0))
73 rec = g_hash_table_lookup(command_redirects, command);
74 else {
75 cmd = g_strndup(command, (int) (p-command));
76 rec = g_hash_table_lookup(command_redirects, cmd);
77 g_free(cmd);
78 }
79 return rec;
80}
81
82static void redirect_cmd_destroy(REDIRECT_CMD_REC *rec)
83{
84 GSList *tmp;
85
86 for (tmp = rec->start; tmp != NULL((void *)0); tmp = tmp->next->next)
87 g_free(tmp->data);
88 for (tmp = rec->stop; tmp != NULL((void *)0); tmp = tmp->next->next)
89 g_free(tmp->data);
90 for (tmp = rec->opt; tmp != NULL((void *)0); tmp = tmp->next->next)
91 g_free(tmp->data);
92 g_slist_free(rec->start);
93 g_slist_free(rec->stop);
94 g_slist_free(rec->opt);
95 g_free(rec->name);
96 g_free(rec);
97}
98
99static void redirect_cmd_ref(REDIRECT_CMD_REC *rec)
100{
101 rec->refcount++;
102}
103
104static void redirect_cmd_unref(REDIRECT_CMD_REC *rec)
105{
106 if (--rec->refcount <= 0)
107 redirect_cmd_destroy(rec);
108}
109
110void server_redirect_destroy(REDIRECT_REC *rec)
111{
112 redirect_cmd_unref(rec->cmd);
113
114 g_free_not_null(rec->prefix)g_free(rec->prefix);
115 g_free_not_null(rec->arg)g_free(rec->arg);
116 g_free_not_null(rec->failure_signal)g_free(rec->failure_signal);
117 g_free_not_null(rec->default_signal)g_free(rec->default_signal);
118 g_free_not_null(rec->first_signal)g_free(rec->first_signal);
119 g_free_not_null(rec->last_signal)g_free(rec->last_signal);
120 g_slist_foreach(rec->signals, (GFunc) g_free, NULL((void *)0));
121 g_slist_free(rec->signals);
122 g_free(rec);
123}
124
125void server_redirect_register(const char *command,
126 int remote, int timeout, ...)
127{
128 va_list va;
129 GSList *start, *stop, *opt, **list;
130 const char *event;
131 int argpos;
132
133 va_start(va, timeout)__builtin_va_start((va), (timeout));
134 start = stop = opt = NULL((void *)0); list = &start;
135 for (;;) {
136 event = va_arg(va, const char *)__builtin_va_arg((va), const char *);
137 if (event == NULL((void *)0)) {
138 if (list == &start)
139 list = &stop;
140 else if (list == &stop)
141 list = &opt;
142 else
143 break;
144 continue;
145 }
146
147 argpos = va_arg(va, int)__builtin_va_arg((va), int);
148 *list = g_slist_append(*list, g_strdup(event));
149 *list = g_slist_append(*list, GINT_TO_POINTER(argpos)((gpointer) (argpos)));
150 }
151
152 va_end(va)__builtin_va_end(va);
153
154 server_redirect_register_list(command, remote, timeout,
155 start, stop, opt);
156}
157
158void server_redirect_register_list(const char *command,
159 int remote, int timeout,
160 GSList *start, GSList *stop, GSList *opt)
161{
162 REDIRECT_CMD_REC *rec;
163 gpointer key, value;
164
165 g_return_if_fail(command != NULL)do{ if (command != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "command != NULL"); return
; }; }while (0)
;
166 g_return_if_fail(stop != NULL)do{ if (stop != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "stop != NULL"); return;
}; }while (0)
;
167
168 if (g_hash_table_lookup_extended(command_redirects, command,
169 &key, &value)) {
170 /* Already registered - might have changed so destroy
171 the old one */
172 g_hash_table_remove(command_redirects, command);
173 redirect_cmd_unref(value);
174 }
175
176 rec = g_new0(REDIRECT_CMD_REC, 1)((REDIRECT_CMD_REC *) g_malloc0 (((gsize) sizeof (REDIRECT_CMD_REC
)) * ((gsize) (1))))
;
177 redirect_cmd_ref(rec);
178 rec->name = g_strdup(command);
179 rec->remote = remote;
180 rec->timeout = timeout > 0 ? timeout : DEFAULT_REDIRECT_TIMEOUT60;
181 rec->start = start;
182 rec->stop = stop;
183 rec->opt = opt;
184 g_hash_table_insert(command_redirects, rec->name, rec);
185}
186
187void server_redirect_event(IRC_SERVER_REC *server, const char *command,
188 int count, const char *arg, int remote,
189 const char *failure_signal, ...)
190{
191 GSList *signals;
192 const char *event, *signal;
193 va_list va;
194
195 va_start(va, failure_signal)__builtin_va_start((va), (failure_signal));
196 signals = NULL((void *)0);
197 while ((event = va_arg(va, const char *)__builtin_va_arg((va), const char *)) != NULL((void *)0)) {
198 signal = va_arg(va, const char *)__builtin_va_arg((va), const char *);
199 if (signal == NULL((void *)0)) {
200 g_warning("server_redirect_event(%s): "g_log (((gchar*) 0), G_LOG_LEVEL_WARNING, "server_redirect_event(%s): "
"signal not specified for event", command)
201 "signal not specified for event", command)g_log (((gchar*) 0), G_LOG_LEVEL_WARNING, "server_redirect_event(%s): "
"signal not specified for event", command)
;
202 break;
203 }
204
205 signals = g_slist_append(signals, g_strdup(event));
206 signals = g_slist_append(signals, g_strdup(signal));
207 }
208
209 va_end(va)__builtin_va_end(va);
210
211 server_redirect_event_list(server, command, count, arg, remote,
212 failure_signal, signals);
213}
214
215/* Find specified event from signals list. If it's found, remove it from the
216 list and return it's target signal. */
217static char *signal_list_move(GSList **signals, const char *event)
218{
219 GSList *link;
220 char *linkevent, *linksignal;
221
222 link = gslist_find_string(*signals, event);
223 if (link == NULL((void *)0))
224 return NULL((void *)0);
225
226 linkevent = link->data;
227 linksignal = link->next->data;
228
229 *signals = g_slist_remove(*signals, linkevent);
230 *signals = g_slist_remove(*signals, linksignal);
231
232 g_free(linkevent);
233 return linksignal;
234}
235
236void server_redirect_event_list(IRC_SERVER_REC *server, const char *command,
237 int count, const char *arg, int remote,
238 const char *failure_signal, GSList *signals)
239{
240 REDIRECT_CMD_REC *cmdrec;
241 REDIRECT_REC *rec;
242
243 g_return_if_fail(IS_IRC_SERVER(server))do{ if ((((IRC_SERVER_REC *) chat_protocol_check_cast(((SERVER_REC
*) module_check_cast(server, __builtin_offsetof(SERVER_REC, type
), "SERVER")), __builtin_offsetof(IRC_SERVER_REC, chat_type),
"IRC")) ? (!(0)) : (0))) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "IS_IRC_SERVER(server)")
; return; }; }while (0)
;
244 g_return_if_fail(command != NULL)do{ if (command != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "command != NULL"); return
; }; }while (0)
;
245 g_return_if_fail((g_slist_length(signals) & 1) == 0)do{ if ((g_slist_length(signals) & 1) == 0) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "(g_slist_length(signals) & 1) == 0"
); return; }; }while (0)
;
246
247 cmdrec = g_hash_table_lookup(command_redirects, command);
248 if (cmdrec == NULL((void *)0)) {
249 g_warning("Unknown redirection command: %s", command)g_log (((gchar*) 0), G_LOG_LEVEL_WARNING, "Unknown redirection command: %s"
, command)
;
250 return;
251 }
252
253 redirect_cmd_ref(cmdrec);
254
255 rec = g_new0(REDIRECT_REC, 1)((REDIRECT_REC *) g_malloc0 (((gsize) sizeof (REDIRECT_REC)) *
((gsize) (1))))
;
256 rec->created = time(NULL((void *)0));
257 rec->cmd = cmdrec;
258 rec->arg = g_strdup(arg);
259 rec->count = count;
260 rec->remote = remote != -1 ? remote : cmdrec->remote;
261 rec->failure_signal = g_strdup(failure_signal);
262
263 rec->default_signal = signal_list_move(&signals, "");
264 rec->first_signal = signal_list_move(&signals, "redirect first");
265 rec->last_signal = signal_list_move(&signals, "redirect last");
266 rec->signals = signals;
267
268 if (server->redirect_next != NULL((void *)0))
269 server_redirect_destroy(server->redirect_next);
270 server->redirect_next = rec;
271}
272
273void server_redirect_command(IRC_SERVER_REC *server, const char *command,
274 REDIRECT_REC *redirect)
275{
276 REDIRECT_CMD_REC *cmdrec;
277
278 g_return_if_fail(IS_IRC_SERVER(server))do{ if ((((IRC_SERVER_REC *) chat_protocol_check_cast(((SERVER_REC
*) module_check_cast(server, __builtin_offsetof(SERVER_REC, type
), "SERVER")), __builtin_offsetof(IRC_SERVER_REC, chat_type),
"IRC")) ? (!(0)) : (0))) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "IS_IRC_SERVER(server)")
; return; }; }while (0)
;
279 g_return_if_fail(command != NULL)do{ if (command != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "command != NULL"); return
; }; }while (0)
;
280
281 if (redirect == NULL((void *)0)) {
282 /* no redirection wanted, but still register the command
283 so future redirections wont get messed up. */
284 cmdrec = redirect_cmd_find(command);
285 if (cmdrec == NULL((void *)0))
286 return;
287
288 redirect_cmd_ref(cmdrec);
289
290 redirect = g_new0(REDIRECT_REC, 1)((REDIRECT_REC *) g_malloc0 (((gsize) sizeof (REDIRECT_REC)) *
((gsize) (1))))
;
291 redirect->created = time(NULL((void *)0));
292 redirect->cmd = cmdrec;
293 redirect->remote = cmdrec->remote;
294 }
295
296 server->redirects = g_slist_append(server->redirects, redirect);
297}
298
299static int redirect_args_match(const char *event_args,
300 const char *arg, int pos)
301{
302 const char *start;
303
304 if (pos == -1)
305 return TRUE(!(0));
306
307 /* skip to the start of the wanted argument */
308 while (pos > 0 && *event_args != '\0') {
309 while (*event_args != ' ' && *event_args != '\0') event_args++;
310 while (*event_args == ' ') event_args++;
311 pos--;
312 }
313
314 /* now compare the arguments */
315 start = event_args;
316 while (*arg != '\0') {
317 while (*arg != '\0' && *arg != ' ' && *event_args != '\0') {
318 if (i_toupper(*arg)__sbtoupper((int) (unsigned char) (*arg)) != i_toupper(*event_args)__sbtoupper((int) (unsigned char) (*event_args)))
319 break;
320 arg++; event_args++;
321 }
322
323 if ((*arg == '\0' || *arg == ' ') &&
324 (*event_args == '\0' || *event_args == ' '))
325 return TRUE(!(0));
326
327 /* compare the next argument */
328 while (*arg != ' ' && *arg != '\0') arg++;
329 while (*arg == ' ') arg++;
330
331 event_args = start;
332 }
333
334 return FALSE(0);
335}
336
337static GSList *redirect_cmd_list_find(GSList *list, const char *event)
338{
339 while (list != NULL((void *)0)) {
340 const char *str = list->data;
341
342 if (strcmp(str, event) == 0)
343 break;
344 list = list->next->next;
345 }
346
347 return list;
348}
349
350#define MATCH_NONE0 0
351#define MATCH_START1 1
352#define MATCH_STOP2 2
353
354static const char *redirect_match(REDIRECT_REC *redirect, const char *event,
355 const char *args, int *match)
356{
357 GSList *tmp, *cmdpos;
358 const char *signal;
359 int match_list;
360
361 if (redirect->aborted)
362 return NULL((void *)0);
363
364 /* get the signal for redirection event - if it's not found we'll
365 use the default signal */
366 signal = NULL((void *)0);
367 for (tmp = redirect->signals; tmp != NULL((void *)0); tmp = tmp->next->next) {
368 if (strcmp(tmp->data, event) == 0) {
369 signal = tmp->next->data;
370 break;
371 }
372 }
373
374 /* find the argument position */
375 if (redirect->destroyed) {
376 /* stop event is already found for this redirection, but
377 we'll still want to look for optional events */
378 cmdpos = redirect_cmd_list_find(redirect->cmd->opt, event);
379 if (cmdpos == NULL((void *)0))
380 return NULL((void *)0);
381
382 match_list = MATCH_STOP2;
383 } else {
384 /* look from start/stop lists */
385 cmdpos = redirect_cmd_list_find(redirect->cmd->start, event);
386 if (cmdpos != NULL((void *)0))
387 match_list = MATCH_START1;
388 else {
389 cmdpos = redirect_cmd_list_find(redirect->cmd->stop,
390 event);
391 if (cmdpos != NULL((void *)0))
392 match_list = MATCH_STOP2;
393 else if (redirect->default_signal != NULL((void *)0) &&
394 args == NULL((void *)0) &&
395 strncmp(event, "event ", 6) == 0 &&
396 i_isdigit(event[6])__isctype(((int) (unsigned char) (event[6])), 0x00000400L)) {
397 /* If there is a default signal, the
398 * redirection has already started and
399 * this is a numeric, use it */
400 /* XXX this should depend on the
401 * REDIRECT_CMD_REC, not REDIRECT_REC */
402 if (signal == NULL((void *)0))
403 signal = redirect->default_signal;
404 match_list = MATCH_START1;
405 } else {
406 match_list = MATCH_NONE0;
407 }
408 }
409 }
410
411 if (signal == NULL((void *)0) && cmdpos == NULL((void *)0)) {
412 /* event not found from specified redirection events nor
413 registered command events, and no default signal */
414 return NULL((void *)0);
415 }
416
417 /* check that arguments match */
418 if (args != NULL((void *)0) && redirect->arg != NULL((void *)0) && cmdpos != NULL((void *)0) &&
419 !redirect_args_match(args, redirect->arg,
420 GPOINTER_TO_INT(cmdpos->next->data)((gint) (cmdpos->next->data))))
421 return NULL((void *)0);
422
423 *match = match_list;
424 return signal != NULL((void *)0) ? signal : redirect->default_signal;
425}
426
427static void redirect_abort(IRC_SERVER_REC *server, REDIRECT_REC *rec)
428{
429 char *str;
430
431 server->redirects =
432 g_slist_remove(server->redirects, rec);
433
434 if (rec->aborted || !rec->destroyed) {
435 /* emit the failure signal */
436 str = g_strdup_printf(rec->failure_signal != NULL((void *)0) ?
437 "FAILED %s: %s" : "FAILED %s",
438 rec->cmd->name, rec->failure_signal);
439 rawlog_redirect(server->rawlog, str);
440 g_free(str);
441
442 if (rec->failure_signal != NULL((void *)0))
443 signal_emit(rec->failure_signal, 1, server);
444 } else if (rec->last_signal != NULL((void *)0)) {
445 /* emit the last signal */
446 signal_emit(rec->last_signal, 1, server);
447 }
448
449 server->redirect_active = g_slist_remove(server->redirect_active, rec);
450
451 server_redirect_destroy(rec);
452}
453
454#define REDIRECT_IS_TIMEOUTED(rec)((now-(rec)->created) > (rec)->cmd->timeout) \
455 ((now-(rec)->created) > (rec)->cmd->timeout)
456
457
458static REDIRECT_REC *redirect_find(IRC_SERVER_REC *server, const char *event,
459 const char *args, const char **signal,
460 int *match)
461{
462 REDIRECT_REC *redirect;
463 GSList *tmp, *next;
464 time_t now;
465 const char *match_signal;
466
467 /* find the redirection */
468 *signal = NULL((void *)0); redirect = NULL((void *)0);
469 for (tmp = server->redirects; tmp != NULL((void *)0); tmp = tmp->next) {
470 REDIRECT_REC *rec = tmp->data;
471
472 /* already active, don't try to start it again */
473 if (g_slist_find(server->redirect_active, rec) != NULL((void *)0))
474 continue;
475
476 match_signal = redirect_match(rec, event, args, match);
477 if (match_signal != NULL((void *)0) && *match != MATCH_NONE0) {
478 redirect = rec;
479 *signal = match_signal;
480 break;
481 }
482 }
483
484 /* remove the destroyed, non-remote and timeouted remote
485 redirections that should have happened before this redirection */
486 now = time(NULL((void *)0));
487 for (tmp = server->redirects; tmp != NULL((void *)0); tmp = next) {
488 REDIRECT_REC *rec = tmp->data;
489
490 if (rec == redirect)
491 break;
492
493 next = tmp->next;
494 if (rec->destroyed) {
495 /* redirection is finished, destroy it */
496 redirect_abort(server, rec);
497 } else if (redirect != NULL((void *)0)) {
498 /* check if redirection failed */
499 if (rec->aborted ||
500 rec->failures++ >= MAX_FAILURE_COUNT1) {
501 /* enough failures, abort it now */
502 if (!rec->remote || REDIRECT_IS_TIMEOUTED(rec)((now-(rec)->created) > (rec)->cmd->timeout))
503 redirect_abort(server, rec);
504 }
505 }
506 }
507
508 return redirect;
509}
510
511static const char *
512server_redirect_get(IRC_SERVER_REC *server, const char *prefix,
513 const char *event, const char *args,
514 REDIRECT_REC **redirect, int *match)
515{
516 const char *signal;
517 GSList *ptr, *next;
518 REDIRECT_REC *r;
519
520 *redirect = NULL((void *)0);
521 *match = MATCH_NONE0;
522
523 if (server->redirects == NULL((void *)0))
[1] Taking false branch
524 return NULL((void *)0);
525
526 for (ptr = server->redirect_active; ptr != NULL((void *)0); ptr = next) {
[2] Loop condition is false. Execution continues on line 550
527 next = ptr->next;
528 r = ptr->data;
529 if (prefix != NULL((void *)0) && r->prefix != NULL((void *)0) &&
530 strcmp(prefix, r->prefix)) {
531 /* not from this server */
532 continue;
533 }
534 /* redirection is already started, now we'll just need to
535 keep redirecting until stop-event is found. */
536 *redirect = r;
537 signal = redirect_match(*redirect, event, NULL((void *)0), match);
538 if (signal == NULL((void *)0)) {
539 /* not a numeric, so we've lost the
540 stop event.. */
541 (*redirect)->aborted = TRUE(!(0));
542 redirect_abort(server, *redirect);
543
544 *redirect = NULL((void *)0);
545 }
546 if (*redirect != NULL((void *)0))
547 break;
548 }
549
550 if (*redirect == NULL((void *)0)) {
[3] Taking false branch
551 /* find the redirection */
552 *redirect = redirect_find(server, event, args, &signal, match);
553 }
554
555 /* remember which server is replying to our request */
556 if (*redirect != NULL((void *)0) && prefix != NULL((void *)0) && (*redirect)->prefix == NULL((void *)0))
[4] Taking false branch
557 (*redirect)->prefix = g_strdup(prefix);
558
559 if (*redirect != NULL((void *)0) && (*redirect)->first_signal != NULL((void *)0) &&
[5] Taking true branch
560 !(*redirect)->first_signal_sent) {
561 /* emit the first_signal */
562 (*redirect)->first_signal_sent = TRUE(!(0));
563 signal_emit((*redirect)->first_signal, 1, server);
564 }
565
566 return signal;
[6] Uninitialized or undefined return value returned to caller
567}
568
569const char *server_redirect_get_signal(IRC_SERVER_REC *server,
570 const char *prefix,
571 const char *event,
572 const char *args)
573{
574 REDIRECT_REC *redirect;
575 const char *signal;
576 int match;
577
578 signal = server_redirect_get(server, prefix, event, args, &redirect, &match);
579 if (redirect == NULL((void *)0))
580 ;
581 else if (match != MATCH_STOP2) {
582 if (g_slist_find(server->redirect_active, redirect) == NULL((void *)0))
583 server->redirect_active = g_slist_prepend(server->redirect_active, redirect);
584 } else {
585 /* stop event - remove this redirection next time this
586 function is called (can't destroy now or our return
587 value would be corrupted) */
588 if (--redirect->count <= 0)
589 redirect->destroyed = TRUE(!(0));
590 server->redirect_active = g_slist_remove(server->redirect_active, redirect);
591 }
592
593 return signal;
594}
595
596const char *server_redirect_peek_signal(IRC_SERVER_REC *server,
597 const char *prefix,
598 const char *event,
599 const char *args,
600 int *redirected)
601{
602 REDIRECT_REC *redirect;
603 const char *signal;
604 int match;
605
606 signal = server_redirect_get(server, prefix, event, args, &redirect, &match);
607 *redirected = match != MATCH_NONE0;
608 return signal;
609}
610
611static void sig_disconnected(IRC_SERVER_REC *server)
612{
613 if (!IS_IRC_SERVER(server)(((IRC_SERVER_REC *) chat_protocol_check_cast(((SERVER_REC *)
module_check_cast(server, __builtin_offsetof(SERVER_REC, type
), "SERVER")), __builtin_offsetof(IRC_SERVER_REC, chat_type),
"IRC")) ? (!(0)) : (0))
)
614 return;
615
616 g_slist_free(server->redirect_active);
617 server->redirect_active = NULL((void *)0);
618 g_slist_foreach(server->redirects,
619 (GFunc) server_redirect_destroy, NULL((void *)0));
620 g_slist_free(server->redirects);
621 server->redirects = NULL((void *)0);
622
623 if (server->redirect_next != NULL((void *)0)) {
624 server_redirect_destroy(server->redirect_next);
625 server->redirect_next = NULL((void *)0);
626 }
627}
628
629static void cmd_redirect_destroy(char *key, REDIRECT_CMD_REC *cmd)
630{
631 redirect_cmd_unref(cmd);
632}
633
634void servers_redirect_init(void)
635{
636 command_redirects = g_hash_table_new((GHashFunc) g_str_hash, (GCompareFunc) g_str_equal);
637
638 /* WHOIS - register as remote command by default
639 with a default timeout */
640 server_redirect_register("whois", TRUE(!(0)), 0,
641 "event 311", 1, /* Begins the WHOIS */
642 NULL((void *)0),
643 "event 401", 1, /* No such nick */
644 "event 318", 1, /* End of WHOIS */
645 "event 402", 1, /* No such server */
646 "event 431", 1, /* No nickname given */
647 "event 461", 1, /* Not enough parameters */
648 NULL((void *)0),
649 "event 318", 1, /* After 401, we should get 318, but in OPN we don't.. */
650 NULL((void *)0));
651
652 /* WHOWAS */
653 server_redirect_register("whowas", FALSE(0), 0,
654 "event 314", 1, /* Begins the WHOWAS */
655 "event 406", 1, /* There was no such nick */
656 NULL((void *)0),
657 "event 369", 1, /* End of WHOWAS */
658 NULL((void *)0),
659 NULL((void *)0));
660
661 /* WHO */
662 server_redirect_register("who", FALSE(0), 0,
663 "event 352", 1, /* Begins the WHO */
664 "event 401", 1, /* No such nick/channel */
665 NULL((void *)0),
666 "event 315", 1, /* End of WHO */
667 "event 403", 1, /* no such channel */
668 NULL((void *)0),
669 NULL((void *)0));
670
671 /* LIST */
672 server_redirect_register("list", FALSE(0), 0,
673 "event 321", 1, /* Begins the LIST */
674 NULL((void *)0),
675 "event 323", 1, /* End of LIST */
676 NULL((void *)0),
677 NULL((void *)0));
678
679 /* ISON */
680 server_redirect_register("ison", FALSE(0), 0,
681 NULL((void *)0),
682 "event 303", -1, /* ISON */
683 NULL((void *)0),
684 NULL((void *)0));
685
686 /* USERHOST */
687 server_redirect_register("userhost", FALSE(0), 0,
688 "event 401", 1, /* no such nick */
689 NULL((void *)0),
690 "event 302", -1, /* Userhost */
691 "event 461", -1, /* Not enough parameters */
692 NULL((void *)0),
693 NULL((void *)0));
694
695 /* MODE user */
696 server_redirect_register("mode user", FALSE(0), 0,
697 NULL((void *)0),
698 "event mode", 0, /* MODE-reply */
699 "event 501", -1, /* Uknown MODE flag */
700 "event 502", -1, /* Can't change mode for other users */
701 "event 403", 1, /* That channel doesn't exist (tried to change mode to others) */
702 NULL((void *)0),
703 NULL((void *)0));
704
705 /* MODE #channel */
706 server_redirect_register("mode channel", FALSE(0), 0,
707 NULL((void *)0),
708 "event 324", 1, /* MODE-reply */
709 "event 403", 1, /* no such channel */
710 "event 442", 1, /* "you're not on that channel" */
711 "event 479", 1, /* "Cannot join channel (illegal name)" IMHO this is not a logical reply from server. */
712 NULL((void *)0),
713 "event 329", 1, /* Channel create time */
714 NULL((void *)0));
715
716 /* MODE #channel b */
717 server_redirect_register("mode b", FALSE(0), 0,
718 "event 367", 1,
719 NULL((void *)0),
720 "event 368", 1, /* End of Channel ban List */
721 "event 403", 1, /* no such channel */
722 "event 442", 1, /* "you're not on that channel" */
723 "event 479", 1, /* "Cannot join channel (illegal name)" IMHO this is not a logical reply from server. */
724 NULL((void *)0),
725 NULL((void *)0));
726
727 /* MODE #channel e */
728 server_redirect_register("mode e", FALSE(0), 0,
729 "event 348", 1,
730 NULL((void *)0),
731 "event 349", 1, /* End of ban exceptions */
732 "event 482", 1, /* not channel operator - OPN's ircd doesn't want non-ops to see ban exceptions */
733 "event 403", 1, /* no such channel */
734 "event 442", 1, /* "you're not on that channel" */
735 "event 479", 1, /* "Cannot join channel (illegal name)" IMHO this is not a logical reply from server. */
736 "event 472", -1, /* unknown mode (you should check e-mode's existance from 004 event instead of relying on this) */
737 NULL((void *)0),
738 NULL((void *)0));
739
740 /* MODE #channel I */
741 server_redirect_register("mode I", FALSE(0), 0,
742 "event 346", 1,
743 NULL((void *)0),
744 "event 347", 1, /* End of invite list */
745 "event 482", 1, /* not channel operator - OPN's ircd doesn't want non-ops to see ban exceptions */
746 "event 403", 1, /* no such channel */
747 "event 442", 1, /* "you're not on that channel" */
748 "event 479", 1, /* "Cannot join channel (illegal name)" IMHO this is not a logical reply from server. */
749 "event 472", -1, /* unknown mode (you should check I-mode's existance from 004 event instead of relying on this) */
750 NULL((void *)0),
751 NULL((void *)0));
752
753 /* PING - use default timeout */
754 server_redirect_register("ping", TRUE(!(0)), 0,
755 NULL((void *)0),
756 "event 402", -1, /* no such server */
757 "event pong", -1, /* PONG */
758 NULL((void *)0),
759 NULL((void *)0));
760
761 signal_add("server disconnected", (SIGNAL_FUNC) sig_disconnected)signal_add_full("irc/core", 0, ("server disconnected"), (SIGNAL_FUNC
) ((SIGNAL_FUNC) sig_disconnected), ((void *)0))
;
762}
763
764void servers_redirect_deinit(void)
765{
766 g_hash_table_foreach(command_redirects,
767 (GHFunc) cmd_redirect_destroy, NULL((void *)0));
768 g_hash_table_destroy(command_redirects);
769
770 signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected)signal_remove_full(("server disconnected"), (SIGNAL_FUNC) ((SIGNAL_FUNC
) sig_disconnected), ((void *)0))
;
771}