session.c 24.4 KB
Newer Older
Linus Tolke's avatar
Linus Tolke committed
1
/*
2
 * $Id: session.c,v 0.62 2001/12/28 19:25:41 ceder Exp $
Per Cederqvist's avatar
Per Cederqvist committed
3
 * Copyright (C) 1991-1994, 1996-2000  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>
Per Cederqvist's avatar
Per Cederqvist committed
38
#include <time.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
49
50
51
#include "internal-connections.h"
#include "manipulate.h"
#include "lyskomd.h"
#include "kom-errno.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
62
63
64
65
66
67
68
69
70

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

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

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

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

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

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

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

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

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

134
    active_connection->flags.invisible = FALSE;
135

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

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

    s_strcpy(&pers_p->username, active_connection->username);
145
146
147
148
149
150

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

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

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

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

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

Per Cederqvist's avatar
Per Cederqvist committed
167
    mark_person_as_changed( pers_no );
168
169
170
171

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

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

Per Cederqvist's avatar
Per Cederqvist committed
178
179
180
    return OK;
}

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

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

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

206
    same_person = (ACTPERS == pers_no) ? TRUE : FALSE;
207

208
    logout();
209

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

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

221
222
223
224
225
    ACTPERS = pers_no;
    ACT_P   = pers_p;

    cached_lock_person(pers_no);
        
226
    pers_p->last_login = active_connection->session_start = current_time;
227
228
229
230
231
232
233
234

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

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

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

246
    if ( s_strcat(&pers_p->username, s_fcrea_str("@")) != OK )
247
248
	restart_kom("prot_a_parse_packet: s_strcat\n");

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

    mark_person_as_changed( pers_no );

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

261
    if (!active_connection->flags.invisible)
262
263
264
265
266
	async_login(ACTPERS, active_connection->session_no);
    
    return OK;
}

Per Cederqvist's avatar
Per Cederqvist committed
267
268
269
270
271
272
273
274
275

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

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

Per Cederqvist's avatar
Per Cederqvist committed
334
335
336
337
338
339
    if (  conference != 0 )
    {
	CHK_EXIST(conference, FAILURE);

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

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

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

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

363
	async_i_am_on(info);
364
365

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

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

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

	s_clear(&info.username);
406
    }
Per Cederqvist's avatar
Per Cederqvist committed
407
408
409
410

    return OK;
}

411

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

Per Cederqvist's avatar
Per Cederqvist committed
425
    cptr = active_connection;
426
427
    session = traverse_connections(0);
    while (session != 0)
Per Cederqvist's avatar
Per Cederqvist committed
428
429
430
    {
	cptr = get_conn_by_number(session);

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

        session = traverse_connections(session);
Per Cederqvist's avatar
Per Cederqvist committed
435
436
437
438
439
    }

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

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

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

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

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

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

    return OK;
}

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

485
    cptr = active_connection;
486
487
    session = traverse_connections(0);
    while (session != 0)
488
489
490
    {
	cptr = get_conn_by_number(session);

491
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
492
	    ++no_of_clients;
493
494

        session = traverse_connections(session);
495
496
497
    }

    result->no_of_persons = no_of_clients;
498
    result->info = tmp_alloc ( no_of_clients * sizeof(Who_info_ident));
499

500
501
502
    i = 0;
    session = traverse_connections(0);
    while ( i < no_of_clients && session != 0)
503
504
505
    {
	cptr = get_conn_by_number(session);

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

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

    return OK;
}

Per Cederqvist's avatar
Per Cederqvist committed
529

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

552
	if (cptr->person == NULL || cptr->flags.invisible == TRUE)
553
554
555
556
	    include_it = want_invisible;
	else
	    include_it = want_visible;

557
558
	if (active_last != 0
	    && ldifftime(current_time, cptr->active_time) > active_last
559
560
561
	    && cptr->flags.user_active_used)
	    include_it = 0;

562
563
	if (include_it != 0)
	    ++no_of_clients;
564
565

        session = traverse_connections(session);
566
567
568
569
570
    }

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

571
572
573
    i = 0;
    session = traverse_connections(0);
    while ( i < no_of_clients && session != 0)
574
575
576
    {
	cptr = get_conn_by_number(session);

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

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

597
598
599
600
601
602
	    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;
603
604
605
606

	    result->sessions[i].what_am_i_doing = cptr->what_am_i_doing;
	    ++i;
	}
607
608

        session = traverse_connections(session);
609
610
611
    }

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

    return OK;
}


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

David Byers's avatar
Server    
David Byers committed
625
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
626
627
628
629
630
631
    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

    if ( cptr != NULL )
    {
632
	init_session_info(result);
Per Cederqvist's avatar
Per Cederqvist committed
633
634
	result->person = cptr->pers_no;
	result->what_am_i_doing = cptr->what_am_i_doing;
635
636
	result->working_conference = filter_conf_no(cptr->cwc,
						    active_connection);
Per Cederqvist's avatar
Per Cederqvist committed
637
638
	result->session = cptr->session_no;
	result->connection_time = cptr->session_start;
639
	result->idle_time = ldifftime(current_time, cptr->active_time);
Per Cederqvist's avatar
Per Cederqvist committed
640

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

	return OK;
    }
    else
    {
649
        err_stat = session_no;
650
651
652
653
654
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}

655
656
657
658
659
660
extern  Success
get_static_session_info (Session_no session_no,
			 Static_session_info *result)
{
    Connection *cptr;

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

	return OK;
    }
    else
    {
679
        err_stat = session_no;
680
681
682
683
684
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}

685
686
687
688
689
690
extern  Success
get_session_info_ident  (Session_no session_no,
			 Session_info_ident *result)
{
    Connection *cptr;

David Byers's avatar
Server    
David Byers committed
691
    CHK_CONNECTION(FAILURE);
692
693
694
695
696
697
    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

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

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

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

    cptr = get_conn_by_number(session_no);

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

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

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

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

793
794
795
    i = 0;
    session = traverse_connections(0);
    while (session != 0 && i < no_of_clients)
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
	{
801
	    init_who_info_old(&result->info[ i ]);
Per Cederqvist's avatar
Per Cederqvist committed
802
803
	    result->info[ i ].person = cptr->pers_no;
	    result->info[ i ].what_am_i_doing = cptr->what_am_i_doing;
804
805
	    result->info[i].working_conference = filter_conf_no(
		cptr->cwc, active_connection);
Per Cederqvist's avatar
Per Cederqvist committed
806
807
	    ++i;
	}
808
        session = traverse_connections(session);
Per Cederqvist's avatar
Per Cederqvist committed
809
810
811
    }
    
    if ( i != no_of_clients )
David Byers's avatar
David Byers committed
812
	kom_log("who_is_on_old: i == %d, no_of_clients == %d\n",
Per Cederqvist's avatar
Per Cederqvist committed
813
814
815
816
817
818
819
820
821
	    i, no_of_clients);

    return OK;
}

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



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

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

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

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

    cptr = get_conn_by_number(session_no);

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

    cptr = get_conn_by_number(session_no);

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


extern Success
accept_async(Number_list *num_list)
{
    int         i;
923
    Success     result;
924
    int		found;
925
926
    

David Byers's avatar
Server    
David Byers committed
927
928
    CHK_CONNECTION(FAILURE);
    
929
    result = OK;
930
931

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


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


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

1001
    return result;
1002
1003
1004
1005
1006
1007
}


extern Success
query_async(Number_list *result)
{
1008
    /* (This static buffer is mentioned in async.h). */
1009
1010
1011
    static long        temp[ay_dummy_last];
    int         i;

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

    return OK;
}
1026
1027
1028
1029

extern Success
user_active(void)
{
David Byers's avatar
Server    
David Byers committed
1030
    CHK_CONNECTION(FAILURE);
1031
    active_connection->active_time = current_time;
1032
    active_connection->flags.user_active_used = TRUE;
1033
1034
    return OK;
}