2 ctrlproxy: A modular IRC proxy
3 (c) 2005 Jelmer Vernooij <jelmer@nl.linux.org>
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 2 of the License, or
8 (at your option) any later version.
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.
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.
20 #include "internals.h"
22 #define DEFAULT_PREFIX "(ov)@+"
23 #define DEFAULT_CHANTYPES "#&"
24 #define DEFAULT_CHARSET "iso8859-15"
26 void network_info_init(struct network_info *info)
28 memset(info, 0, sizeof(struct network_info));
29 info->prefix = g_strdup(DEFAULT_PREFIX);
30 info->chantypes = g_strdup(DEFAULT_CHANTYPES);
31 info->charset = g_strdup(DEFAULT_CHARSET);
34 void free_network_info(struct network_info *info)
37 g_free(info->chantypes);
38 g_free(info->charset);
41 g_free(info->supported_user_modes);
42 g_free(info->supported_channel_modes);
43 g_strfreev(info->chanmodes);
44 g_free(info->chanlimit);
45 g_free(info->maxlist);
47 g_free(info->statusmsg);
50 char *network_info_string(struct network_info *info)
53 GList *fs = NULL, *gl;
56 if (info->name != NULL)
57 fs = g_list_append(fs, g_strdup_printf("NETWORK=%s", info->name));
59 switch (info->casemapping) {
62 casemap = g_strdup("CASEMAPPING=rfc1459");
64 case CASEMAP_STRICT_RFC1459:
65 casemap = g_strdup("CASEMAPPING=strict-rfc1459");
68 casemap = g_strdup("CASEMAPPING=ascii");
73 fs = g_list_append(fs, casemap);
75 if (info->forced_nick_changes)
76 fs = g_list_append(fs, g_strdup("FNC"));
78 if (info->charset != NULL)
79 fs = g_list_append(fs, g_strdup_printf("CHARSET=%s", info->charset));
81 if (info->nicklen != 0)
82 fs = g_list_append(fs, g_strdup_printf("NICKLEN=%d", info->nicklen));
84 if (info->userlen != 0)
85 fs = g_list_append(fs, g_strdup_printf("USERLEN=%d", info->userlen));
87 if (info->hostlen != 0)
88 fs = g_list_append(fs, g_strdup_printf("HOSTLEN=%d", info->hostlen));
90 if (info->channellen != 0)
91 fs = g_list_append(fs, g_strdup_printf("CHANNELLEN=%d", info->channellen));
93 if (info->awaylen != 0)
94 fs = g_list_append(fs, g_strdup_printf("AWAYLEN=%d", info->awaylen));
96 if (info->kicklen != 0)
97 fs = g_list_append(fs, g_strdup_printf("KICKLEN=%d", info->kicklen));
99 if (info->topiclen != 0)
100 fs = g_list_append(fs, g_strdup_printf("TOPICLEN=%d", info->topiclen));
102 if (info->maxchannels != 0)
103 fs = g_list_append(fs, g_strdup_printf("MAXCHANNELS=%d", info->maxchannels));
105 if (info->maxtargets != 0)
106 fs = g_list_append(fs, g_strdup_printf("MAXTARGETS=%d", info->maxtargets));
108 if (info->maxbans != 0)
109 fs = g_list_append(fs, g_strdup_printf("MAXBANS=%d", info->maxbans));
111 if (info->maxmodes != 0)
112 fs = g_list_append(fs, g_strdup_printf("MODES=%d", info->maxmodes));
115 fs = g_list_append(fs, g_strdup("WALLCHOPS"));
117 if (info->wallvoices)
118 fs = g_list_append(fs, g_strdup("WALLVOICES"));
121 fs = g_list_append(fs, g_strdup("RFC2812"));
124 fs = g_list_append(fs, g_strdup("PENALTY"));
127 fs = g_list_append(fs, g_strdup("SAFELIST"));
130 fs = g_list_append(fs, g_strdup("USERIP"));
133 fs = g_list_append(fs, g_strdup("CAPAB"));
136 fs = g_list_append(fs, g_strdup("CPRIVMSG"));
139 fs = g_list_append(fs, g_strdup("CNOTICE"));
142 fs = g_list_append(fs, g_strdup("KNOCK"));
145 fs = g_list_append(fs, g_strdup("VCHANNELS"));
148 fs = g_list_append(fs, g_strdup("WHOX"));
151 fs = g_list_append(fs, g_strdup("CALLERID"));
154 fs = g_list_append(fs, g_strdup("ACCEPT"));
156 if (info->keylen != 0)
157 fs = g_list_append(fs, g_strdup_printf("KEYLEN=%d", info->keylen));
159 if (info->silence != 0)
160 fs = g_list_append(fs, g_strdup_printf("SILENCE=%d", info->silence));
162 if (info->chantypes != NULL)
163 fs = g_list_append(fs, g_strdup_printf("CHANTYPES=%s", info->chantypes));
165 if (info->chanmodes != NULL) {
166 char *tmp = g_strjoinv(",", info->chanmodes);
167 fs = g_list_append(fs, g_strdup_printf("CHANMODES=%s", tmp));
171 if (info->chanlimit != NULL) {
172 fs = g_list_append(fs, g_strdup_printf("CHANLIMIT=%s", info->chanlimit));
175 if (info->excepts_mode != '\0')
176 fs = g_list_append(fs, g_strdup_printf("EXCEPTS=%c", info->excepts_mode));
178 if (info->statusmsg != NULL)
179 fs = g_list_append(fs, g_strdup_printf("STATUSMSG=%s", info->statusmsg));
181 if (info->invex_mode != '\0')
182 fs = g_list_append(fs, g_strdup_printf("INVEX=%c", info->invex_mode));
184 if (info->deaf_mode != '\0')
185 fs = g_list_append(fs, g_strdup_printf("DEAF=%c", info->deaf_mode));
187 if (info->maxlist != NULL)
188 fs = g_list_append(fs, g_strdup_printf("MAXLIST=%s", info->maxlist));
190 if (info->idchan != NULL)
191 fs = g_list_append(fs, g_strdup_printf("IDCHAN=%s", info->idchan));
193 if (info->prefix != NULL)
194 fs = g_list_append(fs, g_strdup_printf("PREFIX=%s", info->prefix));
196 ret = list_make_string(fs);
198 for (gl = fs; gl; gl = gl->next)
206 void network_info_parse(struct network_info *info, const char *parameter)
211 sep = strchr(parameter, '=');
214 key = g_strdup(parameter);
217 key = g_strndup(parameter, sep - parameter);
218 val = g_strdup(sep+1);
221 if(!g_strcasecmp(key, "CASEMAPPING")) {
222 if(!g_strcasecmp(val, "rfc1459")) {
223 info->casemapping = CASEMAP_RFC1459;
224 } else if(!g_strcasecmp(val, "strict-rfc1459")) {
225 info->casemapping = CASEMAP_STRICT_RFC1459;
226 } else if(!g_strcasecmp(val, "ascii")) {
227 info->casemapping = CASEMAP_ASCII;
229 info->casemapping = CASEMAP_UNKNOWN;
230 log_global(LOG_WARNING, "Unknown CASEMAPPING value '%s'", val);
232 } else if (!g_strcasecmp(key, "NETWORK")) {
234 info->name = g_strdup(val);
235 } else if (!g_strcasecmp(key, "NICKLEN") || !g_strcasecmp(key, "MAXNICKLEN")) {
236 info->nicklen = atoi(val);
237 } else if (!g_strcasecmp(key, "USERLEN")) {
238 info->userlen = atoi(val);
239 } else if (!g_strcasecmp(key, "HOSTLEN")) {
240 info->hostlen = atoi(val);
241 } else if (!g_strcasecmp(key, "CHANNELLEN") || !g_strcasecmp(key, "MAXCHANNELLEN")) {
242 info->channellen = atoi(val);
243 } else if (!g_strcasecmp(key, "AWAYLEN")) {
244 info->awaylen = atoi(val);
245 } else if (!g_strcasecmp(key, "KICKLEN")) {
246 info->kicklen = atoi(val);
247 } else if (!g_strcasecmp(key, "TOPICLEN")) {
248 info->topiclen = atoi(val);
249 } else if (!g_strcasecmp(key, "MAXCHANNELS")) {
250 info->maxchannels = atoi(val);
251 } else if (!g_strcasecmp(key, "MAXTARGETS")) {
252 info->maxtargets = atoi(val);
253 } else if (!g_strcasecmp(key, "MAXBANS")) {
254 info->maxbans = atoi(val);
255 } else if (!g_strcasecmp(key, "MODES")) {
256 info->maxmodes = atoi(val);
257 } else if (!g_strcasecmp(key, "WALLCHOPS")) {
258 info->wallchops = TRUE;
259 } else if (!g_strcasecmp(key, "WALLVOICES")) {
260 info->wallvoices = TRUE;
261 } else if (!g_strcasecmp(key, "RFC2812")) {
262 info->rfc2812 = TRUE;
263 } else if (!g_strcasecmp(key, "PENALTY")) {
264 info->penalty = TRUE;
265 } else if (!g_strcasecmp(key, "FNC")) {
266 info->forced_nick_changes = TRUE;
267 } else if (!g_strcasecmp(key, "SAFELIST")) {
268 info->safelist = TRUE;
269 } else if (!g_strcasecmp(key, "USERIP")) {
271 } else if (!g_strcasecmp(key, "CPRIVMSG")) {
272 info->cprivmsg = TRUE;
273 } else if (!g_strcasecmp(key, "CNOTICE")) {
274 info->cnotice = TRUE;
275 } else if (!g_strcasecmp(key, "KNOCK")) {
277 } else if (!g_strcasecmp(key, "CAPAB")) {
279 } else if (!g_strcasecmp(key, "VCHANNELS")) {
280 info->vchannels = TRUE;
281 } else if (!g_strcasecmp(key, "WHOX")) {
283 } else if (!g_strcasecmp(key, "CALLERID")) {
284 info->callerid = TRUE;
285 } else if (!g_strcasecmp(key, "ACCEPT")) {
287 } else if (!g_strcasecmp(key, "KEYLEN")) {
288 info->keylen = atoi(val);
289 } else if (!g_strcasecmp(key, "SILENCE")) {
290 info->silence = atoi(val);
291 } else if (!g_strcasecmp(key, "CHANTYPES")) {
292 g_free(info->chantypes);
293 info->chantypes = g_strdup(val);
294 } else if (!g_strcasecmp(key, "CHANMODES")) {
295 g_strfreev(info->chanmodes);
296 info->chanmodes = g_strsplit(val, ",", 4);
297 /* FIXME: Make sure info->chanmodes length is exactly 4 */
298 } else if (!g_strcasecmp(key, "CHANLIMIT")) {
299 g_free(info->chanlimit);
300 info->chanlimit = g_strdup(val);
301 } else if (!g_strcasecmp(key, "EXCEPTS")) {
303 info->excepts_mode = 'e';
304 else if (strlen(val) > 1)
305 log_global(LOG_WARNING, "Invalid length excepts value: %s", val);
307 info->excepts_mode = val[0];
308 } else if (!g_strcasecmp(key, "INVEX")) {
310 info->invex_mode = 'I';
311 else if (strlen(val) > 1)
312 log_global(LOG_WARNING, "Invalid length invex value: %s", val);
314 info->invex_mode = val[0];
315 } else if (!g_strcasecmp(key, "DEAF")) {
317 info->deaf_mode = 'D';
318 else if (strlen(val) > 1)
319 log_global(LOG_WARNING, "Invalid length deaf value: %s", val);
321 info->deaf_mode = val[0];
322 } else if (!g_strcasecmp(key, "MAXLIST")) {
323 g_free(info->maxlist);
324 info->maxlist = g_strdup(val);
325 } else if (!g_strcasecmp(key, "IDCHAN")) {
326 g_free(info->idchan);
327 info->idchan = g_strdup(val);
328 } else if (!g_strcasecmp(key, "STATUSMSG")) {
329 g_free(info->statusmsg);
330 info->statusmsg = g_strdup(val);
331 } else if (!g_strcasecmp(key, "PREFIX")) {
332 g_free(info->prefix);
333 info->prefix = g_strdup(val);
334 } else if (!g_strcasecmp(key, "CHARSET")) {
335 g_free(info->charset);
336 info->charset = g_strdup(val);
338 log_global(LOG_WARNING, "Unknown 005 parameter `%s'", key);
344 void handle_005(struct network_state *s, struct line *l)
350 g_assert(l->argc >= 1);
352 for (i = 3; i < l->argc-1; i++)
353 network_info_parse(&s->info, l->args[i]);
356 int irccmp(const struct network_info *n, const char *a, const char *b)
358 switch(n != NULL?n->casemapping:CASEMAP_UNKNOWN) {
360 case CASEMAP_UNKNOWN:
361 case CASEMAP_RFC1459:
362 return str_rfc1459cmp(a,b);
364 return str_asciicmp(a,b);
365 case CASEMAP_STRICT_RFC1459:
366 return str_strictrfc1459cmp(a,b);
372 gboolean is_channelname(const char *name, const struct network_info *n)
375 g_assert(n->chantypes != NULL);
377 g_assert(name != NULL);
379 if (strchr(n->chantypes, name[0]))
385 gboolean is_prefix(char p, const struct network_info *n)
387 const char *pref_end;
390 g_assert(n->prefix != NULL);
392 pref_end = strchr(n->prefix, ')');
393 if (!pref_end)pref_end = n->prefix; else pref_end++;
395 if(strchr(pref_end, p)) return TRUE;
399 const char *get_charset(const struct network_info *n)
402 g_assert(n->charset != NULL);
406 char get_prefix_by_mode(char mode, const struct network_info *n)
413 g_assert(n->prefix != NULL);
417 pref_end = strchr(prefix, ')');
418 if(prefix[0] != '(' || !pref_end) {
419 log_global(LOG_WARNING, "Malformed PREFIX data `%s'", prefix);
425 for(i = 0; pref_end[i]; i++) {
426 if(prefix[i] == mode) return pref_end[i];
431 const static char *default_chanmodes[] = {
432 "beI", "k" , "l" , "imnpsta"
435 int network_chanmode_type(char m, struct network_info *n)
438 for (i = 0; i < 4; i++) {
439 if (strchr((n && n->chanmodes)?n->chanmodes[i]:default_chanmodes[i], m)) {