chk_ar.cpp 17.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
/* chk_ar.cpp */

/* Synchronet ARS checking routine */

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
11
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 *																			*
 * This program 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 2			*
 * of the License, or (at your option) any later version.					*
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#include "sbbs.h"

rswindell's avatar
rswindell committed
40
bool sbbs_t::ar_exp(const uchar **ptrptr, user_t* user, client_t* client)
41
{
42
	bool	result,_not,_or,equal;
43
44
	uint	i,n,artype,age;
	ulong	l;
45
	struct tm tm;
rswindell's avatar
rswindell committed
46
	const char*	p;
47
48
49
50
51
52
53
54

	result = true;

	for(;(**ptrptr);(*ptrptr)++) {

		if((**ptrptr)==AR_ENDNEST)
			break;

55
		_not=_or=equal = false;
56
57

		if((**ptrptr)==AR_OR) {
58
			_or=true;
59
60
			(*ptrptr)++; 
		}
61
62
		
		if((**ptrptr)==AR_NOT) {
63
			_not=true;
64
65
			(*ptrptr)++; 
		}
66
67
68

		if((**ptrptr)==AR_EQUAL) {
			equal=true;
69
70
			(*ptrptr)++; 
		}
71

72
		if((result && _or) || (!result && !_or))
73
74
75
76
			break;

		if((**ptrptr)==AR_BEGNEST) {
			(*ptrptr)++;
rswindell's avatar
rswindell committed
77
			if(ar_exp(ptrptr,user,client))
78
				result=!_not;
79
			else
80
				result=_not;
81
82
83
84
			while((**ptrptr)!=AR_ENDNEST && (**ptrptr)) /* in case of early exit */
				(*ptrptr)++;
			if(!(**ptrptr))
				break;
85
86
			continue; 
		}
87
88
89
90
91
92
93
94
95

		artype=(**ptrptr);
		switch(artype) {
			case AR_ANSI:				/* No arguments */
			case AR_RIP:
			case AR_WIP:
			case AR_LOCAL:
			case AR_EXPERT:
			case AR_SYSOP:
96
97
			case AR_GUEST:
			case AR_QNODE:
98
99
100
			case AR_QUIET:
			case AR_OS2:
			case AR_DOS:
101
102
103
			case AR_WIN32:
			case AR_UNIX:
			case AR_LINUX:
104
105
106
			case AR_ACTIVE:
			case AR_INACTIVE:
			case AR_DELETED:
107
108
109
				break;
			default:
				(*ptrptr)++;
110
111
				break; 
		}
112
113
114
115
116
117

		n=(**ptrptr);
		i=(*(short *)*ptrptr);
		switch(artype) {
			case AR_LEVEL:
				if((equal && user->level!=n) || (!equal && user->level<n))
118
					result=_not;
119
				else
120
					result=!_not;
121
122
				if(!result) {
					noaccess_str=text[NoAccessLevel];
123
124
					noaccess_val=n; 
				}
125
126
127
128
				break;
			case AR_AGE:
				age=getage(&cfg,user->birth);
				if((equal && age!=n) || (!equal && age<n))
129
					result=_not;
130
				else
131
					result=!_not;
132
133
				if(!result) {
					noaccess_str=text[NoAccessAge];
134
135
					noaccess_val=n; 
				}
136
137
138
				break;
			case AR_BPS:
				if((equal && cur_rate!=i) || (!equal && cur_rate<i))
139
					result=_not;
140
				else
141
					result=!_not;
142
143
144
				(*ptrptr)++;
				if(!result) {
					noaccess_str=text[NoAccessBPS];
145
146
					noaccess_val=i; 
				}
147
148
149
				break;
			case AR_ANSI:
				if(!(user->misc&ANSI))
150
151
					result=_not;
				else result=!_not;
152
153
154
				break;
			case AR_RIP:
				if(!(user->misc&RIP))
155
156
					result=_not;
				else result=!_not;
157
158
159
				break;
			case AR_WIP:
				if(!(user->misc&WIP))
160
161
					result=_not;
				else result=!_not;
162
163
164
				break;
			case AR_OS2:
				#ifndef __OS2__
165
					result=_not;
166
				#else
167
					result=!_not;
168
169
				#endif
				break;
170
			case AR_DOS:	/* DOS program support */
deuce's avatar
deuce committed
171
				result=_not;
172
173
174
175
176
				if(startup->options&BBS_OPT_NO_DOS)
					break;
				#if defined(_WIN32) || (defined(__linux__) && defined(USE_DOSEMU)) || defined(__FreeBSD__)
					result=!_not;
				#endif
177
178
179
				break;
			case AR_WIN32:
				#ifndef _WIN32
180
					result=_not;
181
				#else
182
					result=!_not;
183
184
185
186
				#endif
				break;
			case AR_UNIX:
				#ifndef __unix__
187
					result=_not;
188
				#else
189
					result=!_not;
190
191
192
193
				#endif
				break;
			case AR_LINUX:
				#ifndef __linux__
194
					result=_not;
195
				#else
196
					result=!_not;
197
198
				#endif
				break;
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
			case AR_ACTIVE:
				if(user->misc&(DELETED|INACTIVE))
					result=_not;
				else result=!_not;
				break;
			case AR_INACTIVE:
				if(!(user->misc&INACTIVE))
					result=_not;
				else result=!_not;
				break;
			case AR_DELETED:
				if(!(user->misc&DELETED))
					result=_not;
				else result=!_not;
				break;
214
215
			case AR_EXPERT:
				if(!(user->misc&EXPERT))
216
217
					result=_not;
				else result=!_not;
218
219
220
				break;
			case AR_SYSOP:
				if(!SYSOP)
221
222
					result=_not;
				else result=!_not;
223
				break;
224
225
226
227
228
229
230
231
232
233
			case AR_GUEST:
				if(!(user->rest&FLAG('G')))
					result=_not;
				else result=!_not;
				break;
			case AR_QNODE:
				if(!(user->rest&FLAG('Q')))
					result=_not;
				else result=!_not;
				break;
234
235
			case AR_QUIET:
				if(thisnode.status!=NODE_QUIET)
236
237
					result=_not;
				else result=!_not;
238
239
240
				break;
			case AR_LOCAL:
				if(online!=ON_LOCAL)
241
242
					result=_not;
				else result=!_not;
243
244
245
				break;
			case AR_DAY:
				now=time(NULL);
246
247
248
				localtime_r(&now,&tm);
				if((equal && tm.tm_wday!=(int)n) 
					|| (!equal && tm.tm_wday<(int)n))
249
					result=_not;
250
				else
251
					result=!_not;
252
253
				if(!result) {
					noaccess_str=text[NoAccessDay];
254
255
					noaccess_val=n; 
				}
256
257
258
259
260
				break;
			case AR_CREDIT:
				l=(ulong)i*1024UL;
				if((equal && user->cdt+user->freecdt!=l)
					|| (!equal && user->cdt+user->freecdt<l))
261
					result=_not;
262
				else
263
					result=!_not;
264
265
266
				(*ptrptr)++;
				if(!result) {
					noaccess_str=text[NoAccessCredit];
267
268
					noaccess_val=l; 
				}
269
270
271
				break;
			case AR_NODE:
				if((equal && cfg.node_num!=n) || (!equal && cfg.node_num<n))
272
					result=_not;
273
				else
274
					result=!_not;
275
276
				if(!result) {
					noaccess_str=text[NoAccessNode];
277
278
					noaccess_val=n; 
				}
279
280
281
				break;
			case AR_USER:
				if((equal && user->number!=i) || (!equal && user->number<i))
282
					result=_not;
283
				else
284
					result=!_not;
285
286
287
				(*ptrptr)++;
				if(!result) {
					noaccess_str=text[NoAccessUser];
288
289
					noaccess_val=i; 
				}
290
291
292
293
294
295
296
				break;
			case AR_GROUP:
				if((equal
					&& (cursubnum>=cfg.total_subs
						|| cfg.sub[cursubnum]->grp!=i))
					|| (!equal && cursubnum<cfg.total_subs
						&& cfg.sub[cursubnum]->grp<i))
297
					result=_not;
298
				else
299
					result=!_not;
300
301
302
				(*ptrptr)++;
				if(!result) {
					noaccess_str=text[NoAccessGroup];
303
304
					noaccess_val=i+1; 
				}
305
306
307
				break;
			case AR_SUB:
				if((equal && cursubnum!=i) || (!equal && cursubnum<i))
308
					result=_not;
309
				else
310
					result=!_not;
311
312
313
				(*ptrptr)++;
				if(!result) {
					noaccess_str=text[NoAccessSub];
314
315
					noaccess_val=i+1; 
				}
316
317
318
				break;
			case AR_SUBCODE:
				if(cursubnum>=cfg.total_subs
rswindell's avatar
rswindell committed
319
					|| !findstr_in_string(cfg.sub[cursubnum]->code,(char*)*ptrptr))
320
					result=_not;
321
				else
322
					result=!_not;
323
324
325
326
327
328
329
330
331
332
333
				while(*(*ptrptr))
					(*ptrptr)++;
				if(!result)
					noaccess_str=text[NoAccessSub];
				break;
			case AR_LIB:
				if((equal
					&& (curdirnum>=cfg.total_dirs
						|| cfg.dir[curdirnum]->lib!=i))
					|| (!equal && curdirnum<cfg.total_dirs
						&& cfg.dir[curdirnum]->lib<i))
334
					result=_not;
335
				else
336
					result=!_not;
337
338
339
				(*ptrptr)++;
				if(!result) {
					noaccess_str=text[NoAccessLib];
340
341
					noaccess_val=i+1; 
				}
342
343
344
				break;
			case AR_DIR:
				if((equal && curdirnum!=i) || (!equal && curdirnum<i))
345
					result=_not;
346
				else
347
					result=!_not;
348
349
350
				(*ptrptr)++;
				if(!result) {
					noaccess_str=text[NoAccessDir];
351
352
					noaccess_val=i+1; 
				}
353
354
355
				break;
			case AR_DIRCODE:
				if(curdirnum>=cfg.total_dirs
rswindell's avatar
rswindell committed
356
					|| !findstr_in_string(cfg.dir[curdirnum]->code,(char *)*ptrptr))
357
					result=_not;
358
				else
359
					result=!_not;
360
361
362
363
364
365
366
367
				while(*(*ptrptr))
					(*ptrptr)++;
				if(!result)
					noaccess_str=text[NoAccessSub];
				break;
			case AR_EXPIRE:
				now=time(NULL);
				if(!user->expire || now+((long)i*24L*60L*60L)>user->expire)
368
					result=_not;
369
				else
370
					result=!_not;
371
372
373
				(*ptrptr)++;
				if(!result) {
					noaccess_str=text[NoAccessExpire];
374
375
					noaccess_val=i; 
				}
376
377
				break;
			case AR_RANDOM:
378
				n=sbbs_random(i+1);
379
				if((equal && n!=i) || (!equal && n<i))
380
					result=_not;
381
				else
382
					result=!_not;
383
384
385
386
387
				(*ptrptr)++;
				break;
			case AR_LASTON:
				now=time(NULL);
				if((now-user->laston)/(24L*60L*60L)<(long)i)
388
					result=_not;
389
				else
390
					result=!_not;
391
392
393
394
				(*ptrptr)++;
				break;
			case AR_LOGONS:
				if((equal && user->logons!=i) || (!equal && user->logons<i))
395
					result=_not;
396
				else
397
					result=!_not;
398
399
400
401
				(*ptrptr)++;
				break;
			case AR_MAIN_CMDS:
				if((equal && main_cmds!=i) || (!equal && main_cmds<i))
402
					result=_not;
403
				else
404
					result=!_not;
405
406
407
408
				(*ptrptr)++;
				break;
			case AR_FILE_CMDS:
				if((equal && xfer_cmds!=i) || (!equal && xfer_cmds<i))
409
					result=_not;
410
				else
411
					result=!_not;
412
413
414
415
				(*ptrptr)++;
				break;
			case AR_TLEFT:
				if(timeleft/60<(ulong)n)
416
					result=_not;
417
				else
418
					result=!_not;
419
420
				if(!result) {
					noaccess_str=text[NoAccessTimeLeft];
421
422
					noaccess_val=n; 
				}
423
424
425
				break;
			case AR_TUSED:
				if((time(NULL)-logontime)/60<(long)n)
426
					result=_not;
427
				else
428
					result=!_not;
429
430
				if(!result) {
					noaccess_str=text[NoAccessTimeUsed];
431
432
					noaccess_val=n; 
				}
433
434
435
				break;
			case AR_TIME:
				now=time(NULL);
436
437
				localtime_r(&now,&tm);
				if((tm.tm_hour*60)+tm.tm_min<(int)i)
438
					result=_not;
439
				else
440
					result=!_not;
441
442
443
				(*ptrptr)++;
				if(!result) {
					noaccess_str=text[NoAccessTime];
444
445
					noaccess_val=i; 
				}
446
				break;
447
			case AR_PCR:	/* post/call ratio (by percentage) */
448
				if(user->logons>user->posts
449
					&& (!user->posts || (100/((float)user->logons/user->posts))<(long)n))
450
					result=_not;
451
				else
452
					result=!_not;
453
454
				if(!result) {
					noaccess_str=text[NoAccessPCR];
455
456
					noaccess_val=n; 
				}
457
				break;
458
			case AR_UDR:	/* up/download byte ratio (by percentage) */
459
460
461
				l=user->dlb;
				if(!l) l=1;
				if(user->dlb>user->ulb
462
					&& (!user->ulb || (100/((float)l/user->ulb))<n))
463
					result=_not;
464
				else
465
					result=!_not;
466
467
				if(!result) {
					noaccess_str=text[NoAccessUDR];
468
469
					noaccess_val=n; 
				}
470
				break;
471
			case AR_UDFR:	/* up/download file ratio (in percentage) */
472
473
474
				i=user->dls;
				if(!i) i=1;
				if(user->dls>user->uls
475
					&& (!user->uls || (100/((float)i/user->uls))<n))
476
					result=_not;
477
				else
478
					result=!_not;
479
480
				if(!result) {
					noaccess_str=text[NoAccessUDFR];
481
482
					noaccess_val=n; 
				}
483
				break;
rswindell's avatar
rswindell committed
484
485
486
487
488
489
490
			case AR_ULS:
				if((equal && user->uls!=i) || (!equal && user->uls<i))
					result=_not;
				else
					result=!_not;
				(*ptrptr)++;
				break;
491
492
493
494
495
496
497
498
499
			case AR_ULK:
				if((equal && (user->ulb/1024)!=i) || (!equal && (user->ulb/1024)<i))
					result=_not;
				else
					result=!_not;
				(*ptrptr)++;
				break;
			case AR_ULM:
				if((equal && (user->ulb/(1024*1024))!=i) || (!equal && (user->ulb/(1024*1024))<i))
rswindell's avatar
rswindell committed
500
501
502
503
504
505
506
507
508
509
510
511
					result=_not;
				else
					result=!_not;
				(*ptrptr)++;
				break;
			case AR_DLS:
				if((equal && user->dls!=i) || (!equal && user->dls<i))
					result=_not;
				else
					result=!_not;
				(*ptrptr)++;
				break;
512
513
514
515
516
517
518
519
520
			case AR_DLK:
				if((equal && user->dlb/1024!=i) || (!equal && user->dlb/1024<i))
					result=_not;
				else
					result=!_not;
				(*ptrptr)++;
				break;
			case AR_DLM:
				if((equal && user->dlb/(1024*1024)!=i) || (!equal && user->dlb/(1024*1024)<i))
rswindell's avatar
rswindell committed
521
522
523
524
525
					result=_not;
				else
					result=!_not;
				(*ptrptr)++;
				break;
526
527
528
			case AR_FLAG1:
				if((!equal && !(user->flags1&FLAG(n)))
					|| (equal && user->flags1!=FLAG(n)))
529
					result=_not;
530
				else
531
					result=!_not;
532
533
				if(!result) {
					noaccess_str=text[NoAccessFlag1];
534
535
					noaccess_val=n; 
				}
536
537
538
539
				break;
			case AR_FLAG2:
				if((!equal && !(user->flags2&FLAG(n)))
					|| (equal && user->flags2!=FLAG(n)))
540
					result=_not;
541
				else
542
					result=!_not;
543
544
				if(!result) {
					noaccess_str=text[NoAccessFlag2];
545
546
					noaccess_val=n; 
				}
547
548
549
550
				break;
			case AR_FLAG3:
				if((!equal && !(user->flags3&FLAG(n)))
					|| (equal && user->flags3!=FLAG(n)))
551
					result=_not;
552
				else
553
					result=!_not;
554
555
				if(!result) {
					noaccess_str=text[NoAccessFlag3];
556
557
					noaccess_val=n; 
				}
558
559
560
561
				break;
			case AR_FLAG4:
				if((!equal && !(user->flags4&FLAG(n)))
					|| (equal && user->flags4!=FLAG(n)))
562
					result=_not;
563
				else
564
					result=!_not;
565
566
				if(!result) {
					noaccess_str=text[NoAccessFlag4];
567
568
					noaccess_val=n; 
				}
569
570
571
572
				break;
			case AR_REST:
				if((!equal && !(user->rest&FLAG(n)))
					|| (equal && user->rest!=FLAG(n)))
573
					result=_not;
574
				else
575
					result=!_not;
576
577
				if(!result) {
					noaccess_str=text[NoAccessRest];
578
579
					noaccess_val=n; 
				}
580
581
582
583
				break;
			case AR_EXEMPT:
				if((!equal && !(user->exempt&FLAG(n)))
					|| (equal && user->exempt!=FLAG(n)))
584
					result=_not;
585
				else
586
					result=!_not;
587
588
				if(!result) {
					noaccess_str=text[NoAccessExempt];
589
590
					noaccess_val=n; 
				}
591
592
593
				break;
			case AR_SEX:
				if(user->sex!=n)
594
					result=_not;
595
				else
596
					result=!_not;
597
598
				if(!result) {
					noaccess_str=text[NoAccessSex];
599
600
					noaccess_val=n; 
				}
601
602
603
				break; 
			case AR_SHELL:
				if(user->shell>=cfg.total_shells
rswindell's avatar
rswindell committed
604
					|| !findstr_in_string(cfg.shell[user->shell]->code,(char*)*ptrptr))
605
606
607
608
609
610
					result=_not;
				else
					result=!_not;
				while(*(*ptrptr))
					(*ptrptr)++;
				break;
611
			case AR_PROT:
rswindell's avatar
rswindell committed
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
				if(client!=NULL)
					p=client->protocol;
				else
					p=user->modem;
				if(!findstr_in_string(p,(char*)*ptrptr))
					result=_not;
				else
					result=!_not;
				while(*(*ptrptr))
					(*ptrptr)++;
				break;
			case AR_HOST:
				if(client!=NULL)
					p=client->host;
				else
					p=user->comp;
				if(!findstr_in_string(p,(char*)*ptrptr))
					result=_not;
				else
					result=!_not;
				while(*(*ptrptr))
					(*ptrptr)++;
				break;
			case AR_IP:
				if(client!=NULL)
					p=client->addr;
				else
deuce's avatar
deuce committed
639
					p=user->ipaddr;
rswindell's avatar
rswindell committed
640
				if(!findstr_in_string(p,(char*)*ptrptr))
641
642
643
644
645
646
					result=_not;
				else
					result=!_not;
				while(*(*ptrptr))
					(*ptrptr)++;
				break;
647
648
		}
	}
649
650
651
	return(result);
}

rswindell's avatar
rswindell committed
652
bool sbbs_t::chk_ar(const uchar *ar, user_t* user, client_t* client)
653
{
654
	const uchar *p;
655
656
657
658

	if(ar==NULL)
		return(true);
	p=ar;
rswindell's avatar
rswindell committed
659
	return(ar_exp(&p,user,client));
660
661
662
663
664
665
666
667
668
669
670
671
}


/****************************************************************************/
/* This function fills the usrsub, usrsubs, usrgrps, curgrp, and cursub     */
/* variables based on the security clearance of the current user (useron)   */
/****************************************************************************/
void sbbs_t::getusrsubs()
{
    uint i,j,k,l;

	for(j=0,i=0;i<cfg.total_grps;i++) {
rswindell's avatar
rswindell committed
672
		if(!chk_ar(cfg.grp[i]->ar,&useron,&client))
673
674
675
			continue;
		for(k=0,l=0;l<cfg.total_subs;l++) {
			if(cfg.sub[l]->grp!=i) continue;
rswindell's avatar
rswindell committed
676
			if(!chk_ar(cfg.sub[l]->ar,&useron,&client))
677
				continue;
678
679
			usrsub[j][k++]=l; 
		}
680
681
682
		usrsubs[j]=k;
		if(!k)          /* No subs accessible in group */
			continue;
683
684
		usrgrp[j++]=i; 
	}
685
	usrgrps=j;
686
687
	if(usrgrps==0)
		return;
688
689
690
691
692
693
694
695
696
697
698
699
700
701
	while((curgrp>=usrgrps || !usrsubs[curgrp]) && curgrp) curgrp--;
	while(cursub[curgrp]>=usrsubs[curgrp] && cursub[curgrp]) cursub[curgrp]--;
}

/****************************************************************************/
/* This function fills the usrdir, usrdirs, usrlibs, curlib, and curdir     */
/* variables based on the security clearance of the current user (useron)   */
/****************************************************************************/
void sbbs_t::getusrdirs()
{
    uint i,j,k,l;

	if(useron.rest&FLAG('T')) {
		usrlibs=0;
702
703
		return; 
	}
704
	for(j=0,i=0;i<cfg.total_libs;i++) {
rswindell's avatar
rswindell committed
705
		if(!chk_ar(cfg.lib[i]->ar,&useron,&client))
706
707
708
			continue;
		for(k=0,l=0;l<cfg.total_dirs;l++) {
			if(cfg.dir[l]->lib!=i) continue;
rswindell's avatar
rswindell committed
709
			if(!chk_ar(cfg.dir[l]->ar,&useron,&client))
710
				continue;
711
712
			usrdir[j][k++]=l; 
		}
713
714
715
		usrdirs[j]=k;
		if(!k)          /* No dirs accessible in lib */
			continue;
716
717
		usrlib[j++]=i; 
	}
718
	usrlibs=j;
719
720
	if(usrlibs==0)
		return;
721
722
723
724
	while((curlib>=usrlibs || !usrdirs[curlib]) && curlib) curlib--;
	while(curdir[curlib]>=usrdirs[curlib] && curdir[curlib]) curdir[curlib]--;
}

725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
uint sbbs_t::getusrgrp(uint subnum)
{
	uint	ugrp;

	if(subnum==INVALID_SUB)
		return(0);

	if(usrgrps<=0)
		return(0);

	for(ugrp=0;ugrp<usrgrps;ugrp++)
		if(usrgrp[ugrp]==cfg.sub[subnum]->grp)
			break;

	return(ugrp+1);
}

uint sbbs_t::getusrsub(uint subnum)
{
	uint	usub;
	uint	ugrp;

	ugrp = getusrgrp(subnum);
	if(ugrp<=0)
		return(0);
750
	ugrp--;
751
752
753
754
755
756
757
	for(usub=0;usub<usrsubs[ugrp];usub++)
		if(usrsub[ugrp][usub]==subnum)
			break;

	return(usub+1);
}

758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
uint sbbs_t::getusrlib(uint dirnum)
{
	uint	ulib;

	if(dirnum == INVALID_DIR)
		return 0;

	if(usrlibs <= 0)
		return 0;

	for(ulib=0; ulib < usrlibs; ulib++)
		if(usrlib[ulib] == cfg.dir[dirnum]->lib)
			break;

	return ulib+1;
}

uint sbbs_t::getusrdir(uint dirnum)
{
	uint	udir;
	uint	ulib;

	ulib = getusrlib(dirnum);
	if(ulib <= 0)
		return 0;
	ulib--;
	for(udir=0; udir < usrdirs[ulib]; udir++)
		if(usrdir[ulib][udir] == dirnum)
			break;

	return udir+1;
}


792
793
int sbbs_t::dir_op(uint dirnum)
{
794
	return(SYSOP || (cfg.dir[dirnum]->op_ar!=NULL && cfg.dir[dirnum]->op_ar[0] && chk_ar(cfg.dir[dirnum]->op_ar,&useron,&client)));
795
796
797
}