membership.c 55.4 KB
Newer Older
Linus Tolke's avatar
Linus Tolke committed
1
/*
2
3
 * $Id: membership.c,v 0.99 2005/12/18 22:18:13 ceder Exp $
 * Copyright (C) 1991-2005  Lysator Academic Computer Association.
Linus Tolke's avatar
Linus Tolke committed
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 *
 * 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.
 *
Per Cederqvist's avatar
Per Cederqvist committed
23
 * Please report bugs at http://bugzilla.lysator.liu.se/. 
Linus Tolke's avatar
Linus Tolke committed
24
 */
Per Cederqvist's avatar
Per Cederqvist committed
25
26
27
28
29
30
/*
 * membership.c
 *
 * All atomic calls that controlls who is a member in what.
 * (The person/conf relation).
 */
Per Cederqvist's avatar
Per Cederqvist committed
31

David Byers's avatar
David Byers committed
32
33
34
35
36
37


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

Per Cederqvist's avatar
Per Cederqvist committed
38
39
#define DEBUG_MARK_AS_READ

40
#include <assert.h>
Per Cederqvist's avatar
Per Cederqvist committed
41
#include <stdio.h>
Per Cederqvist's avatar
Per Cederqvist committed
42
43
44
#ifdef HAVE_STRING_H
#  include <string.h>
#endif
45
#include <stddef.h>
46
#include "timewrap.h"
Per Cederqvist's avatar
Per Cederqvist committed
47
#include <setjmp.h>
48
#include <sys/types.h>
Per Cederqvist's avatar
Per Cederqvist committed
49
50

#include "misc-types.h"
51
#include "s-string.h"
Per Cederqvist's avatar
Per Cederqvist committed
52
53
54
#include "kom-types.h"
#include "services.h"
#include "server/smalloc.h"
Per Cederqvist's avatar
Per Cederqvist committed
55
56
#include "lyskomd.h"
#include "com.h"
57
#include "async.h"
Per Cederqvist's avatar
Per Cederqvist committed
58
59
#include "connections.h"
#include "internal-connections.h"
Per Cederqvist's avatar
Per Cederqvist committed
60
61
62
63
64
#include "kom-errno.h"
#include "manipulate.h"
#include "cache.h"
#include "send-async.h"
#include "minmax.h"
Per Cederqvist's avatar
Per Cederqvist committed
65
#include "kom-memory.h"
66
#include "conf-file.h"
67
#include "param.h"
68
#include "ram-io.h"
69
#include "local-to-global.h"
70
#include "server-time.h"
Per Cederqvist's avatar
Per Cederqvist committed
71
72

#ifdef DEBUG_MARK_AS_READ
73
74
#  include "log.h"
#  include "ram-output.h"
Per Cederqvist's avatar
Per Cederqvist committed
75
76
#endif

77
78
static void
set_membership_type_bits(Membership_type *type,
79
80
81
82
83
84
85
86
			 Bool invitation,
			 Bool passive,
			 Bool secret,
			 Bool passive_message_invert,
			 Bool reserved2,
			 Bool reserved3, 
			 Bool reserved4,
			 Bool reserved5)
87
88
89
90
{
    type->invitation = invitation;
    type->passive = passive;
    type->secret = secret;
91
    type->passive_message_invert = passive_message_invert;
92
93
94
95
96
97
    type->reserved2 = reserved2;
    type->reserved3 = reserved3;
    type->reserved4 = reserved4;
    type->reserved5 = reserved5;
}

98
99
100
101
102
103
104
105
106
107
108
109
110

static enum memb_visibility
check_unread(Pers_no member)
{
    Person *memb_p;
    GET_P_STAT(memb_p, member, mv_none);
    if (memb_p->flags.unread_is_secret)
	return mv_censor_unread;
    else
	return mv_full;
}


111
enum memb_visibility
112
113
114
membership_visible(const Connection *viewer_conn,
		   Pers_no member,
		   Conf_no conf_no,
115
116
117
118
		   Membership_type type,
		   Bool is_supervisor_of_member,
		   Bool is_supervisor_of_conf)

119
{
120
121
122
123
    enum access ma = error;
    enum access ca = error;
    
    if (ENA_C(viewer_conn, admin, 2) || ENA_C(viewer_conn, wheel, 8))
124
125
	return mv_full;

126
127
128
129
130
    if (is_supervisor_of_member
	|| (ma = access_perm(member, viewer_conn, unlimited)) >= unlimited)
    {
	return mv_full;
    }
131

132
133
    if (is_supervisor_of_conf
	|| (ca = access_perm(conf_no, viewer_conn, unlimited)) >= unlimited)
134
135
136
    {
	return check_unread(member);
    }
137
138
139

    if (ma >= read_protected && ca >= read_protected && !type.secret)
	return check_unread(member);
140
141
142
143
    
    return mv_none;
}

Per Cederqvist's avatar
Per Cederqvist committed
144
145
146
147
148
149
150
/*
 * Copy all information that ACTPERS is authorized to know about ORIG_P's
 * membership in all conferences to CENSOR_P.
 *
 * This function is used in get_membership().
 */
static void
David Byers's avatar
Server    
David Byers committed
151
copy_public_confs (Connection * conn, /* The connection for which we copy */
152
		   Pers_no    pers_no,  /* The person being censored */
David Byers's avatar
Server    
David Byers committed
153
                   Person   * censor_p,	/* The censored Person-struct */
Per Cederqvist's avatar
Per Cederqvist committed
154
		   Person   * orig_p,	/* The uncensored Person-struct */
155
156
157
		   Bool       keep_read,
		   Bool       want_read,
		   unsigned long max_ranges)
Per Cederqvist's avatar
Per Cederqvist committed
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
{
    int i;			/* Number of mships lefte in ORIG_P */
    Membership * censor_m;		/* Pointer in CENSOR_P */
    Membership * orig_m;	/* Pointer in ORIG_P */

    /* Copy all information except the secret. */
		    
    censor_p->conferences.confs
	= tmp_alloc( orig_p->conferences.no_of_confs * sizeof(Membership));
    censor_p->conferences.no_of_confs = 0;

    censor_m = censor_p->conferences.confs;
    orig_m   = orig_p->conferences.confs;

    for ( i = 0; i < orig_p->conferences.no_of_confs; i++, orig_m++ )
    {
174
175
176
177
	enum memb_visibility vis = membership_visible(
	    conn, pers_no, orig_m->conf_no, orig_m->type, FALSE, FALSE);

	if (vis > mv_none)
Per Cederqvist's avatar
Per Cederqvist committed
178
179
180
	{
	    *censor_m = *orig_m;

181
	    if (!want_read)
182
183
184
185
186
187
188
189
190
191
192
	    {
		if (keep_read)
		    censor_m->skip_read_texts = TRUE;
		else
		    censor_m->read_ranges = NULL;
	    }
	    else
	    {
		if (max_ranges > 0 && censor_m->no_of_read_ranges > max_ranges)
		    censor_m->no_of_read_ranges = max_ranges;
	    }
Per Cederqvist's avatar
Per Cederqvist committed
193

194
	    if (vis == mv_censor_unread)
Per Cederqvist's avatar
Per Cederqvist committed
195
196
	    {
		censor_m->last_time_read = NO_TIME;
197
198
		censor_m->no_of_read_ranges = 0;
		censor_m->read_ranges = NULL;
Per Cederqvist's avatar
Per Cederqvist committed
199
200
201
202
203
204
205
206
207
208
209
	    }
	    
	    ++censor_m;
	    ++censor_p->conferences.no_of_confs;
	}
    }
}

/*
 * Change the priority of a certain conference in a person.
 */
David Byers's avatar
David Byers committed
210

Per Cederqvist's avatar
Per Cederqvist committed
211
212
static void
do_change_priority (Membership * mship,
213
214
                    Conf_no conf_no,
                    Conference * conf_c,
215
216
		    unsigned char	 priority,
		    unsigned short	 where,
Per Cederqvist's avatar
Per Cederqvist committed
217
		    Pers_no	 pers_no,
218
		    Person     * pers_p,
David Byers's avatar
David Byers committed
219
220
                    Membership_type * type,
                    Bool            fake_passive)
Per Cederqvist's avatar
Per Cederqvist committed
221
222
{
    Membership tmp_conf;
David Byers's avatar
David Byers committed
223
    Member *mem;
Per Cederqvist's avatar
Per Cederqvist committed
224
    
David Byers's avatar
David Byers committed
225
    if (priority == 0 && fake_passive)
226
    {
David Byers's avatar
David Byers committed
227
        type->passive = 1;
228
229
230
231
232
    }
    else
    {
        mship->priority = priority;
    }
David Byers's avatar
David Byers committed
233

234
    mship->type = *type;
Per Cederqvist's avatar
Per Cederqvist committed
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
    
    /* Check range of where */
    
    if ( where >= pers_p->conferences.no_of_confs )
    {
	where = pers_p->conferences.no_of_confs - 1;
    }
    
    /* And now move the conference to slot number 'where' */
    
    if ( mship < pers_p->conferences.confs + where )
    {
	tmp_conf = *mship;
	while ( mship < pers_p->conferences.confs + where)
	{
	    *mship = *(mship + 1);
	    mship++;
	}
	*mship = tmp_conf;
    }
    else
    {
	tmp_conf = *mship;
	while ( mship > pers_p->conferences.confs + where)
	{
	    *mship = *(mship - 1);
	    mship--;
	}
	*mship = tmp_conf;
    }

David Byers's avatar
David Byers committed
266
267
268
    /* Sync the change with the corresponding member list */
    mem = locate_member(pers_no, conf_c);
    if (mem != NULL)
269
    {
David Byers's avatar
David Byers committed
270
271
        mem->type = *type;
        mark_conference_as_changed( conf_no );
272
273
    }

Per Cederqvist's avatar
Per Cederqvist committed
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
    mark_person_as_changed( pers_no );
}


/*
 * Insert a rec_time misc item to a text_status.
 * The item is put at position POS on the list. (0 == first)
 * Take no action if the misc_item at POS is a rec_time.
 * This function is only used when a person marks his letters as read.
 *
 *	Text_stat * text_stat_pointer	Textstatus to modify
 *	int	    pos			Where to insert rec_time
 */

static void
do_add_rec_time (Text_stat    * text_stat_ptr,
		 int		pos)
{
    int i;

    /* Defensive checks */
    if ( pos < 0 || pos > text_stat_ptr->no_of_misc )
    {
	restart_kom("do_add_rec_time() - illegal pos\n");
    }

    /* Check that no rec_time exists */

    if ( pos < text_stat_ptr->no_of_misc
	&& text_stat_ptr->misc_items[ pos ].type == rec_time )
    {
	return;
    }
    
    /* Allocate space */
    text_stat_ptr->misc_items
    = srealloc(text_stat_ptr->misc_items,
	       (++(text_stat_ptr->no_of_misc)) * sizeof(Misc_info));

    /* Move items. */

    for ( i = text_stat_ptr->no_of_misc - 1; i > pos; i-- )
    {
	text_stat_ptr->misc_items[ i ] = text_stat_ptr->misc_items[ i - 1 ];
    }

    /* Set type */
    text_stat_ptr->misc_items[ pos ].type = rec_time;

    /* Set value */
324
    text_stat_ptr->misc_items[ pos ].datum.received_at = current_time.tv_sec;
Per Cederqvist's avatar
Per Cederqvist committed
325
326
327
328
}

/*
 * add_rec_time adds a 'rec_time'  misc_item to text number LOC_NO in
David Byers's avatar
Server    
David Byers committed
329
330
 * conference CONF_C. The item will follow a recpt or cc_recpt to pers_no.
 * No action is taken if PERS_NO is not a recipient of the text, or the text
Per Cederqvist's avatar
Per Cederqvist committed
331
332
333
 * no longer exists, or the text has already been received.
 */
static void
334
add_rec_time(Conference * conf_c,
David Byers's avatar
Server    
David Byers committed
335
336
	     Local_text_no local_no,
             Pers_no pers_no)
Per Cederqvist's avatar
Per Cederqvist committed
337
338
339
340
341
342
{
    Bool 	  found;
    Text_no	  text_no;
    Text_stat 	* t_stat;
    int		  i;
    
343
    text_no = l2g_lookup(&conf_c->texts, local_no);
Per Cederqvist's avatar
Per Cederqvist committed
344
345
346
347
348
349

    if ( text_no == 0 )
    {
	return;			/* Text is deleted. */
    }
    
Per Cederqvist's avatar
Per Cederqvist committed
350
    VOID_GET_T_STAT(t_stat, text_no);
Per Cederqvist's avatar
Per Cederqvist committed
351
352
353
354
355
356
357
358
359

    /* locate the misc_item which says that ACTPERS is a recipient */

    for ( found = FALSE, i = 0; !found && i < t_stat->no_of_misc; i++ )
    {
	switch ( t_stat->misc_items[ i ].type )
	{
	case recpt:
	case cc_recpt:
360
	case bcc_recpt:
361
	    if ( t_stat->misc_items[ i ].datum.recipient == pers_no )
362
	    {
363
		do_add_rec_time( t_stat, i + 2 ); /* Add after loc_no */
364
365
366
367
		found = TRUE;
	    }
	    break;

Per Cederqvist's avatar
Per Cederqvist committed
368
369
370
371
372
373
374
375
376
	case comm_to:
	case comm_in:
	case footn_to:
	case footn_in:
	case loc_no:
	case rec_time:
	case sent_by:
	case sent_at:
	    break;
David Byers's avatar
David Byers committed
377
378
379
380

        case unknown_info:
        default:
            restart_kom("ERROR: bogus misc_info type detected in text %lu\n", text_no);
Per Cederqvist's avatar
Per Cederqvist committed
381
382
383
384
385
	}
    }

    if( found ==  FALSE )
    {
David Byers's avatar
David Byers committed
386
	kom_log("ERROR: add_rec_time(): found==FALSE\n");
Per Cederqvist's avatar
Per Cederqvist committed
387
388
389
390
391
392
393
    }
    
    mark_text_as_changed( text_no);
    return;
}

/*
394
395
 * Check if any read_ranges can be extended due to deleted texts.
 * Merge read_ranges blocks, if possible.
Per Cederqvist's avatar
Per Cederqvist committed
396
 *
397
398
399
 * This is currently only used from mark_as_read(), but it would be
 * good to have a background task that does this whenever a text has
 * been deleted.
400
401
 *
 * Returns non-zero if any change was performed.
Per Cederqvist's avatar
Per Cederqvist committed
402
 */
403
Bool
404
405
adjust_read(Membership *m,
	    const Conference *conf)
Per Cederqvist's avatar
Per Cederqvist committed
406
{
407
408
409
410
411
412
    struct read_range *ptr;
    struct read_range *prev;
    struct read_range *next;
    struct read_range *tail;
    struct read_range *begin;
    struct read_range *end;
413
    Bool change = FALSE;
414

Per Cederqvist's avatar
Per Cederqvist committed
415
416
    Local_text_no   conf_max;	/* Highest used local_text_no in conf */
    Local_text_no   conf_min;	/* Lowest used local_text_no in conf */
417

418
419
420
    Local_text_no   past_block;	/* The next local_text_no after the current block. */
    Local_text_no   limit;

421
422
    /* If nothing is marked as read, there is nothing to adjust.  */
    if (m->no_of_read_ranges == 0)
423
	return change;
Per Cederqvist's avatar
Per Cederqvist committed
424

425
    /* (conf_min <= x < conf_max) if x is an existing local_text_no */
426
    conf_min = l2g_next_key(&conf->texts, 0);
427
428
    if (conf_min == 0)
	conf_min = l2g_first_appendable_key(&conf->texts);
429
    conf_max = l2g_first_appendable_key(&conf->texts);
Per Cederqvist's avatar
Per Cederqvist committed
430

431
432
    begin = &m->read_ranges[0];
    end = begin + m->no_of_read_ranges;
Per Cederqvist's avatar
Per Cederqvist committed
433

434
435
436
437
#ifdef DEBUG_MARK_AS_READ
    
    /* Check that the items in read_texts really ARE sorted in ascending order.
       If not, there is probably a bug in this routine or in mark_as_read. */
Per Cederqvist's avatar
Per Cederqvist committed
438

439
    for (ptr = begin; ptr < end; ptr++)
440
    {
441
	if (ptr->first_read > ptr->last_read)
Per Cederqvist's avatar
Per Cederqvist committed
442
	{
443
444
445
446
447
448
	    kom_log("Bad input to adjust_read. Conference %lu, Priority %lu."
		    " Range %lu-%lu is nonsensical.\n",
		    (unsigned long)m->conf_no,
		    (unsigned long)m->priority,
		    (unsigned long)ptr->first_read,
		    (unsigned long)ptr->last_read);
449
	    return change;
Per Cederqvist's avatar
Per Cederqvist committed
450
	}
451
452

	if (ptr != begin && (ptr-1)->last_read >= ptr->first_read)
453
	{
454
455
456
457
458
459
460
461
	    kom_log("Bad input to adjust_read. Conference %lu, Priority %lu."
		    " Overlapping ranges: %lu-%lu, %lu-%lu.\n",
		    (unsigned long)m->conf_no,
		    (unsigned long)m->priority,
		    (unsigned long)(ptr-1)->first_read,
		    (unsigned long)(ptr-1)->last_read,
		    (unsigned long)ptr->first_read,
		    (unsigned long)ptr->last_read);
462
	    return change;
463
464
	}
    }
465
466
467
#endif

    for (ptr = begin; ptr < end; ptr++)
Per Cederqvist's avatar
Per Cederqvist committed
468
    {
469
470
471
472
473
474
475
476
477
	if (ptr == begin)
	    prev = NULL;
	else
	    prev = ptr - 1;
	next = ptr + 1;
	if (next == end)
	    next = NULL;

	/* Try to lower first_read. */
478
	while (ptr->first_read > 1
479
480
	       && (prev == NULL || prev->last_read + 1 < ptr->first_read)
	       && l2g_lookup(&conf->texts, ptr->first_read - 1) == 0)
Per Cederqvist's avatar
Per Cederqvist committed
481
	{
482
	    change = TRUE;
483
	    ptr->first_read--;
484
485
	    if (ptr->first_read < conf_min)
		ptr->first_read = 1;
Per Cederqvist's avatar
Per Cederqvist committed
486
	}
487

488
489
490
491
492
493
494
495
496
	/* Raise last_read past any deleted texts. */
	past_block = l2g_next_key(&conf->texts, ptr->last_read);
	if (next != NULL)
	    limit = next->first_read;
	else
	    limit = conf_max;

	if (past_block == 0 || past_block > limit)
	    past_block = limit;
497
498
499
500
501
	if (ptr->last_read != past_block - 1)
	{
	    ptr->last_read = past_block - 1;
	    change = TRUE;
	}
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
    }

    /* Join any ranges that became adjacent. */
    tail = begin;
    for (ptr = begin + 1; ptr < end; ptr++)
    {
	if (tail->last_read + 1 == ptr->first_read)
	    tail->last_read = ptr->last_read;
	else if (++tail != ptr)
	    *tail = *ptr;
    }
    if (end != tail + 1)
    {
	end = tail + 1;
	m->no_of_read_ranges = end - begin;
	m->read_ranges = srealloc(
	    m->read_ranges,
	    m->no_of_read_ranges * sizeof(m->read_ranges[0]));
520
	change = TRUE;
Per Cederqvist's avatar
Per Cederqvist committed
521
522
    }

523
#ifndef NDEFENSIVE_CHECKS
Per Cederqvist's avatar
Per Cederqvist committed
524
525
    
    /* Check that the items in read_texts really ARE sorted in ascending order.
526
527
528
       If not, there is probably a bug in this routine or in mark_as_read. */

    for (ptr = begin; ptr < end; ptr++)
Per Cederqvist's avatar
Per Cederqvist committed
529
    {
530
	if (ptr->first_read > ptr->last_read)
Per Cederqvist's avatar
Per Cederqvist committed
531
	{
532
533
534
535
536
537
538
	    kom_log("Bug in adjust_read. Conference %lu, Priority %lu."
		    " Range %lu-%lu is nonsensical (fixed).\n",
		    (unsigned long)m->conf_no,
		    (unsigned long)m->priority,
		    (unsigned long)ptr->first_read,
		    (unsigned long)ptr->last_read);
	    ptr->last_read = ptr->first_read;
539
540
	    change = TRUE;
	    return change;
Per Cederqvist's avatar
Per Cederqvist committed
541
542
	}

543
544
545
546
547
548
549
550
551
552
553
	if (ptr != begin && ptr->first_read <= (ptr-1)->last_read)
	{
	    kom_log("Bug in adjust_read. Conference %lu, Priority %lu."
		    " %lu not greater than %lu (fixed).\n",
		    (unsigned long)m->conf_no,
		    (unsigned long)m->priority,
		    (unsigned long)ptr->first_read,
		    (unsigned long)(ptr-1)->last_read);
	    sfree(m->read_ranges);
	    m->read_ranges = NULL;
	    m->no_of_read_ranges = 0;   
554
555
	    change = TRUE;
	    return change;
556
	}
Per Cederqvist's avatar
Per Cederqvist committed
557
558
    }
#endif
559
    return change;
Per Cederqvist's avatar
Per Cederqvist committed
560
561
562
}

/*
563
 * insert TEXT in the set of read texts in M.
Per Cederqvist's avatar
Per Cederqvist committed
564
565
566
567
568
569
570
571
572
573
 *
 * Returns FAILURE if the text is already read.
 *
 * This is only used from mark_as_read().
 */

static Success
insert_loc_no(Local_text_no   text,
	      Membership    * m)
{
574
575
576
577
578
579
580
581
582
583
    struct read_range *lo;
    struct read_range *hi;
    struct read_range *mid;
    struct read_range *begin;
    struct read_range *end;
    ptrdiff_t save;
    struct read_range *gap;
    struct read_range *move;

    if (m->no_of_read_ranges == 0)
Per Cederqvist's avatar
Per Cederqvist committed
584
    {
585
586
587
588
589
	m->read_ranges = smalloc(sizeof(m->read_ranges[0]));
	m->no_of_read_ranges = 1;
	m->read_ranges[0].first_read = text;
	m->read_ranges[0].last_read = text;
	return OK;
Per Cederqvist's avatar
Per Cederqvist committed
590
591
    }

592
593
594
595
    begin = lo = &m->read_ranges[0];
    end = hi = lo + m->no_of_read_ranges;

    while (hi - lo > 1)
Per Cederqvist's avatar
Per Cederqvist committed
596
    {
597
598
599
600
601
602
	mid = lo + (hi - lo) / 2;
	if (text < mid->first_read - 1)
	    hi = mid;
	else if (text > mid->last_read + 1)
	    lo = mid;
	else
Per Cederqvist's avatar
Per Cederqvist committed
603
	{
604
605
	    lo = mid;
	    hi = mid + 1;
Per Cederqvist's avatar
Per Cederqvist committed
606
	}
607
    }
Per Cederqvist's avatar
Per Cederqvist committed
608

609
610
    if (text >= lo->first_read && text <= lo->last_read)
	return FAILURE;		/* This text was already read. */
Per Cederqvist's avatar
Per Cederqvist committed
611

612
613
    if (text == lo->first_read - 1)
    {
614
615
616
	if (lo > begin && text == (lo-1)->last_read)
	    return FAILURE;

617
618
619
	lo->first_read = text;
	return OK;
    }
Per Cederqvist's avatar
Per Cederqvist committed
620

621
622
    if (text == lo->last_read + 1)
    {
623
624
625
	if (lo < end && (lo+1) < end && text == (lo+1)->first_read)
	    return FAILURE;

626
627
	lo->last_read = text;
	return OK;
Per Cederqvist's avatar
Per Cederqvist committed
628
629
    }

630
631
632
633
634
635
636
637
638
639
640
641
642
643
    /* We have to allocate a new block. */
    if (lo->last_read < text)
	lo++;

    save = lo - begin;
    m->read_ranges = srealloc(
	m->read_ranges,
	++(m->no_of_read_ranges) * sizeof(m->read_ranges[0]));
    begin = &m->read_ranges[0];
    gap = begin + save;
    end = begin + m->no_of_read_ranges;
    for (move = end - 1; move > gap; move--)
	*move = *(move - 1);
    gap->first_read = gap->last_read = text;
Per Cederqvist's avatar
Per Cederqvist committed
644
645
646
    return OK;
}

647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
static void
remove_loc_no(Local_text_no   text,
	      Membership    * m)
{
    struct read_range *lo;
    struct read_range *hi;
    struct read_range *mid;
    struct read_range *begin;
    struct read_range *end;
    ptrdiff_t save;
    struct read_range *gap;
    struct read_range *move;

    if (m->no_of_read_ranges == 0)
	return;

    begin = lo = &m->read_ranges[0];
    end = hi = lo + m->no_of_read_ranges;

    while (hi - lo > 1)
    {
	mid = lo + (hi - lo) / 2;
	if (text < mid->first_read - 1)
	    hi = mid;
	else if (text > mid->last_read + 1)
	    lo = mid;
	else
	{
	    lo = mid;
	    hi = mid + 1;
	}
    }

    if (text < lo->first_read || text > lo->last_read)
	return;			/* This text was already unread. */
    
    if (text == lo->first_read)
    {
	if (lo->first_read != lo->last_read)
	{
	    /* Remove the first text of this range. */
	    lo->first_read++;
	    return;
	}

	/* This range contains a single text.  Remove the entire range.  */
	for (move = lo; move < (end-1); move++)
	    *move = *(move+1);
	m->no_of_read_ranges--;
696
697
698
699
700
701
702
703
704
705
	if (m->no_of_read_ranges == 0)
	{
	    sfree(m->read_ranges);
	    m->read_ranges = NULL;
	}
	else
	    m->read_ranges = srealloc(
		m->read_ranges,
		m->no_of_read_ranges * sizeof(m->read_ranges[0]));

706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
	return;
    }

    if (text == lo->last_read)
    {
	assert(text != lo->first_read);

	/* Remove the last text of this range.  */
	lo->last_read--;
	return;
    }

    assert(lo->first_read < text && text < lo->last_read);

    /* We have to split this block. */
    save = lo - begin;
    m->read_ranges = srealloc(
	m->read_ranges,
	++(m->no_of_read_ranges) * sizeof(m->read_ranges[0]));
    begin = &m->read_ranges[0];
    gap = begin + save;
    end = begin + m->no_of_read_ranges;
    for (move = end - 1; move > gap; move--)
	*move = *(move - 1);

    assert(gap->first_read == (gap+1)->first_read);
    assert(gap->last_read == (gap+1)->last_read);
    assert(text > gap->first_read);
    assert(text < gap->last_read);

    gap->last_read = text - 1;
    (gap+1)->first_read = text + 1;
    return;
}

741
742
743
744
745
746
747

/*
 * Send a new-membership message to the affected person
 */

static void
send_async_new_membership(Pers_no pers_no,
748
			  Conf_no conf_no)
749
750
751
752
753
754
755
756
757
758
759
760
761
762
{
    Connection *cptr = NULL;
    Session_no i = 0;

    while ((i = traverse_connections(i)) != 0)
    {
        cptr = get_conn_by_number(i);
        if (cptr->pers_no == pers_no)
        {
            async_new_membership(cptr, pers_no, conf_no);
        }
    }
}

763
764
765
766
767
768
769
770
771
772
773
774
775
/*
 * Compute the derived last-text-read value.
 */
static inline Local_text_no
last_text_read(const Membership *mship)
{
    if (mship->no_of_read_ranges == 0)
	return 0;
    if (mship->read_ranges[0].first_read > 1)
	return 0;
    return mship->read_ranges[0].last_read;
}

776

Per Cederqvist's avatar
Per Cederqvist committed
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
/*
 * End of static functions
 */

/*
 * Functions that are exported to the server.
 */

/*
 * Add a member to a conference. All errorchecking should already
 * be done when this function is called. The person must not already
 * be a member of the conference. It is _not_ an error to make WHERE bigger
 * than the number of conferences the person is a member in.
 */

void
do_add_member(Conf_no	   conf_no,  /* Conference to add a new member to. */
	      Conference * conf_c,   /* Conf. status. Must NOT be NULL.  */
	      Pers_no	   pers_no,  /* Person to be added. */
	      Person	 * pers_p,   /* Pers. status. Must NOT be NULL. */
David Byers's avatar
Server    
David Byers committed
797
              Pers_no      added_by, /* Person doing the adding */
798
	      unsigned char	   priority, /* Prioritylevel to assign to this conf */
799
	      unsigned short	   where,   /* Sequence number in the list */
David Byers's avatar
David Byers committed
800
801
              Membership_type      * type, /* Type of the membership */
              Bool              fake_passive
802
              )
Per Cederqvist's avatar
Per Cederqvist committed
803
804
{
    Membership  * mship;
David Byers's avatar
David Byers committed
805
806
807
808
809
810
811
812
    Member	* mem;


    if (fake_passive && priority == 0)
    {
        type->passive = 1;
    }

Per Cederqvist's avatar
Per Cederqvist committed
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833

    /* First add the conference in the person-struct.
     * Make room for it.
     */
    
    pers_p->conferences.confs = srealloc( pers_p->conferences.confs,
					 ++(pers_p->conferences.no_of_confs)
					 * sizeof(Membership));
    
    /* Fill in the room */

    /* Find last slot */    
    mship = pers_p->conferences.confs + pers_p->conferences.no_of_confs - 1 ;
    
    /* Move all data beyond WHERE */
    while ( mship > pers_p->conferences.confs + where )
    {
	*mship = *(mship - 1);
	mship--;
    }

834
    init_membership(mship);
Per Cederqvist's avatar
Per Cederqvist committed
835
    
David Byers's avatar
Server    
David Byers committed
836
    mship->added_by = added_by;
837
    mship->added_at = current_time.tv_sec;
Per Cederqvist's avatar
Per Cederqvist committed
838
839
    mship->conf_no = conf_no;
    mship->priority = priority;
840
    mship->last_time_read = current_time.tv_sec;
841
842
    mship->no_of_read_ranges = 0;
    mship->read_ranges = NULL;
843
    mship->type = *type;
844
    mship->skip_read_texts = FALSE;
845

Per Cederqvist's avatar
Per Cederqvist committed
846
847
848
849
850
851
852
853
    /* Make room for the person in the conference */
    
    conf_c->members.members = srealloc( conf_c->members.members,
				       ++(conf_c->members.no_of_members)
				       * sizeof(Member));

    /* New members go to the end of the list */
    
David Byers's avatar
David Byers committed
854
855
    mem = (conf_c->members.members + conf_c->members.no_of_members - 1);
    mem->member = pers_no;
David Byers's avatar
Server    
David Byers committed
856
    mem->added_by = added_by;
857
    mem->added_at = current_time.tv_sec;
David Byers's avatar
David Byers committed
858
    mem->type = *type;
Per Cederqvist's avatar
Per Cederqvist committed
859
860
861
    
    mark_conference_as_changed( conf_no );
    mark_person_as_changed( pers_no );
862

Per Cederqvist's avatar
Per Cederqvist committed
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
    return;
}

/*
 * Send an asynchronous message to person pers_no (if he is logged on)
 * and tell him that he is no longer a member of conf_no. Also calls
 * leave_conf(). 
 */
extern void
forced_leave_conf(Pers_no pers_no,
		  Conf_no conf_no)
{
    Connection *real_active_connection;
    Session_no i = 0;
    
    real_active_connection = active_connection;

    while ( (i = traverse_connections(i)) != 0 )
    {
	active_connection = get_conn_by_number(i);

	if ( active_connection->pers_no == pers_no )
	{
	    async_forced_leave_conf(active_connection, conf_no);

	    if ( active_connection->cwc == conf_no )
David Byers's avatar
Server    
David Byers committed
889
		leave_conf(active_connection);
Per Cederqvist's avatar
Per Cederqvist committed
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
	}
    }

    active_connection = real_active_connection;
}

/*
 * Delete a member from a conference.
 * No checks are made on the parameters.
 * The dynamically allocated areas conf_c->members.members and
 * pers_p->confs are NOT reallocated since they will anyhow sooner or later
 * be flushed from core.
 */

Success
do_sub_member(Conf_no	   conf_no, /* Conf to delete member from. */
	      Conference * conf_c,  /* May be NULL */
907
	      Member     * mbr,     /* May be NULL */
Per Cederqvist's avatar
Per Cederqvist committed
908
909
910
911
912
913
914
915
916
917
918
919
920
921
	      Pers_no	   pers_no, /* Person to be deleted. */
	      Person	 * pers_p,  /* May be NULL */
	      Membership * mship)   /* Pointer to the persons membership in
				       conf., or NULL if not known. */
{
    if ( conf_c == NULL )
	GET_C_STAT(conf_c, conf_no, FAILURE);
    
    if ( pers_p == NULL )
	GET_P_STAT(pers_p, pers_no, FAILURE);
    
    if ( mship == NULL && (mship = locate_membership(conf_no, pers_p)) == NULL)
	restart_kom("do_sub_member() - can't find mship\n");

922
    if ( mbr == NULL && (mbr = locate_member(pers_no, conf_c)) == NULL)
Per Cederqvist's avatar
Per Cederqvist committed
923
924
925
926
927
928
	restart_kom("do_sub_member() - can't find member.\n");

    forced_leave_conf(pers_no, conf_no);
    
    /* Delete from Person */

929
    sfree(mship->read_ranges);
Per Cederqvist's avatar
Per Cederqvist committed
930
931
932
933
934
935
936
937
938
939
940
    --pers_p->conferences.no_of_confs;
    while ( mship
	   < pers_p->conferences.confs + pers_p->conferences.no_of_confs )
    {
	*mship = *(mship + 1);
	++mship;
    }

    /* Delete from Conference */

    --conf_c->members.no_of_members;
941
    while ( mbr < conf_c->members.members + conf_c->members.no_of_members )
Per Cederqvist's avatar
Per Cederqvist committed
942
    {
943
944
	*mbr = *(mbr + 1);
	++mbr;
Per Cederqvist's avatar
Per Cederqvist committed
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
    }

    mark_person_as_changed( pers_no );
    mark_conference_as_changed( conf_no );
    
    return OK;    
}


/*
 * VICTIM is a person or a conference.
 * Meaning of return values:
 *	unlimited: ACTPERS is supervisor of VICTIM, or ACTPERS is admin,
 *		   or ACTPERS is VICTIM
 *	none:	   VICTIM is secret, and ACTPERS is not a member
 *	member:	   ACTPERS is a member in VICTIM, but doesn't have unlimited
 *		   access.
 *	read_protected: The conference is rd_prot and ACTPERS is not a member.
 *	limited:   otherwise.
 *	error:	   see kom_errno
 */

967
static enum access
968
969
access_perm_helper(Conf_no victim,
		   const Connection *conn,
970
		   enum access wanted_access)
Per Cederqvist's avatar
Per Cederqvist committed
971
{
972
    Conf_type   victim_type;
973
    int         victim_type_known = 0;
974
    static int  maxwarnings = 10;
975
976
977
978
979
980
981

    if (!cached_conf_exists(victim))
    {
        kom_errno = KOM_UNDEF_CONF;
        err_stat = victim;
	return error;
    }
David Byers's avatar
Server    
David Byers committed
982

983
    if (victim == conn->pers_no)
Per Cederqvist's avatar
Per Cederqvist committed
984
985
    	return unlimited;

986
    if (ENA_C(conn, admin, 2) || ENA_C(conn, wheel, 8))
Per Cederqvist's avatar
Per Cederqvist committed
987
988
    	return unlimited;

989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
    if (wanted_access <= limited)
    {
	victim_type = cached_get_conf_type(victim);
	victim_type_known = 1;

	if (victim_type.secret == 0)
	{
	    if (victim_type.rd_prot)
	    {
		if (wanted_access <= read_protected)
		    return read_protected;
	    }
	    else
		return limited;
	}
    }

1006
    if (is_supervisor(victim, conn))
Per Cederqvist's avatar
Per Cederqvist committed
1007
1008
    	return unlimited;

1009
    if (conn->pers_no != 0)
1010
    {
1011
	if (conn->person == NULL)
1012
1013
1014
	{
	    if (maxwarnings > 0)
	    {
1015
		kom_log("WNG: conn->person unexpectedly NULL in "
1016
1017
1018
1019
			"access_perm_helper()\n");
		if (--maxwarnings == 0)
		    kom_log("WNG: Won't log the above warning any more.\n");
	    }
1020
1021
1022
	    kom_errno = KOM_INTERNAL_ERROR;
	    err_stat = 0;
	    return error;
1023
	}
1024

1025
1026
	/* FIXME (bug 155): no need to call the expensive
	   locate_membership if supervisor(victim) == victim. */
1027
	if (locate_membership(victim, conn->person) != NULL)
1028
1029
	    return member;
    }
Per Cederqvist's avatar
Per Cederqvist committed
1030

1031
1032
    if (victim_type_known == 0)
	victim_type = cached_get_conf_type(victim);
1033

1034
    if (victim_type.secret)
Per Cederqvist's avatar
Per Cederqvist committed
1035
1036
        return none;

1037
    if (victim_type.rd_prot)
Per Cederqvist's avatar
Per Cederqvist committed
1038
1039
1040
1041
1042
1043
	return read_protected;
    
    return limited;
}


1044
enum access
1045
1046
access_perm(Conf_no victim,
	    const Connection *viewer_conn,
1047
	    enum access wanted_access)
1048
{
1049
    enum access result;
1050

1051
    if (wanted_access != read_protected
1052
1053
	&& wanted_access != limited
	&& wanted_access != unlimited)
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
    {
	static int ctr = 0;
	if (ctr < 10)
	{
	    kom_log("WNG: access_perm called with wanted_access=%d\n",
		    (int)wanted_access);
	    ctr++;
	    if (ctr == 10)
		kom_log("WNG: won't log the above warning any more.\n");
	}
    }

1066
    result = access_perm_helper(victim, viewer_conn, wanted_access);
1067
1068
1069
1070
1071
1072
1073
1074

    if (wanted_access < result)
	return wanted_access;
    else
	return result;
}


1075
1076
1077
1078
1079
1080
1081
1082
1083
Bool
has_access(Conf_no victim,
	   const Connection *viewer_conn,
	   enum access wanted_access)
{
    return access_perm(victim, viewer_conn, wanted_access) >= wanted_access;
}


1084
1085
1086
1087
Conf_no
filter_conf_no(Conf_no victim,
	       const Connection *viewer_conn)
{
1088
    if (has_access(victim, viewer_conn, read_protected))
1089
1090
1091
1092
1093
	return victim;
    else
	return 0;
}

1094

Per Cederqvist's avatar
Per Cederqvist committed
1095
1096
1097
1098
1099
1100
1101
1102
/*
 * Locate the Member struct in CONF_C for person PERS_NO
 */

Member *
locate_member(Pers_no      pers_no,
	      Conference * conf_c)
{
1103
    Member * mbr;
Per Cederqvist's avatar
Per Cederqvist committed
1104
1105
    int      i;

1106
1107
    for(mbr = conf_c->members.members, i = conf_c->members.no_of_members;
	i > 0; i--, mbr++)
Per Cederqvist's avatar
Per Cederqvist committed
1108
    {
1109
	if ( mbr->member == pers_no )
Per Cederqvist's avatar
Per Cederqvist committed
1110
	{
1111
	    return mbr;
Per Cederqvist's avatar
Per Cederqvist committed
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
	}
    }

    return NULL;
}


/*
 * Find the data about PERS_P:s membership in CONF_NO.
 * Return NULL if not found
 */

Membership *
1125
1126
locate_membership(Conf_no       conf_no,
                  const Person *pers_p)
Per Cederqvist's avatar
Per Cederqvist committed
1127
1128
1129
1130
1131
1132
1133
1134
1135
{
    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 )
	{
1136
            confp->position = pers_p->conferences.no_of_confs - i;
Per Cederqvist's avatar
Per Cederqvist committed
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
	    return confp;
	}
    }

    return NULL;
}

/*
 * Atomic functions.
 */

/*
 * Unsubscribe from a conference.
 *
 * You must be supervisor of either conf_no or pers_no to be allowed to
 * do this.
 */
extern Success
sub_member(	Conf_no		conf_no,
		Pers_no		pers_no )
{
    Conference  * conf_c;
    Membership	* mship;
    Person	* pers_p;
    
David Byers's avatar
Server    
David Byers committed
1162
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
1163
1164
1165
    CHK_LOGIN(FAILURE);
    GET_C_STAT(conf_c, conf_no, FAILURE);

1166
    if ((pers_p = cached_get_person_stat(pers_no)) == NULL)
Per Cederqvist's avatar
Per Cederqvist committed
1167
    {
1168
1169
1170
	/* If the conference is secret, we have to return an error
	   code for the conference instead of for the person. */

1171
	if (!has_access(conf_no, active_connection, read_protected))
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
	{
	    kom_errno = KOM_UNDEF_CONF;
	    err_stat = conf_no;
	}
	return FAILURE;
    }

    if ((mship = locate_membership(conf_no, pers_p)) == NULL
	|| membership_visible(active_connection, pers_no, conf_no, 
			      mship->type, FALSE, FALSE) == mv_none)
    {
	/* FIXME (bug 707): If the person is secret, and the viewer
	   has no access to it, we should return KOM_UNDEF_PERS
	   instead of KOM_NOT_MEMBER. */
	set_conf_errno(active_connection, conf_no, KOM_NOT_MEMBER);
Per Cederqvist's avatar
Per Cederqvist committed
1187
1188
1189
	return FAILURE;
    }

1190
1191
1192
1193
    if (!is_supervisor(conf_no, active_connection)
	&& !is_supervisor(pers_no, active_connection)
	&& !ENA(wheel,8)        /* OK -- In an RPC call */
	&& !ENA(admin, 4) )	/* OK -- in an RPC call */
Per Cederqvist's avatar
Per Cederqvist committed
1194
    {
1195
	set_conf_errno(active_connection, conf_no, KOM_PERM);
Per Cederqvist's avatar
Per Cederqvist committed
1196
1197
1198
	return FAILURE;
    }

David Byers's avatar
David Byers committed
1199
1200
1201
1202
    return do_sub_member(conf_no, conf_c, NULL, pers_no, pers_p, mship);
}


Per Cederqvist's avatar
Per Cederqvist committed
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
/*
 * Add a member to a conference (join a conference) or
 * Change the priority of a conference.
 *
 * Anyone may add anyone as a member as long as the new member is not
 * secret and the conference is not rd_prot. This might be a bug.
 *
 * PRIORITY is the assigned priority for the conference. WHERE says
 * where on the list the person wants the conference. 0 is first. WHERE
 * is automatically set to the number of conferences that PERS_NO is member
 * in if WHERE is too big, so it is not an error to give WHERE == ~0 as
 * a parameter.
 *
 * You can only re-prioritize if you are supervisor of pers_no.
 */
1218

David Byers's avatar
David Byers committed
1219
1220
1221
static Success
add_member_common(Conf_no              conf_no,
                  Pers_no              pers_no,
1222
1223
                  unsigned char        priority,
                  unsigned short       where,		/* Range of where is [0..] */
David Byers's avatar
David Byers committed
1224
1225
1226
                  Membership_type     *type,
                  Bool                 fake_passive
    )
Per Cederqvist's avatar
Per Cederqvist committed
1227
{
1228
    Conference  * conf_c;
Per Cederqvist's avatar
Per Cederqvist committed
1229
1230
1231
    Person	* pers_p;
    Membership	* mship;

David Byers's avatar
Server    
David Byers committed
1232
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
1233
1234
1235
1236
    CHK_LOGIN(FAILURE);
    GET_C_STAT(conf_c, conf_no, FAILURE);
    GET_P_STAT(pers_p, pers_no, FAILURE);

David Byers's avatar
David Byers committed
1237
    /* Force invitation bit if not adding as admin or supervisor */
1238
1239
1240
    if (param.invite_by_default
	&& !is_supervisor(pers_no, active_connection)
	&& !ENA(admin, 2))	/* OK -- Guarded */
1241
1242
1243
1244
    {
        type->invitation = 1;
    }

David Byers's avatar
David Byers committed
1245
1246
1247
    /* Check if secret membership bit is set and allowed */
    if (type->secret &&
        (!param.secret_memberships || conf_c->type.forbid_secret))
1248
1249
1250
1251
1252
1253
    {
        err_stat = 0;
        kom_errno = KOM_INVALID_MEMBERSHIP_TYPE;
        return FAILURE;
    }

David Byers's avatar
David Byers committed
1254
    /* Check access to the conference. We need limited access or more */
1255
    if (!has_access(conf_no, active_connection, limited)
David Byers's avatar
Server    
David Byers committed
1256
	&& !ENA(wheel, 8) )     /* OK -- Guarded */
Per Cederqvist's avatar
Per Cederqvist committed
1257
    {
1258
        err_stat = conf_no;
1259
	kom_errno = (conf_c->type).secret ? KOM_UNDEF_CONF : KOM_ACCESS;
Per Cederqvist's avatar
Per Cederqvist committed
1260
1261
1262
1263
1264
1265
1266
	return FAILURE;
    }

    /* Is he already a member? */

    if ( (mship = locate_membership( conf_no, pers_p )) != NULL)
    {
David Byers's avatar
David Byers committed
1267
1268
        Bool pers_supervisor;
        Bool conf_supervisor;
Per Cederqvist's avatar
Per Cederqvist committed
1269

1270
1271
        pers_supervisor = is_supervisor(pers_no, active_connection);
        conf_supervisor = is_supervisor(conf_no, active_connection);
David Byers's avatar
David Byers committed
1272
1273

        /* Already a member, but a secret member? */
1274
1275
1276
        if (mship->type.secret &&
            !pers_supervisor &&
            !conf_supervisor &&
David Byers's avatar
Server    
David Byers committed
1277
1278
            !ENA(admin,2) &&    /* OK -- Guarded */
            !ENA(wheel,8))      /* OK -- Guarded */
David Byers's avatar
David Byers committed
1279
        {
1280
            /* FIXME (bug 156): This leaks secret information */
David Byers's avatar
David Byers committed
1281
1282
1283
1284
1285
1286
1287
1288
            /* The person is already a member, but we are not allowed
               to know this. Pretend that the addition worked, and hope
               that the user does not double-check */

            return OK;
        }

	/* He is already a member. Only change the priority. */
1289
	if( !pers_supervisor &&
David Byers's avatar
Server    
David Byers committed
1290
            !ENA(admin,2) && 
1291
            !ENA(wheel, 8) )
1292
1293
	{
	    /* Noone else can change one's priorities. */
1294
            err_stat = pers_no;
Per Cederqvist's avatar
Per Cederqvist committed
1295
1296
1297
1298
	    kom_errno = KOM_PERM;
	    return FAILURE;
	}

David Byers's avatar
David Byers committed
1299
1300
1301
1302
	do_change_priority( mship, conf_no, conf_c,
                            priority, where, pers_no, pers_p,
                            type, fake_passive );

Per Cederqvist's avatar
Per Cederqvist committed
1303
1304
1305
    }
    else
    {
1306
	if (pers_no != ACTPERS)
1307
        {
David Byers's avatar
David Byers committed
1308
	    kom_log("Person %lu added to conference %lu by %lu.\n",
1309
1310
1311
		(unsigned long)pers_no,
		(unsigned long)conf_no,
		(unsigned long)ACTPERS);
1312
        }
1313

David Byers's avatar
Server    
David Byers committed
1314
	do_add_member(conf_no, conf_c, pers_no, pers_p, ACTPERS,
David Byers's avatar
David Byers committed
1315
1316
                      priority, where, type, fake_passive);

David Byers's avatar
David Byers committed
1317
        send_async_new_membership(pers_no, conf_no);
Per Cederqvist's avatar
Per Cederqvist committed
1318
1319
1320
1321
1322
    }

    return OK;
}

David Byers's avatar
David Byers committed
1323
1324
1325
1326
1327
1328
1329
1330
1331

extern Success
add_member_old(Conf_no	conf_no,
               Pers_no	pers_no,
               unsigned char	priority,
               unsigned short	where)
{
    Membership_type type;

David Byers's avatar
Server    
David Byers committed
1332
    /* CHK_CONNECTION in add_member_common */
1333
    set_membership_type_bits(&type, 0,0,0,0,0,0,0,0);
David Byers's avatar
David Byers committed
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
    return add_member_common(conf_no, pers_no, priority, where, &type, TRUE);
}


extern Success
add_member(Conf_no	conf_no,
           Pers_no	pers_no,
           unsigned char	priority,
           unsigned short	where,		/* Range of where is [0..] */
           Membership_type     *type
           )
{
David Byers's avatar
Server    
David Byers committed
1346
    /* CHK_CONNECTION in add_member_common */