]> jfr.im git - solanum.git/blame - bandb/bantool.c
bandb: update sqlite3 to 3.12.0
[solanum.git] / bandb / bantool.c
CommitLineData
832ed81a
AC
1/**
2 * ircd-ratbox: A slightly useful ircd.
3 * bantool.c: The ircd-ratbox database managment tool.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2008 ircd-ratbox development team
8 * Copyright (C) 2008 Daniel J Reidy <dubkat@gmail.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 * USA
24 *
832ed81a
AC
25 * The following server admins have either contributed various configs to test against,
26 * or helped with debugging and feature requests. Many thanks to them.
27 * stevoo / efnet.port80.se
28 * AndroSyn / irc2.choopa.net, irc.igs.ca
29 * Salvation / irc.blessed.net
30 * JamesOff / efnet.demon.co.uk
31 *
32 * Thanks to AndroSyn for challenging me to learn C on the fly :)
33 * BUGS Direct Question, Bug Reports, and Feature Requests to #ratbox on EFnet.
34 * BUGS Complaints >/dev/null
35 *
36 */
37
832ed81a
AC
38#include <stdio.h>
39#include <stdlib.h>
40#include <time.h>
41
42#include "stdinc.h"
43#include "rsdb.h"
44
45#define EmptyString(x) ((x == NULL) || (*(x) == '\0'))
46#define CheckEmpty(x) EmptyString(x) ? "" : x
47
48#define BT_VERSION "0.4.1"
49
50typedef enum
51{
52 BANDB_KLINE,
53 BANDB_KLINE_PERM,
54 BANDB_DLINE,
55 BANDB_DLINE_PERM,
56 BANDB_XLINE,
57 BANDB_XLINE_PERM,
58 BANDB_RESV,
59 BANDB_RESV_PERM,
60 LAST_BANDB_TYPE
61} bandb_type;
62
63
64static char bandb_letter[LAST_BANDB_TYPE] = {
65 'K', 'K', 'D', 'D', 'X', 'X', 'R', 'R'
66};
67
68static const char *bandb_table[LAST_BANDB_TYPE] = {
69 "kline", "kline", "dline", "dline", "xline", "xline", "resv", "resv"
70};
71
72static const char *bandb_suffix[LAST_BANDB_TYPE] = {
73 "", ".perm",
74 "", ".perm",
75 "", ".perm",
76 "", ".perm"
77};
78
79static char me[PATH_MAX];
80
81/* *INDENT-OFF* */
82/* report counters */
83struct counter
84{
85 unsigned int klines;
86 unsigned int dlines;
87 unsigned int xlines;
88 unsigned int resvs;
89 unsigned int error;
90} count = {0, 0, 0, 0, 0};
91
92/* flags set by command line options */
93struct flags
94{
ab31d2b0
EM
95 bool none;
96 bool export;
97 bool import;
98 bool verify;
99 bool vacuum;
100 bool pretend;
101 bool verbose;
102 bool wipe;
103 bool dupes_ok;
104} flag = {true, false, false, false, false, false, false, false, false};
832ed81a
AC
105/* *INDENT-ON* */
106
107static int table_has_rows(const char *table);
108static int table_exists(const char *table);
109
110static const char *clean_gecos_field(const char *gecos);
111static char *bt_smalldate(const char *string);
112static char *getfield(char *newline);
113static char *strip_quotes(const char *string);
114static char *mangle_reason(const char *string);
115static char *escape_quotes(const char *string);
116
117static void db_error_cb(const char *errstr);
118static void db_reclaim_slack(void);
119static void export_config(const char *conf, int id);
120static void import_config(const char *conf, int id);
121static void check_schema(void);
122static void print_help(int i_exit);
123static void wipe_schema(void);
124static void drop_dupes(const char *user, const char *host, const char *t);
125
126/**
55abcbb2 127 * swing your pants
832ed81a
AC
128 */
129int
130main(int argc, char *argv[])
131{
132 char etc[PATH_MAX];
133 char conf[PATH_MAX];
134 int opt;
135 int i;
136
137 rb_strlcpy(me, argv[0], sizeof(me));
138
139 while((opt = getopt(argc, argv, "hieuspvwd")) != -1)
140 {
141 switch (opt)
142 {
143 case 'h':
144 print_help(EXIT_SUCCESS);
145 break;
146 case 'i':
ab31d2b0
EM
147 flag.none = false;
148 flag.import = true;
832ed81a
AC
149 break;
150 case 'e':
ab31d2b0
EM
151 flag.none = false;
152 flag.export = true;
832ed81a
AC
153 break;
154 case 'u':
ab31d2b0
EM
155 flag.none = false;
156 flag.verify = true;
832ed81a
AC
157 break;
158 case 's':
ab31d2b0
EM
159 flag.none = false;
160 flag.vacuum = true;
832ed81a
AC
161 break;
162 case 'p':
ab31d2b0 163 flag.pretend = true;
832ed81a
AC
164 break;
165 case 'v':
ab31d2b0 166 flag.verbose = true;
832ed81a
AC
167 break;
168 case 'w':
ab31d2b0 169 flag.wipe = true;
832ed81a
AC
170 break;
171 case 'd':
ab31d2b0 172 flag.dupes_ok = true;
832ed81a
AC
173 break;
174 default: /* '?' */
175 print_help(EXIT_FAILURE);
176 }
177 }
178
179 /* they should really read the help. */
180 if(flag.none)
181 print_help(EXIT_FAILURE);
182
183 if((flag.import && flag.export) || (flag.export && flag.wipe)
184 || (flag.verify && flag.pretend) || (flag.export && flag.pretend))
185 {
186 fprintf(stderr, "* Error: Conflicting flags.\n");
187 if(flag.export && flag.pretend)
188 fprintf(stderr, "* There is nothing to 'pretend' when exporting.\n");
189
190 fprintf(stderr, "* For an explination of commands, run: %s -h\n", me);
191 exit(EXIT_FAILURE);
192 }
193
194 if(argv[optind] != NULL)
195 rb_strlcpy(etc, argv[optind], sizeof(etc));
196 else
197 rb_strlcpy(etc, ETCPATH, sizeof(ETCPATH));
198
199 fprintf(stdout,
5c5d0fb7 200 "* charybdis bantool v.%s\n", BT_VERSION);
832ed81a 201
ab31d2b0 202 if(flag.pretend == false)
832ed81a
AC
203 {
204 if(rsdb_init(db_error_cb) == -1)
205 {
206 fprintf(stderr, "* Error: Unable to open database\n");
207 exit(EXIT_FAILURE);
208 }
209 check_schema();
210
211 if(flag.vacuum)
212 db_reclaim_slack();
213
214 if(flag.import && flag.wipe)
215 {
ab31d2b0 216 flag.dupes_ok = true; /* dont check for dupes if we are wiping the db clean */
832ed81a
AC
217 for(i = 0; i < 3; i++)
218 fprintf(stdout,
219 "* WARNING: YOU ARE ABOUT TO WIPE YOUR DATABASE!\n");
220
221 fprintf(stdout, "* Press ^C to abort! ");
222 fflush(stdout);
223 rb_sleep(10, 0);
224 fprintf(stdout, "Carrying on...\n");
225 wipe_schema();
226 }
227 }
ab31d2b0 228 if(flag.verbose && flag.dupes_ok == true)
832ed81a
AC
229 fprintf(stdout, "* Allowing duplicate bans...\n");
230
231 /* checking for our files to import or export */
232 for(i = 0; i < LAST_BANDB_TYPE; i++)
233 {
5203cba5 234 snprintf(conf, sizeof(conf), "%s/%s.conf%s",
832ed81a
AC
235 etc, bandb_table[i], bandb_suffix[i]);
236
ab31d2b0 237 if(flag.import && flag.pretend == false)
832ed81a
AC
238 rsdb_transaction(RSDB_TRANS_START);
239
240 if(flag.import)
241 import_config(conf, i);
242
243 if(flag.export)
244 export_config(conf, i);
245
ab31d2b0 246 if(flag.import && flag.pretend == false)
832ed81a
AC
247 rsdb_transaction(RSDB_TRANS_END);
248 }
249
250 if(flag.import)
251 {
252 if(count.error && flag.verbose)
29c92cf9 253 fprintf(stderr, "* I was unable to locate %u config files to import.\n",
832ed81a
AC
254 count.error);
255
29c92cf9 256 fprintf(stdout, "* Import Stats: Klines: %u, Dlines: %u, Xlines: %u, Resvs: %u \n",
832ed81a
AC
257 count.klines, count.dlines, count.xlines, count.resvs);
258
259 fprintf(stdout,
260 "*\n* If your IRC server is currently running, newly imported bans \n* will not take effect until you issue the command: /quote rehash bans\n");
261
262 if(flag.pretend)
263 fprintf(stdout,
264 "* Pretend mode engaged. Nothing was actually entered into the database.\n");
265 }
266
267 return 0;
268}
269
270
271/**
272 * export the database to old-style flat files
273 */
274static void
275export_config(const char *conf, int id)
276{
277 struct rsdb_table table;
278 static char sql[BUFSIZE * 2];
279 static char buf[512];
280 FILE *fd = NULL;
281 int j;
282
283 /* for sanity sake */
284 const int mask1 = 0;
285 const int mask2 = 1;
286 const int reason = 2;
287 const int oper = 3;
288 const int ts = 4;
289 /* const int perm = 5; */
290
291 if(!table_has_rows(bandb_table[id]))
292 return;
293
294 if(strstr(conf, ".perm") != 0)
5203cba5 295 snprintf(sql, sizeof(sql),
832ed81a
AC
296 "SELECT DISTINCT mask1,mask2,reason,oper,time FROM %s WHERE perm = 1 ORDER BY time",
297 bandb_table[id]);
298 else
5203cba5 299 snprintf(sql, sizeof(sql),
832ed81a
AC
300 "SELECT DISTINCT mask1,mask2,reason,oper,time FROM %s WHERE perm = 0 ORDER BY time",
301 bandb_table[id]);
302
303 rsdb_exec_fetch(&table, sql);
304 if(table.row_count <= 0)
305 {
306 rsdb_exec_fetch_end(&table);
307 return;
308 }
309
310 if(flag.verbose)
311 fprintf(stdout, "* checking for %s: ", conf); /* debug */
312
313 /* open config for reading, or skip to the next */
314 if(!(fd = fopen(conf, "w")))
315 {
316 if(flag.verbose)
317 fprintf(stdout, "\tmissing.\n");
318 count.error++;
319 return;
320 }
321
322 for(j = 0; j < table.row_count; j++)
323 {
324 switch (id)
325 {
326 case BANDB_DLINE:
327 case BANDB_DLINE_PERM:
5203cba5 328 snprintf(buf, sizeof(buf),
832ed81a
AC
329 "\"%s\",\"%s\",\"\",\"%s\",\"%s\",%s\n",
330 table.row[j][mask1],
331 mangle_reason(table.row[j][reason]),
332 bt_smalldate(table.row[j][ts]),
333 table.row[j][oper], table.row[j][ts]);
334 break;
335
336 case BANDB_XLINE:
337 case BANDB_XLINE_PERM:
5203cba5 338 snprintf(buf, sizeof(buf),
832ed81a
AC
339 "\"%s\",\"0\",\"%s\",\"%s\",%s\n",
340 escape_quotes(table.row[j][mask1]),
341 mangle_reason(table.row[j][reason]),
342 table.row[j][oper], table.row[j][ts]);
343 break;
344
345 case BANDB_RESV:
346 case BANDB_RESV_PERM:
5203cba5 347 snprintf(buf, sizeof(buf),
832ed81a
AC
348 "\"%s\",\"%s\",\"%s\",%s\n",
349 table.row[j][mask1],
350 mangle_reason(table.row[j][reason]),
351 table.row[j][oper], table.row[j][ts]);
352 break;
353
354
355 default: /* Klines */
5203cba5 356 snprintf(buf, sizeof(buf),
832ed81a
AC
357 "\"%s\",\"%s\",\"%s\",\"\",\"%s\",\"%s\",%s\n",
358 table.row[j][mask1], table.row[j][mask2],
359 mangle_reason(table.row[j][reason]),
360 bt_smalldate(table.row[j][ts]), table.row[j][oper],
361 table.row[j][ts]);
362 break;
363 }
364
365 fprintf(fd, "%s", buf);
366 }
367
368 rsdb_exec_fetch_end(&table);
369 if(flag.verbose)
370 fprintf(stdout, "\twritten.\n");
371 fclose(fd);
372}
373
374/**
375 * attempt to condense the individual conf functions into one
376 */
377static void
378import_config(const char *conf, int id)
379{
380 FILE *fd;
381
382 char line[BUFSIZE];
383 char *p;
384 int i = 0;
385
386 char f_perm = 0;
f67e7283
JT
387 const char *f_mask1 = NULL;
388 const char *f_mask2 = NULL;
389 const char *f_oper = NULL;
390 const char *f_time = NULL;
391 const char *f_reason = NULL;
392 const char *f_oreason = NULL;
832ed81a
AC
393 char newreason[REASONLEN];
394
395 if(flag.verbose)
396 fprintf(stdout, "* checking for %s: ", conf); /* debug */
397
398 /* open config for reading, or skip to the next */
399 if(!(fd = fopen(conf, "r")))
400 {
401 if(flag.verbose)
402 fprintf(stdout, "%*s", strlen(bandb_suffix[id]) > 0 ? 10 : 15,
403 "missing.\n");
404 count.error++;
405 return;
406 }
407
408 if(strstr(conf, ".perm") != 0)
409 f_perm = 1;
410
411
412 /* xline
413 * "SYSTEM","0","banned","stevoo!stevoo@efnet.port80.se{stevoo}",1111080437
414 * resv
415 * "OseK","banned nickname","stevoo!stevoo@efnet.port80.se{stevoo}",1111031619
416 * dline
417 * "194.158.192.0/19","laptop scammers","","2005/3/17 05.33","stevoo!stevoo@efnet.port80.se{stevoo}",1111033988
418 */
419 while(fgets(line, sizeof(line), fd))
420 {
421 if((p = strpbrk(line, "\r\n")) != NULL)
422 *p = '\0';
423
424 if((*line == '\0') || (*line == '#'))
425 continue;
426
427 /* mask1 */
428 f_mask1 = getfield(line);
429
430 if(EmptyString(f_mask1))
431 continue;
432
433 /* mask2 */
434 switch (id)
435 {
436 case BANDB_XLINE:
437 case BANDB_XLINE_PERM:
438 f_mask1 = escape_quotes(clean_gecos_field(f_mask1));
439 getfield(NULL); /* empty field */
440 break;
441
442 case BANDB_RESV:
443 case BANDB_RESV_PERM:
444 case BANDB_DLINE:
445 case BANDB_DLINE_PERM:
446 break;
447
448 default:
449 f_mask2 = getfield(NULL);
450 if(EmptyString(f_mask2))
451 continue;
452 break;
453 }
454
455 /* reason */
456 f_reason = getfield(NULL);
457 if(EmptyString(f_reason))
458 continue;
459
460 /* oper comment */
461 switch (id)
462 {
463 case BANDB_KLINE:
464 case BANDB_KLINE_PERM:
465 case BANDB_DLINE:
466 case BANDB_DLINE_PERM:
467 f_oreason = getfield(NULL);
468 getfield(NULL);
469 break;
470
471 default:
472 break;
473 }
474
475 f_oper = getfield(NULL);
476 f_time = strip_quotes(f_oper + strlen(f_oper) + 2);
f67e7283
JT
477 if(EmptyString(f_oper))
478 f_oper = "unknown";
832ed81a
AC
479
480 /* meh */
481 if(id == BANDB_KLINE || id == BANDB_KLINE_PERM)
482 {
483 if(strstr(f_mask1, "!") != NULL)
484 {
485 fprintf(stderr,
486 "* SKIPPING INVALID KLINE %s@%s set by %s\n",
487 f_mask1, f_mask2, f_oper);
488 fprintf(stderr, " You may wish to re-apply it correctly.\n");
489 continue;
490 }
491 }
492
493 /* append operreason_field to reason_field */
494 if(!EmptyString(f_oreason))
5203cba5 495 snprintf(newreason, sizeof(newreason), "%s | %s", f_reason, f_oreason);
832ed81a 496 else
5203cba5 497 snprintf(newreason, sizeof(newreason), "%s", f_reason);
832ed81a 498
ab31d2b0 499 if(flag.pretend == false)
832ed81a 500 {
ab31d2b0 501 if(flag.dupes_ok == false)
832ed81a
AC
502 drop_dupes(f_mask1, f_mask2, bandb_table[id]);
503
504 rsdb_exec(NULL,
505 "INSERT INTO %s (mask1, mask2, oper, time, perm, reason) VALUES('%Q','%Q','%Q','%Q','%d','%Q')",
506 bandb_table[id], f_mask1, f_mask2, f_oper, f_time, f_perm,
507 newreason);
508 }
509
510 if(flag.pretend && flag.verbose)
511 fprintf(stdout,
512 "%s: perm(%d) mask1(%s) mask2(%s) oper(%s) reason(%s) time(%s)\n",
513 bandb_table[id], f_perm, f_mask1, f_mask2, f_oper, newreason,
514 f_time);
515
516 i++;
517 }
518
519 switch (bandb_letter[id])
520 {
521 case 'K':
522 count.klines += i;
523 break;
524 case 'D':
525 count.dlines += i;
526 break;
527 case 'X':
528 count.xlines += i;
529 break;
530 case 'R':
531 count.resvs += i;
532 break;
533 default:
534 break;
535 }
536
537 if(flag.verbose)
538 fprintf(stdout, "%*s\n", strlen(bandb_suffix[id]) > 0 ? 10 : 15, "imported.");
539
e3a3eb92
JT
540 fclose(fd);
541
832ed81a
AC
542 return;
543}
544
545/**
546 * getfield
547 *
548 * inputs - input buffer
549 * output - next field
550 * side effects - field breakup for ircd.conf file.
551 */
552char *
553getfield(char *newline)
554{
555 static char *line = NULL;
556 char *end, *field;
557
558 if(newline != NULL)
559 line = newline;
560
561 if(line == NULL)
562 return (NULL);
563
564 field = line;
565
566 /* XXX make this skip to first " if present */
567 if(*field == '"')
568 field++;
569 else
570 return (NULL); /* mal-formed field */
571
572 end = strchr(line, ',');
573
574 while(1)
575 {
576 /* no trailing , - last field */
577 if(end == NULL)
578 {
579 end = line + strlen(line);
580 line = NULL;
581
582 if(*end == '"')
583 {
584 *end = '\0';
585 return field;
586 }
587 else
588 return NULL;
589 }
590 else
591 {
592 /* look for a ", to mark the end of a field.. */
593 if(*(end - 1) == '"')
594 {
595 line = end + 1;
596 end--;
597 *end = '\0';
598 return field;
599 }
600
601 /* search for the next ',' */
602 end++;
603 end = strchr(end, ',');
604 }
605 }
606
607 return NULL;
608}
609
610/**
611 * strip away "quotes" from around strings
612 */
613static char *
614strip_quotes(const char *string)
615{
616 static char buf[14]; /* int(11) + 2 + \0 */
617 char *str = buf;
618
619 if(string == NULL)
620 return NULL;
621
622 while(*string)
623 {
624 if(*string != '"')
625 {
626 *str++ = *string;
627 }
628 string++;
629 }
630 *str = '\0';
631 return buf;
632}
633
634/**
635 * escape quotes in a string
636 */
637static char *
638escape_quotes(const char *string)
639{
640 static char buf[BUFSIZE * 2];
641 char *str = buf;
642
643 if(string == NULL)
644 return NULL;
645
646 while(*string)
647 {
648 if(*string == '"')
649 {
650 *str++ = '\\';
651 *str++ = '"';
652 }
653 else
654 {
655 *str++ = *string;
656 }
657 string++;
658 }
659 *str = '\0';
660 return buf;
661}
662
663
664static char *
665mangle_reason(const char *string)
666{
667 static char buf[BUFSIZE * 2];
668 char *str = buf;
669
670 if(string == NULL)
671 return NULL;
672
673 while(*string)
674 {
675 switch (*string)
676 {
677 case '"':
678 *str = '\'';
679 break;
680 case ':':
681 *str = ' ';
682 break;
683 default:
684 *str = *string;
685 }
686 string++;
687 str++;
688
689 }
690 *str = '\0';
691 return buf;
692}
693
694
695/**
696 * change spaces to \s in gecos field
697 */
698static const char *
699clean_gecos_field(const char *gecos)
700{
701 static char buf[BUFSIZE * 2];
702 char *str = buf;
703
704 if(gecos == NULL)
705 return NULL;
706
707 while(*gecos)
708 {
709 if(*gecos == ' ')
710 {
711 *str++ = '\\';
712 *str++ = 's';
713 }
714 else
715 *str++ = *gecos;
716 gecos++;
717 }
718 *str = '\0';
719 return buf;
720}
721
722/**
723 * verify the database integrity, and if necessary create apropriate tables
724 */
725static void
726check_schema(void)
727{
728 int i, j;
729 char type[8]; /* longest string is 'INTEGER\0' */
730
731 if(flag.verify || flag.verbose)
732 fprintf(stdout, "* Verifying database.\n");
733
734 const char *columns[] = {
735 "perm",
736 "mask1",
737 "mask2",
738 "oper",
739 "time",
740 "reason",
741 NULL
742 };
743
744 for(i = 0; i < LAST_BANDB_TYPE; i++)
745 {
746 if(!table_exists(bandb_table[i]))
747 {
748 rsdb_exec(NULL,
749 "CREATE TABLE %s (mask1 TEXT, mask2 TEXT, oper TEXT, time INTEGER, perm INTEGER, reason TEXT)",
750 bandb_table[i]);
751 }
752
753 /*
754 * i can't think of any better way to do this, other then attempt to
755 * force the creation of column that may, or may not already exist. --dubkat
756 */
757 else
758 {
759 for(j = 0; columns[j] != NULL; j++)
760 {
761 if(!strcmp(columns[j], "time") && !strcmp(columns[j], "perm"))
762 rb_strlcpy(type, "INTEGER", sizeof(type));
763 else
764 rb_strlcpy(type, "TEXT", sizeof(type));
765
766 /* attempt to add a column with extreme prejudice, errors are ignored */
767 rsdb_exec(NULL, "ALTER TABLE %s ADD COLUMN %s %s", bandb_table[i],
768 columns[j], type);
769 }
770 }
771
772 i++; /* skip over .perm */
773 }
774}
775
776static void
777db_reclaim_slack(void)
778{
779 fprintf(stdout, "* Reclaiming free space.\n");
780 rsdb_exec(NULL, "VACUUM");
781}
782
783
784/**
785 * check that appropriate tables exist.
786 */
787static int
788table_exists(const char *dbtab)
789{
790 struct rsdb_table table;
791 rsdb_exec_fetch(&table, "SELECT name FROM sqlite_master WHERE type='table' AND name='%s'",
792 dbtab);
793 rsdb_exec_fetch_end(&table);
794 return table.row_count;
795}
796
797/**
798 * check that there are actual entries in a table
799 */
800static int
801table_has_rows(const char *dbtab)
802{
803 struct rsdb_table table;
804 rsdb_exec_fetch(&table, "SELECT * FROM %s", dbtab);
805 rsdb_exec_fetch_end(&table);
806 return table.row_count;
807}
808
809/**
810 * completly wipes out an existing ban.db of all entries.
811 */
812static void
813wipe_schema(void)
814{
815 int i;
816 rsdb_transaction(RSDB_TRANS_START);
817 for(i = 0; i < LAST_BANDB_TYPE; i++)
818 {
819 rsdb_exec(NULL, "DROP TABLE %s", bandb_table[i]);
820 i++; /* double increment to skip over .perm */
821 }
822 rsdb_transaction(RSDB_TRANS_END);
823
824 check_schema();
825}
826
827/**
828 * remove pre-existing duplicate bans from the database.
829 * we favor the new, imported ban over the one in the database
830 */
831void
832drop_dupes(const char *user, const char *host, const char *t)
833{
834 rsdb_exec(NULL, "DELETE FROM %s WHERE mask1='%Q' AND mask2='%Q'", t, user, host);
835}
836
837static void
838db_error_cb(const char *errstr)
839{
840 return;
841}
842
843
844/**
845 * convert unix timestamp to human readable (small) date
846 */
847static char *
848bt_smalldate(const char *string)
849{
850 static char buf[MAX_DATE_STRING];
851 struct tm *lt;
852 time_t t;
853 t = strtol(string, NULL, 10);
854 lt = gmtime(&t);
855 if(lt == NULL)
856 return NULL;
5203cba5 857 snprintf(buf, sizeof(buf), "%d/%d/%d %02d.%02d",
832ed81a
AC
858 lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min);
859 return buf;
860}
861
862/**
863 * you are here ->.
864 */
865void
866print_help(int i_exit)
867{
5c5d0fb7 868 fprintf(stderr, "bantool v.%s - the charybdis database tool.\n", BT_VERSION);
832ed81a 869 fprintf(stderr, "Copyright (C) 2008 Daniel J Reidy <dubkat@gmail.com>\n");
832ed81a
AC
870 fprintf(stderr, "This program is distributed in the hope that it will be useful,\n"
871 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
872 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
873 "GNU General Public License for more details.\n\n");
874
875 fprintf(stderr, "Usage: %s <-i|-e> [-p] [-v] [-h] [-d] [-w] [path]\n", me);
876 fprintf(stderr, " -h : Display some slightly useful help.\n");
877 fprintf(stderr, " -i : Actually import configs into your database.\n");
878 fprintf(stderr, " -e : Export your database to old-style flat files.\n");
879 fprintf(stderr,
880 " This is suitable for redistrubuting your banlists, or creating backups.\n");
881 fprintf(stderr, " -s : Reclaim empty slack space the database may be taking up.\n");
882 fprintf(stderr, " -u : Update the database tables to support any new features.\n");
883 fprintf(stderr,
884 " This is automaticlly done if you are importing or exporting\n");
885 fprintf(stderr, " but should be run whenever you upgrade the ircd.\n");
886 fprintf(stderr,
887 " -p : pretend, checks for the configs, and parses them, then tells you some data...\n");
888 fprintf(stderr, " but does not touch your database.\n");
889 fprintf(stderr,
890 " -v : Be verbose... and it *is* very verbose! (intended for debugging)\n");
891 fprintf(stderr, " -d : Enable checking for redunant entries.\n");
892 fprintf(stderr, " -w : Completly wipe your database clean. May be used with -i \n");
893 fprintf(stderr,
894 " path : An optional directory containing old ratbox configs for import, or export.\n");
895 fprintf(stderr, " If not specified, it looks in PREFIX/etc.\n");
896 exit(i_exit);
897}