session.c 24.9 KB
Newer Older
Linus Tolke's avatar
Linus Tolke committed
1
/*
2
 * $Id: session.c,v 0.69 2003/08/02 20:44:09 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
77
	restart_kom("create_oldstyle_username(): strcpy\n");

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

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

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
146
    pers_p->last_login = current_time.tv_sec;
    active_connection->session_start = 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
158
	    restart_kom("login: s_strcat (\n");

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

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

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

Per Cederqvist's avatar
Per Cederqvist committed
169
    if ( s_strcat(&pers_p->username, active_connection->hostname) != OK )
170
171
	restart_kom("prot_a_parse_packet: s_strcat II\n");

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

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

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

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

188
189
190
191
192
193
194
195
196
197
198
/*
 * 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;
199
    Bool same_person;
200

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

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

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

215
    logout();
216

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

222
223
224
    /* 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. */
225
    if (same_person == FALSE)
226
227
	++pers_p->sessions;

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

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

    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))
    {
243
	if ( s_strcat(&pers_p->username, s_fcrea_str("(")) != OK )
244
245
	    restart_kom("login: s_strcat (\n");

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

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

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

Per Cederqvist's avatar
Per Cederqvist committed
257
    if ( s_strcat(&pers_p->username, active_connection->hostname) != OK )
258
259
260
261
	restart_kom("prot_a_parse_packet: s_strcat II\n");

    mark_person_as_changed( pers_no );

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

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

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

Per Cederqvist's avatar
Per Cederqvist committed
278
279
280
281
282
283
284
285
286

/*
 * 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
287
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
288
289
    if ( ACTPERS != 0 )		/* Is he logged in? Then log him out. */
    {
290
	if (!active_connection->flags.invisible)
291
292
293
	{
	    async_logout( ACTPERS, active_connection->session_no );
	}
Per Cederqvist's avatar
Per Cederqvist committed
294
	
David Byers's avatar
Server    
David Byers committed
295
	leave_conf(active_connection);
296
	ACT_P->last_login = current_time.tv_sec;
Per Cederqvist's avatar
Per Cederqvist committed
297
	ACT_P->total_time_present +=
298
	    timeval_diff_sec(current_time, active_connection->session_start);
Per Cederqvist's avatar
Per Cederqvist committed
299
300
301
302
303
304
305
306
307
308
309
310
311

	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;
    
312
313
314
    isc_set_acceptable_idle(active_connection->isc_session,
			    param.login_timeout);

Per Cederqvist's avatar
Per Cederqvist committed
315
316
317
318
319
320
321
322
323
324
    return OK;
}


/*
 * Change Conference.
 *
 * You are not allowed to change to a conference unless you are a
 * member in the conference.
 *
325
326
 * You can change_conference(0) to indicate that you are no longer in
 * a certain conference.
Per Cederqvist's avatar
Per Cederqvist committed
327
328
329
330
331
332
333
334
335
336
337
 *
 * 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
338
 * someone change_conference's to it to allow faster response times.
Per Cederqvist's avatar
Per Cederqvist committed
339
340
 */
extern Success
341
change_conference (Conf_no		conference)		
Per Cederqvist's avatar
Per Cederqvist committed
342
{
343
344
    Who_info	 info;
  
David Byers's avatar
Server    
David Byers committed
345
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
346
    CHK_LOGIN(FAILURE);
David Byers's avatar
Server    
David Byers committed
347

Per Cederqvist's avatar
Per Cederqvist committed
348
349
350
351
352
353
    if (  conference != 0 )
    {
	CHK_EXIST(conference, FAILURE);

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

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

David Byers's avatar
Server    
David Byers committed
366
    init_who_info(&info);
367
    if (!active_connection->flags.invisible)
368
369
370
371
372
    {
	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;
373
374
375
376

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

377
	async_i_am_on(info);
378
379

	s_clear(&info.username);
380
    }
Per Cederqvist's avatar
Per Cederqvist committed
381
382
383
384
385
386
387
388
389
390
391
392
    
    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)
{
393
394
    Who_info info;
    
David Byers's avatar
Server    
David Byers committed
395
    CHK_CONNECTION(FAILURE);
396
    init_who_info(&info);
Per Cederqvist's avatar
Per Cederqvist committed
397

398
    if ( s_strlen( what_am_i_doing ) > param.what_do_len )
Per Cederqvist's avatar
Per Cederqvist committed
399
400
    {
	s_clear ( &what_am_i_doing );
401
        err_stat = param.what_do_len;
Per Cederqvist's avatar
Per Cederqvist committed
402
403
404
405
406
407
408
	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;

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

	s_clear(&info.username);
420
    }
Per Cederqvist's avatar
Per Cederqvist committed
421
422
423
424

    return OK;
}

425

Per Cederqvist's avatar
Per Cederqvist committed
426
427
428
429
430
431
432
433
434
435
436
/*
 * 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
437
438
    CHK_CONNECTION(FAILURE);

Per Cederqvist's avatar
Per Cederqvist committed
439
    cptr = active_connection;
440
441
    session = traverse_connections(0);
    while (session != 0)
Per Cederqvist's avatar
Per Cederqvist committed
442
443
444
    {
	cptr = get_conn_by_number(session);

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

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

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

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

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

	    /* 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. */
469
	    create_oldstyle_username(&result->info[i].username, cptr);
470

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

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

    return OK;
}

486
487
488
489
490
491
492
493
494
495
496
/*
 * 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
497
498
    CHK_CONNECTION(FAILURE);

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

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

        session = traverse_connections(session);
509
510
511
    }

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

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

520
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
521
	{
522
	    init_who_info_ident(&result->info[i]);
523
524
525
526
527
	    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;
	    result->info[i].hostname = cptr->hostname;
	    result->info[i].ident_user = cptr->ident_user;
528
529
	    result->info[i].working_conference = filter_conf_no(
		cptr->cwc, active_connection);
530
531
532
	    result->info[i].session_no = cptr->session_no;
	    ++i;
	}
533
        session = traverse_connections(session);
534
535
536
    }

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

    return OK;
}

Per Cederqvist's avatar
Per Cederqvist committed
543

544
545
546
547
548
549
/*
 * Get info about what all the currently logged in persons are doing.
 */
extern Success
who_is_on_dynamic(int want_visible,
		  int want_invisible,
550
		  long active_last,
551
552
553
554
555
556
557
558
		  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
559
    CHK_CONNECTION(FAILURE);
560
    cptr = active_connection;
561
562
    session = traverse_connections(0);
    while (session != 0)
563
564
565
    {
	cptr = get_conn_by_number(session);

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

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

576
577
	if (include_it != 0)
	    ++no_of_clients;
578
579

        session = traverse_connections(session);
580
581
582
583
584
    }

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

585
586
587
    i = 0;
    session = traverse_connections(0);
    while ( i < no_of_clients && session != 0)
588
589
590
    {
	cptr = get_conn_by_number(session);

591
	if (cptr->person == NULL || cptr->flags.invisible == TRUE)
592
593
594
595
	    include_it = want_invisible;
	else
	    include_it = want_visible;
	    
596
	if (active_last != 0
597
	    && timeval_diff_sec(current_time, cptr->active_time) > active_last
598
599
600
	    && cptr->flags.user_active_used)
	    include_it = 0;

601
602
603
604
605
	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;
606
607
	    result->sessions[i].working_conference = filter_conf_no(
		cptr->cwc, active_connection);
608
609
	    result->sessions[i].idle_time = timeval_diff_sec(
		current_time, cptr->active_time);
610

611
612
613
614
615
616
	    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;
617
618
619
620

	    result->sessions[i].what_am_i_doing = cptr->what_am_i_doing;
	    ++i;
	}
621
622

        session = traverse_connections(session);
623
624
625
    }

    if ( i != no_of_clients )
David Byers's avatar
David Byers committed
626
	kom_log("who_is_on_dynamic: i == %ld, no_of_clients == %ld\n",
627
628
629
630
631
632
	    i, no_of_clients);

    return OK;
}


Per Cederqvist's avatar
Per Cederqvist committed
633
634
635
636
637
638
extern  Success
get_session_info  (Session_no session_no,
		   Session_info *result)
{
    Connection *cptr;

David Byers's avatar
Server    
David Byers committed
639
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
640
641
642
643
644
645
    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

    if ( cptr != NULL )
    {
646
	init_session_info(result);
Per Cederqvist's avatar
Per Cederqvist committed
647
648
	result->person = cptr->pers_no;
	result->what_am_i_doing = cptr->what_am_i_doing;
649
650
	result->working_conference = filter_conf_no(cptr->cwc,
						    active_connection);
Per Cederqvist's avatar
Per Cederqvist committed
651
	result->session = cptr->session_no;
652
653
	result->connection_time = cptr->session_start.tv_sec;
	result->idle_time = timeval_diff_sec(current_time, cptr->active_time);
Per Cederqvist's avatar
Per Cederqvist committed
654

655
656
	/* Backward compatibility. result->username is free()d in
	   prot_a_reply() prot-a.c. */
657
	create_oldstyle_username(&result->username, cptr);
658
659
660
661
662

	return OK;
    }
    else
    {
663
        err_stat = session_no;
664
665
666
667
668
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}

669
670
671
672
673
674
extern  Success
get_static_session_info (Session_no session_no,
			 Static_session_info *result)
{
    Connection *cptr;

David Byers's avatar
Server    
David Byers committed
675
    CHK_CONNECTION(FAILURE);
676
677
678
679
680
681
682
683
684
685
686
    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

    if ( cptr != NULL )
    {
	init_static_session_info(result);

	result->username = cptr->username;
	result->hostname = cptr->hostname;
	result->ident_user = cptr->ident_user;
687
	result->connection_time = cptr->session_start.tv_sec;
688
689
690
691
692

	return OK;
    }
    else
    {
693
        err_stat = session_no;
694
695
696
697
698
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}

699
700
701
702
703
704
extern  Success
get_session_info_ident  (Session_no session_no,
			 Session_info_ident *result)
{
    Connection *cptr;

David Byers's avatar
Server    
David Byers committed
705
    CHK_CONNECTION(FAILURE);
706
707
708
709
710
711
    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

    if ( cptr != NULL )
    {
712
	init_session_info_ident(result);
713
714
	result->person = cptr->pers_no;
	result->what_am_i_doing = cptr->what_am_i_doing;
715
716
	result->working_conference = filter_conf_no(cptr->cwc,
						    active_connection);
717
	result->session = cptr->session_no;
718
719
	result->connection_time = cptr->session_start.tv_sec;
	result->idle_time = timeval_diff_sec(current_time, cptr->active_time);
720
721
722
723
	result->username = cptr->username;
	result->hostname = cptr->hostname;
	result->ident_user = cptr->ident_user;

Per Cederqvist's avatar
Per Cederqvist committed
724
725
726
727
	return OK;
    }
    else
    {
728
        err_stat = session_no;
Per Cederqvist's avatar
Per Cederqvist committed
729
730
731
732
733
734
735
736
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}

extern  Success
who_am_i (Session_no *session_no)
{
David Byers's avatar
Server    
David Byers committed
737
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
738
739
740
741
742
743
744
745
746
747
748
    *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
749
    CHK_CONNECTION(FAILURE);
750
751
    if ( session_no != active_connection->session_no &&
         session_no != 0 )
Per Cederqvist's avatar
Per Cederqvist committed
752
753
754
755
756
757
	CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

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

    
David Byers's avatar
Server    
David Byers committed
793
    CHK_CONNECTION(FAILURE);
794
795
    session = traverse_connections(0);
    while (session != 0)
Per Cederqvist's avatar
Per Cederqvist committed
796
797
798
    {
	cptr = get_conn_by_number(session);

799
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
Per Cederqvist's avatar
Per Cederqvist committed
800
	    ++no_of_clients;
801
        session = traverse_connections(session);
Per Cederqvist's avatar
Per Cederqvist committed
802
803
804
805
806
    }

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

807
808
809
    i = 0;
    session = traverse_connections(0);
    while (session != 0 && i < no_of_clients)
Per Cederqvist's avatar
Per Cederqvist committed
810
811
812
    {
	cptr = get_conn_by_number(session);

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

    return OK;
}

/*
 * Ask the server what it thinks the time is.
 */
extern Success
836
get_time( time_t *clk )
Per Cederqvist's avatar
Per Cederqvist committed
837
{
David Byers's avatar
Server    
David Byers committed
838
    CHK_CONNECTION(FAILURE);
839
    *clk = current_time.tv_sec;
Per Cederqvist's avatar
Per Cederqvist committed
840
841
842
843
844
845
846
    
    return OK;
}



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

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

David Byers's avatar
David Byers committed
864
865
    if (s_strlen(client_name) > param.client_data_len
	|| s_strlen(client_version) > param.client_data_len)
Per Cederqvist's avatar
Per Cederqvist committed
866
    {
David Byers's avatar
David Byers committed
867
        err_stat = param.client_data_len;
Per Cederqvist's avatar
Per Cederqvist committed
868
869
870
	kom_errno = KOM_LONG_STR;
	return FAILURE;
    }
871
872
873
874
875
876
877
    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
878
879
880
881
882
883
884
885
886
887
888
889

    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
890
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
891
892
893
894
895
896
897
898
899
900
901
    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

    if ( cptr != NULL )
    {
	*result = cptr->client_name;
	return OK;
    }
    else
    {
902
        err_stat = session_no;
Per Cederqvist's avatar
Per Cederqvist committed
903
904
905
906
907
908
909
910
911
912
913
	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
914
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
915
916
917
918
919
920
921
922
923
924
925
    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

    if ( cptr != NULL )
    {
	*result = cptr->client_version;
	return OK;
    }
    else
    {
926
        err_stat = session_no;
Per Cederqvist's avatar
Per Cederqvist committed
927
928
929
930
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}
931
932
933
934
935
936


extern Success
accept_async(Number_list *num_list)
{
    int         i;
937
    Success     result;
938
    int		found;
939
940
    

David Byers's avatar
Server    
David Byers committed
941
942
    CHK_CONNECTION(FAILURE);
    
943
    result = OK;
944
945

    /*
946
     * Check against maliciously long arrays.
947
     */
948
    if (num_list->length > param.accept_async_len)
949
    {
950
        err_stat = 0;
951
        kom_errno = KOM_LONG_ARRAY;
952
953
954
955
956
957
958
959
960
961
        return FAILURE;
    }


    /*
     * Clear the accept list
     */
    
    for (i = 0; i < ay_dummy_last; i++)
    {
962
        active_connection->want_async[i] = FALSE;
963
964
965
966
    }


    /*
967
     * Enter the new accept list -- non-silently ignore requests for
968
     * messages that this version of the server doesn't understand.
969
970
971
972
     */
    
    for (i = 0; i < num_list->length; i++)
    {
973
	found = 0;
974
975
        if (num_list->data[i] >= 0 &&
            num_list->data[i] < ay_dummy_last)
976
	{
977
	    switch ((enum async)num_list->data[i])
978
979
980
981
982
983
984
985
986
987
988
989
	    {
	    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
990
991
992
            case ay_new_recipient:
            case ay_sub_recipient:
            case ay_new_membership:
993
            case ay_new_user_area:
994
995
996
#ifdef DEBUG_CALLS
	    case ay_garb_ended:
#endif
997
998
999
1000
1001
1002
		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
1003
		   will warn if new values are added to ``enum async''
1004
1005
1006
1007
1008
		   but not to this switch. */
	    }
	}
	
	if (!found && result == OK) /* Remember the first offender. */
1009
1010
1011
1012
1013
        {
            err_stat  = num_list->data[i];
            kom_errno = KOM_UNKNOWN_ASYNC;
            result    = FAILURE;
        }
1014
1015
    }

1016
    return result;
1017
1018
1019
1020
1021
1022
}


extern Success
query_async(Number_list *result)
{
1023
    /* (This static buffer is mentioned in async.h). */
1024
1025
1026
    static long        temp[ay_dummy_last];
    int         i;

David Byers's avatar
Server    
David Byers committed
1027
    CHK_CONNECTION(FAILURE);
1028
1029
1030
    result->length = 0;
    for (i = 0; i < ay_dummy_last; i++)
    {
1031
        if (active_connection->want_async[i] != FALSE)
1032
1033
1034
1035
1036
1037
1038
1039
1040
        {
            temp[result->length] = i;
            result->length += 1;
        }
    }
    result->data = temp;

    return OK;
}
1041
1042
1043
1044

extern Success
user_active(void)
{
David Byers's avatar
Server    
David Byers committed
1045
    CHK_CONNECTION(FAILURE);
1046
    active_connection->active_time = current_time;
1047
    active_connection->flags.user_active_used = TRUE;
1048
1049
    return OK;
}