]> jfr.im git - irc/evilnet/x3.git/blame - src/tools.c
mod-python: remove unused function
[irc/evilnet/x3.git] / src / tools.c
CommitLineData
d76ed9a9 1/* tools.c - miscellaneous utility functions
2 * Copyright 2000-2004 srvx Development Team
3 *
83ff05c3 4 * This file is part of x3.
d76ed9a9 5 *
d0f04f71 6 * x3 is free software; you can redistribute it and/or modify
d76ed9a9 7 * it under the terms of the GNU General Public License as published by
348683aa 8 * the Free Software Foundation; either version 3 of the License, or
d76ed9a9 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 srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 */
20
21#include "helpfile.h"
22#include "log.h"
23#include "nickserv.h"
24#include "recdb.h"
25
26#ifdef HAVE_NETDB_H
27#include <netdb.h>
28#endif
29#ifdef HAVE_SYS_SOCKET_H
30#include <sys/socket.h>
31#endif
32#ifdef HAVE_ARPA_INET_H
33#include <arpa/inet.h>
34#endif
35
36#define NUMNICKLOG 6
37#define NUMNICKBASE (1 << NUMNICKLOG)
38#define NUMNICKMASK (NUMNICKBASE - 1)
39
40/* Yes, P10's encoding here is almost-but-not-quite MIME Base64. Yay
41 * for gratuitous incompatibilities. */
42static const char convert2y[256] = {
43 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
44 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
45 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
46 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','[',']'
47};
48
49static const unsigned char convert2n[256] = {
50 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
52 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2f61d1d7 53 52,53,54,55,56,57,58,59,60,61, 0, 0, 0, 0, 0, 0,
d76ed9a9 54 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
55 15,16,17,18,19,20,21,22,23,24,25,62, 0,63, 0, 0,
56 0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
57 41,42,43,44,45,46,47,48,49,50,51, 0, 0, 0, 0, 0
58};
59
2f61d1d7 60static const unsigned char ctype[256] = {
61 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
62 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
65 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
66 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
67 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
68};
69
d76ed9a9 70unsigned long int
71base64toint(const char* s, int count)
72{
73 unsigned int i = 0;
74 while (*s && count) {
75 i = (i << NUMNICKLOG) + convert2n[(unsigned char)*s++];
76 count--;
77 }
78 return i;
79}
80
81const char* inttobase64(char* buf, unsigned int v, unsigned int count)
82{
83 buf[count] = '\0';
84 while (count > 0) {
85 buf[--count] = convert2y[(unsigned char)(v & NUMNICKMASK)];
86 v >>= NUMNICKLOG;
87 }
88 return buf;
89}
90
2f61d1d7 91unsigned int
92irc_ntop(char *output, unsigned int out_size, const irc_in_addr_t *addr)
93{
94 static const char hexdigits[] = "0123456789abcdef";
95 unsigned int pos;
96
97 assert(output);
98 assert(addr);
99
100 if (irc_in_addr_is_ipv4(*addr)) {
101 unsigned int ip4;
102
103 ip4 = (ntohs(addr->in6[6]) << 16) | ntohs(addr->in6[7]);
104 pos = snprintf(output, out_size, "%u.%u.%u.%u", (ip4 >> 24), (ip4 >> 16) & 255, (ip4 >> 8) & 255, ip4 & 255);
105 } else {
106 unsigned int part, max_start, max_zeros, curr_zeros, ii;
107
108 /* Find longest run of zeros. */
109 for (max_start = max_zeros = curr_zeros = ii = 0; ii < 8; ++ii) {
110 if (!addr->in6[ii])
111 curr_zeros++;
112 else if (curr_zeros > max_zeros) {
113 max_start = ii - curr_zeros;
114 max_zeros = curr_zeros;
115 curr_zeros = 0;
116 }
117 }
118 if (curr_zeros > max_zeros) {
119 max_start = ii - curr_zeros;
120 max_zeros = curr_zeros;
121 }
122
123 /* Print out address. */
124#define APPEND(CH) do { if (pos < out_size) output[pos] = (CH); pos++; } while (0)
125 for (pos = 0, ii = 0; ii < 8; ++ii) {
126 if ((max_zeros > 0) && (ii == max_start)) {
127 if (ii == 0)
128 APPEND(':');
129 APPEND(':');
130 ii += max_zeros - 1;
131 continue;
132 }
133 part = ntohs(addr->in6[ii]);
134 if (part >= 0x1000)
135 APPEND(hexdigits[part >> 12]);
136 if (part >= 0x100)
137 APPEND(hexdigits[(part >> 8) & 15]);
138 if (part >= 0x10)
139 APPEND(hexdigits[(part >> 4) & 15]);
140 APPEND(hexdigits[part & 15]);
141 if (ii < 7)
142 APPEND(':');
143 }
144#undef APPEND
145 output[pos < out_size ? pos : out_size - 1] = '\0';
146 }
147
148 return pos;
149}
150
151unsigned int
152irc_ntop_mask(char *output, unsigned int out_size, const irc_in_addr_t *addr, unsigned char bits)
153{
154 char base_addr[IRC_NTOP_MAX_SIZE];
155 int len;
156
157 if (bits >= 128)
158 return irc_ntop(output, out_size, addr);
159 if (!irc_ntop(base_addr, sizeof(base_addr), addr))
160 return 0;
161 len = snprintf(output, out_size, "%s/%d", base_addr, bits);
162 if ((unsigned int)len >= out_size)
163 return 0;
164 return len;
165}
166
167static unsigned int
168irc_pton_ip4(const char *input, unsigned char *pbits, uint32_t *output)
169{
170 unsigned int dots = 0, pos = 0, part = 0, ip = 0, bits = 32;
171
172 /* Intentionally no support for bizarre IPv4 formats (plain
173 * integers, octal or hex components) -- only vanilla dotted
174 * decimal quads, optionally with trailing /nn.
175 */
176 if (input[0] == '.')
177 return 0;
178 while (1) switch (input[pos]) {
179 default:
180 if (dots < 3)
181 return 0;
182 out:
183 ip |= part << (24 - 8 * dots++);
184 *output = htonl(ip);
185 if (pbits)
186 *pbits = bits;
187 return pos;
188 case '.':
189 if (input[++pos] == '.')
190 return 0;
191 ip |= part << (24 - 8 * dots++);
192 part = 0;
193 if (input[pos] == '*') {
194 while (input[++pos] == '*') ;
195 if (input[pos] != '\0')
196 return 0;
197 if (pbits)
198 *pbits = dots * 8;
199 *output = htonl(ip);
200 return pos;
201 }
202 break;
203 case '/':
204 if (!pbits || !isdigit(input[pos + 1]))
205 return 0;
206 for (bits = 0; isdigit(input[++pos]); )
207 bits = bits * 10 + input[pos] - '0';
208 if (bits > 32)
209 return 0;
210 goto out;
211 case '0': case '1': case '2': case '3': case '4':
212 case '5': case '6': case '7': case '8': case '9':
213 part = part * 10 + input[pos++] - '0';
214 if (part > 255)
215 return 0;
216 break;
217 }
218}
219
220unsigned int
221irc_pton(irc_in_addr_t *addr, unsigned char *bits, const char *input)
222{
223 const char *part_start = NULL;
224 char *colon;
225 char *dot;
226 unsigned int part = 0, pos = 0, ii = 0, cpos = 8;
227
228 assert(input);
229 memset(addr, 0, sizeof(*addr));
230 colon = strchr(input, ':');
231 dot = strchr(input, '.');
232
233 if (colon && (!dot || (dot > colon))) {
234 /* Parse IPv6, possibly like ::127.0.0.1.
235 * This is pretty straightforward; the only trick is borrowed
236 * from Paul Vixie (BIND): when it sees a "::" continue as if
237 * it were a single ":", but note where it happened, and fill
238 * with zeros afterwards.
239 */
240 if (input[pos] == ':') {
241 if ((input[pos+1] != ':') || (input[pos+2] == ':'))
242 return 0;
243 cpos = 0;
244 pos += 2;
245 part_start = input + pos;
246 }
247 while (ii < 8) switch (input[pos]) {
248 case '0': case '1': case '2': case '3': case '4':
249 case '5': case '6': case '7': case '8': case '9':
250 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
251 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
252 part = (part << 4) | (ctype[(unsigned char)input[pos++]] & 15);
253 if (part > 0xffff)
254 return 0;
255 break;
256 case ':':
257 part_start = input + ++pos;
258 if (input[pos] == '.')
259 return 0;
260 addr->in6[ii++] = htons(part);
261 part = 0;
262 if (input[pos] == ':') {
263 if (cpos < 8)
264 return 0;
265 cpos = ii;
266 }
267 break;
268 case '.': {
269 uint32_t ip4;
270 unsigned int len;
271 len = irc_pton_ip4(part_start, bits, &ip4);
272 if (!len || (ii > 6))
273 return 0;
274 memcpy(addr->in6 + ii, &ip4, sizeof(ip4));
275 if (bits)
276 *bits += 96;
277 ii += 2;
278 pos = part_start + len - input;
279 goto finish;
280 }
281 case '/':
282 if (!bits || !isdigit(input[pos + 1]))
283 return 0;
284 addr->in6[ii++] = htons(part);
285 for (part = 0; isdigit(input[++pos]); )
286 part = part * 10 + input[pos] - '0';
287 if (part > 128)
288 return 0;
289 *bits = part;
290 goto finish;
291 case '*':
292 while (input[++pos] == '*') ;
293 if (input[pos] != '\0' || cpos < 8)
294 return 0;
295 if (bits)
296 *bits = ii * 16;
297 return pos;
298 default:
299 addr->in6[ii++] = htons(part);
300 if (cpos == 8 && ii < 8)
301 return 0;
302 if (bits)
303 *bits = 128;
304 goto finish;
305 }
306 finish:
307 /* Shift stuff after "::" up and fill middle with zeros. */
308 if (cpos < 8) {
309 unsigned int jj;
310 for (jj = 0; jj < ii - cpos; jj++)
311 addr->in6[7 - jj] = addr->in6[ii - jj - 1];
312 for (jj = 0; jj < 8 - ii; jj++)
313 addr->in6[cpos + jj] = 0;
314 }
315 } else if (dot) {
1136f709 316 uint32_t ip4;
2f61d1d7 317 pos = irc_pton_ip4(input, bits, &ip4);
318 if (pos) {
319 addr->in6[5] = htons(65535);
320 addr->in6[6] = htons(ntohl(ip4) >> 16);
321 addr->in6[7] = htons(ntohl(ip4) & 65535);
322 if (bits)
323 *bits += 96;
324 }
325 } else if (input[0] == '*') {
326 while (input[++pos] == '*') ;
327 if (input[pos] != '\0')
328 return 0;
329 if (bits)
330 *bits = 0;
331 }
332 return pos;
333}
334
335const char *irc_ntoa(const irc_in_addr_t *addr)
336{
337 static char ntoa[IRC_NTOP_MAX_SIZE];
338 irc_ntop(ntoa, sizeof(ntoa), addr);
339 return ntoa;
340}
341
342unsigned int
343irc_check_mask(const irc_in_addr_t *check, const irc_in_addr_t *mask, unsigned char bits)
344{
345 unsigned int ii;
346
347 for (ii = 0; (ii < 8) && (bits > 16); bits -= 16, ++ii)
348 if (check->in6[ii] != mask->in6[ii])
349 return 0;
350 if (ii < 8 && bits > 0
351 && (ntohs(check->in6[ii] ^ mask->in6[ii]) >> (16 - bits)))
352 return 0;
353 return 1;
354}
355
d76ed9a9 356static char irc_tolower[256];
357#undef tolower
358#define tolower(X) irc_tolower[(unsigned char)(X)]
359
d6b0769f 360void
361irc_strtolower(char *str) {
362 char *p;
363 for(p = str;*p;p++) {
364 *p = tolower(*p);
365 }
366}
367
d76ed9a9 368int
369irccasecmp(const char *stra, const char *strb) {
370 while (*stra && (tolower(*stra) == tolower(*strb)))
371 stra++, strb++;
372 return tolower(*stra) - tolower(*strb);
373}
374
375int
376ircncasecmp(const char *stra, const char *strb, unsigned int len) {
377 len--;
378 while (*stra && (tolower(*stra) == tolower(*strb)) && len)
379 stra++, strb++, len--;
380 return tolower(*stra) - tolower(*strb);
381}
382
383const char *
384irccasestr(const char *haystack, const char *needle) {
385 unsigned int hay_len = strlen(haystack), needle_len = strlen(needle), pos;
386 if (hay_len < needle_len)
387 return NULL;
388 for (pos=0; pos<hay_len+1-needle_len; ++pos) {
389 if ((tolower(haystack[pos]) == tolower(*needle))
390 && !ircncasecmp(haystack+pos, needle, needle_len))
391 return haystack+pos;
392 }
393 return NULL;
394}
395
1136f709 396char *
397ircstrlower(char *str) {
398 size_t ii;
399 for (ii = 0; str[ii] != '\0'; ++ii)
400 str[ii] = tolower(str[ii]);
401 return str;
402}
403
d76ed9a9 404int
405split_line(char *line, int irc_colon, int argv_size, char *argv[])
406{
407 int argc = 0;
408 int n;
409 while (*line && (argc < argv_size)) {
410 while (*line == ' ')
411 *line++ = 0;
412 if (*line == ':' && irc_colon && argc > 0) {
413 /* the rest is a single parameter */
414 argv[argc++] = line + 1;
415 break;
416 }
417 if (!*line)
418 break;
419 argv[argc++] = line;
420 if (argc >= argv_size)
421 break;
422 while (*line != ' ' && *line)
423 line++;
424 }
425#ifdef NDEBUG
426 n = 0;
427#else
428 for (n=argc; n<argv_size; n++)
429 argv[n] = (char*)0xFEEDBEEF;
430#endif
431 return argc;
432}
433
434/* This is ircu's mmatch() function, from match.c. */
435int mmatch(const char *old_mask, const char *new_mask)
436{
437 register const char *m = old_mask;
438 register const char *n = new_mask;
439 const char *ma = m;
440 const char *na = n;
441 int wild = 0;
442 int mq = 0, nq = 0;
443
444 while (1)
445 {
446 if (*m == '*')
447 {
448 while (*m == '*')
449 m++;
450 wild = 1;
451 ma = m;
452 na = n;
453 }
454
455 if (!*m)
456 {
457 if (!*n)
458 return 0;
459 for (m--; (m > old_mask) && (*m == '?'); m--)
460 ;
461 if ((*m == '*') && (m > old_mask) && (m[-1] != '\\'))
462 return 0;
463 if (!wild)
464 return 1;
465 m = ma;
466
467 /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
468 if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
469 ++na;
470
471 n = ++na;
472 }
473 else if (!*n)
474 {
475 while (*m == '*')
476 m++;
477 return (*m != 0);
478 }
479 if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
480 {
481 m++;
482 mq = 1;
483 }
484 else
485 mq = 0;
486
487 /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
488 if ((*n == '\\') && ((n[1] == '*') || (n[1] == '?')))
489 {
490 n++;
491 nq = 1;
492 }
493 else
494 nq = 0;
495
496/*
497 * This `if' has been changed compared to match() to do the following:
498 * Match when:
499 * old (m) new (n) boolean expression
500 * * any (*m == '*' && !mq) ||
501 * ? any except '*' (*m == '?' && !mq && (*n != '*' || nq)) ||
502 * any except * or ? same as m (!((*m == '*' || *m == '?') && !mq) &&
503 * toLower(*m) == toLower(*n) &&
504 * !((mq && !nq) || (!mq && nq)))
505 *
506 * Here `any' also includes \* and \? !
507 *
508 * After reworking the boolean expressions, we get:
509 * (Optimized to use boolean shortcircuits, with most frequently occuring
510 * cases upfront (which took 2 hours!)).
511 */
512 if ((*m == '*' && !mq) ||
513 ((!mq || nq) && tolower(*m) == tolower(*n)) ||
514 (*m == '?' && !mq && (*n != '*' || nq)))
515 {
516 if (*m)
517 m++;
518 if (*n)
519 n++;
520 }
521 else
522 {
523 if (!wild)
524 return 1;
525 m = ma;
526
527 /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
528 if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
529 ++na;
530
531 n = ++na;
532 }
533 }
534}
535
536int
537match_ircglob(const char *text, const char *glob)
538{
dee9951d 539 const char *m = glob, *n = text;
540 const char *m_tmp = glob, *n_tmp = text;
541 int star_p;
542
543 for (;;) switch (*m) {
544 case '\0':
545 if (!*n)
546 return 1;
547 backtrack:
548 if (m_tmp == glob)
549 return 0;
550 m = m_tmp;
551 n = ++n_tmp;
1136f709 552 if (!*n)
553 return 0;
dee9951d 554 break;
555 case '\\':
556 m++;
557 /* allow escaping to force capitalization */
558 if (*m++ != *n++)
2f61d1d7 559 goto backtrack;
dee9951d 560 break;
561 case '*': case '?':
562 for (star_p = 0; ; m++) {
563 if (*m == '*')
564 star_p = 1;
565 else if (*m == '?') {
566 if (!*n++)
567 goto backtrack;
568 } else break;
569 }
570 if (star_p) {
571 if (!*m)
d76ed9a9 572 return 1;
dee9951d 573 else if (*m == '\\') {
574 m_tmp = ++m;
575 if (!*m)
d76ed9a9 576 return 0;
dee9951d 577 for (n_tmp = n; *n && *n != *m; n++) ;
578 } else {
579 m_tmp = m;
580 for (n_tmp = n; *n && tolower(*n) != tolower(*m); n++) ;
581 }
582 }
583 /* and fall through */
584 default:
585 if (!*n)
586 return *m == '\0';
587 if (tolower(*m) != tolower(*n))
588 goto backtrack;
589 m++;
590 n++;
591 break;
d76ed9a9 592 }
593}
594
595extern const char *hidden_host_suffix;
596
d1a65675 597/* Prevent *@* *@** *@*a* type masks, while allowing anything else. This is the best way iv found to detect
598 * a global matching mask; if it matches this string, it'll match almost anything :) */
599int is_overmask(char *mask)
600{
601 return(match_ircglob("abcdefghijklmnopqrstuv!frcmbghilnrtoasde@apdic.yfa.dsfsdaffsdasfdasfd.abcdefghijklmnopqrstuvwxyz.asdfasfdfsdsfdasfda.ydfbe", mask));
602}
603
d76ed9a9 604int
277ad996 605user_matches_glob(struct userNode *user, const char *orig_glob, int flags, int shared)
d76ed9a9 606{
2e9062b9 607 char *tmpglob, *glob, *marker;
634d32a3 608 char exttype = 0;
80ca5a69 609 int extreverse = 0, is_extended = 0, match = 0, banned = 0;
610 unsigned int count, n;
611 struct modeNode *mn;
277ad996 612 struct chanNode *channel;
613 struct banNode *ban;
d76ed9a9 614
615 /* Make a writable copy of the glob */
616 glob = alloca(strlen(orig_glob)+1);
617 strcpy(glob, orig_glob);
634d32a3 618
619 /* Extended bans */
620 tmpglob = alloca(strlen(orig_glob)+1);
621 tmpglob = strdup(orig_glob);
622
623 if (*tmpglob == '~') {
624 tmpglob++; /* get rid of the ~ */
625
626 if (*tmpglob == '!') {
627 extreverse = 1;
628 tmpglob++; /* get rid of the ! */
629 }
630
631 exttype = *tmpglob;
632 tmpglob++; /* get rid of the type */
633
634 if (*tmpglob == ':') {
635 is_extended = 1;
636 tmpglob++; /* get rid of the : */
637 glob = strdup(tmpglob);
638 }
639 }
640
641 if (is_extended) {
642 log_module(MAIN_LOG, LOG_DEBUG, "Extended ban. T (%c) R (%d) M (%s)", exttype, extreverse, glob);
643 switch (exttype) {
644 case 'a':
645 if (user->handle_info) {
646 if (extreverse) {
647 if (0 != strcasecmp(glob, user->handle_info->handle))
648 return 1;
649 } else {
650 if (0 == strcasecmp(glob, user->handle_info->handle))
651 return 1;
652 }
653 } else {
654 if (extreverse)
655 return 1;
656 }
657 return match_ircglob(user->hostname, glob);
80ca5a69 658 case 'c':
659 if (!strstr(glob, "#"))
3b7fa78b 660 return -1;
80ca5a69 661
80ca5a69 662 if (extreverse) {
663 for (n=count=0; n<user->channels.used; n++) {
664 mn = user->channels.list[n];
665 match = 0;
666
2e9062b9 667 if (*glob == '#') {
668 if (0 == strcasecmp(glob, mn->channel->name))
80ca5a69 669 match = 1;
2e9062b9 670 } else {
671 if (0 == strcasecmp(glob+1, mn->channel->name)) {
672 if ((*glob == '@') && (mn->modes & MODE_CHANOP))
673 match = 1;
674 else if ((*glob == '%') && (mn->modes & MODE_HALFOP))
675 match = 1;
676 else if ((*glob == '+') && (mn->modes & MODE_VOICE))
677 match = 1;
678 }
80ca5a69 679 }
680
681 if (match == 0)
682 banned = 1;
683 else {
684 banned = 0;
685 break;
686 }
687 }
688 } else {
689 for (n=count=0; n<user->channels.used; n++) {
690 mn = user->channels.list[n];
691 match = 0;
692
2e9062b9 693 if (*glob == '#') {
694 if (0 == strcasecmp(glob, mn->channel->name))
80ca5a69 695 match = 1;
2e9062b9 696 } else {
697 if (0 == strcasecmp(glob+1, mn->channel->name)) {
698 if ((*glob == '@') && (mn->modes & MODE_CHANOP))
699 match = 1;
700 else if ((*glob == '%') && (mn->modes & MODE_HALFOP))
701 match = 1;
702 else if ((*glob == '+') && (mn->modes & MODE_VOICE))
703 match = 1;
704 }
80ca5a69 705 }
2e9062b9 706
80ca5a69 707 if (match == 1)
708 banned = 1;
709 }
710 }
711
712 if (banned)
713 return 1;
714 else
715 return match_ircglob(user->hostname, glob);
277ad996 716 case 'j':
717 if (shared == 0) {
95b9d0bc 718 if (*glob != '#')
719 return -1;
277ad996 720 if ((channel = GetChannel(glob))) {
721 for (n = 0; n < channel->banlist.used; n++) {
722 ban = channel->banlist.list[n];
723 if (user_matches_glob(user, ban->ban, flags, 1))
724 return 1;
725 }
726 }
727 }
728 return match_ircglob(user->hostname, glob);
80ca5a69 729 case 'n': /* this is handled ircd side */
730 return match_ircglob(user->hostname, glob);
277ad996 731 case 'q': /* this is handled ircd side */
732 return match_ircglob(user->hostname, glob);
80ca5a69 733 case 't': /* this is handled ircd side */
734 return match_ircglob(user->hostname, glob);
634d32a3 735 default:
3b7fa78b 736 return -1;
634d32a3 737 }
738 }
739
d76ed9a9 740 /* Check the nick, if it's present */
2f61d1d7 741 if (flags & MATCH_USENICK) {
d76ed9a9 742 if (!(marker = strchr(glob, '!'))) {
2f61d1d7 743 log_module(MAIN_LOG, LOG_ERROR, "user_matches_glob(\"%s\", \"%s\", %d) called, and glob doesn't include a '!'", user->nick, orig_glob, flags);
d76ed9a9 744 return 0;
745 }
746 *marker = 0;
747 if (!match_ircglob(user->nick, glob)) return 0;
748 glob = marker + 1;
749 }
750 /* Check the ident */
751 if (!(marker = strchr(glob, '@'))) {
2f61d1d7 752 log_module(MAIN_LOG, LOG_ERROR, "user_matches_glob(\"%s\", \"%s\", %d) called, and glob doesn't include an '@'", user->nick, orig_glob, flags);
d76ed9a9 753 return 0;
754 }
755 *marker = 0;
2f61d1d7 756 if (!match_ircglob(user->ident, glob))
757 return 0;
d76ed9a9 758 glob = marker + 1;
ec1a68c8 759 /* Check for a fakehost match. */
760 if (IsFakeHost(user) && match_ircglob(user->fakehost, glob))
efabf227 761 return 1;
2f61d1d7 762
763 /* Check for a sethost (S:lines) */
764 if (IsSetHost(user) && match_ircglob(user->sethost, glob))
efabf227 765 return 1;
2f61d1d7 766
ec1a68c8 767 /* Check for an account match. */
768 if (hidden_host_suffix && user->handle_info) {
769 char hidden_host[HOSTLEN+1];
770 snprintf(hidden_host, sizeof(hidden_host), "%s.%s", user->handle_info->handle, hidden_host_suffix);
771 if (match_ircglob(hidden_host, glob))
a32da4c7 772 return 1;
d76ed9a9 773 }
f16ad9e7 774
775 /* Match crypt hostname */
776 if (match_ircglob(user->crypthost, glob))
777 return 1;
778
779 /* Match crypt IP */
780 if (match_ircglob(user->cryptip, glob))
781 return 1;
782
2f61d1d7 783 /* If only matching the visible hostnames, bail early. */
784 if ((flags & MATCH_VISIBLE) && IsHiddenHost(user)
785 && (IsFakeHost(user) || (hidden_host_suffix && user->handle_info)))
786 return 0;
787 /* If it might be an IP glob, test that. */
788 if (!glob[strspn(glob, "0123456789./*?")]
789 && match_ircglob(irc_ntoa(&user->ip), glob))
790 return 1;
ec1a68c8 791 /* None of the above; could only be a hostname match. */
792 return match_ircglob(user->hostname, glob);
d76ed9a9 793}
794
795int
796is_ircmask(const char *text)
797{
8062bfc3 798 char *tmptext;
799
800 if (*text == '~') {
801 tmptext = alloca(strlen(text)+1);
802 tmptext = strdup(text);
803
804 tmptext++; /* get rid of the ~ */
805
806 if (*tmptext == '!')
807 tmptext++; /* get rid of the ! if it exists */
808
809 tmptext++; /* get rid of the ext ban type */
810
811 if (*tmptext == ':') {
812 tmptext++; /* get rid of the : */
813 while (*tmptext && !isspace((char)*tmptext))
814 tmptext++; /* get rid of the rest */
815 return !*tmptext;
816 }
817 }
818
d76ed9a9 819 while (*text && (isalnum((char)*text) || strchr("-_[]|\\`^{}?*", *text)))
820 text++;
821 if (*text++ != '!')
822 return 0;
823 while (*text && *text != '@' && !isspace((char)*text))
824 text++;
825 if (*text++ != '@')
826 return 0;
827 while (*text && !isspace((char)*text))
828 text++;
829 return !*text;
830}
831
832int
833is_gline(const char *text)
d914d1cb 834{
835 if (*text == '@')
836 return 0;
837 text += strcspn(text, "@!% \t\r\n");
838 if (*text++ != '@')
839 return 0;
840 if (!*text)
841 return 0;
842 while (*text && (isalnum((char)*text) || strchr(".-?*:", *text)))
843 text++;
844 return !*text;
845}
846
847int
848is_shun(const char *text)
d76ed9a9 849{
850 if (*text == '@')
851 return 0;
852 text += strcspn(text, "@!% \t\r\n");
853 if (*text++ != '@')
854 return 0;
855 if (!*text)
856 return 0;
ec1a68c8 857 while (*text && (isalnum((char)*text) || strchr(".-?*:", *text)))
d76ed9a9 858 text++;
859 return !*text;
860}
861
862int
863split_ircmask(char *text, char **nick, char **ident, char **host)
864{
865 char *start;
866
867 start = text;
868 while (isalnum((char)*text) || strchr("=[]\\`^{}?*", *text))
869 text++;
870 if (*text != '!' || ((text - start) > NICKLEN))
871 return 0;
872 *text = 0;
873 if (nick)
874 *nick = start;
875
876 start = ++text;
877 while (*text && *text != '@' && !isspace((char)*text))
878 text++;
879 if (*text != '@' || ((text - start) > USERLEN))
880 return 0;
881 *text = 0;
882 if (ident)
883 *ident = start;
884
885 start = ++text;
ec1a68c8 886 while (*text && (isalnum((char)*text) || strchr(".-?*:", *text)))
d76ed9a9 887 text++;
888 if (host)
889 *host = start;
890 return !*text && ((text - start) <= HOSTLEN) && nick && ident && host;
891}
892
893char *
894sanitize_ircmask(char *input)
895{
896 unsigned int length, flag;
897 char *mask, *start, *output;
898
899 /* Sanitize everything in place; input *must* be a valid
900 hostmask. */
901 output = input;
902 flag = 0;
903
904 /* The nick is truncated at the end. */
905 length = 0;
906 mask = input;
907 while(*input++ != '!')
908 {
909 length++;
910 }
911 if(length > NICKLEN)
912 {
913 mask += NICKLEN;
914 *mask++ = '!';
915
916 /* This flag is used to indicate following parts should
917 be shifted. */
918 flag = 1;
919 }
920 else
921 {
922 mask = input;
923 }
924
925 /* The ident and host must be truncated at the beginning and
926 replaced with a '*' to be compatible with ircu. */
927 length = 0;
928 start = input;
929 while(*input++ != '@')
930 {
931 length++;
932 }
933 if(length > USERLEN || flag)
934 {
935 if(length > USERLEN)
936 {
937 start = input - USERLEN;
938 *mask++ = '*';
939 }
940 while(*start != '@')
941 {
942 *mask++ = *start++;
943 }
944 *mask++ = '@';
945
946 flag = 1;
947 }
948 else
949 {
950 mask = input;
951 }
952
953 length = 0;
954 start = input;
955 while(*input++)
956 {
957 length++;
958 }
959 if(length > HOSTLEN || flag)
960 {
961 if(length > HOSTLEN)
962 {
963 start = input - HOSTLEN;
964 *mask++ = '*';
965 }
966 while(*start)
967 {
968 *mask++ = *start++;
969 }
970 *mask = '\0';
971 }
972
973 return output;
974}
975
976static long
977TypeLength(char type)
978{
979 switch (type) {
980 case 'y': return 365*24*60*60;
ca22ccd3 981 case 'M': return 30*24*60*60;
d76ed9a9 982 case 'w': return 7*24*60*60;
983 case 'd': return 24*60*60;
984 case 'h': return 60*60;
985 case 'm': return 60;
986 case 's': return 1;
987 default: return 0;
988 }
989}
990
ca22ccd3 991/* This function is not entirely accurate as it does not take into account leap units
992 * or varying months. TODO: use proper dateadd functions to calculate real seconds
993 * from now for the units (eg 1M should be give us seconds till todays date next month)
994 */
d76ed9a9 995unsigned long
996ParseInterval(const char *interval)
997{
998 unsigned long seconds = 0;
999 int partial = 0;
1000 char c;
1001
1002 /* process the string, resetting the count if we find a unit character */
1003 while ((c = *interval++)) {
1136f709 1004 if (isdigit((int)c)) {
1005 partial = partial*10 + c - '0';
1006 } else if (strchr("yMwdhms", c)) {
1007 seconds += TypeLength(c) * partial;
1008 partial = 0;
1009 } else {
1010 return 0;
1011 }
d76ed9a9 1012 }
1013 /* assume the last chunk is seconds (the normal case) */
1014 return seconds + partial;
1015}
1016
1017static long
1018GetSizeMultiplier(char type)
1019{
1020 switch (type) {
1021 case 'G': case 'g': return 1024*1024*1024;
1022 case 'M': case 'm': return 1024*1024;
1023 case 'K': case 'k': return 1024;
1024 case 'B': case 'b': return 1;
1025 default: return 0;
1026 }
1027}
1028
1029unsigned long
1030ParseVolume(const char *volume)
1031{
1032 unsigned long accum = 0, partial = 0;
1033 char c;
1034 while ((c = *volume++)) {
1035 if (isdigit((int)c)) {
1036 partial = partial*10 + c - '0';
1037 } else {
1038 accum += GetSizeMultiplier(c) * partial;
1039 partial = 0;
1040 }
1041 }
1042 return accum + partial;
1043}
1044
d76ed9a9 1045char *
1046unsplit_string(char *set[], unsigned int max, char *dest)
1047{
1048 static char unsplit_buffer[MAXLEN*2];
1049 unsigned int ii, jj, pos;
1050
1051 if (!dest)
1052 dest = unsplit_buffer;
1053 for (ii=pos=0; ii<max; ii++) {
1054 for (jj=0; set[ii][jj]; jj++)
1055 dest[pos++] = set[ii][jj];
1056 dest[pos++] = ' ';
1057 }
1058 dest[--pos] = 0;
1059 return dest;
1060}
1061
1062char *
1063intervalString(char *output, time_t interval, struct handle_info *hi)
1064{
1065 static const struct {
1066 const char *msg_single;
1067 const char *msg_plural;
1068 long length;
1069 } unit[] = {
1070 { "MSG_YEAR", "MSG_YEARS", 365 * 24 * 60 * 60 },
1071 { "MSG_WEEK", "MSG_WEEKS", 7 * 24 * 60 * 60 },
1072 { "MSG_DAY", "MSG_DAYS", 24 * 60 * 60 },
1073 { "MSG_HOUR", "MSG_HOURS", 60 * 60 },
1074 { "MSG_MINUTE", "MSG_MINUTES", 60 },
1075 { "MSG_SECOND", "MSG_SECONDS", 1 }
1076 };
1077 struct language *lang;
1078 const char *msg;
1079 unsigned int type, words, pos, count;
1080
1081 lang = hi ? hi->language : lang_C;
1082 if(!interval)
1083 {
1084 msg = language_find_message(lang, "MSG_0_SECONDS");
1085 return strcpy(output, msg);
1086 }
1087
1088 for (type = 0, words = pos = 0;
1089 interval && (words < 2) && (type < ArrayLength(unit));
1090 type++) {
1091 if (interval < unit[type].length)
1092 continue;
1093 count = interval / unit[type].length;
1094 interval = interval % unit[type].length;
1095
1096 if (words++ == 1) {
1097 msg = language_find_message(lang, "MSG_AND");
de9510bc 1098 pos += sprintf(output + pos, "%s ", msg);
d76ed9a9 1099 }
1100 if (count == 1)
1101 msg = language_find_message(lang, unit[type].msg_single);
1102 else
1103 msg = language_find_message(lang, unit[type].msg_plural);
de9510bc 1104 pos += sprintf(output + pos, "%d%s", count, msg);
d76ed9a9 1105 }
1106
1107 output[pos] = 0;
1108 return output;
1109}
1110
1111int
1112getipbyname(const char *name, unsigned long *ip)
1113{
1114 struct hostent *he = gethostbyname(name);
1115 if (!he)
1116 return 0;
1117 if (he->h_addrtype != AF_INET)
1118 return 0;
1119 memcpy(ip, he->h_addr_list[0], sizeof(*ip));
1120 return 1;
1121}
1122
1123DEFINE_LIST(string_buffer, char)
1124
1125void
1126string_buffer_append_substring(struct string_buffer *buf, const char *tail, unsigned int len)
1127{
1128 while (buf->used + len >= buf->size) {
1129 if (!buf->size)
1130 buf->size = 16;
1131 else
1132 buf->size <<= 1;
1133 buf->list = realloc(buf->list, buf->size*sizeof(buf->list[0]));
1134 }
1135 memcpy(buf->list + buf->used, tail, len+1);
1136 buf->used += len;
1137}
1138
1139void
1140string_buffer_append_string(struct string_buffer *buf, const char *tail)
1141{
1142 string_buffer_append_substring(buf, tail, strlen(tail));
1143}
1144
1145void
1146string_buffer_append_vprintf(struct string_buffer *buf, const char *fmt, va_list args)
1147{
1148 va_list working;
1149 unsigned int len;
1150 int ret;
1151
1152 VA_COPY(working, args);
1153 len = strlen(fmt);
1154 if (!buf->list || ((buf->used + buf->size) < len)) {
1155 buf->size = buf->used + len;
1156 buf->list = realloc(buf->list, buf->size);
1157 }
1158 ret = vsnprintf(buf->list + buf->used, buf->size - buf->used, fmt, working);
1159 if (ret <= 0) {
1160 /* pre-C99 behavior; double buffer size until it is big enough */
1161 va_end(working);
1162 VA_COPY(working, args);
a32da4c7 1163 while ((ret = vsnprintf(buf->list + buf->used, buf->size - buf->used, fmt, working)) <= 0) {
d76ed9a9 1164 buf->size += len;
1165 buf->list = realloc(buf->list, buf->size);
1166 va_end(working);
1167 VA_COPY(working, args);
1168 }
1169 buf->used += ret;
1170 } else if (buf->used + ret < buf->size) {
1171 /* no need to increase allocation size */
1172 buf->used += ret;
1173 } else {
1174 /* now we know exactly how much space we need */
1175 if (buf->size <= buf->used + ret) {
1176 buf->size = buf->used + ret + 1;
1177 buf->list = realloc(buf->list, buf->size);
1178 }
1179 va_end(working);
1180 VA_COPY(working, args);
1181 buf->used += vsnprintf(buf->list + buf->used, buf->size, fmt, working);
1182 }
1183 va_end(working);
1184 va_end(args);
1185}
1186
1187void string_buffer_append_printf(struct string_buffer *buf, const char *fmt, ...)
1188{
1189 va_list args;
1190 va_start(args, fmt);
1191 string_buffer_append_vprintf(buf, fmt, args);
1192}
1193
1194void
1195string_buffer_replace(struct string_buffer *buf, unsigned int from, unsigned int len, const char *repl)
1196{
1197 unsigned int repl_len = strlen(repl);
1198 if (from > buf->used)
1199 return;
1200 if (len + from > buf->used)
1201 len = buf->used - from;
1202 buf->used = buf->used + repl_len - len;
1203 if (buf->size <= buf->used) {
1204 while (buf->used >= buf->size)
1205 buf->size <<= 1;
1206 buf->list = realloc(buf->list, buf->size*sizeof(buf->list[0]));
1207 }
1208 memmove(buf->list+from+repl_len, buf->list+from+len, strlen(buf->list+from+len));
1209 strcpy(buf->list+from, repl);
1210}
1211
1212struct string_list str_tab;
1213
1214const char *
1215strtab(unsigned int ii) {
1216 if (ii > 65536)
1217 return NULL;
1218 if (ii > str_tab.size) {
1219 unsigned int old_size = str_tab.size;
1220 while (ii >= str_tab.size)
1221 str_tab.size <<= 1;
1222 str_tab.list = realloc(str_tab.list, str_tab.size*sizeof(str_tab.list[0]));
1223 memset(str_tab.list+old_size, 0, (str_tab.size-old_size)*sizeof(str_tab.list[0]));
1224 }
1225 if (!str_tab.list[ii]) {
1226 str_tab.list[ii] = malloc(12);
1227 sprintf(str_tab.list[ii], "%u", ii);
1228 }
1229 return str_tab.list[ii];
1230}
1231
1232void
1233tools_init(void)
1234{
1235 unsigned int upr, lwr;
1236 for (lwr=0; lwr<256; ++lwr)
1237 tolower(lwr) = lwr;
1238 for (upr='A', lwr='a'; lwr <= 'z'; ++upr, ++lwr)
1239 tolower(upr) = lwr;
1240#ifdef WITH_PROTOCOL_P10
1241 for (upr='[', lwr='{'; lwr <= '~'; ++upr, ++lwr)
1242 tolower(upr) = lwr;
1243 for (upr=0xc0, lwr=0xe0; lwr <= 0xf6; ++upr, ++lwr)
1244 tolower(upr) = lwr;
1245 for (upr=0xd8, lwr=0xf8; lwr <= 0xfe; ++upr, ++lwr)
1246 tolower(upr) = lwr;
1247#endif
1248 str_tab.size = 1001;
1249 str_tab.list = calloc(str_tab.size, sizeof(str_tab.list[0]));
1250}
1251
1252void
1253tools_cleanup(void)
1254{
1255 unsigned int ii;
1256 for (ii=0; ii<str_tab.size; ++ii)
1257 free(str_tab.list[ii]);
1258 free(str_tab.list);
1259}
2aef5f4b 1260
1261/* mysep() is my answer to the strtok/strsep
1262 * issue. strsep is nice but doesn't skip
1263 * multiple dilimiters, which can really
1264 * offset tokens and cause huge corruption
1265 * so this function will use strsep but
31f23f13 1266 * act like strtok in that sense.
2aef5f4b 1267 */
1268char *mysep(char **sepstr, char *delim)
1269{
1270 static char *retstr;
1271
1272 if(!*sepstr || !**sepstr)
1273 return(NULL);
1274
1275 do
1276 {
1277 retstr = strsep(sepstr, delim);
1278 }while (retstr && !(*retstr));
1279
1280 return(retstr);
1281}
1282
c9bf23fe 1283/* Mallocing snprintf *
1284 *
1285 * If it overruns size, it will simply be safely truncated.
1286 */
1287char *
1288x3_msnprintf(const int size, const char *format, ...)
1289{
1290 va_list ap;
1291 char* buff = calloc(sizeof(char *), size+1);
1292
1293 va_start(ap, format);
1294 vsnprintf(buff, size, format, ap);
1295 va_end(ap);
1296 buff = realloc(buff, strlen(buff) + 1);
1297 return buff;
1298}
1299
eb5d6b73 1300char *time2str(time_t thetime)
1301{
1302 char *buf, *tmp;
1303
1304 buf = ctime(&thetime);
1305 tmp = (char *)strchr(buf, '\n');
1306 *tmp = '\0';
1307 return(buf);
1308}
1309
63665495 1310char* x3_strtok(char **save, char *str, char *fs)
1311{
1312 char *pos = *save; /* keep last position across calls */
1313 char *tmp;
1314
1315 if (str)
1316 pos = str; /* new string scan */
1317
1318 while (pos && *pos && strchr(fs, *pos) != NULL)
1319 pos++; /* skip leading separators */
1320
1321 if (!pos || !*pos)
1322 return (pos = *save = NULL); /* string contains only sep's */
1323
1324 tmp = pos; /* now, keep position of the token */
1325
1326 while (*pos && strchr(fs, *pos) == NULL)
1327 pos++; /* skip content of the token */
1328
1329 if (*pos)
1330 *pos++ = '\0'; /* remove first sep after the token */
1331 else
1332 pos = NULL; /* end of string */
1333
1334 *save = pos;
1335 return (tmp);
1336}
1337
4c26ef3e 1338int valid_email(const char *email)
1339{
1340 unsigned int i;
1341 for (i=0;i<strlen(email);i++)
1342 {
1343 if(!isalnum(email[i]) &&
1344 email[i] != '.' &&
1345 email[i] != '@' &&
1346 email[i] != '-' &&
1347 email[i] != '+' &&
1348 email[i] != '_' )
1349 return false;
1350 }
1351 if(strchr(email, '@') == NULL)
1352 return false;
1353 return true;
1354}
1355
668dc38e 1356/*
1357 * Create a string of form "foo!bar@fubar" given foo, bar and fubar
1358 * as the parameters. If NULL, they become "*".
1359 */
1360#define NUH_BUFSIZE (NICKLEN + USERLEN + HOSTLEN + 10)
1361static char *make_nick_user_host(char *namebuf, const char *nick,
1362 const char *name, const char *host)
1363{
1364 snprintf(namebuf, NUH_BUFSIZE, "%s!%s@%s", nick, name, host);
1365 return namebuf;
1366}
1367
1368/*
1369 * pretty_mask
1370 *
1371 * by Carlo Wood (Run), 05 Oct 1998.
1372 *
1373 * Canonify a mask.
1374 *
1375 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1376 * When the user name or host name are too long (USERLEN and HOSTLEN
1377 * respectively) then they are cut off at the start with a '*'.
1378 *
1379 * The following transformations are made:
1380 *
1381 * 1) xxx -> nick!*@*
1382 * 2) xxx.xxx -> *!*@host
1383 * 3) xxx!yyy -> nick!user@*
1384 * 4) xxx@yyy -> *!user@host
1385 * 5) xxx!yyy@zzz -> nick!user@host
1386 */
1387char *pretty_mask(char *mask)
1388{
1389 static char star[2] = { '*', 0 };
1390 static char retmask[NUH_BUFSIZE] = "";
1391 char *last_dot = NULL;
1392 char *ptr = NULL;
1393
1394 /* Case 1: default */
1395 char *nick = mask;
1396 char *user = star;
1397 char *host = star;
1398
1399 /* Do a _single_ pass through the characters of the mask: */
1400 for (ptr = mask; *ptr; ++ptr)
1401 {
1402 if (*ptr == '!')
1403 {
1404 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1405 user = ++ptr;
1406 host = star;
1407 }
1408 else if (*ptr == '@')
1409 {
1410 /* Case 4: Found last '@' (without finding a '!' yet) */
1411 nick = star;
1412 user = mask;
1413 host = ++ptr;
1414 }
1415 else if (*ptr == '.')
1416 {
1417 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1418 last_dot = ptr;
1419 continue;
1420 }
1421 else
1422 continue;
1423 for (; *ptr; ++ptr)
1424 {
1425 if (*ptr == '@')
1426 {
1427 /* Case 4 or 5: Found last '@' */
1428 host = ptr + 1;
1429 }
1430 }
1431 break;
1432 }
1433 if (user == star && last_dot)
1434 {
1435 /* Case 2: */
1436 nick = star;
1437 user = star;
1438 host = mask;
1439 }
1440 /* Check lengths */
1441 if (nick != star)
1442 {
1443 char *nick_end = (user != star) ? user - 1 : ptr;
1444 if (nick_end - nick > NICKLEN)
1445 nick[NICKLEN] = 0;
1446 *nick_end = 0;
1447 }
1448 if (user != star)
1449 {
1450 char *user_end = (host != star) ? host - 1 : ptr;
1451 if (user_end - user > USERLEN)
1452 {
1453 user = user_end - USERLEN;
1454 *user = '*';
1455 }
1456 *user_end = 0;
1457 }
1458 if (host != star && ptr - host > HOSTLEN)
1459 {
1460 host = ptr - HOSTLEN;
1461 *host = '*';
1462 }
1463 return make_nick_user_host(retmask, nick, user, host);
1464}
c9bf23fe 1465
7a278540 1466int str_is_number(const char *str)
c9bf23fe 1467{
1468 char *ptr;
1469 int ret = false;
7a278540 1470 for(ptr = (char *)str;*ptr;ptr++) {
c9bf23fe 1471 if((*ptr >= '0' && *ptr <= '9') || *ptr == '-')
1472 ret = true;
1473 else
1474 return false;
1475 }
1476 return ret;
1477}