session.c 25.2 KB
Newer Older
Linus Tolke's avatar
Linus Tolke committed
1
/*
2
 * $Id: session.c,v 0.71 2003/08/08 20:57:23 ceder Exp $
Per Cederqvist's avatar
Per Cederqvist committed
3
 * Copyright (C) 1991-1994, 1996-2002  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
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
/*
 * session.c
 *
 * Session control and miscellaneous.
 */

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
#include <stdio.h>
#include <setjmp.h>
38
#include "timewrap.h"
Per Cederqvist's avatar
Per Cederqvist committed
39
#include <sys/types.h>
Per Cederqvist's avatar
Per Cederqvist committed
40

41
42
#include "oop.h"

43
#include "ldifftime.h"
Per Cederqvist's avatar
Per Cederqvist committed
44
45
46
#include "s-string.h"
#include "kom-types.h"
#include "services.h"
Per Cederqvist's avatar
Per Cederqvist committed
47
#include "com.h"
48
#include "async.h"
Per Cederqvist's avatar
Per Cederqvist committed
49
#include "connections.h"
Per Cederqvist's avatar
Per Cederqvist committed
50
#include "internal-connections.h"
51
#include "kom-errno.h"
Per Cederqvist's avatar
Per Cederqvist committed
52
53
#include "manipulate.h"
#include "lyskomd.h"
Per Cederqvist's avatar
Per Cederqvist committed
54
#include "log.h"
Per Cederqvist's avatar
Per Cederqvist committed
55
56
#include "cache.h"
#include "send-async.h"
David Byers's avatar
David Byers committed
57
#include "kom-config.h"
Per Cederqvist's avatar
Per Cederqvist committed
58
#include "server/smalloc.h"
59
#include "param.h"
Per Cederqvist's avatar
Per Cederqvist committed
60
#include "kom-memory.h"
61
#include "string-malloc.h"
62
#include "server-time.h"
63
#include "timeval-util.h"
64
#include "isc-interface.h"
65
66
67
68
69
70
71
72
73
74

/*
 * Create an oldstyle username, user%host.domain@host.domain.
 * The RESULT must be initialized to a string (such as EMPTY_STRING).
 * A new string will be allocated in RESULT. (The old will be freed).
 */
static void
create_oldstyle_username(String *result,
			 Connection *connection)
{
75
    if ( s_strcpy(result, connection->username) != OK )
76
	restart_kom("create_oldstyle_username(): s_strcpy\n");
77

78
    if ( s_strcat(result, s_fcrea_str("@")) != OK )
79
80
	restart_kom("create_oldstyle_username: s_strcat\n");

81
82
    if ( s_strcat(result, connection->isc_session->remote) != OK )
	restart_kom("create_oldstyle_username: s_strcat II\n");
83
84
}

Per Cederqvist's avatar
Per Cederqvist committed
85
86
/*
 * This function is called whenever a person leaves a conf,
87
 * i e when he change_conference():s or logout():s.
Per Cederqvist's avatar
Per Cederqvist committed
88
89
90
 */

extern void
David Byers's avatar
Server    
David Byers committed
91
leave_conf(Connection *conn)
Per Cederqvist's avatar
Per Cederqvist committed
92
93
94
{
    Membership * mship;

David Byers's avatar
Server    
David Byers committed
95
    if (conn->cwc != 0 )
Per Cederqvist's avatar
Per Cederqvist committed
96
    {
David Byers's avatar
Server    
David Byers committed
97
	if ((mship = locate_membership( conn->cwc, conn->person ))
Per Cederqvist's avatar
Per Cederqvist committed
98
99
	    != NULL )
	{
100
	    mship->last_time_read = current_time.tv_sec;
David Byers's avatar
Server    
David Byers committed
101
	    mark_person_as_changed (conn->pers_no);
Per Cederqvist's avatar
Per Cederqvist committed
102
103
104
	}
	else
	{
David Byers's avatar
David Byers committed
105
	    kom_log("ERROR: leave_conf(): Can't find membership of cwc.\n");
Per Cederqvist's avatar
Per Cederqvist committed
106
107
	}
	
David Byers's avatar
Server    
David Byers committed
108
109
	cached_unlock_conf( conn->cwc );
	conn->cwc = 0;
Per Cederqvist's avatar
Per Cederqvist committed
110
111
112
113
114
115
116
117
118
    }
}

/*
 * Log in as user pers_no. If ACTPERS is a supervisor of pers_no the login
 * will succeed regardless of the passwd. An logout() will automatically
 * be performed if ACTPERS is logged in.
 */
extern Success
119
120
login_old (Pers_no       pers_no,
	   const String  passwd)
Per Cederqvist's avatar
Per Cederqvist committed
121
122
{
    Person *pers_p;
David Byers's avatar
Server    
David Byers committed
123
124
    
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
125
    GET_P_STAT(pers_p, pers_no, FAILURE);
126

127
    if ( !is_supervisor(pers_no, ACTPERS, ACT_P) &&
David Byers's avatar
Server    
David Byers committed
128
         !ENA(wheel, 8) &&      /* OK -- In an RPC call */
129
         chk_passwd(pers_p->pwd, passwd) == FAILURE )
Per Cederqvist's avatar
Per Cederqvist committed
130
    {
131
        err_stat = pers_no;
Per Cederqvist's avatar
Per Cederqvist committed
132
133
134
135
	kom_errno = KOM_PWD;
	return FAILURE;
    }

136
    logout();
Per Cederqvist's avatar
Per Cederqvist committed
137

138
    active_connection->flags.invisible = FALSE;
139

Per Cederqvist's avatar
Per Cederqvist committed
140
141
142
143
144
    ACTPERS = pers_no;
    ACT_P   = pers_p;

    cached_lock_person(pers_no);
        
145
    pers_p->last_login = current_time.tv_sec;
146
    active_connection->login_time = current_time;
Per Cederqvist's avatar
Per Cederqvist committed
147
148
149
    ++pers_p->sessions;

    s_strcpy(&pers_p->username, active_connection->username);
150
151
152
153
154
155

    /* A Person should have separate fields for ident_user and hostname.
       But for now, we use the syntax username(ident_user)@hostname. */

    if (!s_empty(active_connection->ident_user))
    {
156
	if ( s_strcat(&pers_p->username, s_fcrea_str("(")) != OK )
157
	    restart_kom("login_old: s_strcat (\n");
158

Per Cederqvist's avatar
Per Cederqvist committed
159
	if ( s_strcat(&pers_p->username, active_connection->ident_user) != OK )
160
	    restart_kom("login_old: s_strcat ident_user\n");
161

162
	if ( s_strcat(&pers_p->username, s_fcrea_str(")")) != OK )
163
	    restart_kom("login_old: s_strcat )\n");
164
165
    }

166
    if ( s_strcat(&pers_p->username, s_fcrea_str("@")) != OK )
167
	restart_kom("login_old: s_strcat\n");
168

169
170
171
    if (s_strcat(&pers_p->username,
		 active_connection->isc_session->remote) != OK)
	restart_kom("login_old: s_strcat II\n");
172

Per Cederqvist's avatar
Per Cederqvist committed
173
    mark_person_as_changed( pers_no );
174
175
176
177

    if (param.log_login == TRUE)
    {
	char *id = s_crea_c_str (pers_p->username);
David Byers's avatar
David Byers committed
178
	kom_log ("Login %d %s\n", ACTPERS, id);
179
180
181
	string_free (id);
    }

182
183
    isc_set_acceptable_idle(active_connection->isc_session,
			    param.active_timeout);
Per Cederqvist's avatar
Per Cederqvist committed
184
    async_login(ACTPERS, active_connection->session_no);
185

Per Cederqvist's avatar
Per Cederqvist committed
186
187
188
    return OK;
}

189
190
191
192
193
194
195
196
197
198
199
/*
 * Log in as user pers_no. If ACTPERS is a supervisor of pers_no the login
 * will succeed regardless of the passwd. An logout() will automatically
 * be performed if ACTPERS is logged in.
 */
extern Success
login (Pers_no       pers_no,
       const String  passwd,
       Bool	     invisible)
{
    Person *pers_p;
200
    Bool same_person;
201

David Byers's avatar
Server    
David Byers committed
202
    CHK_CONNECTION(FAILURE);
203
204
    GET_P_STAT(pers_p, pers_no, FAILURE);

205
    if ( !is_supervisor(pers_no, ACTPERS, ACT_P) &&
David Byers's avatar
Server    
David Byers committed
206
         !ENA(wheel, 8) &&      /* OK -- In an RPC call */
207
         chk_passwd(pers_p->pwd, passwd) == FAILURE )
208
    {
209
        err_stat = pers_no;
210
211
212
213
	kom_errno = KOM_PWD;
	return FAILURE;
    }

214
    same_person = (ACTPERS == pers_no) ? TRUE : FALSE;
215

216
    logout();
217

218
    if (invisible)
219
      active_connection->flags.invisible = TRUE;
220
    else
221
      active_connection->flags.invisible = FALSE;
222

223
224
225
    /* Don't count this as a new session if the person already was
       logged on.  The elisp-client version 0.38.1 logs on invisibly
       automatically to indicate that the user is inactve. */
226
    if (same_person == FALSE)
227
228
	++pers_p->sessions;

229
230
231
232
233
    ACTPERS = pers_no;
    ACT_P   = pers_p;

    cached_lock_person(pers_no);
        
234
    pers_p->last_login = current_time.tv_sec;
235
    active_connection->login_time = current_time;
236
237
238
239
240
241
242
243

    s_strcpy(&pers_p->username, active_connection->username);

    /* A Person should have separate fields for ident_user and hostname.
       But for now, we use the syntax username(ident_user)@hostname. */

    if (!s_empty(active_connection->ident_user))
    {
244
	if ( s_strcat(&pers_p->username, s_fcrea_str("(")) != OK )
245
246
	    restart_kom("login: s_strcat (\n");

Per Cederqvist's avatar
Per Cederqvist committed
247
	if ( s_strcat(&pers_p->username, active_connection->ident_user) != OK )
248
249
	    restart_kom("login: s_strcat ident_user\n");

Per Cederqvist's avatar
Per Cederqvist committed
250
	if ( s_strcat(&pers_p->username,
251
		      s_fcrea_str(")")) != OK )
252
253
254
	    restart_kom("login: s_strcat )\n");
    }

255
    if ( s_strcat(&pers_p->username, s_fcrea_str("@")) != OK )
256
	restart_kom("login: s_strcat\n");
257

258
259
260
    if (s_strcat(&pers_p->username,
		 active_connection->isc_session->remote) != OK)
	restart_kom("login: s_strcat II\n");
261
262
263

    mark_person_as_changed( pers_no );

264
    if (param.log_login == TRUE && same_person == FALSE)
265
266
    {
	char *id = s_crea_c_str (pers_p->username);
David Byers's avatar
David Byers committed
267
	kom_log ("Login %d %s\n", ACTPERS, id);
268
269
270
	string_free (id);
    }

271
    if (!active_connection->flags.invisible)
272
	async_login(ACTPERS, active_connection->session_no);
273
274
275

    isc_set_acceptable_idle(active_connection->isc_session,
			    param.active_timeout);
276
277
278
279
    
    return OK;
}

Per Cederqvist's avatar
Per Cederqvist committed
280
281
282
283
284
285
286
287
288

/*
 * Log out. Does not disconnect the client. The person is also automatically
 * logged out if the connection is closed. Takes no action if noone is logged
 * in on this line. Never fails.
 */
extern Success
logout(	void )
{
David Byers's avatar
Server    
David Byers committed
289
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
290
291
    if ( ACTPERS != 0 )		/* Is he logged in? Then log him out. */
    {
292
	if (!active_connection->flags.invisible)
293
294
295
	{
	    async_logout( ACTPERS, active_connection->session_no );
	}
Per Cederqvist's avatar
Per Cederqvist committed
296
	
David Byers's avatar
Server    
David Byers committed
297
	leave_conf(active_connection);
298
	ACT_P->last_login = current_time.tv_sec;
Per Cederqvist's avatar
Per Cederqvist committed
299
	ACT_P->total_time_present +=
300
301
	    timeval_diff_sec(current_time, active_connection->login_time);
	active_connection->login_time = current_time;
Per Cederqvist's avatar
Per Cederqvist committed
302
303
304
305
306
307
308
309
310
311
312
313
314

	cached_unlock_person( ACTPERS );
	mark_person_as_changed( ACTPERS );
    }
    
    
    s_clear(&active_connection -> what_am_i_doing);
    
    active_connection->person		= NULL;
    active_connection->cwc		= 0;
    active_connection->pers_no		= 0;
    active_connection->ena_level	= 0;
    
315
316
317
    isc_set_acceptable_idle(active_connection->isc_session,
			    param.login_timeout);

Per Cederqvist's avatar
Per Cederqvist committed
318
319
320
321
322
323
324
325
326
327
    return OK;
}


/*
 * Change Conference.
 *
 * You are not allowed to change to a conference unless you are a
 * member in the conference.
 *
328
329
 * You can change_conference(0) to indicate that you are no longer in
 * a certain conference.
Per Cederqvist's avatar
Per Cederqvist committed
330
331
332
333
334
335
336
337
338
339
340
 *
 * There are two reasons to use this call:
 *	1) Other persons want to know what you are doing.
 *	2) When the server checks that you have permission to
 *	   read a certain text it first checks if you current working
 *	   conference is a recipient of the text, since that is a
 *	   cheap test. If that test fails it will have to read in the
 *	   conference structs for the recipients of the text until it
 *	   finds an open one.
 *
 * In the future the server might read in the conference in advance when
341
 * someone change_conference's to it to allow faster response times.
Per Cederqvist's avatar
Per Cederqvist committed
342
343
 */
extern Success
344
change_conference (Conf_no		conference)		
Per Cederqvist's avatar
Per Cederqvist committed
345
{
346
347
    Who_info	 info;
  
David Byers's avatar
Server    
David Byers committed
348
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
349
    CHK_LOGIN(FAILURE);
David Byers's avatar
Server    
David Byers committed
350

Per Cederqvist's avatar
Per Cederqvist committed
351
352
353
354
355
356
    if (  conference != 0 )
    {
	CHK_EXIST(conference, FAILURE);

	if ( locate_membership( conference, ACT_P) == NULL )
	{
357
            err_stat = conference;
Per Cederqvist's avatar
Per Cederqvist committed
358
359
360
361
362
	    kom_errno = KOM_NOT_MEMBER;
	    return FAILURE;
	}
    }

David Byers's avatar
Server    
David Byers committed
363
    leave_conf(active_connection);
Per Cederqvist's avatar
Per Cederqvist committed
364
365
366
367
368
    
    active_connection->cwc = conference;
    if ( conference != 0 )
	cached_lock_conf( conference );

David Byers's avatar
Server    
David Byers committed
369
    init_who_info(&info);
370
    if (!active_connection->flags.invisible)
371
372
373
374
375
    {
	info.person = ACTPERS;
	info.what_am_i_doing = active_connection->what_am_i_doing;
	info.working_conference = conference;
	info.session_no = active_connection->session_no;
376
377
378
379

	/* Bug compatibility. */
	create_oldstyle_username(&info.username, active_connection);

380
	async_i_am_on(info);
381
382

	s_clear(&info.username);
383
    }
Per Cederqvist's avatar
Per Cederqvist committed
384
385
386
387
388
389
390
391
392
393
394
395
    
    return OK;
}


/*
 * Tell the server what you are doing. This string is sent to anyone
 * who does a 'who_is_on()'.
 */
extern Success
change_what_i_am_doing (String  what_am_i_doing)
{
396
397
    Who_info info;
    
David Byers's avatar
Server    
David Byers committed
398
    CHK_CONNECTION(FAILURE);
399
    init_who_info(&info);
Per Cederqvist's avatar
Per Cederqvist committed
400

401
    if ( s_strlen( what_am_i_doing ) > param.what_do_len )
Per Cederqvist's avatar
Per Cederqvist committed
402
403
    {
	s_clear ( &what_am_i_doing );
404
        err_stat = param.what_do_len;
Per Cederqvist's avatar
Per Cederqvist committed
405
406
407
408
409
410
411
	kom_errno = KOM_LONG_STR;
	return FAILURE;
    }
    
    s_clear ( &active_connection->what_am_i_doing );
    active_connection->what_am_i_doing = what_am_i_doing;

412
    if (!active_connection->flags.invisible)
413
414
415
    {
	info.person = ACTPERS;
	info.what_am_i_doing = active_connection->what_am_i_doing;
416
	create_oldstyle_username(&info.username, active_connection);
417
418
	info.working_conference = active_connection->cwc;
	info.session_no = active_connection->session_no;
Per Cederqvist's avatar
Per Cederqvist committed
419
    
420
	async_i_am_on(info);
421
422

	s_clear(&info.username);
423
    }
Per Cederqvist's avatar
Per Cederqvist committed
424
425
426
427

    return OK;
}

428

Per Cederqvist's avatar
Per Cederqvist committed
429
430
431
432
433
434
435
436
437
438
439
/*
 * Get info about what all the currently logged in persons are doing.
 */
extern Success
who_is_on( Who_info_list *result )
{
    Connection *cptr;
    int 	    no_of_clients = 0;
    int		    i;
    Session_no      session;
    
David Byers's avatar
Server    
David Byers committed
440
441
    CHK_CONNECTION(FAILURE);

442
443
    session = traverse_connections(0);
    while (session != 0)
Per Cederqvist's avatar
Per Cederqvist committed
444
445
446
    {
	cptr = get_conn_by_number(session);

447
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
Per Cederqvist's avatar
Per Cederqvist committed
448
	    ++no_of_clients;
449
450

        session = traverse_connections(session);
Per Cederqvist's avatar
Per Cederqvist committed
451
452
453
454
455
    }

    result->no_of_persons = no_of_clients;
    result->info = tmp_alloc ( no_of_clients * sizeof(Who_info));

456
457
458
    i = 0;
    session = traverse_connections(0);
    while ( i < no_of_clients && session != 0)
Per Cederqvist's avatar
Per Cederqvist committed
459
460
461
    {
	cptr = get_conn_by_number(session);

462
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
Per Cederqvist's avatar
Per Cederqvist committed
463
	{
464
	    init_who_info(&result->info[ i ]);
Per Cederqvist's avatar
Per Cederqvist committed
465
466
	    result->info[ i ].person = cptr->pers_no;
	    result->info[ i ].what_am_i_doing = cptr->what_am_i_doing;
467
468
469
470

	    /* Backward compatibility: Old clients want the username to be
	       user%host@host. result->info[i].username is free()d in
	       prot_a_output_who_info_list() in prot-a-output.c. */
471
	    create_oldstyle_username(&result->info[i].username, cptr);
472

473
474
	    result->info[ i ].working_conference = filter_conf_no(
		cptr->cwc, active_connection);
Per Cederqvist's avatar
Per Cederqvist committed
475
476
477
	    result->info[ i ].session_no = cptr->session_no;
	    ++i;
	}
478
        session = traverse_connections(session);
Per Cederqvist's avatar
Per Cederqvist committed
479
480
481
    }

    if ( i != no_of_clients )
David Byers's avatar
David Byers committed
482
	kom_log("who_is_on: i == %d, no_of_clients == %d\n",
Per Cederqvist's avatar
Per Cederqvist committed
483
484
485
486
487
	    i, no_of_clients);

    return OK;
}

488
489
490
491
492
493
494
495
496
497
498
/*
 * Get info about what all the currently logged in persons are doing.
 */
extern Success
who_is_on_ident( Who_info_ident_list *result )
{
    Connection *cptr;
    int 	    no_of_clients = 0;
    int		    i;
    Session_no      session;
    
David Byers's avatar
Server    
David Byers committed
499
500
    CHK_CONNECTION(FAILURE);

501
502
    session = traverse_connections(0);
    while (session != 0)
503
504
505
    {
	cptr = get_conn_by_number(session);

506
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
507
	    ++no_of_clients;
508
509

        session = traverse_connections(session);
510
511
512
    }

    result->no_of_persons = no_of_clients;
513
    result->info = tmp_alloc ( no_of_clients * sizeof(Who_info_ident));
514

515
516
517
    i = 0;
    session = traverse_connections(0);
    while ( i < no_of_clients && session != 0)
518
519
520
    {
	cptr = get_conn_by_number(session);

521
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
522
	{
523
	    init_who_info_ident(&result->info[i]);
524
525
526
	    result->info[i].person = cptr->pers_no;
	    result->info[i].what_am_i_doing = cptr->what_am_i_doing;
	    result->info[i].username = cptr->username;
527
	    result->info[i].hostname = cptr->isc_session->remote;
528
	    result->info[i].ident_user = cptr->ident_user;
529
530
	    result->info[i].working_conference = filter_conf_no(
		cptr->cwc, active_connection);
531
532
533
	    result->info[i].session_no = cptr->session_no;
	    ++i;
	}
534
        session = traverse_connections(session);
535
536
537
    }

    if ( i != no_of_clients )
David Byers's avatar
David Byers committed
538
	kom_log("who_is_on_ident: i == %d, no_of_clients == %d\n",
539
540
541
542
543
	    i, no_of_clients);

    return OK;
}

Per Cederqvist's avatar
Per Cederqvist committed
544

545
546
547
548
549
550
/*
 * Get info about what all the currently logged in persons are doing.
 */
extern Success
who_is_on_dynamic(int want_visible,
		  int want_invisible,
551
		  long active_last,
552
553
554
555
556
557
558
559
		  Dynamic_session_info_list *result)
{
    Connection *cptr;
    long	    no_of_clients = 0;
    long	    i;
    Session_no      session;
    int             include_it = 0;

David Byers's avatar
Server    
David Byers committed
560
    CHK_CONNECTION(FAILURE);
561
562
    session = traverse_connections(0);
    while (session != 0)
563
564
565
    {
	cptr = get_conn_by_number(session);

566
567
568
	if (!handshake_ok(cptr, 0))
	    include_it = 0;
	else if (cptr->person == NULL || cptr->flags.invisible == TRUE)
569
570
571
572
	    include_it = want_invisible;
	else
	    include_it = want_visible;

573
	if (active_last != 0
574
	    && include_it
575
	    && timeval_diff_sec(current_time, cptr->active_time) > active_last
576
577
578
	    && cptr->flags.user_active_used)
	    include_it = 0;

579
580
	if (include_it != 0)
	    ++no_of_clients;
581
582

        session = traverse_connections(session);
583
584
585
586
587
    }

    result->no_of_sessions = no_of_clients;
    result->sessions = tmp_alloc(no_of_clients * sizeof(Dynamic_session_info));

588
589
590
    i = 0;
    session = traverse_connections(0);
    while ( i < no_of_clients && session != 0)
591
592
593
    {
	cptr = get_conn_by_number(session);

594
595
596
	if (!handshake_ok(cptr, 0))
	    include_it = 0;
	else 	if (cptr->person == NULL || cptr->flags.invisible == TRUE)
597
598
599
600
	    include_it = want_invisible;
	else
	    include_it = want_visible;
	    
601
	if (active_last != 0
602
	    && include_it
603
	    && timeval_diff_sec(current_time, cptr->active_time) > active_last
604
605
606
	    && cptr->flags.user_active_used)
	    include_it = 0;

607
608
609
610
611
	if (include_it != 0)
	{
	    init_dynamic_session_info(&result->sessions[i]);
	    result->sessions[i].session = cptr->session_no;
	    result->sessions[i].person = cptr->pers_no;
612
613
	    result->sessions[i].working_conference = filter_conf_no(
		cptr->cwc, active_connection);
614
615
	    result->sessions[i].idle_time = timeval_diff_sec(
		current_time, cptr->active_time);
616

617
618
619
620
621
622
	    result->sessions[i].flags = cptr->flags;

	    /* Special case: sessions that are not logged in are
	       always invisible. */
	    if (cptr->person == NULL)
		result->sessions[i].flags.invisible = TRUE;
623
624
625
626

	    result->sessions[i].what_am_i_doing = cptr->what_am_i_doing;
	    ++i;
	}
627
628

        session = traverse_connections(session);
629
630
631
    }

    if ( i != no_of_clients )
David Byers's avatar
David Byers committed
632
	kom_log("who_is_on_dynamic: i == %ld, no_of_clients == %ld\n",
633
634
635
636
637
638
	    i, no_of_clients);

    return OK;
}


Per Cederqvist's avatar
Per Cederqvist committed
639
640
641
642
643
644
extern  Success
get_session_info  (Session_no session_no,
		   Session_info *result)
{
    Connection *cptr;

David Byers's avatar
Server    
David Byers committed
645
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
646
647
648
649
    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

650
    if (cptr != NULL && handshake_ok(cptr, 0))
Per Cederqvist's avatar
Per Cederqvist committed
651
    {
652
	init_session_info(result);
Per Cederqvist's avatar
Per Cederqvist committed
653
654
	result->person = cptr->pers_no;
	result->what_am_i_doing = cptr->what_am_i_doing;
655
656
	result->working_conference = filter_conf_no(cptr->cwc,
						    active_connection);
Per Cederqvist's avatar
Per Cederqvist committed
657
	result->session = cptr->session_no;
658
	result->connection_time = cptr->connect_time.tv_sec;
659
	result->idle_time = timeval_diff_sec(current_time, cptr->active_time);
Per Cederqvist's avatar
Per Cederqvist committed
660

661
662
	/* Backward compatibility. result->username is free()d in
	   prot_a_reply() prot-a.c. */
663
	create_oldstyle_username(&result->username, cptr);
664
665
666
667
668

	return OK;
    }
    else
    {
669
        err_stat = session_no;
670
671
672
673
674
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}

675
676
677
678
679
680
extern  Success
get_static_session_info (Session_no session_no,
			 Static_session_info *result)
{
    Connection *cptr;

David Byers's avatar
Server    
David Byers committed
681
    CHK_CONNECTION(FAILURE);
682
683
684
685
    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

686
    if (cptr != NULL && handshake_ok(cptr, 0))
687
688
689
690
    {
	init_static_session_info(result);

	result->username = cptr->username;
691
	result->hostname = cptr->isc_session->remote;
692
	result->ident_user = cptr->ident_user;
693
	result->connection_time = cptr->connect_time.tv_sec;
694
695
696
697
698

	return OK;
    }
    else
    {
699
        err_stat = session_no;
700
701
702
703
704
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}

705
706
707
708
709
710
extern  Success
get_session_info_ident  (Session_no session_no,
			 Session_info_ident *result)
{
    Connection *cptr;

David Byers's avatar
Server    
David Byers committed
711
    CHK_CONNECTION(FAILURE);
712
713
714
715
    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

716
    if (cptr != NULL && handshake_ok(cptr, 0))
717
    {
718
	init_session_info_ident(result);
719
720
	result->person = cptr->pers_no;
	result->what_am_i_doing = cptr->what_am_i_doing;
721
722
	result->working_conference = filter_conf_no(cptr->cwc,
						    active_connection);
723
	result->session = cptr->session_no;
724
	result->connection_time = cptr->connect_time.tv_sec;
725
	result->idle_time = timeval_diff_sec(current_time, cptr->active_time);
726
	result->username = cptr->username;
727
	result->hostname = cptr->isc_session->remote;
728
729
	result->ident_user = cptr->ident_user;

Per Cederqvist's avatar
Per Cederqvist committed
730
731
732
733
	return OK;
    }
    else
    {
734
        err_stat = session_no;
Per Cederqvist's avatar
Per Cederqvist committed
735
736
737
738
739
740
741
742
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}

extern  Success
who_am_i (Session_no *session_no)
{
David Byers's avatar
Server    
David Byers committed
743
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
744
745
746
747
748
749
750
751
752
753
754
    *session_no = active_connection->session_no;
    return OK;
}



extern  Success
disconnect (Session_no session_no)
{
    Connection *cptr;

David Byers's avatar
Server    
David Byers committed
755
    CHK_CONNECTION(FAILURE);
756
757
    if ( session_no != active_connection->session_no &&
         session_no != 0 )
Per Cederqvist's avatar
Per Cederqvist committed
758
759
760
761
	CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

762
    if (cptr != NULL && handshake_ok(cptr, 0))
Per Cederqvist's avatar
Per Cederqvist committed
763
    {
764
765
	if ( session_no == active_connection->session_no   ||
             session_no == 0 ||
David Byers's avatar
Server    
David Byers committed
766
             ENA(wheel, 8) ||   /* OK -- In an RPC call */
767
             is_supervisor(cptr->pers_no, ACTPERS, ACT_P) == TRUE
768
             )
Per Cederqvist's avatar
Per Cederqvist committed
769
	{
770
	    add_to_kill_list(cptr);
Per Cederqvist's avatar
Per Cederqvist committed
771
772
773
774
	    return OK;
	}
	else
	{
775
            err_stat = session_no;
Per Cederqvist's avatar
Per Cederqvist committed
776
777
778
779
780
781
	    kom_errno = KOM_PERM;
	    return FAILURE;
	}
    }
    else
    {
782
        err_stat = session_no;
Per Cederqvist's avatar
Per Cederqvist committed
783
784
785
786
787
788
789
790
791
792
793
794
795
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}


/* Get less info */
extern Success
who_is_on_old( Who_info_list_old *result )
{
    Connection *cptr;
    int 	    no_of_clients = 0;
    int		    i;
796
    Session_no	    session;
Per Cederqvist's avatar
Per Cederqvist committed
797
798

    
David Byers's avatar
Server    
David Byers committed
799
    CHK_CONNECTION(FAILURE);
800
801
    session = traverse_connections(0);
    while (session != 0)
Per Cederqvist's avatar
Per Cederqvist committed
802
803
804
    {
	cptr = get_conn_by_number(session);

805
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
Per Cederqvist's avatar
Per Cederqvist committed
806
	    ++no_of_clients;
807
        session = traverse_connections(session);
Per Cederqvist's avatar
Per Cederqvist committed
808
809
810
811
812
    }

    result->no_of_persons = no_of_clients;
    result->info = tmp_alloc ( no_of_clients * sizeof(Who_info));

813
814
815
    i = 0;
    session = traverse_connections(0);
    while (session != 0 && i < no_of_clients)
Per Cederqvist's avatar
Per Cederqvist committed
816
817
818
    {
	cptr = get_conn_by_number(session);

819
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
Per Cederqvist's avatar
Per Cederqvist committed
820
	{
821
	    init_who_info_old(&result->info[ i ]);
Per Cederqvist's avatar
Per Cederqvist committed
822
823
	    result->info[ i ].person = cptr->pers_no;
	    result->info[ i ].what_am_i_doing = cptr->what_am_i_doing;
824
825
	    result->info[i].working_conference = filter_conf_no(
		cptr->cwc, active_connection);
Per Cederqvist's avatar
Per Cederqvist committed
826
827
	    ++i;
	}
828
        session = traverse_connections(session);
Per Cederqvist's avatar
Per Cederqvist committed
829
830
831
    }
    
    if ( i != no_of_clients )
David Byers's avatar
David Byers committed
832
	kom_log("who_is_on_old: i == %d, no_of_clients == %d\n",
Per Cederqvist's avatar
Per Cederqvist committed
833
834
835
836
837
838
839
840
841
	    i, no_of_clients);

    return OK;
}

/*
 * Ask the server what it thinks the time is.
 */
extern Success
842
get_time( time_t *clk )
Per Cederqvist's avatar
Per Cederqvist committed
843
{
David Byers's avatar
Server    
David Byers committed
844
    CHK_CONNECTION(FAILURE);
845
    *clk = current_time.tv_sec;
Per Cederqvist's avatar
Per Cederqvist committed
846
847
848
849
850
851
852
    
    return OK;
}



/*
853
 * Set ena_level. 0 means don't use any privileges.
Per Cederqvist's avatar
Per Cederqvist committed
854
855
856
857
 */
extern Success
enable (u_char ena_level)
{
David Byers's avatar
Server    
David Byers committed
858
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
859
860
861
862
    CHK_LOGIN(FAILURE);
    active_connection->ena_level = ena_level;
    return OK;
}
Per Cederqvist's avatar
Per Cederqvist committed
863
864
865
866
867

extern  Success
set_client_version (const String client_name,
		    const String client_version)
{
David Byers's avatar
Server    
David Byers committed
868
869
    CHK_CONNECTION(FAILURE);

David Byers's avatar
David Byers committed
870
871
    if (s_strlen(client_name) > param.client_data_len
	|| s_strlen(client_version) > param.client_data_len)
Per Cederqvist's avatar
Per Cederqvist committed
872
    {
David Byers's avatar
David Byers committed
873
        err_stat = param.client_data_len;
Per Cederqvist's avatar
Per Cederqvist committed
874
875
876
	kom_errno = KOM_LONG_STR;
	return FAILURE;
    }
877
878
879
880
881
882
883
    if (s_empty(active_connection->client_name) == FALSE
	|| s_empty(active_connection->client_version) == FALSE)
    {
	err_stat = 0;
	kom_errno = KOM_CLIENT_IS_CRAZY;
	return FAILURE;
    }
Per Cederqvist's avatar
Per Cederqvist committed
884
885
886
887
888
889
890
891
892
893
894
895

    s_strcpy(&active_connection->client_name, client_name);
    s_strcpy(&active_connection->client_version, client_version);
    return OK;
}

extern  Success
get_client_name (Session_no session_no,
		 String *result)
{
    Connection *cptr;

David Byers's avatar
Server    
David Byers committed
896
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
897
898
899
900
    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

901
    if (cptr != NULL && handshake_ok(cptr, 0))
Per Cederqvist's avatar
Per Cederqvist committed
902
903
904
905
906
907
    {
	*result = cptr->client_name;
	return OK;
    }
    else
    {
908
        err_stat = session_no;
Per Cederqvist's avatar
Per Cederqvist committed
909
910
911
912
913
914
915
916
917
918
919
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}

extern  Success
get_client_version (Session_no session_no,
		    String *result)
{
    Connection *cptr;

David Byers's avatar
Server    
David Byers committed
920
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
921
922
923
924
    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

925
    if (cptr != NULL && handshake_ok(cptr, 0))
Per Cederqvist's avatar
Per Cederqvist committed
926
927
928
929
930
931
    {
	*result = cptr->client_version;
	return OK;
    }
    else
    {
932
        err_stat = session_no;
Per Cederqvist's avatar
Per Cederqvist committed
933
934
935
936
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}
937
938
939
940
941
942


extern Success
accept_async(Number_list *num_list)
{
    int         i;
943
    Success     result;
944
    int		found;
945
946
    

David Byers's avatar
Server    
David Byers committed
947
948
    CHK_CONNECTION(FAILURE);
    
949
    result = OK;
950
951

    /*
952
     * Check against maliciously long arrays.
953
     */
954
    if (num_list->length > param.accept_async_len)
955
    {
956
        err_stat = 0;
957
        kom_errno = KOM_LONG_ARRAY;
958
959
960
961
962
963
964
965
966
967
        return FAILURE;
    }


    /*
     * Clear the accept list
     */
    
    for (i = 0; i < ay_dummy_last; i++)
    {
968
        active_connection->want_async[i] = FALSE;
969
970
971
972
    }


    /*
973
     * Enter the new accept list -- non-silently ignore requests for
974
     * messages that this version of the server doesn't understand.
975
976
977
978
     */
    
    for (i = 0; i < num_list->length; i++)
    {
979
	found = 0;
980
981
        if (num_list->data[i] >= 0 &&
            num_list->data[i] < ay_dummy_last)
982
	{
983
	    switch ((enum async)num_list->data[i])
984
985
986
987
988
989
990
991
992
993
994
995
	    {
	    case ay_new_text_old:
	    case ay_new_name:
	    case ay_i_am_on:
	    case ay_sync_db:
	    case ay_leave_conf:
	    case ay_login:
	    case ay_rejected_connection:
	    case ay_send_message:
	    case ay_logout:
	    case ay_deleted_text:
	    case ay_new_text:
David Byers's avatar
David Byers committed
996
997
998
            case ay_new_recipient:
            case ay_sub_recipient:
            case ay_new_membership:
999
            case ay_new_user_area:
1000
            case ay_new_presentation:
1001
1002
1003
#ifdef DEBUG_CALLS
	    case ay_garb_ended:
#endif
1004
1005
1006
1007
1008
1009
		found = 1;
		active_connection->want_async[num_list->data[i]] = TRUE;
		break;
	    case ay_dummy_last:
		break;
		/* Trick: since we don't use a default label here gcc
1010
		   will warn if new values are added to ``enum async''
1011
1012
1013
1014
1015
		   but not to this switch. */
	    }
	}
	
	if (!found && result == OK) /* Remember the first offender. */
1016
1017
1018
1019
1020
        {
            err_stat  = num_list->data[i];
            kom_errno = KOM_UNKNOWN_ASYNC;
            result    = FAILURE;
        }
1021
1022
    }

1023
    return result;
1024
1025
1026
1027
1028
1029
}


extern Success
query_async(Number_list *result)
{
1030
    /* (This static buffer is mentioned in async.h). */
1031
1032
1033
    static long        temp[ay_dummy_last];
    int         i;

David Byers's avatar
Server    
David Byers committed
1034
    CHK_CONNECTION(FAILURE);
1035
1036
1037
    result->length = 0;
    for (i = 0; i < ay_dummy_last; i++)
    {
1038
        if (active_connection->want_async[i] != FALSE)
1039
1040
1041
1042
1043
1044
1045
1046
1047
        {
            temp[result->length] = i;
            result->length += 1;
        }
    }
    result->data = temp;

    return OK;
}
1048
1049
1050
1051

extern Success
user_active(void)
{
David Byers's avatar
Server    
David Byers committed
1052
    CHK_CONNECTION(FAILURE);
1053
    active_connection->active_time = current_time;
1054
    active_connection->flags.user_active_used = TRUE;
1055
1056
    return OK;
}