session.c 24.6 KB
Newer Older
Linus Tolke Y's avatar
Linus Tolke Y committed
1
/*
2
 * $Id: session.c,v 0.68 2003/07/12 22:26:35 ceder Exp $
Per Cederqvist's avatar
Per Cederqvist committed
3
 * Copyright (C) 1991-1994, 1996-2002  Lysator Academic Computer Association.
Linus Tolke Y's avatar
Linus Tolke Y committed
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * This file is part of the LysKOM server.
 * 
 * LysKOM is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; either version 1, or (at your option) 
 * any later version.
 * 
 * LysKOM is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with LysKOM; see the file COPYING.  If not, write to
 * Lysator, c/o ISY, Linkoping University, S-581 83 Linkoping, SWEDEN,
 * or the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, 
 * MA 02139, USA.
 *
 * Please mail bug reports to bug-lyskom@lysator.liu.se. 
 */
Per Cederqvist's avatar
Per Cederqvist committed
25
26
27
28
29
30
/*
 * 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
#include "ldifftime.h"
Per Cederqvist's avatar
Per Cederqvist committed
42
43
44
#include "s-string.h"
#include "kom-types.h"
#include "services.h"
Per Cederqvist's avatar
Per Cederqvist committed
45
#include "com.h"
46
#include "async.h"
Per Cederqvist's avatar
Per Cederqvist committed
47
#include "connections.h"
Per Cederqvist's avatar
Per Cederqvist committed
48
#include "internal-connections.h"
49
#include "kom-errno.h"
Per Cederqvist's avatar
Per Cederqvist committed
50
51
#include "manipulate.h"
#include "lyskomd.h"
Per Cederqvist's avatar
Per Cederqvist committed
52
#include "log.h"
Per Cederqvist's avatar
Per Cederqvist committed
53
54
#include "cache.h"
#include "send-async.h"
David Byers's avatar
David Byers committed
55
#include "kom-config.h"
Per Cederqvist's avatar
Per Cederqvist committed
56
#include "server/smalloc.h"
57
#include "param.h"
Per Cederqvist's avatar
Per Cederqvist committed
58
#include "kom-memory.h"
59
#include "string-malloc.h"
60
#include "server-time.h"
61
#include "timeval-util.h"
62
63
64
65
66
67
68
69
70
71

/*
 * 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)
{
72
    if ( s_strcpy(result, connection->username) != OK )
73
74
	restart_kom("create_oldstyle_username(): strcpy\n");

75
    if ( s_strcat(result, s_fcrea_str("@")) != OK )
76
77
	restart_kom("create_oldstyle_username: s_strcat\n");

78
    if ( s_strcat(result, connection->hostname) != OK )
79
80
81
	restart_kom("prot_a_parse_packet: s_strcat II\n");
}

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

extern void
David Byers's avatar
Server  
David Byers committed
88
leave_conf(Connection *conn)
Per Cederqvist's avatar
Per Cederqvist committed
89
90
91
{
    Membership * mship;

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

/*
 * 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
116
117
login_old (Pers_no       pers_no,
	   const String  passwd)
Per Cederqvist's avatar
Per Cederqvist committed
118
119
{
    Person *pers_p;
David Byers's avatar
Server  
David Byers committed
120
121
    
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
122
    GET_P_STAT(pers_p, pers_no, FAILURE);
123

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

133
    logout();
Per Cederqvist's avatar
Per Cederqvist committed
134

135
    active_connection->flags.invisible = FALSE;
136

Per Cederqvist's avatar
Per Cederqvist committed
137
138
139
140
141
    ACTPERS = pers_no;
    ACT_P   = pers_p;

    cached_lock_person(pers_no);
        
142
143
    pers_p->last_login = current_time.tv_sec;
    active_connection->session_start = current_time;
Per Cederqvist's avatar
Per Cederqvist committed
144
145
146
    ++pers_p->sessions;

    s_strcpy(&pers_p->username, active_connection->username);
147
148
149
150
151
152

    /* 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))
    {
153
	if ( s_strcat(&pers_p->username, s_fcrea_str("(")) != OK )
154
155
	    restart_kom("login: s_strcat (\n");

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

159
	if ( s_strcat(&pers_p->username, s_fcrea_str(")")) != OK )
160
161
162
	    restart_kom("login: s_strcat )\n");
    }

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

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

Per Cederqvist's avatar
Per Cederqvist committed
169
    mark_person_as_changed( pers_no );
170
171
172
173

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

Per Cederqvist's avatar
Per Cederqvist committed
178
    async_login(ACTPERS, active_connection->session_no);
179

Per Cederqvist's avatar
Per Cederqvist committed
180
181
182
    return OK;
}

183
184
185
186
187
188
189
190
191
192
193
/*
 * 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;
194
    Bool same_person;
195

David Byers's avatar
Server  
David Byers committed
196
    CHK_CONNECTION(FAILURE);
197
198
    GET_P_STAT(pers_p, pers_no, FAILURE);

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

208
    same_person = (ACTPERS == pers_no) ? TRUE : FALSE;
209

210
    logout();
211

212
    if (invisible)
213
      active_connection->flags.invisible = TRUE;
214
    else
215
      active_connection->flags.invisible = FALSE;
216

217
218
219
    /* 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. */
220
    if (same_person == FALSE)
221
222
	++pers_p->sessions;

223
224
225
226
227
    ACTPERS = pers_no;
    ACT_P   = pers_p;

    cached_lock_person(pers_no);
        
228
229
    pers_p->last_login = current_time.tv_sec;
    active_connection->session_start = current_time;
230
231
232
233
234
235
236
237

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

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

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

249
    if ( s_strcat(&pers_p->username, s_fcrea_str("@")) != OK )
250
251
	restart_kom("prot_a_parse_packet: s_strcat\n");

Per Cederqvist's avatar
Per Cederqvist committed
252
    if ( s_strcat(&pers_p->username, active_connection->hostname) != OK )
253
254
255
256
	restart_kom("prot_a_parse_packet: s_strcat II\n");

    mark_person_as_changed( pers_no );

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

264
    if (!active_connection->flags.invisible)
265
266
267
268
269
	async_login(ACTPERS, active_connection->session_no);
    
    return OK;
}

Per Cederqvist's avatar
Per Cederqvist committed
270
271
272
273
274
275
276
277
278

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

	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;
    
    return OK;
}


/*
 * Change Conference.
 *
 * You are not allowed to change to a conference unless you are a
 * member in the conference.
 *
314
315
 * You can change_conference(0) to indicate that you are no longer in
 * a certain conference.
Per Cederqvist's avatar
Per Cederqvist committed
316
317
318
319
320
321
322
323
324
325
326
 *
 * 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
327
 * someone change_conference's to it to allow faster response times.
Per Cederqvist's avatar
Per Cederqvist committed
328
329
 */
extern Success
330
change_conference (Conf_no		conference)		
Per Cederqvist's avatar
Per Cederqvist committed
331
{
332
333
    Who_info	 info;
  
David Byers's avatar
Server  
David Byers committed
334
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
335
    CHK_LOGIN(FAILURE);
David Byers's avatar
Server  
David Byers committed
336

Per Cederqvist's avatar
Per Cederqvist committed
337
338
339
340
341
342
    if (  conference != 0 )
    {
	CHK_EXIST(conference, FAILURE);

	if ( locate_membership( conference, ACT_P) == NULL )
	{
343
            err_stat = conference;
Per Cederqvist's avatar
Per Cederqvist committed
344
345
346
347
348
	    kom_errno = KOM_NOT_MEMBER;
	    return FAILURE;
	}
    }

David Byers's avatar
Server  
David Byers committed
349
    leave_conf(active_connection);
Per Cederqvist's avatar
Per Cederqvist committed
350
351
352
353
354
    
    active_connection->cwc = conference;
    if ( conference != 0 )
	cached_lock_conf( conference );

David Byers's avatar
Server  
David Byers committed
355
    init_who_info(&info);
356
    if (!active_connection->flags.invisible)
357
358
359
360
361
    {
	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;
362
363
364
365

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

366
	async_i_am_on(info);
367
368

	s_clear(&info.username);
369
    }
Per Cederqvist's avatar
Per Cederqvist committed
370
371
372
373
374
375
376
377
378
379
380
381
    
    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)
{
382
383
    Who_info info;
    
David Byers's avatar
Server  
David Byers committed
384
    CHK_CONNECTION(FAILURE);
385
    init_who_info(&info);
Per Cederqvist's avatar
Per Cederqvist committed
386

387
    if ( s_strlen( what_am_i_doing ) > param.what_do_len )
Per Cederqvist's avatar
Per Cederqvist committed
388
389
    {
	s_clear ( &what_am_i_doing );
390
        err_stat = param.what_do_len;
Per Cederqvist's avatar
Per Cederqvist committed
391
392
393
394
395
396
397
	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;

398
    if (!active_connection->flags.invisible)
399
400
401
    {
	info.person = ACTPERS;
	info.what_am_i_doing = active_connection->what_am_i_doing;
402
	create_oldstyle_username(&info.username, active_connection);
403
404
	info.working_conference = active_connection->cwc;
	info.session_no = active_connection->session_no;
Per Cederqvist's avatar
Per Cederqvist committed
405
    
406
	async_i_am_on(info);
407
408

	s_clear(&info.username);
409
    }
Per Cederqvist's avatar
Per Cederqvist committed
410
411
412
413

    return OK;
}

414

Per Cederqvist's avatar
Per Cederqvist committed
415
416
417
418
419
420
421
422
423
424
425
/*
 * 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
426
427
    CHK_CONNECTION(FAILURE);

Per Cederqvist's avatar
Per Cederqvist committed
428
    cptr = active_connection;
429
430
    session = traverse_connections(0);
    while (session != 0)
Per Cederqvist's avatar
Per Cederqvist committed
431
432
433
    {
	cptr = get_conn_by_number(session);

434
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
Per Cederqvist's avatar
Per Cederqvist committed
435
	    ++no_of_clients;
436
437

        session = traverse_connections(session);
Per Cederqvist's avatar
Per Cederqvist committed
438
439
440
441
442
    }

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

443
444
445
    i = 0;
    session = traverse_connections(0);
    while ( i < no_of_clients && session != 0)
Per Cederqvist's avatar
Per Cederqvist committed
446
447
448
    {
	cptr = get_conn_by_number(session);

449
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
Per Cederqvist's avatar
Per Cederqvist committed
450
	{
451
	    init_who_info(&result->info[ i ]);
Per Cederqvist's avatar
Per Cederqvist committed
452
453
	    result->info[ i ].person = cptr->pers_no;
	    result->info[ i ].what_am_i_doing = cptr->what_am_i_doing;
454
455
456
457

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

460
461
	    result->info[ i ].working_conference = filter_conf_no(
		cptr->cwc, active_connection);
Per Cederqvist's avatar
Per Cederqvist committed
462
463
464
	    result->info[ i ].session_no = cptr->session_no;
	    ++i;
	}
465
        session = traverse_connections(session);
Per Cederqvist's avatar
Per Cederqvist committed
466
467
468
    }

    if ( i != no_of_clients )
David Byers's avatar
David Byers committed
469
	kom_log("who_is_on: i == %d, no_of_clients == %d\n",
Per Cederqvist's avatar
Per Cederqvist committed
470
471
472
473
474
	    i, no_of_clients);

    return OK;
}

475
476
477
478
479
480
481
482
483
484
485
/*
 * 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
486
487
    CHK_CONNECTION(FAILURE);

488
    cptr = active_connection;
489
490
    session = traverse_connections(0);
    while (session != 0)
491
492
493
    {
	cptr = get_conn_by_number(session);

494
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
495
	    ++no_of_clients;
496
497

        session = traverse_connections(session);
498
499
500
    }

    result->no_of_persons = no_of_clients;
501
    result->info = tmp_alloc ( no_of_clients * sizeof(Who_info_ident));
502

503
504
505
    i = 0;
    session = traverse_connections(0);
    while ( i < no_of_clients && session != 0)
506
507
508
    {
	cptr = get_conn_by_number(session);

509
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
510
	{
511
	    init_who_info_ident(&result->info[i]);
512
513
514
515
516
	    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;
517
518
	    result->info[i].working_conference = filter_conf_no(
		cptr->cwc, active_connection);
519
520
521
	    result->info[i].session_no = cptr->session_no;
	    ++i;
	}
522
        session = traverse_connections(session);
523
524
525
    }

    if ( i != no_of_clients )
David Byers's avatar
David Byers committed
526
	kom_log("who_is_on_ident: i == %d, no_of_clients == %d\n",
527
528
529
530
531
	    i, no_of_clients);

    return OK;
}

Per Cederqvist's avatar
Per Cederqvist committed
532

533
534
535
536
537
538
/*
 * Get info about what all the currently logged in persons are doing.
 */
extern Success
who_is_on_dynamic(int want_visible,
		  int want_invisible,
539
		  long active_last,
540
541
542
543
544
545
546
547
		  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
548
    CHK_CONNECTION(FAILURE);
549
    cptr = active_connection;
550
551
    session = traverse_connections(0);
    while (session != 0)
552
553
554
    {
	cptr = get_conn_by_number(session);

555
	if (cptr->person == NULL || cptr->flags.invisible == TRUE)
556
557
558
559
	    include_it = want_invisible;
	else
	    include_it = want_visible;

560
	if (active_last != 0
561
	    && timeval_diff_sec(current_time, cptr->active_time) > active_last
562
563
564
	    && cptr->flags.user_active_used)
	    include_it = 0;

565
566
	if (include_it != 0)
	    ++no_of_clients;
567
568

        session = traverse_connections(session);
569
570
571
572
573
    }

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

574
575
576
    i = 0;
    session = traverse_connections(0);
    while ( i < no_of_clients && session != 0)
577
578
579
    {
	cptr = get_conn_by_number(session);

580
	if (cptr->person == NULL || cptr->flags.invisible == TRUE)
581
582
583
584
	    include_it = want_invisible;
	else
	    include_it = want_visible;
	    
585
	if (active_last != 0
586
	    && timeval_diff_sec(current_time, cptr->active_time) > active_last
587
588
589
	    && cptr->flags.user_active_used)
	    include_it = 0;

590
591
592
593
594
	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;
595
596
	    result->sessions[i].working_conference = filter_conf_no(
		cptr->cwc, active_connection);
597
598
	    result->sessions[i].idle_time = timeval_diff_sec(
		current_time, cptr->active_time);
599

600
601
602
603
604
605
	    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;
606
607
608
609

	    result->sessions[i].what_am_i_doing = cptr->what_am_i_doing;
	    ++i;
	}
610
611

        session = traverse_connections(session);
612
613
614
    }

    if ( i != no_of_clients )
David Byers's avatar
David Byers committed
615
	kom_log("who_is_on_dynamic: i == %ld, no_of_clients == %ld\n",
616
617
618
619
620
621
	    i, no_of_clients);

    return OK;
}


Per Cederqvist's avatar
Per Cederqvist committed
622
623
624
625
626
627
extern  Success
get_session_info  (Session_no session_no,
		   Session_info *result)
{
    Connection *cptr;

David Byers's avatar
Server  
David Byers committed
628
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
629
630
631
632
633
634
    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

    if ( cptr != NULL )
    {
635
	init_session_info(result);
Per Cederqvist's avatar
Per Cederqvist committed
636
637
	result->person = cptr->pers_no;
	result->what_am_i_doing = cptr->what_am_i_doing;
638
639
	result->working_conference = filter_conf_no(cptr->cwc,
						    active_connection);
Per Cederqvist's avatar
Per Cederqvist committed
640
	result->session = cptr->session_no;
641
642
	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
643

644
645
	/* Backward compatibility. result->username is free()d in
	   prot_a_reply() prot-a.c. */
646
	create_oldstyle_username(&result->username, cptr);
647
648
649
650
651

	return OK;
    }
    else
    {
652
        err_stat = session_no;
653
654
655
656
657
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}

658
659
660
661
662
663
extern  Success
get_static_session_info (Session_no session_no,
			 Static_session_info *result)
{
    Connection *cptr;

David Byers's avatar
Server  
David Byers committed
664
    CHK_CONNECTION(FAILURE);
665
666
667
668
669
670
671
672
673
674
675
    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;
676
	result->connection_time = cptr->session_start.tv_sec;
677
678
679
680
681

	return OK;
    }
    else
    {
682
        err_stat = session_no;
683
684
685
686
687
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}

688
689
690
691
692
693
extern  Success
get_session_info_ident  (Session_no session_no,
			 Session_info_ident *result)
{
    Connection *cptr;

David Byers's avatar
Server  
David Byers committed
694
    CHK_CONNECTION(FAILURE);
695
696
697
698
699
700
    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

    if ( cptr != NULL )
    {
701
	init_session_info_ident(result);
702
703
	result->person = cptr->pers_no;
	result->what_am_i_doing = cptr->what_am_i_doing;
704
705
	result->working_conference = filter_conf_no(cptr->cwc,
						    active_connection);
706
	result->session = cptr->session_no;
707
708
	result->connection_time = cptr->session_start.tv_sec;
	result->idle_time = timeval_diff_sec(current_time, cptr->active_time);
709
710
711
712
	result->username = cptr->username;
	result->hostname = cptr->hostname;
	result->ident_user = cptr->ident_user;

Per Cederqvist's avatar
Per Cederqvist committed
713
714
715
716
	return OK;
    }
    else
    {
717
        err_stat = session_no;
Per Cederqvist's avatar
Per Cederqvist committed
718
719
720
721
722
723
724
725
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}

extern  Success
who_am_i (Session_no *session_no)
{
David Byers's avatar
Server  
David Byers committed
726
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
727
728
729
730
731
732
733
734
735
736
737
    *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
738
    CHK_CONNECTION(FAILURE);
739
740
    if ( session_no != active_connection->session_no &&
         session_no != 0 )
Per Cederqvist's avatar
Per Cederqvist committed
741
742
743
744
745
746
	CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

    if ( cptr != NULL )
    {
747
748
	if ( session_no == active_connection->session_no   ||
             session_no == 0 ||
David Byers's avatar
Server  
David Byers committed
749
             ENA(wheel, 8) ||   /* OK -- In an RPC call */
750
             is_supervisor(cptr->pers_no, ACTPERS, ACT_P) == TRUE
751
             )
Per Cederqvist's avatar
Per Cederqvist committed
752
	{
753
	    add_to_kill_list(cptr);
Per Cederqvist's avatar
Per Cederqvist committed
754
755
756
757
	    return OK;
	}
	else
	{
758
            err_stat = session_no;
Per Cederqvist's avatar
Per Cederqvist committed
759
760
761
762
763
764
	    kom_errno = KOM_PERM;
	    return FAILURE;
	}
    }
    else
    {
765
        err_stat = session_no;
Per Cederqvist's avatar
Per Cederqvist committed
766
767
768
769
770
771
772
773
774
775
776
777
778
	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;
779
    Session_no	    session;
Per Cederqvist's avatar
Per Cederqvist committed
780
781

    
David Byers's avatar
Server  
David Byers committed
782
    CHK_CONNECTION(FAILURE);
783
784
    session = traverse_connections(0);
    while (session != 0)
Per Cederqvist's avatar
Per Cederqvist committed
785
786
787
    {
	cptr = get_conn_by_number(session);

788
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
Per Cederqvist's avatar
Per Cederqvist committed
789
	    ++no_of_clients;
790
        session = traverse_connections(session);
Per Cederqvist's avatar
Per Cederqvist committed
791
792
793
794
795
    }

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

796
797
798
    i = 0;
    session = traverse_connections(0);
    while (session != 0 && i < no_of_clients)
Per Cederqvist's avatar
Per Cederqvist committed
799
800
801
    {
	cptr = get_conn_by_number(session);

802
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
Per Cederqvist's avatar
Per Cederqvist committed
803
	{
804
	    init_who_info_old(&result->info[ i ]);
Per Cederqvist's avatar
Per Cederqvist committed
805
806
	    result->info[ i ].person = cptr->pers_no;
	    result->info[ i ].what_am_i_doing = cptr->what_am_i_doing;
807
808
	    result->info[i].working_conference = filter_conf_no(
		cptr->cwc, active_connection);
Per Cederqvist's avatar
Per Cederqvist committed
809
810
	    ++i;
	}
811
        session = traverse_connections(session);
Per Cederqvist's avatar
Per Cederqvist committed
812
813
814
    }
    
    if ( i != no_of_clients )
David Byers's avatar
David Byers committed
815
	kom_log("who_is_on_old: i == %d, no_of_clients == %d\n",
Per Cederqvist's avatar
Per Cederqvist committed
816
817
818
819
820
821
822
823
824
	    i, no_of_clients);

    return OK;
}

/*
 * Ask the server what it thinks the time is.
 */
extern Success
825
get_time( time_t *clk )
Per Cederqvist's avatar
Per Cederqvist committed
826
{
David Byers's avatar
Server  
David Byers committed
827
    CHK_CONNECTION(FAILURE);
828
    *clk = current_time.tv_sec;
Per Cederqvist's avatar
Per Cederqvist committed
829
830
831
832
833
834
835
    
    return OK;
}



/*
836
 * Set ena_level. 0 means don't use any privileges.
Per Cederqvist's avatar
Per Cederqvist committed
837
838
839
840
 */
extern Success
enable (u_char ena_level)
{
David Byers's avatar
Server  
David Byers committed
841
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
842
843
844
845
    CHK_LOGIN(FAILURE);
    active_connection->ena_level = ena_level;
    return OK;
}
Per Cederqvist's avatar
Per Cederqvist committed
846
847
848
849
850

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

David Byers's avatar
David Byers committed
853
854
    if (s_strlen(client_name) > param.client_data_len
	|| s_strlen(client_version) > param.client_data_len)
Per Cederqvist's avatar
Per Cederqvist committed
855
    {
David Byers's avatar
David Byers committed
856
        err_stat = param.client_data_len;
Per Cederqvist's avatar
Per Cederqvist committed
857
858
859
	kom_errno = KOM_LONG_STR;
	return FAILURE;
    }
860
861
862
863
864
865
866
    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
867
868
869
870
871
872
873
874
875
876
877
878

    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
879
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
880
881
882
883
884
885
886
887
888
889
890
    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

    if ( cptr != NULL )
    {
	*result = cptr->client_name;
	return OK;
    }
    else
    {
891
        err_stat = session_no;
Per Cederqvist's avatar
Per Cederqvist committed
892
893
894
895
896
897
898
899
900
901
902
	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
903
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
904
905
906
907
908
909
910
911
912
913
914
    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

    if ( cptr != NULL )
    {
	*result = cptr->client_version;
	return OK;
    }
    else
    {
915
        err_stat = session_no;
Per Cederqvist's avatar
Per Cederqvist committed
916
917
918
919
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}
920
921
922
923
924
925


extern Success
accept_async(Number_list *num_list)
{
    int         i;
926
    Success     result;
927
    int		found;
928
929
    

David Byers's avatar
Server  
David Byers committed
930
931
    CHK_CONNECTION(FAILURE);
    
932
    result = OK;
933
934

    /*
935
     * Check against maliciously long arrays.
936
     */
937
    if (num_list->length > param.accept_async_len)
938
    {
939
        err_stat = 0;
940
        kom_errno = KOM_LONG_ARRAY;
941
942
943
944
945
946
947
948
949
950
        return FAILURE;
    }


    /*
     * Clear the accept list
     */
    
    for (i = 0; i < ay_dummy_last; i++)
    {
951
        active_connection->want_async[i] = FALSE;
952
953
954
955
    }


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

1005
    return result;
1006
1007
1008
1009
1010
1011
}


extern Success
query_async(Number_list *result)
{
1012
    /* (This static buffer is mentioned in async.h). */
1013
1014
1015
    static long        temp[ay_dummy_last];
    int         i;

David Byers's avatar
Server  
David Byers committed
1016
    CHK_CONNECTION(FAILURE);
1017
1018
1019
    result->length = 0;
    for (i = 0; i < ay_dummy_last; i++)
    {
1020
        if (active_connection->want_async[i] != FALSE)
1021
1022
1023
1024
1025
1026
1027
1028
1029
        {
            temp[result->length] = i;
            result->length += 1;
        }
    }
    result->data = temp;

    return OK;
}
1030
1031
1032
1033

extern Success
user_active(void)
{
David Byers's avatar
Server  
David Byers committed
1034
    CHK_CONNECTION(FAILURE);
1035
    active_connection->active_time = current_time;
1036
    active_connection->flags.user_active_used = TRUE;
1037
1038
    return OK;
}