session.c 24.4 KB
Newer Older
Linus Tolke's avatar
Linus Tolke committed
1
/*
David Byers's avatar
David Byers committed
2
 * $Id: session.c,v 0.47 1999/05/18 13:07:01 byers Exp $
Per Cederqvist's avatar
Per Cederqvist committed
3
 * Copyright (C) 1991, 1992, 1993, 1994, 1996  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

36
static const char *
David Byers's avatar
David Byers committed
37
rcsid = "$Id: session.c,v 0.47 1999/05/18 13:07:01 byers Exp $";
38
39
#include "rcs.h"
USE(rcsid);
Per Cederqvist's avatar
Per Cederqvist committed
40

Per Cederqvist's avatar
Per Cederqvist committed
41
42
#include <stdio.h>
#include <setjmp.h>
43
44
45
#ifdef HAVE_STDARG_H
#  include <stdarg.h>
#endif
Per Cederqvist's avatar
Per Cederqvist committed
46
#include <time.h>
Per Cederqvist's avatar
Per Cederqvist committed
47
#include <sys/types.h>
Per Cederqvist's avatar
Per Cederqvist committed
48

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

/*
 * 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)
{
79
    if ( s_strcpy(result, connection->username) != OK )
80
81
82
83
84
	restart_kom("create_oldstyle_username(): strcpy\n");

    if ( s_strcat(result, s_fcrea_str((const unsigned char *)"@")) != OK )
	restart_kom("create_oldstyle_username: s_strcat\n");

85
    if ( s_strcat(result, connection->hostname) != OK )
86
87
88
	restart_kom("prot_a_parse_packet: s_strcat II\n");
}

Per Cederqvist's avatar
Per Cederqvist committed
89
90
/*
 * This function is called whenever a person leaves a conf,
91
 * i e when he change_conference():s or logout():s.
Per Cederqvist's avatar
Per Cederqvist committed
92
93
94
95
96
97
98
99
100
101
102
103
 */

extern void
leave_conf(void)
{
    Membership * mship;

    if (active_connection->cwc != 0 )
    {
	if ((mship = locate_membership( active_connection->cwc, ACT_P ))
	    != NULL )
	{
104
	    mship->last_time_read = current_time;
Per Cederqvist's avatar
Per Cederqvist committed
105
106
107
108
	    mark_person_as_changed (active_connection->pers_no);
	}
	else
	{
David Byers's avatar
David Byers committed
109
	    kom_log("ERROR: leave_conf(): Can't find membership of cwc.\n");
Per Cederqvist's avatar
Per Cederqvist committed
110
111
112
113
114
115
116
117
118
119
120
121
122
	}
	
	cached_unlock_conf( active_connection->cwc );
	active_connection->cwc = 0;
    }
}

/*
 * 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
123
124
login_old (Pers_no       pers_no,
	   const String  passwd)
Per Cederqvist's avatar
Per Cederqvist committed
125
126
127
128
{
    Person *pers_p;

    GET_P_STAT(pers_p, pers_no, FAILURE);
129

Per Cederqvist's avatar
Per Cederqvist committed
130
131
132
#if 0
    if ( !logins_allowed  && !pers_p->privileges.wheel)
    {
133
        err_stat = 0;
Per Cederqvist's avatar
Per Cederqvist committed
134
135
136
137
138
	kom_errno = KOM_LOGIN_DISALLOWED;
	return FAILURE;
    }
#endif
    
139
140
141
    if ( !is_supervisor(pers_no, NULL, ACTPERS, ACT_P) &&
         !ENA(wheel, 8) &&
         chk_passwd(pers_p->pwd, passwd) == FAILURE )
Per Cederqvist's avatar
Per Cederqvist committed
142
    {
143
        err_stat = pers_no;
Per Cederqvist's avatar
Per Cederqvist committed
144
145
146
147
	kom_errno = KOM_PWD;
	return FAILURE;
    }

148
    logout();	/*FIXME: How many tries are allowed before disconnection? */
Per Cederqvist's avatar
Per Cederqvist committed
149

150
    active_connection->flags.invisible = FALSE;
151

Per Cederqvist's avatar
Per Cederqvist committed
152
153
154
155
156
    ACTPERS = pers_no;
    ACT_P   = pers_p;

    cached_lock_person(pers_no);
        
157
    pers_p->last_login = active_connection->session_start = current_time;
Per Cederqvist's avatar
Per Cederqvist committed
158
159
160
    ++pers_p->sessions;

    s_strcpy(&pers_p->username, active_connection->username);
161
162
163
164
165
166

    /* 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))
    {
Per Cederqvist's avatar
Per Cederqvist committed
167
	if ( s_strcat(&pers_p->username,
168
169
170
		      s_fcrea_str((const unsigned char *)"(")) != OK )
	    restart_kom("login: s_strcat (\n");

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

Per Cederqvist's avatar
Per Cederqvist committed
174
	if ( s_strcat(&pers_p->username,
175
176
177
178
		      s_fcrea_str((const unsigned char *)")")) != OK )
	    restart_kom("login: s_strcat )\n");
    }

Per Cederqvist's avatar
Per Cederqvist committed
179
    if ( s_strcat(&pers_p->username,
180
181
182
		  s_fcrea_str((const unsigned char *)"@")) != OK )
	restart_kom("prot_a_parse_packet: s_strcat\n");

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

Per Cederqvist's avatar
Per Cederqvist committed
186
    mark_person_as_changed( pers_no );
187
188
189
190

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

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

Per Cederqvist's avatar
Per Cederqvist committed
197
198
199
    return OK;
}

200
201
202
203
204
205
206
207
208
209
210
/*
 * 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;
211
    Bool same_person;
212
213
214
215
216
217

    GET_P_STAT(pers_p, pers_no, FAILURE);

#if 0
    if ( !logins_allowed  && !pers_p->privileges.wheel)
    {
218
        err_stat = 0;
219
220
221
222
223
	kom_errno = KOM_LOGIN_DISALLOWED;
	return FAILURE;
    }
#endif
    
224
225
226
    if ( !is_supervisor(pers_no, NULL, ACTPERS, ACT_P) &&
         !ENA(wheel, 8) &&
         chk_passwd(pers_p->pwd, passwd) == FAILURE )
227
    {
228
        err_stat = pers_no;
229
230
231
232
	kom_errno = KOM_PWD;
	return FAILURE;
    }

233
    same_person = (ACTPERS == pers_no) ? TRUE : FALSE;
234

235
236
    logout();	/*+++ How many tries are allowed before disconnection? */

237
    if (invisible)
238
      active_connection->flags.invisible = TRUE;
239
    else
240
      active_connection->flags.invisible = FALSE;
241

242
243
244
    /* 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. */
245
    if (same_person == FALSE)
246
247
	++pers_p->sessions;

248
249
250
251
252
    ACTPERS = pers_no;
    ACT_P   = pers_p;

    cached_lock_person(pers_no);
        
253
    pers_p->last_login = active_connection->session_start = current_time;
254
255
256
257
258
259
260
261

    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))
    {
Per Cederqvist's avatar
Per Cederqvist committed
262
	if ( s_strcat(&pers_p->username,
263
264
265
		      s_fcrea_str((const unsigned char *)"(")) != OK )
	    restart_kom("login: s_strcat (\n");

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

Per Cederqvist's avatar
Per Cederqvist committed
269
	if ( s_strcat(&pers_p->username,
270
271
272
273
		      s_fcrea_str((const unsigned char *)")")) != OK )
	    restart_kom("login: s_strcat )\n");
    }

Per Cederqvist's avatar
Per Cederqvist committed
274
    if ( s_strcat(&pers_p->username,
275
276
277
		  s_fcrea_str((const unsigned char *)"@")) != OK )
	restart_kom("prot_a_parse_packet: s_strcat\n");

Per Cederqvist's avatar
Per Cederqvist committed
278
    if ( s_strcat(&pers_p->username, active_connection->hostname) != OK )
279
280
281
282
	restart_kom("prot_a_parse_packet: s_strcat II\n");

    mark_person_as_changed( pers_no );

283
    if (param.log_login == TRUE && same_person == FALSE)
284
285
    {
	char *id = s_crea_c_str (pers_p->username);
David Byers's avatar
David Byers committed
286
	kom_log ("Login %d %s\n", ACTPERS, id);
287
288
289
	string_free (id);
    }

290
    if (!active_connection->flags.invisible)
291
292
293
294
295
	async_login(ACTPERS, active_connection->session_no);
    
    return OK;
}

Per Cederqvist's avatar
Per Cederqvist committed
296
297
298
299
300
301
302
303
304
305
306

/*
 * 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 )
{
    if ( ACTPERS != 0 )		/* Is he logged in? Then log him out. */
    {
307
	if (!active_connection->flags.invisible)
308
309
310
	{
	    async_logout( ACTPERS, active_connection->session_no );
	}
Per Cederqvist's avatar
Per Cederqvist committed
311
312
	
	leave_conf();
313
	ACT_P->last_login = current_time;
Per Cederqvist's avatar
Per Cederqvist committed
314
	ACT_P->total_time_present +=
315
	    ldifftime(current_time, active_connection->session_start);
Per Cederqvist's avatar
Per Cederqvist committed
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338

	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.
 *
339
340
 * You can change_conference(0) to indicate that you are no longer in
 * a certain conference.
Per Cederqvist's avatar
Per Cederqvist committed
341
342
343
344
345
346
347
348
349
350
351
 *
 * 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
352
 * someone change_conference's to it to allow faster response times.
Per Cederqvist's avatar
Per Cederqvist committed
353
354
 */
extern Success
355
change_conference (Conf_no		conference)		
Per Cederqvist's avatar
Per Cederqvist committed
356
{
357
358
359
    Who_info	 info;
  
    init_who_info(&info);
Per Cederqvist's avatar
Per Cederqvist committed
360
361
362
363
364
365
366
    CHK_LOGIN(FAILURE);
    if (  conference != 0 )
    {
	CHK_EXIST(conference, FAILURE);

	if ( locate_membership( conference, ACT_P) == NULL )
	{
367
            err_stat = conference;
Per Cederqvist's avatar
Per Cederqvist committed
368
369
370
371
372
373
374
375
376
377
378
	    kom_errno = KOM_NOT_MEMBER;
	    return FAILURE;
	}
    }

    leave_conf();
    
    active_connection->cwc = conference;
    if ( conference != 0 )
	cached_lock_conf( conference );

379
    if (!active_connection->flags.invisible)
380
381
382
383
384
    {
	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;
385
386
387
388

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

389
	async_i_am_on(info);
390
391

	s_clear(&info.username);
392
    }
Per Cederqvist's avatar
Per Cederqvist committed
393
394
395
396
397
398
399
400
401
402
403
404
    
    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)
{
405
406
407
    Who_info info;
    
    init_who_info(&info);
Per Cederqvist's avatar
Per Cederqvist committed
408

409
    if ( s_strlen( what_am_i_doing ) > param.what_do_len )
Per Cederqvist's avatar
Per Cederqvist committed
410
411
    {
	s_clear ( &what_am_i_doing );
412
        err_stat = param.what_do_len;
Per Cederqvist's avatar
Per Cederqvist committed
413
414
415
416
417
418
419
	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;

420
    if (!active_connection->flags.invisible)
421
422
423
    {
	info.person = ACTPERS;
	info.what_am_i_doing = active_connection->what_am_i_doing;
424
	create_oldstyle_username(&info.username, active_connection);
425
426
	info.working_conference = active_connection->cwc;
	info.session_no = active_connection->session_no;
Per Cederqvist's avatar
Per Cederqvist committed
427
    
428
	async_i_am_on(info);
429
430

	s_clear(&info.username);
431
    }
Per Cederqvist's avatar
Per Cederqvist committed
432
433
434
435

    return OK;
}

436

Per Cederqvist's avatar
Per Cederqvist committed
437
438
439
440
441
442
443
444
445
446
447
448
449
/*
 * 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;
    
    cptr = active_connection;
    
450
451
    session = traverse_connections(0);
    while (session != 0)
Per Cederqvist's avatar
Per Cederqvist committed
452
453
454
    {
	cptr = get_conn_by_number(session);

455
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
Per Cederqvist's avatar
Per Cederqvist committed
456
	    ++no_of_clients;
457
458

        session = traverse_connections(session);
Per Cederqvist's avatar
Per Cederqvist committed
459
460
461
462
463
    }

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

464
465
466
    i = 0;
    session = traverse_connections(0);
    while ( i < no_of_clients && session != 0)
Per Cederqvist's avatar
Per Cederqvist committed
467
468
469
    {
	cptr = get_conn_by_number(session);

470
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
Per Cederqvist's avatar
Per Cederqvist committed
471
	{
472
	    init_who_info(&result->info[ i ]);
Per Cederqvist's avatar
Per Cederqvist committed
473
474
	    result->info[ i ].person = cptr->pers_no;
	    result->info[ i ].what_am_i_doing = cptr->what_am_i_doing;
475
476
477
478

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

Per Cederqvist's avatar
Per Cederqvist committed
481
482
483
484
	    result->info[ i ].working_conference = cptr->cwc;
	    result->info[ i ].session_no = cptr->session_no;
	    ++i;
	}
485
        session = traverse_connections(session);
Per Cederqvist's avatar
Per Cederqvist committed
486
487
488
    }

    if ( i != no_of_clients )
David Byers's avatar
David Byers committed
489
	kom_log("who_is_on: i == %d, no_of_clients == %d\n",
Per Cederqvist's avatar
Per Cederqvist committed
490
491
492
493
494
	    i, no_of_clients);

    return OK;
}

495
496
497
498
499
500
501
502
503
504
505
506
507
/*
 * 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;
    
    cptr = active_connection;
    
508
509
    session = traverse_connections(0);
    while (session != 0)
510
511
512
    {
	cptr = get_conn_by_number(session);

513
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
514
	    ++no_of_clients;
515
516

        session = traverse_connections(session);
517
518
519
    }

    result->no_of_persons = no_of_clients;
520
    result->info = tmp_alloc ( no_of_clients * sizeof(Who_info_ident));
521

522
523
524
    i = 0;
    session = traverse_connections(0);
    while ( i < no_of_clients && session != 0)
525
526
527
    {
	cptr = get_conn_by_number(session);

528
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
529
	{
530
	    init_who_info_ident(&result->info[i]);
531
532
533
534
535
536
537
538
539
	    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;
	    result->info[i].working_conference = cptr->cwc;
	    result->info[i].session_no = cptr->session_no;
	    ++i;
	}
540
        session = traverse_connections(session);
541
542
543
    }

    if ( i != no_of_clients )
David Byers's avatar
David Byers committed
544
	kom_log("who_is_on_ident: i == %d, no_of_clients == %d\n",
545
546
547
548
549
	    i, no_of_clients);

    return OK;
}

Per Cederqvist's avatar
Per Cederqvist committed
550

551
552
553
554
555
556
/*
 * Get info about what all the currently logged in persons are doing.
 */
extern Success
who_is_on_dynamic(int want_visible,
		  int want_invisible,
557
		  long active_last,
558
559
560
561
562
563
564
565
566
567
		  Dynamic_session_info_list *result)
{
    Connection *cptr;
    long	    no_of_clients = 0;
    long	    i;
    Session_no      session;
    int             include_it = 0;

    cptr = active_connection;

568
569
570

    session = traverse_connections(0);
    while (session != 0)
571
572
573
    {
	cptr = get_conn_by_number(session);

574
	if (cptr->person == NULL || cptr->flags.invisible == TRUE)
575
576
577
578
	    include_it = want_invisible;
	else
	    include_it = want_visible;

579
580
	if (active_last != 0
	    && ldifftime(current_time, cptr->active_time) > active_last
581
582
583
	    && cptr->flags.user_active_used)
	    include_it = 0;

584
585
	if (include_it != 0)
	    ++no_of_clients;
586
587

        session = traverse_connections(session);
588
589
590
591
592
    }

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

593
594
595
    i = 0;
    session = traverse_connections(0);
    while ( i < no_of_clients && session != 0)
596
597
598
    {
	cptr = get_conn_by_number(session);

599
	if (cptr->person == NULL || cptr->flags.invisible == TRUE)
600
601
602
603
	    include_it = want_invisible;
	else
	    include_it = want_visible;
	    
604
605
	if (active_last != 0
	    && ldifftime(current_time, cptr->active_time) > active_last
606
607
608
	    && cptr->flags.user_active_used)
	    include_it = 0;

609
610
611
612
613
614
	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;
	    result->sessions[i].working_conference = cptr->cwc;
615
616
	    result->sessions[i].idle_time = ldifftime(current_time,
						      cptr->active_time);
617

618
619
620
621
622
623
	    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;
624
625
626
627

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

        session = traverse_connections(session);
630
631
632
    }

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

    return OK;
}


Per Cederqvist's avatar
Per Cederqvist committed
640
641
642
643
644
645
646
647
648
649
650
651
extern  Success
get_session_info  (Session_no session_no,
		   Session_info *result)
{
    Connection *cptr;

    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

    if ( cptr != NULL )
    {
652
	init_session_info(result);
Per Cederqvist's avatar
Per Cederqvist committed
653
654
655
656
657
	result->person = cptr->pers_no;
	result->what_am_i_doing = cptr->what_am_i_doing;
	result->working_conference = cptr->cwc;
	result->session = cptr->session_no;
	result->connection_time = cptr->session_start;
658
	result->idle_time = ldifftime(current_time, cptr->active_time);
Per Cederqvist's avatar
Per Cederqvist committed
659

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

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

674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
extern  Success
get_static_session_info (Session_no session_no,
			 Static_session_info *result)
{
    Connection *cptr;

    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
    {
697
        err_stat = session_no;
698
699
700
701
702
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}

703
704
705
706
707
708
709
710
711
712
713
714
extern  Success
get_session_info_ident  (Session_no session_no,
			 Session_info_ident *result)
{
    Connection *cptr;

    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

    if ( cptr != NULL )
    {
715
	init_session_info_ident(result);
716
717
718
719
720
	result->person = cptr->pers_no;
	result->what_am_i_doing = cptr->what_am_i_doing;
	result->working_conference = cptr->cwc;
	result->session = cptr->session_no;
	result->connection_time = cptr->session_start;
721
	result->idle_time = ldifftime(current_time, cptr->active_time);
722
723
724
725
	result->username = cptr->username;
	result->hostname = cptr->hostname;
	result->ident_user = cptr->ident_user;

Per Cederqvist's avatar
Per Cederqvist committed
726
727
728
729
	return OK;
    }
    else
    {
730
        err_stat = session_no;
Per Cederqvist's avatar
Per Cederqvist committed
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}

extern  Success
who_am_i (Session_no *session_no)
{
    *session_no = active_connection->session_no;
    return OK;
}



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

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 ||
760
             ENA(wheel, 8) ||
761
762
             is_supervisor(cptr->pers_no, NULL, ACTPERS, ACT_P) == TRUE
             )
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

    
793
794
    session = traverse_connections(0);
    while (session != 0)
Per Cederqvist's avatar
Per Cederqvist committed
795
796
797
    {
	cptr = get_conn_by_number(session);

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

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

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

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

    return OK;
}

/*
 * Ask the server what it thinks the time is.
 */
extern Success
834
get_time( time_t *clk )
Per Cederqvist's avatar
Per Cederqvist committed
835
{
836
    *clk = current_time;
Per Cederqvist's avatar
Per Cederqvist committed
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
    
    return OK;
}



/*
 * Set ena_level. 0 means don't use any privileges. ///
 */
extern Success
enable (u_char ena_level)
{
    CHK_LOGIN(FAILURE);
    active_connection->ena_level = ena_level;
    return OK;
}
Per Cederqvist's avatar
Per Cederqvist committed
853
854
855
856
857

extern  Success
set_client_version (const String client_name,
		    const String client_version)
{
David Byers's avatar
David Byers committed
858
859
    if (s_strlen(client_name) > param.client_data_len
	|| s_strlen(client_version) > param.client_data_len)
Per Cederqvist's avatar
Per Cederqvist committed
860
    {
David Byers's avatar
David Byers committed
861
        err_stat = param.client_data_len;
Per Cederqvist's avatar
Per Cederqvist committed
862
863
864
	kom_errno = KOM_LONG_STR;
	return FAILURE;
    }
865
866
867
868
869
870
871
    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
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894

    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;

    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

    if ( cptr != NULL )
    {
	*result = cptr->client_name;
	return OK;
    }
    else
    {
895
        err_stat = session_no;
Per Cederqvist's avatar
Per Cederqvist committed
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}

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

    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

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


extern Success
accept_async(Number_list *num_list)
{
    int         i;
929
    Success     result;
930
    int		found;
931
932
933
    

    result = OK;
934
935
936
937
938

    /*
     * Check agains maliciously long arrays
     */
    
David Byers's avatar
David Byers committed
939
940
941
942
943
    /* FIXME: The following test only needs one branch depending on
       FIXME: which implementation of prot_a_parse_num_list we go with. */

    if (num_list->length > param.accept_async_len ||
        (num_list->data == NULL && num_list->length > 0))
944
    {
945
        err_stat = 0;
946
        kom_errno = KOM_LONG_ARRAY;
947
948
949
950
951
952
953
954
955
956
        return FAILURE;
    }


    /*
     * Clear the accept list
     */
    
    for (i = 0; i < ay_dummy_last; i++)
    {
957
        active_connection->want_async[i] = FALSE;
958
959
960
961
    }


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

1007
    return result;
1008
1009
1010
1011
1012
1013
}


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

    result->length = 0;
    for (i = 0; i < ay_dummy_last; i++)
    {
1021
        if (active_connection->want_async[i] != FALSE)
1022
1023
1024
1025
1026
1027
1028
1029
1030
        {
            temp[result->length] = i;
            result->length += 1;
        }
    }
    result->data = temp;

    return OK;
}
1031
1032
1033
1034

extern Success
user_active(void)
{
1035
    active_connection->active_time = current_time;
1036
    active_connection->flags.user_active_used = TRUE;
1037
1038
    return OK;
}