dbck.c 40.4 KB
Newer Older
Linus Tolke Y's avatar
Linus Tolke Y committed
1
/*
2
 * $Id: dbck.c,v 0.73 2003/07/12 22:26:32 ceder Exp $
Per Cederqvist's avatar
Per Cederqvist committed
3
 * Copyright (C) 1991-2002  Lysator Academic Computer Association.
Linus Tolke Y's avatar
Linus Tolke Y committed
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * This file is part of the LysKOM server.
 * 
 * LysKOM is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; either version 1, or (at your option) 
 * any later version.
 * 
 * LysKOM is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with LysKOM; see the file COPYING.  If not, write to
 * Lysator, c/o ISY, Linkoping University, S-581 83 Linkoping, SWEDEN,
 * or the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, 
 * MA 02139, USA.
 *
 * Please mail bug reports to bug-lyskom@lysator.liu.se. 
 */
Per Cederqvist's avatar
Per Cederqvist committed
25
26
27
28
29
30
/*
 * dbck.c - A simple database checker and corrector.
 *
 * Author: Per Cederqvist.
 */

David Byers's avatar
David Byers committed
31
32
33
34
35

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

Per Cederqvist's avatar
Per Cederqvist committed
36
37
38
#ifdef HAVE_STDLIB_H
#  include <stdlib.h>
#endif
Per Cederqvist's avatar
Per Cederqvist committed
39
#include <stdio.h>
Per Cederqvist's avatar
Per Cederqvist committed
40
41
42
#ifdef HAVE_STDARG_H
#  include <stdarg.h>
#endif
43
#include "timewrap.h"
44
#include <sys/types.h>
45
46
47
48
49
50
#ifdef HAVE_CRYPT_H
#  include <crypt.h>
#endif
#ifdef HAVE_UNISTD_H
#  include <unistd.h>
#endif
51
52
53
#ifdef HAVE_STRING_H
#  include <string.h>
#endif
54
#include <assert.h>
David Byers's avatar
Server  
David Byers committed
55
#include <setjmp.h>
56
#include <errno.h>
57

Per Cederqvist's avatar
Per Cederqvist committed
58
#include "getopt.h"
Per Cederqvist's avatar
Per Cederqvist committed
59
#include "misc-types.h"
60
#include "s-string.h"
Per Cederqvist's avatar
Per Cederqvist committed
61
#include "kom-types.h"
Per Cederqvist's avatar
Per Cederqvist committed
62
#include "lyskomd.h"
Per Cederqvist's avatar
Per Cederqvist committed
63
64
#include "log.h"
#include "server/smalloc.h"
Per Cederqvist's avatar
Per Cederqvist committed
65
#include "misc-parser.h"
Per Cederqvist's avatar
Per Cederqvist committed
66
#include "cache.h"
David Byers's avatar
David Byers committed
67
#include "kom-config.h"
Per Cederqvist's avatar
Per Cederqvist committed
68
#include "debug.h"
Per Cederqvist's avatar
Per Cederqvist committed
69
#include "dbck-cache.h"
70
71
#include "param.h"
#include "server-config.h"
David Byers's avatar
Server  
David Byers committed
72
73
74
#include "async.h"
#include "com.h"
#include "connections.h"
75
#include "kom-errno.h"
76
#include "manipulate.h"
Per Cederqvist's avatar
Per Cederqvist committed
77
#include "version-info.h"
78
#include "ram-output.h"
79
#include "unused.h"
80
#include "local-to-global.h"
81
#include "lockdb.h"
Per Cederqvist's avatar
Per Cederqvist committed
82
#include "linkansi.h"
83
#include "eintr.h"
Per Cederqvist's avatar
Per Cederqvist committed
84

85
86
87
88
89
90
91
92

#define OPT_PERS_PRESENTATION_CONF      1
#define OPT_CONF_PRESENTATION_CONF      2
#define OPT_MOTD_CONF                   3
#define OPT_MOTD_OF_KOM                 4
#define OPT_KOM_NEWS_CONF               5


Per Cederqvist's avatar
Per Cederqvist committed
93
94
95
96
97
98
99
100
101
102
103
104
static struct option longopts[] = {
    {"compact-text-mass", 0, 0, 'g' },
    {"interactive", 0, 0, 'i' },
    {"auto-repair", 0, 0, 'r' },
    {"verbose", 0, 0, 'v' },
    {"print-statistics", 0, 0, 's' },
    {"list-text-no", 0, 0, 't' },
    {"set-change-name", 0, 0, 'c' },
    {"clear-password", required_argument, 0, 'P' },
    {"grant-all", required_argument, 0, 'G' },
    {"output-version", required_argument, 0, 'o' },
    {"force-output", 0, 0, 'F' },
105
106
107
108
109
110
111
    {"pers-pres-conf", required_argument, 0, 
     OPT_PERS_PRESENTATION_CONF },
    {"conf-pres-conf", required_argument, 0, 
     OPT_CONF_PRESENTATION_CONF },
    {"motd-conf", required_argument, 0, OPT_MOTD_CONF },
    {"motd-of-kom", required_argument, 0, OPT_MOTD_OF_KOM },
    {"kom-news-conf", required_argument, 0, OPT_KOM_NEWS_CONF },
Per Cederqvist's avatar
Per Cederqvist committed
112
113
114
115
116
    {"help", 0, 0, 'h' },
    { 0, 0, 0, 0 }
};

    
117

118
extern Info kom_info;
Per Cederqvist's avatar
Per Cederqvist committed
119

120
121
122
123
/* This is set to TRUE if init_cache finds out that the last part of the
   database is missing. */
Bool truncated_texts = FALSE;

Per Cederqvist's avatar
Per Cederqvist committed
124
int vflag=0;			/* Verbose - list statistics also. */
Per Cederqvist's avatar
Per Cederqvist committed
125
126
127
128
static int iflag=0;		/* Interactive - prompt user and repair. */
static int rflag=0;		/* Repair simple error without confirmation. */
static int gflag=0;		/* Garbage collect text-file. */
static int sflag=0;		/* Statistic flag. */
Per Cederqvist's avatar
Per Cederqvist committed
129
130
static Pers_no reset_pwd=0;	/* Person whose password should be cleared. */
static Pers_no grant_all=0;	/* Person which should receive all bits. */
131
132
133

/* The following variable holds the output format */

134
long oformat=-1;		/* Output format */
Per Cederqvist's avatar
Per Cederqvist committed
135
static long force_output=0;	/* Force sync (for conversions) */
136

137
138
139
140
141
/* The following variables hold kom_info modifications */

int pers_pres_conf = -1;
int conf_pres_conf = -1;
int motd_conf = -1;
142
Text_no motd_of_lyskom = (Text_no)-1;
143
144
145
int kom_news_conf = -1;


146
147
/* The following variable corresponds to the -c flag, and is
   present here due to a bug in lyskomd 1.6.1. */
Per Cederqvist's avatar
Per Cederqvist committed
148
static int unset_change_name_is_error=0;
149

150
151
/* A list of all available text numbers was useful when developing
   new data structures in lyskomd in 1995.  Option: -t. */
Per Cederqvist's avatar
Per Cederqvist committed
152
static int dump_text_numbers=0;
153

Per Cederqvist's avatar
Per Cederqvist committed
154
155
156
157
158
159
160
161
int modifications = 0;

typedef struct {
    int	created_confs;
} Person_scratchpad;

static const Person_scratchpad   EMPTY_PERSON_SCRATCHPAD = { 0 };

David Byers's avatar
David Byers committed
162
static Person_scratchpad **person_scratchpad = NULL;
Per Cederqvist's avatar
Per Cederqvist committed
163

David Byers's avatar
David Byers committed
164
165
int buglevel = 0;
BUGDECL;
Per Cederqvist's avatar
Per Cederqvist committed
166

167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198

struct delete_list {
    struct delete_list *next;
    Local_text_no lno;
};

static void
delete_list_append(struct delete_list **head,
		   Local_text_no lno)
{
    struct delete_list *item = smalloc(sizeof(struct delete_list));
    item->next = *head;
    item->lno =  lno;
    *head = item;
}

static void
execute_deletions(Local_to_global *l2g,
		  struct delete_list **head)
{
    struct delete_list *item;

    while (*head != NULL)
    {
	item = *head;
	*head = item->next;
	l2g_delete(l2g, item->lno);
	sfree(item);
    }
}


Per Cederqvist's avatar
Per Cederqvist committed
199
#if defined(HAVE_VFPRINTF) && defined(HAVE_STDARG_H)
Per Cederqvist's avatar
Per Cederqvist committed
200
extern void
David Byers's avatar
David Byers committed
201
kom_log (const char * format, ...)
Per Cederqvist's avatar
Per Cederqvist committed
202
203
204
205
206
207
208
209
210
{
    va_list AP;

    va_start(AP, format);

    vfprintf(stdout, format, AP);

    va_end(AP);
}
211
212
#else
extern void
David Byers's avatar
David Byers committed
213
kom_log (format, a, b, c, d, e, f, g)
214
215
     const char * format;
     int a, b, c, d, e, f, g;
216
217
218
219
{
    fprintf(stdout, format, a, b, c, d, e, f, g);
}
#endif
Per Cederqvist's avatar
Per Cederqvist committed
220

Per Cederqvist's avatar
Per Cederqvist committed
221
#if defined(HAVE_VFPRINTF) && defined(HAVE_STDARG_H)
Per Cederqvist's avatar
Per Cederqvist committed
222
223
224
225
226
227
228
229
230
231
232
233
extern void
restart_kom (const char * format, ...)
{
    va_list AP;

    va_start(AP, format);

    vfprintf(stdout, format, AP);

    va_end(AP);
    exit(1);
}
Per Cederqvist's avatar
Per Cederqvist committed
234
#else
235
extern void
236
237
238
restart_kom (format, a, b, c, d, e, f, g)
     const char * format;
     int a, b, c, d, e, f, g;
239
240
241
242
243
{
    fprintf(stdout, format, a, b, c, d, e, f, g);
    exit(1);
}
#endif
Per Cederqvist's avatar
Per Cederqvist committed
244

245

Per Cederqvist's avatar
Per Cederqvist committed
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
static Person_scratchpad *
alloc_person_scratchpad(void)
{
    Person_scratchpad *p;

    p = smalloc(sizeof(Person_scratchpad));
    *p = EMPTY_PERSON_SCRATCHPAD;
    return p;
}


static Bool
is_comment_to(Text_no    comment,
	      Text_stat *parent)
{
    int i;

    for ( i = 0; i < parent->no_of_misc; i++ )
    {
	switch( parent->misc_items[ i ].type )
	{
	case comm_in:
268
	    if ( parent->misc_items[ i ].datum.text_link == comment )
Per Cederqvist's avatar
Per Cederqvist committed
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
		return TRUE;
	    break;
	default:
	    break;
	}
    }

    return FALSE;
}

static Bool
is_commented_in(Text_no    parent,
		Text_stat *child)
{
    int i;

    for ( i = 0; i < child->no_of_misc; i++ )
    {
	switch( child->misc_items[ i ].type )
	{
	case comm_to:
290
	    if ( child->misc_items[ i ].datum.text_link == parent )
Per Cederqvist's avatar
Per Cederqvist committed
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
		return TRUE;
	    break;
	default:
	    break;
	}
    }

    return FALSE;
}
	
static Bool
is_footnote_to(Text_no    footnote,
	       Text_stat *parent)
{
    int i;

    for ( i = 0; i < parent->no_of_misc; i++ )
    {
	switch( parent->misc_items[ i ].type )
	{
	case footn_in:
312
	    if ( parent->misc_items[ i ].datum.text_link == footnote )
Per Cederqvist's avatar
Per Cederqvist committed
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
		return TRUE;
	    break;
	default:
	    break;
	}
    }

    return FALSE;
}

static Bool
is_footnoted_in(Text_no    parent,
		Text_stat *child)
{
    int i;

    for ( i = 0; i < child->no_of_misc; i++ )
    {
	switch( child->misc_items[ i ].type )
	{
	case footn_to:
334
	    if ( child->misc_items[ i ].datum.text_link == parent )
Per Cederqvist's avatar
Per Cederqvist committed
335
336
337
338
339
340
341
342
343
344
		return TRUE;
	    break;
	default:
	    break;
	}
    }

    return FALSE;
}

345
Member *
Per Cederqvist's avatar
Per Cederqvist committed
346
347
348
locate_member(Pers_no      pers_no,
	      Conference * conf_c)
{
349
    Member * mbr;
Per Cederqvist's avatar
Per Cederqvist committed
350
351
    int      i;

352
353
    for(mbr = conf_c->members.members, i = conf_c->members.no_of_members;
	i > 0; i--, mbr++)
Per Cederqvist's avatar
Per Cederqvist committed
354
    {
355
	if ( mbr->member == pers_no )
Per Cederqvist's avatar
Per Cederqvist committed
356
	{
357
	    return mbr;
Per Cederqvist's avatar
Per Cederqvist committed
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
	}
    }

    return NULL;
}

/*
 * Delete a misc_info.
 * If it is a recpt, cc_recpt, comm_to or footn_to delete any
 * loc_no, rec_time, sent_by or sent_at that might follow it.
 *
 * Note that the Misc_info is not reallocated.
 */

static void
delete_misc (Text_stat *tstat,
	     Misc_info *misc)	/* Pointer to first misc_item to delete. */
{
    int del = 1;		/* Number of items to delete. */
    				/* Always delete at least one item. */
378
    Bool ready = FALSE;
Per Cederqvist's avatar
Per Cederqvist committed
379
380
381
382
383
384
    
    /* Check range of misc */

    if (misc < tstat->misc_items
	|| misc >= tstat->misc_items + tstat->no_of_misc )
    {
385
	restart_kom("delete_misc() - misc out of range\n");
Per Cederqvist's avatar
Per Cederqvist committed
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
    }

    while (ready == FALSE
	   && misc + del < tstat->misc_items + tstat->no_of_misc )
    {
	switch ( misc[ del ].type )
	{
	case loc_no:
	case rec_time:
	case sent_by:
	case sent_at:
	    del++;
	    break;

	case recpt:
	case cc_recpt:
402
        case bcc_recpt:
Per Cederqvist's avatar
Per Cederqvist committed
403
404
405
406
407
408
409
410
411
412
	case footn_to:
	case footn_in:
	case comm_to:
	case comm_in:
	    ready = TRUE;
	    break;

#ifndef COMPILE_CHECKS
	default:
#endif
413
414
	case unknown_info:
	    restart_kom("delete_misc() - illegal misc found.\n");
Per Cederqvist's avatar
Per Cederqvist committed
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
	}
    }

    tstat->no_of_misc -= del;

    /* Move items beyond the deleted ones. */

    while ( misc < tstat->misc_items + tstat->no_of_misc )
    {
	misc[ 0 ] = misc[ del ];
	misc++;
    }
}

static int
430
confirm(const char *question)
Per Cederqvist's avatar
Per Cederqvist committed
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
{
    if ( iflag )
    {
	fputs(question, stdout);
	fputs(" (y/n) ", stdout);
	while(1)
	    switch(getchar())
	    {
	    case 'y':
	    case 'Y':
		return 1;
	    case 'n':
	    case 'N':
	    case EOF:
		return 0;
	    default:
		break;
	    }
    }
    else
	return 0;
}
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529


static long
check_misc_any_recipient(Text_no tno,
			 Text_stat *tstat,
			 const char *pretty_type,
			 Conf_no rcpt,
			 Local_text_no lno,
			 Misc_info *previous,
			 const Misc_info **misc)
{
    Conference *c;
    long errors = 0;
    Local_text_no conf_min;
    Local_text_no conf_max;

    c = cached_get_conf_stat(rcpt);
    if (c == NULL && rcpt == 0)
    {
	kom_log("Conference 0 is a %s of text %lu.\n",
		pretty_type, (unsigned long)tno);
	if (rflag || confirm("Repair by deleting misc_item? "))
	{
	    delete_misc(tstat, previous);
	    kom_log("Repaired: Conference 0 is no longer a %s.\n",
		    pretty_type);
	    mark_text_as_changed(tno);
	    modifications++;
	    *misc = previous;
	}
	else
	    errors++;

	return errors;
    }

    if (c == NULL)
	return errors;

    /* Check loc_no */
    conf_min = l2g_lookup(&c->texts, 0);
    conf_max = l2g_first_appendable_key(&c->texts);

    if (lno < conf_min)
    {
	kom_log("Text %lu: %s %lu<%lu>: loc_no is less than %lu\n",
		(unsigned long)tno,
		pretty_type,
		(unsigned long)rcpt,
		(unsigned long)lno,
		(unsigned long)conf_min);
	errors++;
    }
    else if (lno >= conf_max)
    {
	kom_log("Text %lu: %s %lu<%lu>: loc_no is greater than %lu\n",
		(unsigned long)tno,
		pretty_type,
		(unsigned long)rcpt,
		(unsigned long)lno,
		(unsigned long)conf_max);
	errors++;
    }
    else if (l2g_lookup(&c->texts, lno) != tno)
    {
	kom_log("Text %lu: %s %lu<%lu>: that local number is mapped to %lu.\n",
		(unsigned long)tno,
		pretty_type,
		(unsigned long)rcpt,
		(unsigned long)lno,
		(unsigned long)l2g_lookup(&c->texts, lno));
	errors++;
    }

    return errors;
}

Per Cederqvist's avatar
Per Cederqvist committed
530
531
532
533
534
535
536
537
538
    
static long
check_misc_infos(Text_no    tno,
		 Text_stat *tstat)
{
    const Misc_info   * misc = tstat->misc_items;
    Misc_info   * previous;
    Misc_info_group group;
    Text_stat *t;
539
    
540
    long errors=0;
Per Cederqvist's avatar
Per Cederqvist committed
541
542
543
544
545
546
547
548
549

    while (previous = (Misc_info *)misc,
	   group = parse_next_misc(&misc,
				   tstat->misc_items + tstat->no_of_misc),
	   group.type != m_end_of_list && group.type != m_error )
    {
	switch ( group.type )
	{
	case m_recpt:
550
551
552
	    check_misc_any_recipient(tno, tstat, "recipient",
				     group.recipient, group.local_no,
				     previous, &misc);
Per Cederqvist's avatar
Per Cederqvist committed
553
554
555
	    break;

	case m_cc_recpt:
556
557
558
	    check_misc_any_recipient(tno, tstat, "cc_recipient",
				     group.cc_recipient, group.local_no,
				     previous, &misc);
Per Cederqvist's avatar
Per Cederqvist committed
559
560
	    break;

561
	case m_bcc_recpt:
562
563
564
	    check_misc_any_recipient(tno, tstat, "bcc_recipient",
				     group.bcc_recipient, group.local_no,
				     previous, &misc);
565
566
	    break;

Per Cederqvist's avatar
Per Cederqvist committed
567
568
569
570
571
	case m_comm_to:
	    t = cached_get_text_stat(group.comment_to);

	    if ( t == NULL )
	    {
David Byers's avatar
David Byers committed
572
		kom_log("Text %lu is a comment to %lu, which doesn't exist.\n",
573
		    (unsigned long)tno, (unsigned long)group.comment_to);
Per Cederqvist's avatar
Per Cederqvist committed
574
575
576
577
578
579

		if (rflag || confirm("Repair by deleting misc_item? "))
		{
		    delete_misc(tstat, previous);
		    mark_text_as_changed(tno);
		    modifications++;
David Byers's avatar
David Byers committed
580
		    kom_log("Repaired: Comment-link deleted.\n");
Per Cederqvist's avatar
Per Cederqvist committed
581
582
583
		    misc = previous;
		}
		else
584
		    errors++;
Per Cederqvist's avatar
Per Cederqvist committed
585
		    
586
		errors++;
Per Cederqvist's avatar
Per Cederqvist committed
587
588
589
	    }
	    else if (!is_comment_to(tno, t))
	    {
David Byers's avatar
David Byers committed
590
		kom_log("Text %lu is a comment to %lu, but not the reverse.\n",
591
		    (unsigned long)tno, (unsigned long)group.comment_to);
592
		errors++;
Per Cederqvist's avatar
Per Cederqvist committed
593
594
595
596
597
598
599
600
601
	    }

	    break;

	case m_comm_in:
	    t = cached_get_text_stat(group.commented_in);

	    if ( t == NULL )
	    {
David Byers's avatar
David Byers committed
602
		kom_log("Text %lu is commented in %lu, which doesn't exist.\n",
603
		    (unsigned long)tno, (unsigned long)group.commented_in);
Per Cederqvist's avatar
Per Cederqvist committed
604
605
606
607
608
609

		if (rflag || confirm("Repair by deleting misc_item? "))
		{
		    delete_misc(tstat, previous);
		    mark_text_as_changed(tno);
		    modifications++;
David Byers's avatar
David Byers committed
610
		    kom_log("Repaired: Comment-link deleted.\n");
Per Cederqvist's avatar
Per Cederqvist committed
611
612
613
		    misc = previous;
		}
		else
614
		    errors++;
Per Cederqvist's avatar
Per Cederqvist committed
615
616
617
	    }
	    else if (!is_commented_in(tno, t))
	    {
David Byers's avatar
David Byers committed
618
		kom_log("Text %lu is commented in %lu, but not the reverse.\n",
619
		    (unsigned long)tno, (unsigned long)group.commented_in);
620
		errors++;
Per Cederqvist's avatar
Per Cederqvist committed
621
622
623
624
625
626
627
628
629
	    }

	    break;

	case m_footn_to:
	    t = cached_get_text_stat(group.footnote_to);

	    if ( t == NULL )
	    {
David Byers's avatar
David Byers committed
630
		kom_log("Text %lu is a footnote to %lu, which doesn't exist.\n",
631
		    (unsigned long)tno, (unsigned long)group.footnote_to);
Per Cederqvist's avatar
Per Cederqvist committed
632
633
634
635
636
637

		if (rflag || confirm("Repair by deleting misc_item? "))
		{
		    delete_misc(tstat, previous);
		    mark_text_as_changed(tno);
		    modifications++;
David Byers's avatar
David Byers committed
638
		    kom_log("Repaired: Footnote-link deleted.\n");
Per Cederqvist's avatar
Per Cederqvist committed
639
640
641
		    misc = previous;
		}
		else
642
		    errors++;
Per Cederqvist's avatar
Per Cederqvist committed
643
644
645
	    }
	    else if (!is_footnote_to(tno, t))
	    {
David Byers's avatar
David Byers committed
646
		kom_log("Text %lu is a footnote to %lu, but not the reverse.\n",
647
		    (unsigned long)tno, (unsigned long)group.footnote_to);
648
		errors++;
Per Cederqvist's avatar
Per Cederqvist committed
649
650
651
652
653
654
655
656
657
	    }

	    break;
	    
	case m_footn_in:
	    t = cached_get_text_stat(group.footnoted_in);

	    if ( t == NULL )
	    {
David Byers's avatar
David Byers committed
658
		kom_log("Text %lu is footnoted in %lu, which doesn't exist.\n",
659
		    (unsigned long)tno, (unsigned long)group.footnoted_in);
Per Cederqvist's avatar
Per Cederqvist committed
660
661
662
663
664
665

		if (rflag || confirm("Repair by deleting misc_item? "))
		{
		    delete_misc(tstat, previous);
		    mark_text_as_changed(tno);
		    modifications++;
David Byers's avatar
David Byers committed
666
		    kom_log("Repaired: Footnote-link deleted.\n");
Per Cederqvist's avatar
Per Cederqvist committed
667
668
669
		    misc = previous;
		}
		else
670
		    errors++;
Per Cederqvist's avatar
Per Cederqvist committed
671
672
673
	    }
	    else if (!is_footnoted_in(tno, t))
	    {
David Byers's avatar
David Byers committed
674
		kom_log("Text %lu is footnoted in %lu, but not the reverse.\n",
675
		    (unsigned long)tno, (unsigned long)group.footnoted_in);
676
		errors++;
Per Cederqvist's avatar
Per Cederqvist committed
677
678
679
680
681
	    }

	    break;

	default:
David Byers's avatar
David Byers committed
682
	    kom_log("check_misc_infos(): parse_next_misc returned type %lu\n",
683
		(unsigned long)group.type);
Per Cederqvist's avatar
Per Cederqvist committed
684
685
686
687
688
689
	    break;
	}
    }

    if ( group.type == m_error )
    {
David Byers's avatar
David Byers committed
690
	kom_log("Text %lu has a bad misc_info_list.\n", (unsigned long)tno);
691
	errors++;
Per Cederqvist's avatar
Per Cederqvist committed
692
693
    }

694
    return errors;
Per Cederqvist's avatar
Per Cederqvist committed
695
696
697
698
699
700
701
702
703
704
705
706
}

		    
		     
		 
static long
check_texts(void)
{
    Text_no    ct = 0;
    Text_stat *ctp=NULL;
    long	errors = 0;
    Text_no	number_of_texts = 0;
707
708
    unsigned long	bytes=0;
    unsigned long	max_bytes=0;
Per Cederqvist's avatar
Per Cederqvist committed
709
710
    Text_no	max_text=0;

711
    while ( (ct = traverse_text(ct)) != 0 )
Per Cederqvist's avatar
Per Cederqvist committed
712
713
714
715
716
717
    {
	number_of_texts++;
	
	ctp = cached_get_text_stat( ct );
	if ( ctp == NULL )
	{
David Byers's avatar
David Byers committed
718
	    kom_log("Text %lu nonexistent.\n", ct);
Per Cederqvist's avatar
Per Cederqvist committed
719
720
721
722
	    errors++;
	}
	else
	{
723
	    if (dump_text_numbers)
David Byers's avatar
David Byers committed
724
		kom_log("Checking text_no %ld\n", (unsigned long)ct);
725

Per Cederqvist's avatar
Per Cederqvist committed
726
	    bytes += ctp->no_of_chars;
David Byers's avatar
David Byers committed
727
	    if ( (unsigned long)ctp->no_of_chars > max_bytes )
Per Cederqvist's avatar
Per Cederqvist committed
728
729
730
731
732
	    {
		max_bytes = ctp->no_of_chars;
		max_text = ct;
	    }
	    
733
	    /* FIXME (bug 147): no_of_marks is not yet checked. */
Per Cederqvist's avatar
Per Cederqvist committed
734
735
736
737
738
739
740
	    errors += check_misc_infos(ct, ctp);
	}
    }

    if (vflag)
    {
	if ( number_of_texts == 0 )
David Byers's avatar
David Byers committed
741
	    kom_log("WARNING: No texts found.\n");
Per Cederqvist's avatar
Per Cederqvist committed
742
743
	else
	{
David Byers's avatar
David Byers committed
744
	    kom_log("Total of %lu texts (total %lu bytes, avg. %lu bytes/text).\n",
745
746
747
		(unsigned long)number_of_texts,
		(unsigned long)bytes,
		(unsigned long)(bytes/number_of_texts));
David Byers's avatar
David Byers committed
748
	    kom_log("Longest text is %lu (%lu bytes).\n",
749
		(unsigned long)max_text, (unsigned long)max_bytes);
Per Cederqvist's avatar
Per Cederqvist committed
750
751
752
753
754
755
756
757
758
	}
    }
    
    return errors;
}


static int
check_created_texts(Pers_no pno,
759
		    Local_to_global *created)
Per Cederqvist's avatar
Per Cederqvist committed
760
761
{
    Text_stat *t;
762
    int errors=0;
763
764
    L2g_iterator iter;
    struct delete_list *del_list = NULL;
Per Cederqvist's avatar
Per Cederqvist committed
765

766
    for (l2gi_searchall(&iter, created); !iter.search_ended; l2gi_next(&iter))
Per Cederqvist's avatar
Per Cederqvist committed
767
    {
768
769
	assert(iter.tno != 0);
	assert(iter.lno != 0);
Per Cederqvist's avatar
Per Cederqvist committed
770

771
772
773
	t = cached_get_text_stat(iter.tno);
	if ( t != NULL && t->author != pno)
	{
David Byers's avatar
David Byers committed
774
	    kom_log("Person %lu is author of text %lu whose author is %lu.\n",
775
776
777
		(unsigned long)pno, (unsigned long)iter.tno,
		(unsigned long)t->author);
	    errors++;
Per Cederqvist's avatar
Per Cederqvist committed
778
779
	}

780
	if ( t == NULL )
Per Cederqvist's avatar
Per Cederqvist committed
781
	{
David Byers's avatar
David Byers committed
782
	    kom_log("Person %lu is author of text %lu, which doesn't exist.\n",
783
784
785
786
787
788
789
		(unsigned long)pno, (unsigned long)iter.tno);
	    if ( rflag ||
		 confirm("Repair by setting to text_no to 0 in local map"))
	    {
		delete_list_append(&del_list, iter.lno);
		mark_person_as_changed(pno);
		modifications++;
David Byers's avatar
David Byers committed
790
		kom_log("Repaired: created_texts corrected.\n");
791
792
793
	    }
	    else
		errors++;
Per Cederqvist's avatar
Per Cederqvist committed
794
	}
795
	
Per Cederqvist's avatar
Per Cederqvist committed
796
    }
797
    execute_deletions(created, &del_list);
Per Cederqvist's avatar
Per Cederqvist committed
798
    
799
    return errors;
Per Cederqvist's avatar
Per Cederqvist committed
800
801
802
803
}

static int
check_membership(Pers_no pno,
David Byers's avatar
David Byers committed
804
		 Membership *mship)
Per Cederqvist's avatar
Per Cederqvist committed
805
{
806
    int errors=0;
Per Cederqvist's avatar
Per Cederqvist committed
807
808
    Conference *conf;
    Local_text_no last=0;
David Byers's avatar
David Byers committed
809
    Member *mem;
810
811
812
813
    struct read_range *begin;
    struct read_range *end;
    struct read_range *ptr;
    
Per Cederqvist's avatar
Per Cederqvist committed
814
815
816
817
    
    conf = cached_get_conf_stat(mship->conf_no);
    if ( conf == NULL )
    {
David Byers's avatar
David Byers committed
818
	kom_log("Person %lu is a member in the non-existing conference %lu.\n",
819
	    (unsigned long)pno, (unsigned long)mship->conf_no);
820
	errors++;
Per Cederqvist's avatar
Per Cederqvist committed
821
822
823
824
825
    }
    else
    {
	/* Check read texts */

826
827
	last = 0;
	if (mship->no_of_read_ranges > 0)
Per Cederqvist's avatar
Per Cederqvist committed
828
	{
829
830
831
832
	    begin = &mship->read_ranges[0];
	    end = begin + mship->no_of_read_ranges;

	    for (ptr = begin; ptr < end; ptr++)
Per Cederqvist's avatar
Per Cederqvist committed
833
	    {
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
		if (ptr->first_read > ptr->last_read)
		{
		    kom_log("Person %lu's membership in %lu is corrupt: "
			    "bad range: %lu-%lu.\n",
			    (unsigned long)pno, (unsigned long)mship->conf_no,
			    (unsigned long)ptr->first_read,
			    (unsigned long)ptr->last_read);
		    errors++;
		}
		if (ptr != begin && last + 1 == ptr->first_read)
		{
		    kom_log("Person %lu's membership in %lu is corrupt: "
			    "adjoining ranges not joined at around %lu.\n",
			    (unsigned long)pno, (unsigned long)mship->conf_no,
			    (unsigned long)ptr->first_read);
		    errors++;
		}
		if (ptr != begin && last >= ptr->first_read)
		{
		    kom_log("Person %lu's membership in %lu is corrupt: "
			    "overlapping ranges: %lu-%lu, %lu-%lu.\n",
			    (unsigned long)pno, (unsigned long)mship->conf_no,
			    (unsigned long)(ptr-1)->first_read,
			    (unsigned long)(ptr-1)->last_read,
			    (unsigned long)ptr->first_read,
			    (unsigned long)ptr->last_read);
		    errors++;
		}
		last = ptr->last_read;
Per Cederqvist's avatar
Per Cederqvist committed
863
	    }
864
865
866
867
868
869
870
871
872
873
874
	}
	
	if (last >= l2g_first_appendable_key(&conf->texts))
	{
	    kom_log("Person %lu has read text %lu in conf %lu, "
		    "which only has %lu texts.\n",
		    (unsigned long)pno,
		    (unsigned long)last,
		    (unsigned long)mship->conf_no,
		    (unsigned long)(l2g_first_appendable_key(&conf->texts)-1));
	    errors++;
Per Cederqvist's avatar
Per Cederqvist committed
875
876
877
	}

	/* Check that he is a member */
David Byers's avatar
David Byers committed
878
	if ( (mem = locate_member(pno, conf)) == NULL )
Per Cederqvist's avatar
Per Cederqvist committed
879
	{
David Byers's avatar
David Byers committed
880
	    kom_log("Person %lu is a member in %lu in which he isn't a member.\n",
881
		(unsigned long)pno, (unsigned long)mship->conf_no);
882
	    errors++;
Per Cederqvist's avatar
Per Cederqvist committed
883
	}
David Byers's avatar
David Byers committed
884
885
886
887
888
889
890
891
892
893
        else
        {
            /* Check duplicated information
               Short circuit and in each check sets foo_e
               if an error has been detected
            */

            if (mem->type.invitation != mship->type.invitation ||
                mem->type.passive != mship->type.passive ||
                mem->type.secret != mship->type.secret ||
894
895
                mem->type.passive_message_invert !=
		mship->type.passive_message_invert ||
David Byers's avatar
David Byers committed
896
897
898
899
900
901
902
                mem->type.reserved2 != mship->type.reserved2 ||
                mem->type.reserved3 != mship->type.reserved3 ||
                mem->type.reserved4 != mship->type.reserved4 ||
                mem->type.reserved5 != mship->type.reserved5 ||
                mem->added_at != mship->added_at ||
                mem->added_by != mship->added_by)
            {
David Byers's avatar
David Byers committed
903
                kom_log("Person %lu membership in %lu does not match member record.\n",
David Byers's avatar
David Byers committed
904
905
906
907
908
909
910
911
912
913
914
                    (unsigned long)pno,
                    (unsigned long)mship->conf_no
                    );

                errors++;

                fputs("Membership:", stdout);
                printf("  type:      %s%s%s%s%s%s%s%s\n",
                       mship->type.invitation ? "invitation " : "",
                       mship->type.passive ? "passive " : "",
                       mship->type.secret ? "secret " : "",
915
916
                       mship->type.passive_message_invert ?
		       "passive_message_invert "  : "",
David Byers's avatar
David Byers committed
917
918
919
920
921
922
923
924
925
926
927
                       mship->type.reserved2 ? "rsv2 "  : "",
                       mship->type.reserved3 ? "rsv3 "  : "",
                       mship->type.reserved4 ? "rsv4 "  : "",
                       mship->type.reserved5 ? "rsv5"  : "");
                printf("  added_by: %lu\n", (unsigned long)mship->added_by);
                printf("  added_at: %lu\n", (unsigned long)mship->added_at);
                fputs("Member:", stdout);
                printf("  type:      %s%s%s%s%s%s%s%s\n",
                       mem->type.invitation ? "invitation " : "",
                       mem->type.passive ? "passive " : "",
                       mem->type.secret ? "secret " : "",
928
929
                       mem->type.passive_message_invert ?
		       "passive_message_invert "  : "",
David Byers's avatar
David Byers committed
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
                       mem->type.reserved2 ? "rsv2 "  : "",
                       mem->type.reserved3 ? "rsv3 "  : "",
                       mem->type.reserved4 ? "rsv4 "  : "",
                       mem->type.reserved5 ? "rsv5"  : "");
                printf("  added_by: %lu\n", (unsigned long)mem->added_by);
                printf("  added_at: %lu\n", (unsigned long)mem->added_at);

                if (confirm("Copy membership to member"))
                {
                    mem->added_at = mship->added_at;
                    mem->added_by = mship->added_by;
                    mem->type = mship->type;
                    modifications++;
                }
                else if (confirm("Copy member to membership"))
                {
                    mship->added_at = mem->added_at;
                    mship->added_by = mem->added_by;
                    mship->type = mem->type;
                    modifications++;
                }
            }
        }
Per Cederqvist's avatar
Per Cederqvist committed
953
954
    }

955
    return errors;
Per Cederqvist's avatar
Per Cederqvist committed
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
}

	    

static int
check_membership_list(Pers_no pno,
		      const Membership_list *mlist)
{
    int errors=0;
    int i;
    
    for (i = 0; i < mlist->no_of_confs; i++)
	errors += check_membership(pno, &mlist->confs[i]);

    return errors;
}


static int
check_persons(void)
{
Per Cederqvist's avatar
Per Cederqvist committed
977
978
    static char crypt_seed[] = 
	"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
Per Cederqvist's avatar
Per Cederqvist committed
979
980
981
982
983
984
    Pers_no     cp = 0;
    Person     *pstat=NULL;
    Conference *cstat=NULL;
    long	errors = 0;
    Pers_no	number_of_persons=0;

985
    while ( (cp = traverse_person(cp)) != 0 )
Per Cederqvist's avatar
Per Cederqvist committed
986
987
988
989
990
991
992
    {
	number_of_persons++;
	pstat = cached_get_person_stat (cp);
	cstat = cached_get_conf_stat (cp);
	
	if ( pstat == NULL )
	{
David Byers's avatar
David Byers committed
993
	    kom_log("Person %lu nonexistent.\n", (unsigned long)cp);
Per Cederqvist's avatar
Per Cederqvist committed
994
995
996
997
	    errors++;
	}
	else if (cstat == NULL)
	{
David Byers's avatar
David Byers committed
998
	    kom_log("Person %lu has no conference.\n", (unsigned long)cp);
Per Cederqvist's avatar
Per Cederqvist committed
999
1000
1001
1002
	    errors++;
	}
	else if (!cstat->type.letter_box)
	{
David Byers's avatar
David Byers committed
1003
	    kom_log("Person %lu's conference is not a letter_box.\n",
1004
		(unsigned long)cp);
Per Cederqvist's avatar
Per Cederqvist committed
1005
1006
1007
1008
1009
1010
1011
	    errors++;
	}
	else
	{
	    errors += (check_created_texts(cp, &pstat->created_texts)
		       + check_membership_list(cp, &pstat->conferences));
	}
1012
1013
1014
1015

	if (unset_change_name_is_error == 1
	    && pstat->privileges.change_name == 0)
	{
David Byers's avatar
David Byers committed
1016
	    kom_log("Person %lu has no change_name capability.\n",
1017
		(unsigned long)cp);
Per Cederqvist's avatar
Per Cederqvist committed
1018

1019
1020
1021
1022
1023
1024
1025
1026
1027
	    if (rflag || confirm("Grant him the capability"))
	    {
		pstat->privileges.change_name = 1;
		mark_person_as_changed(cp);
		modifications++;
	    }
	    else
		errors++;
	}
Per Cederqvist's avatar
Per Cederqvist committed
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
	if (cp == reset_pwd)
	{
	    char salt[3];
	  
	    salt[0] = crypt_seed [rand() % (sizeof (crypt_seed) - 1)];
	    salt[1] = crypt_seed [rand() % (sizeof (crypt_seed) - 1)];
	    salt[2] = '\0';
	  
	    strcpy((char *)pstat->pwd, (const char *)crypt("", salt));
	    mark_person_as_changed(cp);
	    modifications++;
	}

	if (cp == grant_all)
	{
	    pstat->privileges.wheel = 1;
	    pstat->privileges.admin = 1;
	    pstat->privileges.statistic = 1;
	    pstat->privileges.create_pers = 1;
	    pstat->privileges.create_conf = 1;
	    pstat->privileges.change_name = 1;
1049
	    pstat->privileges.flg7 = 1;
Per Cederqvist's avatar
Per Cederqvist committed
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
	    pstat->privileges.flg8 = 1;
	    pstat->privileges.flg9 = 1;
	    pstat->privileges.flg10 = 1;
	    pstat->privileges.flg11 = 1;
	    pstat->privileges.flg12 = 1;
	    pstat->privileges.flg13 = 1;
	    pstat->privileges.flg14 = 1;
	    pstat->privileges.flg15 = 1;
	    pstat->privileges.flg16 = 1;
	    mark_person_as_changed(cp);
	    modifications++;
	}
Per Cederqvist's avatar
Per Cederqvist committed
1062
1063
1064
    }

    if (vflag)
David Byers's avatar
David Byers committed
1065
	kom_log("Total of %lu persons.\n", (unsigned long)number_of_persons);
Per Cederqvist's avatar
Per Cederqvist committed
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
    
    return errors;
}

static Bool
is_recipient(Conf_no	 conf_no,
	     Text_stat * t_stat)
{
    int i;
    
    for ( i = 0; i < t_stat->no_of_misc; i++ )
    {
	switch( t_stat->misc_items[ i ].type )
	{
	case recpt:
	case cc_recpt:
1082
	case bcc_recpt:
1083
	    if ( t_stat->misc_items[ i ].datum.recipient == conf_no )
1084
1085
1086
1087
	    {
		return TRUE;
	    }
	    break;
1088

Per Cederqvist's avatar
Per Cederqvist committed
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
	case rec_time:
	case comm_to:
	case comm_in:
	case footn_to:
	case footn_in:
	case sent_by:
	case sent_at:
	case loc_no:
	    break;
	    
#ifndef COMPILE_CHECKS
	default:
#endif
1102
1103
	case unknown_info:
	    restart_kom("is_recipient(): illegal misc_item\n");
Per Cederqvist's avatar
Per Cederqvist committed
1104
1105
1106
1107
1108
1109
1110
1111
	}
    }

    return FALSE;
}

static int
check_texts_in_conf(Conf_no cc,
1112
		    Local_to_global *tlist)
Per Cederqvist's avatar
Per Cederqvist committed
1113
1114
{
    Text_stat *t;
1115
    int errors=0;
1116
1117
1118
1119
    L2g_iterator iter;
    struct delete_list *del_list = NULL;
    
    for (l2gi_searchall(&iter, tlist); !iter.search_ended; l2gi_next(&iter))
Per Cederqvist's avatar
Per Cederqvist committed
1120
    {
1121
1122
1123
1124
	assert(iter.lno != 0);
	assert(iter.tno != 0);
	t = cached_get_text_stat(iter.tno);
	if (t == NULL)
Per Cederqvist's avatar
Per Cederqvist committed
1125
	{
David Byers's avatar
David Byers committed
1126
	    kom_log("Text %lu<%lu> in conference %lu is non-existent.\n",
1127
1128
1129
1130
1131
		(unsigned long)iter.tno,
		(unsigned long)iter.lno,
		(unsigned long)cc);

	    if (rflag || confirm("Repair by deleting the Text_no in the map?"))
Per Cederqvist's avatar
Per Cederqvist committed
1132
	    {
1133
1134
1135
		delete_list_append(&del_list, iter.lno);
		mark_conference_as_changed(cc);
		modifications++;
David Byers's avatar
David Byers committed
1136
		kom_log("Repaired: %lu is no longer a recipient.\n",
1137
		    (unsigned long)cc);
1138
1139
1140
1141
1142
1143
1144
1145
	    }
	    else
		errors++;
	}
	else
	{
	    if (!is_recipient(cc, t))
	    {
David Byers's avatar
David Byers committed
1146
		kom_log("Text %lu<%lu> in conference %lu %s.\n",
1147
1148
1149
1150
		    (unsigned long)iter.tno,
		    (unsigned long)iter.lno,
		    (unsigned long)cc,
		    "doesn't have the conference as recipient");
Per Cederqvist's avatar
Per Cederqvist committed
1151

1152
		if (confirm("Repair by deleting Text_no from the map?") )
Per Cederqvist's avatar
Per Cederqvist committed
1153
		{
1154
		    delete_list_append(&del_list, iter.lno);
Per Cederqvist's avatar
Per Cederqvist committed
1155
1156
		    mark_conference_as_changed(cc);
		    modifications++;
David Byers's avatar
David Byers committed
1157
		    kom_log("Repaired: %lu is no longer a recipient.\n",
1158
			(unsigned long)cc);
Per Cederqvist's avatar
Per Cederqvist committed
1159
1160
		}
		else
1161
		    errors++;
Per Cederqvist's avatar
Per Cederqvist committed
1162
1163
1164
	    }
	}
    }
1165
    execute_deletions(tlist, &del_list);
Per Cederqvist's avatar
Per Cederqvist committed
1166

1167
    return errors;
Per Cederqvist's avatar
Per Cederqvist committed
1168
1169
}

1170
Membership *
1171
1172
locate_membership(Conf_no       conf_no,
		  const Person *pers_p)
Per Cederqvist's avatar
Per Cederqvist committed
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
{
    Membership * confp;
    int    i;

    for(confp = pers_p->conferences.confs, i = pers_p->conferences.no_of_confs;
	i > 0; i--, confp++)
    {
	if ( confp->conf_no == conf_no )
	{
	    return confp;
	}
    }

    return NULL;
}

static int
check_member(Conf_no cc,
	     Member *memb)
{
    Person *pp;
1194
    int errors=0;
Per Cederqvist's avatar
Per Cederqvist committed
1195
1196
1197
1198

    pp = cached_get_person_stat(memb->member);
    if ( pp == NULL )
    {
David Byers's avatar
David Byers committed
1199
	kom_log("Person %lu, supposedly a member in conf %lu, is nonexistent.\n",
1200
	    (unsigned long)memb->member, (unsigned long)cc);
1201
	errors++;
Per Cederqvist's avatar
Per Cederqvist committed
1202
1203
1204
1205
1206
    }
    else
    {
	if ( locate_membership(cc, pp) == NULL )
	{
David Byers's avatar
David Byers committed
1207
	    kom_log("Person %lu is not a member in conf %lu.\n",
1208
1209
		(unsigned long)memb->member,
		(unsigned long)cc);
1210
	    errors++;
Per Cederqvist's avatar
Per Cederqvist committed
1211
1212
1213
	}
    }

1214
    return errors;
Per Cederqvist's avatar
Per Cederqvist committed
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
}

static int
check_member_list(Conf_no cc,
		  const Member_list *mlist)
{
    int errors=0;
    int i;
    
    for (i = 0; i < mlist->no_of_members; i++)
	errors += check_member(cc, &mlist->members[i]);

    return errors;
}


static int
check_confs(void)
{
    Conf_no     cc = 0;
    Person     *pstat=NULL;
    Conference *cstat=NULL;
    long	errors = 0;
    Conf_no	number_of_confs = 0;

    while ( (cc = traverse_conference(cc)) != 0 )
    {
	number_of_confs++;
	cstat = cached_get_conf_stat (cc);
	
	if ( cstat == NULL )
	{
David Byers's avatar
David Byers committed
1247
	    kom_log("Conference %lu nonexistent.\n", (unsigned long)cc);
Per Cederqvist's avatar
Per Cederqvist committed
1248
1249
1250
1251
1252
1253
1254
1255
1256
	    errors++;
	}
	else
	{
	    if (cstat->type.letter_box)
	    {
		pstat = cached_get_person_stat(cc);
		if (pstat == NULL)
		{
David Byers's avatar
David Byers committed
1257
		    kom_log("Mailbox %lu has no person.\n", (unsigned long)cc);
Per Cederqvist's avatar
Per Cederqvist committed
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
		    errors++;
		}
	    }
	    else		/* not letter_box */
	    {
		/* Remember that the creator might no longer exist. */
		if ( person_scratchpad[ cstat->creator ] != NULL )
		    ++person_scratchpad[ cstat->creator ]->created_confs;
	    }

	    errors += (check_texts_in_conf(cc, &cstat->texts)
		       + check_member_list(cc, &cstat->members));
	}
    }

    if ( vflag )
David Byers's avatar
David Byers committed
1274
	kom_log("Total of %lu conferences.\n", (unsigned long)number_of_confs);
Per Cederqvist's avatar
Per Cederqvist committed
1275
1276
1277
1278
1279
1280
1281
1282

    return errors;
}

static void
init_person_scratch(void)
{
    Pers_no pno = 0;
1283
    Pers_no i = 0;
Per Cederqvist's avatar
Per Cederqvist committed
1284
    
David Byers's avatar
David Byers committed
1285
1286
1287
    if (person_scratchpad == NULL)
    {
        person_scratchpad = smalloc(sizeof(*person_scratchpad) * param.max_conf);
1288
1289
        for (i = 0; i < param.max_conf; i++)
            person_scratchpad[i] = NULL;
David Byers's avatar
David Byers committed
1290
1291
    }

Per Cederqvist's avatar
Per Cederqvist committed
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
    while( (pno = traverse_person(pno)) != 0 )
    {
	person_scratchpad[pno] = alloc_person_scratchpad();
    }
}