ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/vendor/ircservices-5.1.24/tools/convert-db.c
Revision: 3389
Committed: Fri Apr 25 14:12:15 2014 UTC (11 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 29194 byte(s)
Log Message:
- Imported ircservices-5.1.24

File Contents

# Content
1 /* Convert other programs' databases to XML.
2 *
3 * IRC Services is copyright (c) 1996-2009 Andrew Church.
4 * E-mail: <achurch@achurch.org>
5 * Parts written by Andrew Kempe and others.
6 * This program is free but copyrighted software; see the file GPL.txt for
7 * details.
8 */
9
10 #define CONVERT_DB_MAIN
11 #define STANDALONE_NICKSERV
12 #define STANDALONE_CHANSERV
13 #include "convert-db.h"
14 #include "language.h"
15 #include "modules/misc/xml.h"
16
17 /*************************************************************************/
18
19 /* Data read in. */
20
21 NickGroupInfo *ngi_list;
22 NickInfo *ni_list;
23 ChannelInfo *ci_list;
24 NewsItem *news_list;
25 MaskData *md_list[256];
26 ServerStats *ss_list;
27 int32 maxusercnt;
28 time_t maxusertime;
29 Password supass;
30 int no_supass = 1;
31
32 /* Symbols needed for core's misc.c. */
33 char **RejectEmail = NULL;
34 int RejectEmail_count = 0;
35
36 /*************************************************************************/
37
38 /* NULL-terminated list of supported database types. */
39
40 extern DBTypeInfo ALL_DB_TYPES();
41 static DBTypeInfo *dbtypes[] = {
42 ALL_DB_TYPES(&),
43 NULL
44 };
45
46 /*************************************************************************/
47 /*************************** Exported routines ***************************/
48 /*************************************************************************/
49
50 /* Safe memory allocation and string duplication (from memory.c). */
51
52 void *smalloc(long size)
53 {
54 void *ptr;
55 if (!size)
56 size = 1;
57 ptr = malloc(size);
58 if (!ptr) {
59 fprintf(stderr, "Out of memory\n");
60 exit(1);
61 }
62 return ptr;
63 }
64
65 void *scalloc(long els, long elsize)
66 {
67 void *ptr;
68 if (!(els*elsize))
69 els = elsize = 1;
70 ptr = calloc(els, elsize);
71 if (!ptr) {
72 fprintf(stderr, "Out of memory\n");
73 exit(1);
74 }
75 return ptr;
76 }
77
78 void *srealloc(void *ptr, long size)
79 {
80 if (!size)
81 size = 1;
82 ptr = realloc(ptr, size);
83 if (!ptr) {
84 fprintf(stderr, "Out of memory\n");
85 exit(1);
86 }
87 return ptr;
88 }
89
90 char *sstrdup(const char *s)
91 {
92 int len = strlen(s)+1;
93 char *d = smalloc(len);
94 memcpy(d, s, len);
95 return d;
96 }
97
98 /*************************************************************************/
99
100 /* Initialize or clear a Password structure (from encrypt.c). */
101
102 void init_password(Password *password)
103 {
104 memset(password, 0, sizeof(*password));
105 password->cipher = NULL;
106 }
107
108 void clear_password(Password *password)
109 {
110 memset(password, 0, sizeof(*password));
111 free((char *)password->cipher);
112 password->cipher = NULL;
113 }
114
115 /*************************************************************************/
116
117 /* NickInfo/NickGroupInfo allocation (from modules/nickserv/util.c). The
118 * NickInfo and NickGroupInfo (if appropriate) are added into their
119 * respective hash tables. Always succeeds (if the memory allocations
120 * fail, aborts the program).
121 */
122
123 #include "modules/nickserv/util.c"
124
125 NickInfo *makenick(const char *nick, NickGroupInfo **nickgroup_ret)
126 {
127 NickInfo *ni = new_nickinfo();
128 strbcpy(ni->nick, nick);
129 if (nickgroup_ret) {
130 NickGroupInfo *ngi = new_nickgroupinfo(ni->nick);
131 while (get_nickgroupinfo(ngi->id)) {
132 /* We assume that eventually we'll find one that's not in use */
133 ngi->id = rand() + rand();
134 if (ngi->id == 0)
135 ngi->id = 1;
136 }
137 ni->nickgroup = ngi->id;
138 ARRAY_EXTEND(ngi->nicks);
139 strbcpy(ngi->nicks[0], nick);
140 add_nickgroupinfo(ngi);
141 *nickgroup_ret = ngi;
142 }
143 add_nickinfo(ni);
144 return ni;
145 }
146
147 /*************************************************************************/
148
149 /* ChannelInfo allocation. The channel is added to the hash table. */
150
151 #include "modules/chanserv/util.c"
152
153 ChannelInfo *makechan(const char *name)
154 {
155 ChannelInfo *ci = new_channelinfo();
156 strbcpy(ci->name, name);
157 add_channelinfo(ci);
158 return ci;
159 }
160
161 /*************************************************************************/
162
163 /* Open a (Services pre-5.0 style) data file and check the version number.
164 * Prints an error message and exits with 1 if either the file cannot be
165 * opened or the version number is wrong. If `version_ret' is non-NULL,
166 * the version number is stored there.
167 */
168
169 dbFILE *open_db_ver(const char *dir, const char *name, int32 min_version,
170 int32 max_version, int32 *version_ret)
171 {
172 char filename[PATH_MAX+1];
173 dbFILE *f;
174 int32 ver;
175
176 snprintf(filename, sizeof(filename), "%s/%s", dir, name);
177 f = open_db(filename, "r", 0);
178 if (!f) {
179 fprintf(stderr, "Can't open %s for reading: %s\n", filename,
180 strerror(errno));
181 exit(1);
182 }
183 if (read_int32(&ver, f) < 0) {
184 fprintf(stderr, "Error reading version number on %s\n", filename);
185 exit(1);
186 }
187 if (ver < min_version || ver > max_version) {
188 fprintf(stderr, "Wrong version number on %s\n", filename);
189 exit(1);
190 }
191 if (version_ret)
192 *version_ret = ver;
193 return f;
194 }
195
196 /*************************************************************************/
197
198 /* Retrieve the NickGroupInfo structure for the given nick. Returns NULL
199 * if the nick does not exist or is forbidden (i.e. has no NickGroupInfo).
200 */
201
202 NickGroupInfo *get_nickgroupinfo_by_nick(const char *nick)
203 {
204 NickInfo *ni = get_nickinfo(nick);
205 return ni ? get_nickgroupinfo(ni->nickgroup) : NULL;
206 }
207
208 /*************************************************************************/
209
210 /* Set the OperServ privilege level (os_priv) for the nickgroup associated
211 * with `nick' to `level', if it is not already greater than `level'. Does
212 * nothing if `nick' is NULL or does not have an associated nickgroup.
213 */
214
215 void set_os_priv(const char *nick, int16 level)
216 {
217 NickGroupInfo *ngi;
218
219 if (!nick)
220 return;
221 ngi = get_nickgroupinfo_by_nick(nick);
222 if (ngi && ngi->os_priv < level)
223 ngi->os_priv = level;
224 }
225
226 /*************************************************************************/
227
228 /* Return the Services 5.0 channel access level that corresponds to the
229 * given pre-5.0 level. Code taken from modules/database/version4.c
230 * (convert_old_level()).
231 */
232
233 int16 convert_acclev(int16 old)
234 {
235 if (old < 0)
236 return -convert_acclev(-old); /* avoid negative division */
237 else if (old <= 25)
238 return old*10; /* 0.. 25 -> 0..250 (10x) */
239 else if (old <= 50)
240 return 200 + old*2; /* 25.. 50 -> 250..300 ( 2x) */
241 else if (old <= 100)
242 return 280 + old*2/5; /* 50.. 100 -> 300..320 ( 0.4x) */
243 else if (old <= 1000)
244 return 300 + old/5; /* 100..1000 -> 320..500 ( 0.2x) */
245 else if (old <= 2000)
246 return 400 + old/10; /* 1000..2000 -> 500..600 ( 0.1x) */
247 else
248 return 500 + old/20; /* 2000..9999 -> 600..999 ( 0.05x) */
249 }
250
251 /*************************************************************************/
252 /*************************************************************************/
253
254 /* Replacements for database functions. add_*() functions are defined as
255 * macros in convert-db.h. */
256
257 /*************************************************************************/
258
259 static NickGroupInfo *ngi_iter;
260
261 NickGroupInfo *get_nickgroupinfo(uint32 id)
262 {
263 NickGroupInfo *ngi;
264 if (!id)
265 return NULL;
266 LIST_SEARCH_SCALAR(ngi_list, id, id, ngi);
267 return ngi;
268 }
269
270 NickGroupInfo *first_nickgroupinfo(void)
271 {
272 ngi_iter = ngi_list;
273 return next_nickgroupinfo();
274 }
275
276 NickGroupInfo *next_nickgroupinfo(void)
277 {
278 NickGroupInfo *retval = ngi_iter;
279 if (ngi_iter)
280 ngi_iter = ngi_iter->next;
281 return retval;
282 }
283
284 /*************************************************************************/
285
286 static NickInfo *ni_iter;
287
288 NickInfo *get_nickinfo(const char *nick)
289 {
290 NickInfo *ni;
291 LIST_SEARCH(ni_list, nick, nick, stricmp, ni);
292 return ni;
293 }
294
295 NickInfo *first_nickinfo(void)
296 {
297 ni_iter = ni_list;
298 return next_nickinfo();
299 }
300
301 NickInfo *next_nickinfo(void)
302 {
303 NickInfo *retval = ni_iter;
304 if (ni_iter)
305 ni_iter = ni_iter->next;
306 return retval;
307 }
308
309 /*************************************************************************/
310
311 static ChannelInfo *ci_iter;
312
313 ChannelInfo *get_channelinfo(const char *channel)
314 {
315 ChannelInfo *ci;
316 LIST_SEARCH(ci_list, name, channel, stricmp, ci);
317 return ci;
318 }
319
320 ChannelInfo *first_channelinfo(void)
321 {
322 ci_iter = ci_list;
323 return next_channelinfo();
324 }
325
326 ChannelInfo *next_channelinfo(void)
327 {
328 ChannelInfo *retval = ci_iter;
329 if (ci_iter)
330 ci_iter = ci_iter->next;
331 return retval;
332 }
333
334 /*************************************************************************/
335
336 static NewsItem *news_iter;
337
338 NewsItem *first_news(void)
339 {
340 news_iter = news_list;
341 return next_news();
342 }
343
344 NewsItem *next_news(void)
345 {
346 NewsItem *retval = news_iter;
347 if (news_iter)
348 news_iter = news_iter->next;
349 return retval;
350 }
351
352 /*************************************************************************/
353
354 static MaskData *md_iter[256];
355
356 MaskData *first_maskdata(uint8 type)
357 {
358 md_iter[type] = md_list[type];
359 return next_maskdata(type);
360 }
361
362 MaskData *next_maskdata(uint8 type)
363 {
364 MaskData *retval = md_iter[type];
365 if (md_iter[type])
366 md_iter[type] = md_iter[type]->next;
367 return retval;
368 }
369
370 /*************************************************************************/
371
372 static ServerStats *ss_iter;
373
374 ServerStats *first_serverstats(void)
375 {
376 ss_iter = ss_list;
377 return next_serverstats();
378 }
379
380 ServerStats *next_serverstats(void)
381 {
382 ServerStats *retval = ss_iter;
383 if (ss_iter)
384 ss_iter = ss_iter->next;
385 return retval;
386 }
387
388 /*************************************************************************/
389
390 int get_operserv_data(int what, void *ptr)
391 {
392 switch (what) {
393 case OSDATA_MAXUSERCNT:
394 *(int32 *)ptr = maxusercnt;
395 break;
396 case OSDATA_MAXUSERTIME:
397 *(time_t *)ptr = maxusertime;
398 break;
399 case OSDATA_SUPASS:
400 *(Password **)ptr = no_supass ? NULL : &supass;
401 break;
402 default:
403 return 0;
404 }
405 return 1;
406 }
407
408 /*************************************************************************/
409 /*************************************************************************/
410
411 /* Perform sanity checks on the data after it's been read in. */
412
413 static void sanity_check_nicks(void);
414 static void sanity_check_nickgroups(void);
415 static void sanity_check_channels(void);
416 static void sanity_check_maskdata(void);
417
418 static void sanity_checks(void)
419 {
420 sanity_check_nicks();
421 sanity_check_nickgroups();
422 sanity_check_channels();
423 sanity_check_maskdata();
424 }
425
426 /*************************************************************************/
427
428 static void sanity_check_nicks(void)
429 {
430 NickInfo *ni;
431 NickGroupInfo *ngi;
432 char *s;
433 int i;
434
435 for (ni = first_nickinfo(); ni; ni = next_nickinfo()) {
436
437 /* Forbidden nicks should have no other data associated with them. */
438 if (ni->status & NS_VERBOTEN) {
439 ni->status &= ~(NS_VERBOTEN);
440 ni->last_usermask = NULL;
441 ni->last_realmask = NULL;
442 ni->last_realname = NULL;
443 ni->last_quit = NULL;
444 ni->last_seen = 0;
445 if (ni->nickgroup) {
446 fprintf(stderr, "BUG: Forbidden nickname %s associated with"
447 " nickgroup %u! Clearing nickgroup field.\n",
448 ni->nick, ni->nickgroup);
449 ni->nickgroup = 0;
450 }
451 ni->id_stamp = 0;
452 continue;
453 }
454
455 /* The nick isn't a forbidden nick. First make sure it has the
456 * right nickgroup. */
457 if (!ni->nickgroup) {
458 fprintf(stderr, "BUG: Nickname %s has no nickgroup! Deleting.\n",
459 ni->nick);
460 del_nickinfo(ni);
461 continue;
462 }
463 ngi = get_nickgroupinfo(ni->nickgroup);
464 if (!ngi) {
465 fprintf(stderr, "BUG: Nickname %s points to nonexistent nickgroup"
466 " %u! Deleting.\n", ni->nick, ni->nickgroup);
467 del_nickinfo(ni);
468 } else {
469 /* Nicknames in the nicks[] array should match those in the
470 * NickInfo structure, so use strcmp() (this keeps us from
471 * having to worry about irc_stricmp() idiosyncrasies). */
472 ARRAY_SEARCH_PLAIN(ngi->nicks, ni->nick, strcmp, i);
473 if (i >= ngi->nicks_count) {
474 fprintf(stderr, "BUG: Nickname %s points to nickgroup %u,"
475 " but the nickgroup doesn't contain the nickname!"
476 " Deleting.\n", ni->nick, ni->nickgroup);
477 del_nickinfo(ni);
478 }
479 }
480
481 /* Clear unknown flags. */
482 ni->status &= NS_PERMANENT;
483
484 /* Make sure usermasks actually have non-empty user and host parts. */
485 if (ni->last_usermask) {
486 s = strchr(ni->last_usermask, '@');
487 if (!s || s==ni->last_usermask || !s[1]) {
488 fprintf(stderr, "Last usermask for nickname %s isn't a valid"
489 " user@host mask, clearing.\n", ni->nick);
490 ni->last_usermask = NULL;
491 }
492 }
493 if (ni->last_realmask) {
494 s = strchr(ni->last_realmask, '@');
495 if (!s || s==ni->last_realmask || !s[1]) {
496 fprintf(stderr, "Last real usermask for nickname %s isn't"
497 " a valid user@host mask, clearing.\n", ni->nick);
498 ni->last_realmask = NULL;
499 }
500 }
501
502 /* Make sure last-seen time is not earlier than registered time.
503 * Allow zero, to accommodate cases where the nickname was
504 * registered by an outside entity without the user actually
505 * logging on. */
506 if (ni->last_seen && ni->last_seen < ni->time_registered) {
507 fprintf(stderr, "Last-seen time for nickname %s is earlier than"
508 " registration time! Setting last-seen time to"
509 " registration time.\n", ni->nick);
510 ni->last_seen = ni->time_registered;
511 }
512
513 } /* for all nicks */
514 }
515
516 /*************************************************************************/
517
518 static void sanity_check_nickgroups(void)
519 {
520 NickInfo *ni;
521 NickGroupInfo *ngi;
522 char *s;
523 int i;
524
525 for (ngi = first_nickgroupinfo(); ngi; ngi = next_nickgroupinfo()) {
526
527 /* Make sure nickgroups don't contain extra nicks. */
528 ARRAY_FOREACH(i, ngi->nicks) {
529 ni = get_nickinfo(ngi->nicks[i]);
530 if (!ni) {
531 fprintf(stderr, "BUG: Nickgroup %u contains nonexistent"
532 " nickname %s! Removing nickname from group.\n",
533 ngi->id, ngi->nicks[i]);
534 ARRAY_REMOVE(ngi->nicks, i);
535 if (ngi->mainnick >= i)
536 ngi->mainnick--;
537 i--; /* to make sure we don't skip any */
538 }
539 }
540
541 /* Check for empty nickgroups (possibly from extraneous nickname
542 * removal above). */
543 if (ngi->nicks_count == 0) {
544 fprintf(stderr, "Removing empty nickgroup %u.\n", ngi->id);
545 del_nickgroupinfo(ngi);
546 continue;
547 }
548
549 /* Make sure main nick is a valid index. */
550 if (ngi->mainnick >= ngi->nicks_count) {
551 fprintf(stderr, "Invalid main nick index in nickgroup %u,"
552 " resetting.\n", ngi->id);
553 ngi->mainnick = 0;
554 }
555
556 /* If an authcode is set, make sure the reason is valid. If not,
557 * clear the auth-related fields. */
558 if (ngi->authcode && (ngi->authreason < NICKAUTH_MIN
559 || ngi->authreason > NICKAUTH_MAX)) {
560 fprintf(stderr, "Authentication code set for nickgroup %u but"
561 " reason code invalid, setting to SETAUTH.\n", ngi->id);
562 ngi->authreason = NICKAUTH_SETAUTH;
563 } else {
564 ngi->authset = 0;
565 ngi->authreason = 0;
566 }
567
568 /* Clear all unknown flags. */
569 ngi->flags &= NF_ALLFLAGS;
570
571 /* Make sure language setting is in range. */
572 if ((ngi->language < 0 || ngi->language >= NUM_LANGS)
573 && ngi->language != LANG_DEFAULT
574 ) {
575 fprintf(stderr, "Invalid language set for nickgroup %u,"
576 " resetting to default.\n", ngi->id);
577 ngi->language = LANG_DEFAULT;
578 }
579
580 /* Make sure access, autojoin, and ignore counts are non-negative. */
581 if (ngi->access_count < 0) {
582 fprintf(stderr, "BUG: Access entry count for nickgroup %u is"
583 " negative! Clearing.\n", ngi->id);
584 ngi->access = NULL;
585 ngi->access_count = 0;
586 }
587 if (ngi->ajoin_count < 0) {
588 fprintf(stderr, "BUG: Autojoin entry count for nickgroup %u is"
589 " negative! Clearing.\n", ngi->id);
590 ngi->ajoin = NULL;
591 ngi->ajoin_count = 0;
592 }
593 if (ngi->ignore_count < 0) {
594 fprintf(stderr, "BUG: Ignore entry count for nickgroup %u is"
595 " negative! Clearing.\n", ngi->id);
596 ngi->ignore = NULL;
597 ngi->ignore_count = 0;
598 }
599
600 /* Make sure all access entries have non-empty user and host parts. */
601 ARRAY_FOREACH (i, ngi->access) {
602 if (!ngi->access[i]
603 || !(s = strchr(ngi->access[i], '@'))
604 || s == ngi->access[i]
605 || !s[1]
606 ) {
607 fprintf(stderr, "Access entry %d for nickgroup %u %s,"
608 " deleting.\n", i, ngi->id,
609 !ngi->access[i] ? "is empty"
610 : "isn't a valid user@host mask");
611 ARRAY_REMOVE(ngi->access, i);
612 i--;
613 }
614 }
615
616 /* Make sure memo count is non-negative. */
617 if (ngi->memos.memos_count < 0) {
618 fprintf(stderr, "BUG: Memo count for nickgroup %u is negative!"
619 " Clearing.\n", ngi->id);
620 ngi->memos.memos = NULL;
621 ngi->memos.memos_count = 0;
622 }
623
624 /* Clear unknown flags from memos. */
625 ARRAY_FOREACH (i, ngi->memos.memos)
626 ngi->memos.memos[i].flags &= MF_ALLFLAGS;
627
628 } /* for all nickgroups */
629 }
630
631 /*************************************************************************/
632
633 static void sanity_check_channels(void)
634 {
635 ChannelInfo *ci;
636 char *s;
637 int i;
638
639 for (ci = first_channelinfo(); ci; ci = next_channelinfo()) {
640
641 /* Forbidden channels should have no other data associated with
642 * them. */
643 if (ci->flags & CF_VERBOTEN) {
644 ci->founder = 0;
645 ci->successor = 0;
646 init_password(&ci->founderpass);
647 ci->desc = NULL;
648 ci->url = NULL;
649 ci->email = NULL;
650 ci->last_used = 0;
651 ci->last_topic = NULL;
652 memset(ci->last_topic_setter, 0, sizeof(ci->last_topic_setter));
653 ci->last_topic_time = 0;
654 ci->flags &= ~(CF_VERBOTEN);
655 reset_levels(ci);
656 ci->access = NULL;
657 ci->access_count = 0;
658 ci->akick = NULL;
659 ci->akick_count = 0;
660 ci->mlock.on = NULL;
661 ci->mlock.off = NULL;
662 ci->mlock.limit = 0;
663 ci->mlock.key = NULL;
664 ci->mlock.link = NULL;
665 ci->mlock.flood = NULL;
666 ci->mlock.joindelay = 0;
667 ci->mlock.joinrate1 = 0;
668 ci->mlock.joinrate2 = 0;
669 ci->entry_message = NULL;
670 continue;
671 }
672
673 /* Channel is not forbidden. First make sure it has a (valid)
674 * founder. */
675 if (!ci->founder) {
676 fprintf(stderr, "BUG: Channel %s has no founder! Deleting.\n",
677 ci->name);
678 del_channelinfo(ci);
679 } else if (!get_nickgroupinfo(ci->founder)) {
680 fprintf(stderr, "BUG: Channel %s founder nickgroup %u is"
681 " missing! Deleting channel.\n", ci->name, ci->founder);
682 del_channelinfo(ci);
683 }
684
685 /* Make sure that the successor is valid if set. */
686 if (ci->successor && !get_nickgroupinfo(ci->successor)) {
687 fprintf(stderr, "BUG: Channel %s successor nickgroup %u is"
688 " missing! Clearing.", ci->name, ci->successor);
689 ci->successor = 0;
690 }
691
692 /* Make sure last-used time is not earlier than registered time.
693 * Allow zero, to accommodate cases where the channel was
694 * registered by an outside entity. */
695 if (ci->last_used && ci->last_used < ci->time_registered) {
696 fprintf(stderr, "Last-used time for channel %s is earlier than"
697 " registration time! Setting last-used time to"
698 " registration time.\n", ci->name);
699 ci->last_used = ci->time_registered;
700 }
701
702 /* If there is no saved topic, clear the topic setter and time. */
703 if (!ci->last_topic) {
704 memset(ci->last_topic_setter, 0, sizeof(ci->last_topic_setter));
705 ci->last_topic_time = 0;
706 }
707
708 /* Clear unknown flags. */
709 ci->flags &= CF_ALLFLAGS;
710
711 /* Check privilege level settings for vaility. */
712 for (i = 0; i < CA_SIZE; i++) {
713 if (ci->levels[i] != ACCLEV_DEFAULT
714 && ci->levels[i] != ACCLEV_INVALID
715 && ci->levels[i] != ACCLEV_FOUNDER
716 && (ci->levels[i] < ACCLEV_MIN
717 || ci->levels[i] > ACCLEV_MAX)
718 ) {
719 fprintf(stderr, "Privilege level %d on channel %s is"
720 "invalid, resetting to default.\n", i, ci->name);
721 ci->levels[i] = ACCLEV_DEFAULT;
722 break;
723 }
724 }
725
726 /* Check access level nickgroups and levels for validity. */
727 ARRAY_FOREACH (i, ci->access) {
728 if (!ci->access[i].nickgroup)
729 continue;
730 if (!get_nickgroupinfo(ci->access[i].nickgroup)) {
731 fprintf(stderr, "BUG: Channel %s access entry %d has an"
732 " invalid nickgroup! Clearing.\n", ci->name, i);
733 ci->access[i].nickgroup = 0;
734 ci->access[i].level = 0;
735 } else if (ci->access[i].level < ACCLEV_MIN
736 || ci->access[i].level > ACCLEV_MAX) {
737 fprintf(stderr, "BUG: Channel %s access entry %d has an"
738 "out-of-range level (%d)! Clearing.\n",
739 ci->name, i, ci->access[i].level);
740 ci->access[i].nickgroup = 0;
741 ci->access[i].level = 0;
742 }
743 }
744
745 /* Make sure all autokick entries have non-empty user and host
746 * parts. */
747 ARRAY_FOREACH (i, ci->akick) {
748 if (!ci->akick[i].mask)
749 continue;
750 s = strchr(ci->akick[i].mask, '@');
751 if (!s || s==ci->akick[i].mask || !s[1]) {
752 fprintf(stderr, "Autokick entry %d for channel %s isn't a"
753 " valid user@host mask, deleting.\n", i, ci->name);
754 ci->akick[i].mask = NULL;
755 }
756 }
757
758 } /* for all channels */
759
760 /* Check that channel successors and access list entries have valid
761 * nickgroup IDs, and that access levels are in range */
762 for (ci = first_channelinfo(); ci; ci = next_channelinfo()) {
763 if (ci->flags & CF_VERBOTEN)
764 continue;
765 }
766 }
767
768 /*************************************************************************/
769
770 static void sanity_check_maskdata(void)
771 {
772 MaskData *md;
773 char *s;
774 int i;
775
776 /* Make sure all MaskData entries actually have masks allocated. */
777 for (i = 0; i < 256; i++) {
778 for (md = first_maskdata(i); md; md = next_maskdata(i)) {
779 if (!md->mask)
780 del_maskdata(i, md);
781 }
782 }
783
784 /* Make sure every autokill has a valid user@host mask and a reason. */
785 for (md = first_maskdata(MD_AKILL); md; md = next_maskdata(MD_AKILL)) {
786 s = strchr(md->mask, '@');
787 if (!s || s==md->mask || !s[1]) {
788 fprintf(stderr, "Autokill %s isn't a valid user@host mask,"
789 " deleting.\n", md->mask);
790 del_maskdata(MD_AKILL, md);
791 continue;
792 }
793 if (!md->reason)
794 md->reason = "Reason unknown";
795 }
796 }
797
798 /*************************************************************************/
799 /****************************** Main program *****************************/
800 /*************************************************************************/
801
802 void usage(const char *progname)
803 {
804 int i;
805
806 fprintf(stderr, "Usage: %s [-v] [+program-name] [options...] dir\n"
807 "The following program names are known:\n", progname);
808 for (i = 0; dbtypes[i]; i++)
809 fprintf(stderr, " %s\n", dbtypes[i]->id);
810 fprintf(stderr,
811 "See the manual for options available for each database type.\n");
812 exit(1);
813 }
814
815 /*************************************************************************/
816
817 int main(int ac, char **av)
818 {
819 int newac = 0; /* For passing to processing function */
820 char **newav;
821 char *dir = NULL; /* Source data file directory */
822 int verbose = 0; /* Verbose output? */
823 void (*load)(const char *, int, int, char **) = NULL;
824 int i;
825 char oldpath[PATH_MAX+1], newpath[PATH_MAX+1];
826
827 #if CLEAN_COMPILE
828 free_nickinfo(NULL);
829 free_nickgroupinfo(NULL);
830 free_channelinfo(NULL);
831 #endif
832
833 init_password(&supass);
834
835 /* Parse command-line parameters */
836 newac = 1;
837 newav = malloc(sizeof(*newav) * ac);
838 newav[0] = av[0];
839 for (i = 1; i < ac; i++) {
840 if (strcmp(av[i],"-v") == 0) {
841 verbose++;
842 } else if (strcmp(av[i],"-h") == 0
843 || strcmp(av[i],"-?") == 0
844 || strcmp(av[i],"-help") == 0
845 || strcmp(av[i],"--help") == 0) {
846 usage(av[0]);
847 } else if (av[i][0] == '+') {
848 int j;
849 for (j = 0; dbtypes[j]; j++) {
850 if (stricmp(av[i]+1, dbtypes[j]->id) == 0) {
851 load = dbtypes[j]->load;
852 break;
853 }
854 }
855 if (!load) {
856 fprintf(stderr, "Unknown database type `%s'\n", av[i]+1);
857 usage(av[0]);
858 }
859 } else if (av[i][0] == '-') {
860 newav[newac++] = av[i];
861 } else {
862 if (dir) {
863 fprintf(stderr, "Only one source directory may be specified\n");
864 usage(av[0]);
865 }
866 dir = av[i];
867 }
868 }
869
870 /* Make sure that we have a source directory and that it's valid */
871 if (!dir) {
872 fprintf(stderr, "Directory name must be specified\n");
873 usage(av[0]);
874 }
875 if (access(dir, R_OK) < 0) {
876 perror(dir);
877 exit(1);
878 }
879
880 /* If the source directory name is relative, make it absolute */
881 if (*dir != '/') {
882 if (!getcwd(oldpath, sizeof(oldpath))) {
883 perror("Unable to read current directory name");
884 fprintf(stderr, "Try using an absolute pathname for the source directory.\n");
885 return 1;
886 }
887 if (strlen(oldpath) + 1 + strlen(dir) + 1 > sizeof(newpath)) {
888 fprintf(stderr, "Source directory pathname too long\n");
889 return 1;
890 }
891 sprintf(newpath, "%s/%s", oldpath, dir);
892 dir = newpath;
893 }
894
895 /* If we weren't given a database type, try to figure one out */
896 if (!load) {
897 for (i = 0; dbtypes[i]; i++) {
898 const char *s;
899 if ((s = dbtypes[i]->check(dir)) != NULL) {
900 fprintf(stderr, "Found %s databases\n", s);
901 load = dbtypes[i]->load;
902 break;
903 }
904 }
905 if (!load) {
906 fprintf(stderr, "Can't determine database type; use +name option\n");
907 usage(av[0]);
908 }
909 }
910
911 /* Actually load the databases. If an error occurs, load() will abort the
912 * program for us */
913 load(dir, verbose, newac, newav);
914 if (verbose)
915 fprintf(stderr, "Data files successfully loaded.\n");
916
917 /* Do sanity checks. */
918 if (verbose)
919 fprintf(stderr, "Checking data integrity...\n");
920 sanity_checks();
921
922 /* Write the database to standard output in XML format */
923 if (verbose)
924 fprintf(stderr, "Writing converted data...\n");
925 xml_export((xml_writefunc_t)fprintf, stdout);
926
927 /* Success */
928 if (verbose)
929 fprintf(stderr, "Done.\n");
930 return 0;
931 }
932
933 /*************************************************************************/
934
935 /*
936 * Local variables:
937 * c-file-style: "stroustrup"
938 * c-file-offsets: ((case-label . *) (statement-case-intro . *))
939 * indent-tabs-mode: nil
940 * End:
941 *
942 * vim: expandtab shiftwidth=4:
943 */