Properly send non-data lines when using repl_lastdisconnect. (#146).
[jelmer/ctrlproxy.git] / src / repl_backends.c
1 /* 
2         ctrlproxy: A modular IRC proxy
3         (c) 2002-2007 Jelmer Vernooij <jelmer@nl.linux.org>
4
5         This program is free software; you can redistribute it and/or modify
6         it under the terms of the GNU General Public License as published by
7         the Free Software Foundation; either version 3 of the License, or
8         (at your option) any later version.
9
10         This program is distributed in the hope that it will be useful,
11         but WITHOUT ANY WARRANTY; without even the implied warranty of
12         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13         GNU General Public License for more details.
14
15         You should have received a copy of the GNU General Public License
16         along with this program; if not, write to the Free Software
17         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include "ctrlproxy.h"
21 #include <string.h>
22
23 static char **matches = NULL;
24 static GHashTable *markers = NULL;
25 static GHashTable *lastdisconnect_backlog = NULL;
26 static GHashTable *simple_backlog = NULL;
27
28 static gboolean check_highlight(struct line *l, time_t t, void *userdata)
29 {
30         struct client *c = userdata;
31     int i;
32
33         if (g_strcasecmp(l->args[0], "PRIVMSG") != 0 &&
34                 g_strcasecmp(l->args[0], "NOTICE") != 0) 
35                 return TRUE;
36         
37         for (i = 0; matches && matches[i]; i++) {
38                 if (strstr(l->args[2], matches[i]) != NULL) {
39                         return client_send_line(c, l);
40                 }
41         }
42
43         return TRUE;
44 }
45
46 static void highlight_replicate(struct client *c)
47 {
48         struct linestack_marker *lm = g_hash_table_lookup(markers, c->network);
49
50         if (c->network->state) {
51                 client_send_state(c, c->network->state);
52         }
53
54         if (c->network->linestack == NULL)
55                 return;
56
57         linestack_traverse(c->network->linestack, lm, NULL, check_highlight, c);
58         g_hash_table_replace(markers, c->network, linestack_get_marker(c->network->linestack));
59 }
60
61 static void none_replicate(struct client *c)
62 {
63         if (c->network->state)
64                 client_send_state(c, c->network->state);
65 }
66
67 static void lastdisconnect_mark(struct client *c, void *userdata)
68 {
69         if (!c->network)
70                 return;
71
72         if (c->network->linestack != NULL) 
73                 g_hash_table_replace(lastdisconnect_backlog, c->network, 
74                                                          linestack_get_marker(c->network->linestack));
75 }
76
77 static void lastdisconnect_replicate(struct client *c)
78 {
79         struct linestack_marker *lm = g_hash_table_lookup(lastdisconnect_backlog, c->network);
80         struct network_state *ns;
81
82         if (c->network->linestack == NULL)
83                 return;
84
85         ns = linestack_get_state(c->network->linestack, lm);
86         if (ns != NULL) {
87                 client_send_state(c, ns);
88         }
89         free_network_state(ns);
90
91         linestack_send(c->network->linestack, lm, NULL, c, FALSE, 
92                                    c->network->global->config->report_time);
93 }
94
95 static gboolean log_data(struct network *n, const struct line *l, enum data_direction dir, void *userdata) 
96 {
97         if(dir != TO_SERVER) return TRUE;
98
99         if (g_strcasecmp(l->args[0], "PRIVMSG") && 
100                 g_strcasecmp(l->args[0], "NOTICE")) return TRUE;
101
102         if (n->linestack != NULL) 
103                 g_hash_table_replace(simple_backlog, n, linestack_get_marker(n->linestack));
104
105         return TRUE;
106 }
107
108 static void simple_replicate(struct client *c)
109 {
110         struct linestack_marker *m;
111         struct network_state *ns;
112
113         if (c->network->linestack == NULL)
114                 return;
115
116         m = g_hash_table_lookup(simple_backlog, c->network);
117         ns = linestack_get_state(c->network->linestack, m);
118         if (ns) {
119                 client_send_state(c, ns);
120         }
121         free_network_state(ns);
122
123         linestack_send(c->network->linestack, m, NULL, c, FALSE, 
124                                    c->network->global->config->report_time);
125 }
126
127 static const struct replication_backend backends[] = {
128         { "none", none_replicate },
129         { "highlight", highlight_replicate },
130         { "lastdisconnect", lastdisconnect_replicate },
131         { "simple", simple_replicate },
132         { NULL }
133 };
134
135 static void load_config(struct global *global)
136 {
137     matches = g_key_file_get_string_list(global->config->keyfile,
138                            "global", "match", NULL, NULL);
139         markers = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)linestack_free_marker);
140 }
141
142 gboolean init_replication(void)
143 {
144         int i;
145         for (i = 0; backends[i].name; i++) 
146                 register_replication_backend(&backends[i]);
147
148         register_load_config_notify(load_config);
149         add_lose_client_hook("repl_lastdisconnect", lastdisconnect_mark, NULL);
150         lastdisconnect_backlog = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)linestack_free_marker);
151         simple_backlog = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)linestack_free_marker);
152         add_server_filter("repl_simple", log_data, NULL, 200);
153
154         return TRUE;
155 }