~ctrlproxy/ctrlproxy/trunk

« back to all changes in this revision

Viewing changes to mods/strip.c

  • Committer: jelmer
  • Date: 2003-10-18 22:02:02 UTC
  • Revision ID: jelmer@samba.org-20031018220202-6801a76318fb4d13
Update

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
        ctrlproxy: A modular IRC proxy
 
3
        strip: Module that removes replies to commands from other 
 
4
        clients
 
5
        (c) 2002-2003 Jelmer Vernooij <jelmer@nl.linux.org>
 
6
 
 
7
        This program is free software; you can redistribute it and/or modify
 
8
        it under the terms of the GNU General Public License as published by
 
9
        the Free Software Foundation; either version 2 of the License, or
 
10
        (at your option) any later version.
 
11
 
 
12
        This program is distributed in the hope that it will be useful,
 
13
        but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
        GNU General Public License for more details.
 
16
 
 
17
        You should have received a copy of the GNU General Public License
 
18
        along with this program; if not, write to the Free Software
 
19
        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
20
*/
 
21
 
 
22
#define _GNU_SOURCE
 
23
#include "ctrlproxy.h"
 
24
#include <string.h>
 
25
#include "irc.h"
 
26
 
 
27
struct query_stack {
 
28
        struct query *query;
 
29
        struct network *network;
 
30
        struct client *client;  
 
31
        struct query_stack *next;
 
32
};
 
33
 
 
34
struct query_stack *stack = NULL;
 
35
 
 
36
struct query {
 
37
        char *name;
 
38
        int replies[20];
 
39
        int end_replies[20];
 
40
        /* Should add this query to the stack. return TRUE if this has 
 
41
         * been done successfully, FALSE otherwise */
 
42
        int (*handle) (struct line *, struct query *);
 
43
};
 
44
 
 
45
int handle_default(struct line *, struct query *);
 
46
int handle_topic(struct line *, struct query *);
 
47
 
 
48
struct query queries[] = {
 
49
/* Commands that get a one-client reply: 
 
50
 * WHOIS [<server>] <nickmask>[,<nickmask>[,...]] */
 
51
        {"WHOIS", 
 
52
                { ERR_NOSUCHSERVER, RPL_WHOISUSER, RPL_WHOISCHANNELS, RPL_AWAY,
 
53
                  RPL_WHOISIDLE, RPL_ENDOFWHOIS, ERR_NONICKNAMEGIVEN, RPL_WHOISCHANNELS,
 
54
                  RPL_WHOISSERVER, RPL_WHOISOPERATOR, ERR_NOSUCHNICK, 0 }, 
 
55
                { ERR_NOSUCHSERVER, ERR_NONICKNAMEGIVEN, ERR_NOSUCHNICK, 
 
56
                  RPL_ENDOFWHOIS, 0 }, 
 
57
                handle_default
 
58
        },
 
59
 
 
60
        /* WHO [<name> [<o>]] */
 
61
        {"WHO", 
 
62
            { ERR_NOSUCHSERVER, RPL_WHOREPLY, RPL_ENDOFWHO, 0 }, 
 
63
                { ERR_NOSUCHSERVER, RPL_ENDOFWHO, 0 },
 
64
                handle_default 
 
65
        },
 
66
 
 
67
        /* NAMES [<channel>{,<channel>}]*/
 
68
        {"NAMES", 
 
69
                { RPL_NAMREPLY, RPL_ENDOFNAMES, 0 }, 
 
70
                { RPL_ENDOFNAMES, 0 },
 
71
                handle_default
 
72
        },
 
73
 
 
74
 /* LIST [<channel>{,<channel>} [<server>]*/
 
75
        {"LIST", 
 
76
                { ERR_NOSUCHSERVER, RPL_LIST, RPL_LISTSTART, RPL_LISTEND, 0 }, 
 
77
                { ERR_NOSUCHSERVER, RPL_LISTEND, 0 },
 
78
                handle_default
 
79
        },
 
80
        
 
81
 /* TOPIC <channel> [<topic>]*/
 
82
        {"TOPIC", 
 
83
                { ERR_NEEDMOREPARAMS, RPL_NOTOPIC, ERR_NOTONCHANNEL, RPL_TOPIC, 
 
84
                  ERR_CHANOPRIVSNEEDED, 0 }, 
 
85
                { ERR_NEEDMOREPARAMS, RPL_NOTOPIC, ERR_NOTONCHANNEL, RPL_TOPIC, 
 
86
                  ERR_CHANOPRIVSNEEDED, 0 }, 
 
87
                handle_topic
 
88
        },
 
89
        
 
90
 /* WHOWAS <nickname> [<count> [<server>]]*/
 
91
        {"WHOWAS", 
 
92
                { ERR_NONICKNAMEGIVEN, ERR_WASNOSUCHNICK, RPL_WHOWASUSER,
 
93
                  RPL_WHOISSERVER, RPL_ENDOFWHOWAS, 0 },
 
94
                { ERR_NONICKNAMEGIVEN, ERR_WASNOSUCHNICK, RPL_ENDOFWHOWAS, 
 
95
                  RPL_WHOISSERVER, 0 },
 
96
                handle_default
 
97
        },
 
98
        
 
99
 /* STATS [<query> [<server>]]*/
 
100
        {"STATS", 
 
101
                { ERR_NOSUCHSERVER, RPL_STATSCLINE, RPL_STATSILINE, RPL_STATSQLINE, 
 
102
                  RPL_STATSLINKINFO, RPL_STATSCOMMANDS, RPL_STATSHLINE, RPL_STATSNLINE,
 
103
                  RPL_STATSKLINE, RPL_STATSLLINE, RPL_STATSUPTIME, RPL_STATSOLINE, 
 
104
                  RPL_ENDOFSTATS, 0 },
 
105
                { ERR_NOSUCHSERVER, RPL_ENDOFSTATS, 0 },
 
106
                handle_default
 
107
        }, 
 
108
        
 
109
 /* VERSION [<server>]*/
 
110
        {"VERSION",
 
111
                { ERR_NOSUCHSERVER, RPL_VERSION, 0 },
 
112
                { ERR_NOSUCHSERVER, RPL_VERSION, 0 },
 
113
                handle_default
 
114
        }, 
 
115
                
 
116
 /* LINKS [[<remote server>] <server mask>]*/
 
117
        {"LINKS",
 
118
                { ERR_NOSUCHSERVER, RPL_LINKS, RPL_ENDOFLINKS, 0 },
 
119
                { ERR_NOSUCHSERVER, RPL_ENDOFLINKS, 0 },
 
120
                handle_default
 
121
        },
 
122
        
 
123
 /* TIME [<server>]*/
 
124
        {"TIME",
 
125
                { ERR_NOSUCHSERVER, RPL_TIME, 0 },
 
126
                { ERR_NOSUCHSERVER, RPL_TIME, 0 },
 
127
                handle_default
 
128
        },
 
129
 
 
130
 /* TRACE [<server>]*/
 
131
#if 0
 
132
        /* This one is ifdef'ed out because there is no response that 
 
133
         * can be used as a 'end-of-response' indicator. */
 
134
        {"TRACE",
 
135
                { ERR_NOSUCHSERVER, RPL_TRACELINK, RPL_TRACECONNECTING, 
 
136
                  RPL_TRACEUNKNOWN, RPL_TRACEUSER, RPL_TRACECLASS, 
 
137
                  RPL_TRACEHANDSHAKE, RPL_TRACEOPERATOR,
 
138
                  RPL_TRACESERVER, RPL_TRACENEWTYPE, 0 },
 
139
                { ERR_NOSUCHSERVER, 0 },
 
140
                handle_default
 
141
        },
 
142
#endif
 
143
        
 
144
 /* SUMMON <user> [<server>]*/
 
145
        {"SUMMON",
 
146
                { ERR_NORECIPIENT, ERR_FILEERROR, ERR_NOLOGIN, ERR_NOSUCHSERVER,
 
147
                  RPL_SUMMONING, 0 },
 
148
                { ERR_NORECIPIENT, ERR_FILEERROR, ERR_NOLOGIN, ERR_NOSUCHSERVER,
 
149
                  RPL_SUMMONING, 0 },
 
150
                handle_default
 
151
        },
 
152
        
 
153
 /* USERS [<server>]*/
 
154
        {"USERS",
 
155
                { ERR_NOSUCHSERVER, ERR_FILEERROR, RPL_USERSSTART, RPL_USERS,
 
156
                  RPL_NOUSERS, RPL_ENDOFUSERS, ERR_USERSDISABLED, 0 },
 
157
                { ERR_NOSUCHSERVER, ERR_FILEERROR, ERR_USERSDISABLED, RPL_ENDOFUSERS, 0 },
 
158
                handle_default
 
159
        },
 
160
        
 
161
 /* USERHOST <nickname>{ <nickname>}{ ...}*/
 
162
        {"USERHOST",
 
163
                { RPL_USERHOST, ERR_NEEDMOREPARAMS, 0 },
 
164
                { RPL_USERHOST, ERR_NEEDMOREPARAMS, 0 },
 
165
                handle_default
 
166
        },
 
167
                
 
168
 /* ISON <nickname>{ <nickname>}{ ...} */
 
169
        {"ISON",
 
170
                { RPL_ISON, ERR_NEEDMOREPARAMS, 0 },
 
171
                { RPL_ISON, ERR_NEEDMOREPARAMS, 0 },
 
172
            handle_default
 
173
        },
 
174
 
 
175
        { NULL }
 
176
};
 
177
 
 
178
int is_reply(int *replies, int r)
 
179
{
 
180
        int i;
 
181
        for(i = 0; i < 20 && replies[i]; i++) {
 
182
                if(replies[i] == r) return 1;
 
183
        }
 
184
        return 0;
 
185
}
 
186
 
 
187
int is_numeric(char *s)
 
188
{
 
189
        while(*s) {
 
190
                if(*s < '0' || *s > '9')return 0;
 
191
                s++;
 
192
        }
 
193
        return 1;
 
194
}
 
195
 
 
196
struct query *find_query(char *name)
 
197
{
 
198
        int i;
 
199
        for(i = 0; queries[i].name; i++) {
 
200
                if(!strcasecmp(queries[i].name, name)) return &queries[i];
 
201
        }
 
202
 
 
203
        return NULL;
 
204
}
 
205
 
 
206
static gboolean handle_data(struct line *l) {
 
207
        struct query *q;
 
208
        
 
209
        if(l->direction == TO_SERVER) {
 
210
                q = find_query(l->args[0]);
 
211
                if(!q) return TRUE;
 
212
                /* Push it up the stack! */
 
213
                if(q->handle(l, q)) {
 
214
                        /* Don't send this line to other clients */
 
215
                        l->options |= LINE_IS_PRIVATE;
 
216
                        return TRUE;
 
217
                }
 
218
        } else { 
 
219
                struct query_stack *s = stack, *p = NULL;
 
220
                int n;
 
221
                if(!is_numeric(l->args[0])) return TRUE;
 
222
        
 
223
                n = atoi(l->args[0]);
 
224
                
 
225
                /* Loop thru the stack until we find something that's matching */
 
226
                while(s) {
 
227
                        if(is_reply(s->query->replies, n) && s->network == l->network) {
 
228
                                /* Send to client that queried, if that client still exists */
 
229
                                if(verify_client(s->network, s->client)) 
 
230
                                        irc_send_line(s->client->incoming, l);
 
231
 
 
232
                                if(is_reply(s->query->end_replies, n)) {
 
233
                                        /* Remove from stack */
 
234
                                        if(!p)stack = s->next;  
 
235
                                        else p->next = s->next;
 
236
                                        free(s);
 
237
                                }
 
238
 
 
239
                                l->options |= LINE_DONT_SEND;
 
240
 
 
241
                                return TRUE;
 
242
                        }
 
243
                        p = s; s = s->next;
 
244
                }
 
245
        }
 
246
        return TRUE;
 
247
}
 
248
 
 
249
gboolean fini_plugin(struct plugin *p) {
 
250
        del_filter(handle_data);
 
251
        return TRUE;
 
252
}
 
253
 
 
254
gboolean init_plugin(struct plugin *p) {
 
255
        add_filter("strip", handle_data);
 
256
        return TRUE;
 
257
}
 
258
 
 
259
int handle_default(struct line *l, struct query *q)
 
260
{
 
261
        struct query_stack *s = malloc(sizeof(struct query_stack));
 
262
        s->network = l->network;
 
263
        s->client = l->client;
 
264
        s->query = q;
 
265
        s->next = stack;
 
266
        stack = s;
 
267
        return 1;
 
268
}
 
269
 
 
270
int handle_topic(struct line *l, struct query *q)
 
271
{
 
272
        if(l->args[2])return 0;
 
273
        return handle_default(l,q);
 
274
}