Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

str.cpp 32.2 KB
Newer Older
1 2 3 4 5 6
/* Synchronet high-level string i/o routines */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
7
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *																			*
 * 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										*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#include "sbbs.h"

/****************************************************************************/
/* Lists all users who have access to the current sub.                      */
/****************************************************************************/
27
void sbbs_t::userlist(long mode)
28
{
29 30 31
	char	name[256],sort=0;
	char 	tmp[512];
	int		i,j,k,users=0;
32
	char *	line[2500];
33
	user_t	user;
34

35
	if(lastuser(&cfg)<=(sizeof(line)/sizeof(line[0])))
36 37
		sort=yesno(text[SortAlphaQ]);
	if(sort) {
rswindell's avatar
rswindell committed
38 39
		bputs(text[CheckingSlots]); 
	}
40
	else {
rswindell's avatar
rswindell committed
41 42
		CRLF; 
	}
43 44
	j=0;
	k=lastuser(&cfg);
45
	int userfile = openuserdat(&cfg, /* for_modify: */FALSE);
46 47 48 49
	for(i=1;i<=k && !msgabort();i++) {
		if(sort && (online==ON_LOCAL || !rioctl(TXBC)))
			bprintf("%-4d\b\b\b\b",i);
		user.number=i;
rswindell's avatar
rswindell committed
50 51 52 53
		if(fgetuserdat(&cfg, &user, userfile) != 0)
			continue;
		if(user.alias[0] <= ' ')
			continue;
54 55 56 57 58 59
		if(user.misc&(DELETED|INACTIVE))
			continue;
		users++;
		if(mode==UL_SUB) {
			if(!usrgrps)
				continue;
rswindell's avatar
rswindell committed
60
			if(!chk_ar(cfg.grp[usrgrp[curgrp]]->ar,&user,/* client: */NULL))
61
				continue;
rswindell's avatar
rswindell committed
62
			if(!chk_ar(cfg.sub[usrsub[curgrp][cursub[curgrp]]]->ar,&user,/* client: */NULL)
63
				|| (cfg.sub[usrsub[curgrp][cursub[curgrp]]]->read_ar[0]
64
					&& !chk_ar(cfg.sub[usrsub[curgrp][cursub[curgrp]]]->read_ar,&user,/* client: */NULL)))
rswindell's avatar
rswindell committed
65 66
				continue; 
		}
67 68 69 70 71
		else if(mode==UL_DIR) {
			if(user.rest&FLAG('T'))
				continue;
			if(!usrlibs)
				continue;
rswindell's avatar
rswindell committed
72
			if(!chk_ar(cfg.lib[usrlib[curlib]]->ar,&user,/* client: */NULL))
73
				continue;
rswindell's avatar
rswindell committed
74
			if(!chk_ar(cfg.dir[usrdir[curlib][curdir[curlib]]]->ar,&user,/* client: */NULL))
rswindell's avatar
rswindell committed
75 76
				continue; 
		}
77
		if(sort) {
deuce's avatar
deuce committed
78
			if((line[j]=(char *)malloc(128))==0) {
79 80
				errormsg(WHERE,ERR_ALLOC,nulstr,83);
				for(i=0;i<j;i++)
deuce's avatar
deuce committed
81
					free(line[i]);
rswindell's avatar
rswindell committed
82 83
				return; 
			}
84 85
			sprintf(name,"%s #%d",user.alias,i);
			sprintf(line[j],text[UserListFmt],name
86
				,cfg.sys_misc&SM_LISTLOC ? user.location : user.note
87
				,unixtodstr(&cfg,user.laston,tmp)
rswindell's avatar
rswindell committed
88 89
				,user.modem); 
		}
90 91 92
		else {
			sprintf(name,"%s #%u",user.alias,i);
			bprintf(text[UserListFmt],name
93
				,cfg.sys_misc&SM_LISTLOC ? user.location : user.note
94
				,unixtodstr(&cfg,user.laston,tmp)
rswindell's avatar
rswindell committed
95 96 97 98
				,user.modem); 
		}
		j++; 
	}
99
	closeuserdat(userfile);
100 101 102
	if(i<=k) {	/* aborted */
		if(sort)
			for(i=0;i<j;i++)
deuce's avatar
deuce committed
103
				free(line[i]);
rswindell's avatar
rswindell committed
104 105
		return; 
	}
106
	if(!sort) {
rswindell's avatar
rswindell committed
107 108
		CRLF; 
	}
109 110 111 112 113 114 115 116 117 118 119 120 121
	bprintf(text[NTotalUsers],users);
	if(mode==UL_SUB)
		bprintf(text[NUsersOnCurSub],j);
	else if(mode==UL_DIR)
		bprintf(text[NUsersOnCurDir],j);
	if(!sort)
		return;
	CRLF;
	qsort((void *)line,j,sizeof(line[0])
		,(int(*)(const void*, const void*))pstrcmp);
	for(i=0;i<j && !msgabort();i++)
		bputs(line[i]);
	for(i=0;i<j;i++)
deuce's avatar
deuce committed
122
		free(line[i]);
123 124 125 126 127 128 129
}

/****************************************************************************/
/* SIF input function. See SIF.DOC for more info        					*/
/****************************************************************************/
void sbbs_t::sif(char *fname, char *answers, long len)
{
deuce's avatar
deuce committed
130
	char	str[256],tmplt[256],*buf;
131 132 133 134
	uint	t,max,min,mode,cr;
	int		file;
	long	length,l=0,m,top,a=0;

135
	sprintf(str,"%s%s.sif",cfg.text_dir,fname);
136 137 138
	if((file=nopen(str,O_RDONLY))==-1) {
		errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
		answers[0]=0;
rswindell's avatar
rswindell committed
139 140
		return; 
	}
141
	length=(long)filelength(file);
142
	if((buf=(char *)calloc(length + 1, 1))==0) {
143 144 145
		close(file);
		errormsg(WHERE,ERR_ALLOC,str,length);
		answers[0]=0;
rswindell's avatar
rswindell committed
146 147
		return; 
	}
148 149
	if(lread(file,buf,length)!=length) {
		close(file);
rswindell's avatar
rswindell committed
150
		free(buf);
151 152
		errormsg(WHERE,ERR_READ,str,length);
		answers[0]=0;
rswindell's avatar
rswindell committed
153 154
		return; 
	}
155 156 157 158 159 160 161 162
	close(file);
	while(l<length && online) {
		mode=min=max=t=cr=0;
		top=l;
		while(l<length && buf[l++]!=STX);
		for(m=l;m<length;m++)
			if(buf[m]==ETX || !buf[m]) {
				buf[m]=0;
rswindell's avatar
rswindell committed
163 164
				break; 
			}
165 166 167
		if(l>=length) break;
		if(online==ON_REMOTE) {
			rioctl(IOCM|ABORT);
rswindell's avatar
rswindell committed
168 169
			rioctl(IOCS|ABORT); 
		}
170 171 172 173 174 175 176 177 178
		putmsg(buf+l,P_SAVEATR);
		m++;
		if(toupper(buf[m])!='C' && toupper(buf[m])!='S')
			continue;
		SYNC;
		if(online==ON_REMOTE)
			rioctl(IOSM|ABORT);
		if(a>=len) {
			errormsg(WHERE,ERR_LEN,fname,len);
rswindell's avatar
rswindell committed
179 180
			break; 
		}
181 182 183
		if((buf[m]&0xdf)=='C') {
    		if((buf[m+1]&0xdf)=='U') {		/* Uppercase only */
				mode|=K_UPPER;
rswindell's avatar
rswindell committed
184 185
				m++; 
			}
186 187
			else if((buf[m+1]&0xdf)=='N') {	/* Numbers only */
				mode|=K_NUMBER;
rswindell's avatar
rswindell committed
188 189
				m++; 
			}
190
			if((buf[m+1]&0xdf)=='L') {		/* Draw line */
191
        		if(term_supports(COLOR))
192 193
					attr(cfg.color[clr_inputline]);
				else
194
					attr(BLACK|BG_LIGHTGRAY);
195
				bputs(" \b");
rswindell's avatar
rswindell committed
196 197
				m++; 
			}
198 199
			if((buf[m+1]&0xdf)=='R') {		/* Add CRLF */
				cr=1;
rswindell's avatar
rswindell committed
200 201
				m++; 
			}
202 203 204 205 206
			if(buf[m+1]=='"') {
				m+=2;
				for(l=m;l<length;l++)
					if(buf[l]=='"') {
						buf[l]=0;
rswindell's avatar
rswindell committed
207 208 209 210
						break; 
					}
				answers[a++]=(char)getkeys((char *)buf+m,0); 
			}
211 212 213 214
			else {
				answers[a]=getkey(mode);
				outchar(answers[a++]);
				attr(LIGHTGRAY);
rswindell's avatar
rswindell committed
215 216
				CRLF; 
			}
217 218
			if(cr) {
				answers[a++]=CR;
rswindell's avatar
rswindell committed
219 220 221
				answers[a++]=LF; 
			} 
		}
222 223 224
		else if((buf[m]&0xdf)=='S') {		/* String */
			if((buf[m+1]&0xdf)=='U') {		/* Uppercase only */
				mode|=K_UPPER;
rswindell's avatar
rswindell committed
225 226
				m++; 
			}
227 228
			else if((buf[m+1]&0xdf)=='F') { /* Force Upper/Lowr case */
				mode|=K_UPRLWR;
rswindell's avatar
rswindell committed
229 230
				m++; 
			}
231 232
			else if((buf[m+1]&0xdf)=='N') {	/* Numbers only */
				mode|=K_NUMBER;
rswindell's avatar
rswindell committed
233 234
				m++; 
			}
235 236
			if((buf[m+1]&0xdf)=='L') {		/* Draw line */
				mode|=K_LINE;
rswindell's avatar
rswindell committed
237 238
				m++; 
			}
239 240
			if((buf[m+1]&0xdf)=='R') {		/* Add CRLF */
				cr=1;
rswindell's avatar
rswindell committed
241 242
				m++; 
			}
243
			if(IS_DIGIT(buf[m+1])) {
244
				max=buf[++m]&0xf;
245
				if(IS_DIGIT(buf[m+1]))
rswindell's avatar
rswindell committed
246 247
					max=max*10+(buf[++m]&0xf); 
			}
248
			if(buf[m+1]=='.' && IS_DIGIT(buf[m+2])) {
249 250
				m++;
				min=buf[++m]&0xf;
251
				if(IS_DIGIT(buf[m+1]))
rswindell's avatar
rswindell committed
252 253
					min=min*10+(buf[++m]&0xf); 
			}
254 255 256 257 258 259
			if(buf[m+1]=='"') {
				m++;
				mode&=~K_NUMBER;
				while(buf[++m]!='"' && t<80)
					tmplt[t++]=buf[m];
				tmplt[t]=0;
rswindell's avatar
rswindell committed
260 261
				max=strlen(tmplt); 
			}
262 263 264
			if(t) {
				if(gettmplt(str,tmplt,mode)<min) {
					l=top;
rswindell's avatar
rswindell committed
265 266 267
					continue; 
				} 
			}
268 269 270 271 272
			else {
				if(!max)
					continue;
				if(getstr(str,max,mode)<min) {
					l=top;
rswindell's avatar
rswindell committed
273 274 275
					continue; 
				} 
			}
276 277 278 279 280
			if(!cr) {
				for(cr=0;str[cr];cr++)
					answers[a+cr]=str[cr];
				while(cr<max)
					answers[a+cr++]=ETX;
rswindell's avatar
rswindell committed
281 282
				a+=max; 
			}
283 284 285
			else {
				putrec(answers,a,max,str);
				putrec(answers,a+max,2,crlf);
rswindell's avatar
rswindell committed
286 287 288 289
				a+=max+2; 
			} 
		} 
	}
290
	answers[a]=0;
deuce's avatar
deuce committed
291
	free((char *)buf);
292 293 294 295 296 297 298
}

/****************************************************************************/
/* SIF output function. See SIF.DOC for more info        					*/
/****************************************************************************/
void sbbs_t::sof(char *fname, char *answers, long len)
{
deuce's avatar
deuce committed
299
	char str[256],*buf,max,min,cr;
300 301 302
	int file;
	long length,l=0,m,a=0;

303
	sprintf(str,"%s%s.sif",cfg.text_dir,fname);
304 305 306
	if((file=nopen(str,O_RDONLY))==-1) {
		errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
		answers[0]=0;
rswindell's avatar
rswindell committed
307 308
		return; 
	}
309
	length=(long)filelength(file);
310
	if((buf=(char *)calloc(length + 1, 1))==0) {
311 312 313
		close(file);
		errormsg(WHERE,ERR_ALLOC,str,length);
		answers[0]=0;
rswindell's avatar
rswindell committed
314 315
		return; 
	}
316 317 318 319
	if(lread(file,buf,length)!=length) {
		close(file);
		errormsg(WHERE,ERR_READ,str,length);
		answers[0]=0;
rswindell's avatar
rswindell committed
320
		free(buf);
rswindell's avatar
rswindell committed
321 322
		return; 
	}
323 324 325 326 327 328 329
	close(file);
	while(l<length && online) {
		min=max=cr=0;
		while(l<length && buf[l++]!=STX);
		for(m=l;m<length;m++)
			if(buf[m]==ETX || !buf[m]) {
				buf[m]=0;
rswindell's avatar
rswindell committed
330 331
				break; 
			}
332 333 334
		if(l>=length) break;
		if(online==ON_REMOTE) {
			rioctl(IOCM|ABORT);
rswindell's avatar
rswindell committed
335 336
			rioctl(IOCS|ABORT); 
		}
337 338 339 340 341 342 343 344 345 346
		putmsg(buf+l,P_SAVEATR);
		m++;
		if(toupper(buf[m])!='C' && toupper(buf[m])!='S')
			continue;
		SYNC;
		if(online==ON_REMOTE)
			rioctl(IOSM|ABORT);
		if(a>=len) {
			bprintf("\r\nSOF: %s defined more data than buffer size "
				"(%lu bytes)\r\n",fname,len);
rswindell's avatar
rswindell committed
347 348
			break; 
		}
349 350 351 352 353 354
		if((buf[m]&0xdf)=='C') {
			if((buf[m+1]&0xdf)=='U')  		/* Uppercase only */
				m++;
			else if((buf[m+1]&0xdf)=='N')  	/* Numbers only */
				m++;
			if((buf[m+1]&0xdf)=='L') {		/* Draw line */
355
        		if(term_supports(COLOR))
356 357
					attr(cfg.color[clr_inputline]);
				else
358
					attr(BLACK|BG_LIGHTGRAY);
359
				bputs(" \b");
rswindell's avatar
rswindell committed
360 361
				m++; 
			}
362 363
			if((buf[m+1]&0xdf)=='R') {		/* Add CRLF */
				cr=1;
rswindell's avatar
rswindell committed
364 365
				m++; 
			}
366 367 368 369
			outchar(answers[a++]);
			attr(LIGHTGRAY);
			CRLF;
			if(cr)
rswindell's avatar
rswindell committed
370 371
				a+=2; 
		}
372 373 374 375 376 377 378 379
		else if((buf[m]&0xdf)=='S') {		/* String */
			if((buf[m+1]&0xdf)=='U')
				m++;
			else if((buf[m+1]&0xdf)=='F')
				m++;
			else if((buf[m+1]&0xdf)=='N')   /* Numbers only */
				m++;
			if((buf[m+1]&0xdf)=='L') {
380
        		if(term_supports(COLOR))
381 382
					attr(cfg.color[clr_inputline]);
				else
383
					attr(BLACK|BG_LIGHTGRAY);
rswindell's avatar
rswindell committed
384 385
				m++; 
			}
386 387
			if((buf[m+1]&0xdf)=='R') {
				cr=1;
rswindell's avatar
rswindell committed
388 389
				m++; 
			}
390
			if(IS_DIGIT(buf[m+1])) {
391
				max=buf[++m]&0xf;
392
				if(IS_DIGIT(buf[m+1]))
rswindell's avatar
rswindell committed
393 394
					max=max*10+(buf[++m]&0xf); 
			}
395
			if(buf[m+1]=='.' && IS_DIGIT(buf[m+2])) {
396 397
				m++;
				min=buf[++m]&0xf;
398
				if(IS_DIGIT(buf[m+1]))
rswindell's avatar
rswindell committed
399 400
					min=min*10+(buf[++m]&0xf); 
			}
401 402 403 404
			if(buf[m+1]=='"') {
				max=0;
				m++;
				while(buf[++m]!='"' && max<80)
rswindell's avatar
rswindell committed
405 406
					max++; 
			}
407 408 409 410 411 412 413 414 415
			if(!max)
				continue;
			getrec(answers,a,max,str);
			bputs(str);
			attr(LIGHTGRAY);
			CRLF;
			if(!cr)
				a+=max;
			else
rswindell's avatar
rswindell committed
416 417 418
				a+=max+2; 
		} 
	}
deuce's avatar
deuce committed
419
	free((char *)buf);
420 421 422 423 424 425 426 427 428 429
}

/****************************************************************************/
/* Creates data file 'datfile' from input via sif file 'siffile'            */
/****************************************************************************/
void sbbs_t::create_sif_dat(char *siffile, char *datfile)
{
	char *buf;
	int file;

deuce's avatar
deuce committed
430
	if((buf=(char *)malloc(SIF_MAXBUF))==NULL) {
431
		errormsg(WHERE,ERR_ALLOC,siffile,SIF_MAXBUF);
rswindell's avatar
rswindell committed
432 433
		return; 
	}
434
	memset(buf,0,SIF_MAXBUF);	 /* initialize to null */
435 436
	sif(siffile,buf,SIF_MAXBUF);
	if((file=nopen(datfile,O_WRONLY|O_TRUNC|O_CREAT))==-1) {
deuce's avatar
deuce committed
437
		free(buf);
438
		errormsg(WHERE,ERR_OPEN,datfile,O_WRONLY|O_TRUNC|O_CREAT);
rswindell's avatar
rswindell committed
439 440
		return; 
	}
441 442
	write(file,buf,strlen(buf));
	close(file);
deuce's avatar
deuce committed
443
	free(buf);
444 445 446 447 448 449 450 451 452 453 454 455 456
}

/****************************************************************************/
/* Reads data file 'datfile' and displays output via sif file 'siffile'     */
/****************************************************************************/
void sbbs_t::read_sif_dat(char *siffile, char *datfile)
{
	char *buf;
	int file;
	long length;

	if((file=nopen(datfile,O_RDONLY))==-1) {
		errormsg(WHERE,ERR_OPEN,datfile,O_RDONLY);
rswindell's avatar
rswindell committed
457 458
		return; 
	}
459
	length=(long)filelength(file);
460 461
	if(!length) {
		close(file);
rswindell's avatar
rswindell committed
462 463
		return; 
	}
deuce's avatar
deuce committed
464
	if((buf=(char *)malloc(length))==NULL) {
465 466
		close(file);
		errormsg(WHERE,ERR_ALLOC,datfile,length);
rswindell's avatar
rswindell committed
467 468
		return; 
	}
469 470 471
	read(file,buf,length);
	close(file);
	sof(siffile,buf,length);
deuce's avatar
deuce committed
472
	free(buf);
473 474 475 476 477 478 479
}

/****************************************************************************/
/* Get string by template. A=Alpha, N=Number, !=Anything                    */
/* First character MUST be an A,N or !.                                     */
/* Modes - K_LINE and K_UPPER are supported.                                */
/****************************************************************************/
480
size_t sbbs_t::gettmplt(char *strout, const char *templt, long mode)
481 482 483 484 485 486
{
	char	ch,str[256];
	char	tmplt[128];
	uint	t=strlen(templt),c=0;

	sys_status&=~SS_ABORT;
487
	SAFECOPY(tmplt, templt);
488
	strupr(tmplt);
489
	if(term_supports(ANSI)) {
490
		if(mode&K_LINE) {
491
			if(term_supports(COLOR))
492 493
				attr(cfg.color[clr_inputline]);
			else
rswindell's avatar
rswindell committed
494 495
				attr(BLACK|BG_LIGHTGRAY); 
		}
496 497
		while(c<t) {
			if(tmplt[c]=='N' || tmplt[c]=='A' || tmplt[c]=='!')
498
				outchar(' ');
499 500
			else
				outchar(tmplt[c]);
rswindell's avatar
rswindell committed
501 502 503 504
			c++; 
		}
		cursor_left(t); 
	}
505 506
	c=0;
	if(mode&K_EDIT) {
Rob Swindell's avatar
Rob Swindell committed
507
		SAFECOPY(str,strout);
508
		bputs(str);
rswindell's avatar
rswindell committed
509 510
		c=strlen(str); 
	}
511
	while((ch=getkey(mode))!=CR && online && !(sys_status&SS_ABORT)) {
512
		if(ch==BS || ch==DEL) {
513 514 515 516 517
			if(!c)
				continue;
			for(ch=1,c--;c;c--,ch++)
				if(tmplt[c]=='N' || tmplt[c]=='A' || tmplt[c]=='!')
					break;
rswindell's avatar
rswindell committed
518
			cursor_left(ch);
519
			bputs(" \b");
rswindell's avatar
rswindell committed
520 521
			continue; 
		}
522
		if(ch==CTRL_X) {
523
			for(;c;c--) {
524
				outchar(BS);
525 526 527 528
				if(tmplt[c-1]=='N' || tmplt[c-1]=='A' || tmplt[c-1]=='!')
					bputs(" \b"); 
			}
		}
529
		else if(c<t) {
530
			if(tmplt[c]=='N' && !IS_DIGIT(ch))
531
				continue;
532
			if(tmplt[c]=='A' && !IS_ALPHA(ch))
533 534 535 536 537
				continue;
			outchar(ch);
			str[c++]=ch;
			while(c<t && tmplt[c]!='N' && tmplt[c]!='A' && tmplt[c]!='!'){
				str[c]=tmplt[c];
rswindell's avatar
rswindell committed
538 539 540 541
				outchar(tmplt[c++]); 
			} 
		} 
	}
542 543 544 545
	str[c]=0;
	attr(LIGHTGRAY);
	CRLF;
	if(!(sys_status&SS_ABORT))
546
		strcpy(strout,str);	// Not SAFECOPY()able
547 548 549 550 551 552 553
	return(c);
}

/*****************************************************************************/
/* Accepts a user's input to change a new-scan time pointer                  */
/* Returns 0 if input was aborted or invalid, 1 if complete					 */
/*****************************************************************************/
deuce's avatar
deuce committed
554 555 556 557 558 559
bool sbbs_t::inputnstime32(time32_t *dt)
{
	bool retval;
	time_t	tmptime=*dt;

	retval=inputnstime(&tmptime);
560
	*dt=(time32_t)tmptime;
deuce's avatar
deuce committed
561 562 563
	return(retval);
}

564 565 566 567
bool sbbs_t::inputnstime(time_t *dt)
{
	int hour;
	struct tm tm;
568 569
	bool pm=false;
	char str[256];
570 571

	bputs(text[NScanDate]);
572
	bputs(timestr(*dt));
573
	CRLF;
574
	if(localtime_r(dt,&tm)==NULL) {
575 576 577 578 579
		errormsg(WHERE,ERR_CHK,"time ptr",0);
		return(FALSE);
	}

	bputs(text[NScanYear]);
580
	ultoa(tm.tm_year+1900,str,10);
581 582
	if(!getstr(str,4,K_EDIT|K_AUTODEL|K_NUMBER|K_NOCRLF) || sys_status&SS_ABORT) {
		CRLF;
rswindell's avatar
rswindell committed
583 584
		return(false); 
	}
585 586 587
	tm.tm_year=atoi(str);
	if(tm.tm_year<1970) {		/* unix time is seconds since 1/1/1970 */
		CRLF;
rswindell's avatar
rswindell committed
588 589
		return(false); 
	}
590 591 592
	tm.tm_year-=1900;	/* tm_year is years since 1900 */

	bputs(text[NScanMonth]);
593
	ultoa(tm.tm_mon+1,str,10);
594 595
	if(!getstr(str,2,K_EDIT|K_AUTODEL|K_NUMBER|K_NOCRLF) || sys_status&SS_ABORT) {
		CRLF;
rswindell's avatar
rswindell committed
596 597
		return(false); 
	}
598 599 600
	tm.tm_mon=atoi(str);
	if(tm.tm_mon<1 || tm.tm_mon>12) {
		CRLF;
rswindell's avatar
rswindell committed
601 602
		return(false); 
	}
603 604 605
	tm.tm_mon--;		/* tm_mon is zero-based */

	bputs(text[NScanDay]);
606
	ultoa(tm.tm_mday,str,10);
607 608
	if(!getstr(str,2,K_EDIT|K_AUTODEL|K_NUMBER|K_NOCRLF) || sys_status&SS_ABORT) {
		CRLF;
rswindell's avatar
rswindell committed
609 610
		return(false); 
	}
611 612 613
	tm.tm_mday=atoi(str);
	if(tm.tm_mday<1 || tm.tm_mday>31) {
		CRLF;
rswindell's avatar
rswindell committed
614 615
		return(false); 
	}
616 617 618 619 620
	bputs(text[NScanHour]);
	if(cfg.sys_misc&SM_MILITARY)
		hour=tm.tm_hour;
	else {
		if(tm.tm_hour==0) {	/* 12 midnite */
621
			pm=false;
rswindell's avatar
rswindell committed
622 623
			hour=12; 
		}
624 625
		else if(tm.tm_hour>12) {
			hour=tm.tm_hour-12;
rswindell's avatar
rswindell committed
626 627
			pm=true; 
		}
628 629
		else {
			hour=tm.tm_hour;
rswindell's avatar
rswindell committed
630 631 632
			pm=false; 
		} 
	}
633
	ultoa(hour,str,10);
634 635
	if(!getstr(str,2,K_EDIT|K_AUTODEL|K_NUMBER|K_NOCRLF) || sys_status&SS_ABORT) {
		CRLF;
rswindell's avatar
rswindell committed
636 637
		return(false); 
	}
638 639 640
	tm.tm_hour=atoi(str);
	if(tm.tm_hour>24) {
		CRLF;
rswindell's avatar
rswindell committed
641 642
		return(false); 
	}
643 644

	bputs(text[NScanMinute]);
645
	ultoa(tm.tm_min,str,10);
646 647
	if(!getstr(str,2,K_EDIT|K_AUTODEL|K_NUMBER|K_NOCRLF) || sys_status&SS_ABORT) {
		CRLF;
rswindell's avatar
rswindell committed
648 649
		return(false); 
	}
650 651 652 653

	tm.tm_min=atoi(str);
	if(tm.tm_min>59) {
		CRLF;
rswindell's avatar
rswindell committed
654 655
		return(false); 
	}
656 657 658 659
	tm.tm_sec=0;
	if(!(cfg.sys_misc&SM_MILITARY) && tm.tm_hour && tm.tm_hour<13) {
		if(pm && yesno(text[NScanPmQ])) {
				if(tm.tm_hour<12)
rswindell's avatar
rswindell committed
660 661
					tm.tm_hour+=12; 
		}
662 663
		else if(!pm && !yesno(text[NScanAmQ])) {
				if(tm.tm_hour<12)
rswindell's avatar
rswindell committed
664 665
					tm.tm_hour+=12; 
		}
666
		else if(tm.tm_hour==12)
rswindell's avatar
rswindell committed
667 668
			tm.tm_hour=0; 
	}
669
	else {
rswindell's avatar
rswindell committed
670 671
		CRLF; 
	}
672
	tm.tm_isdst=-1;	/* Do not adjust for DST */
673 674 675 676 677 678 679
	*dt=mktime(&tm);
	return(true);
}

/*****************************************************************************/
/* Checks a password for uniqueness and validity                              */
/*****************************************************************************/
680
bool sbbs_t::chkpass(char *passwd, user_t* user, bool unique)
681
{
682 683
	char first[128],last[128],sysop[41],sysname[41],*p;
	int  c, d;
684
	char alias[LEN_ALIAS+1], name[LEN_NAME+1], handle[LEN_HANDLE+1];
685 686 687 688
	char pass[LEN_PASS+1];

	SAFECOPY(pass,passwd);
	strupr(pass);
689

690
	if(strlen(pass) < cfg.min_pwlen) {
691
		bputs(text[PasswordTooShort]);
692
		return(false); 
rswindell's avatar
rswindell committed
693
	}
694 695
	if(!strcmp(pass,user->pass)) {
		bputs(text[PasswordNotChanged]);
696
		return(false); 
rswindell's avatar
rswindell committed
697
	}
698 699 700 701 702 703
	d=strlen(pass);
	for(c=1;c<d;c++)
		if(pass[c]!=pass[c-1])
			break;
	if(c==d) {
		bputs(text[PasswordInvalid]);
704
		return(false); 
rswindell's avatar
rswindell committed
705
	}
706 707 708 709 710
	for(c=0;c<3;c++)	/* check for 1234 and ABCD */
		if(pass[c]!=pass[c+1]+1)
			break;
	if(c==3) {
		bputs(text[PasswordObvious]);
711
		return(false); 
rswindell's avatar
rswindell committed
712
	}
713 714 715 716 717
	for(c=0;c<3;c++)	/* check for 4321 and ZYXW */
		if(pass[c]!=pass[c+1]-1)
			break;
	if(c==3) {
		bputs(text[PasswordObvious]);
718
		return(false); 
rswindell's avatar
rswindell committed
719
	}
720
	SAFECOPY(name,user->name);
721
	strupr(name);
722
	SAFECOPY(alias,user->alias);
723
	strupr(alias);
724
	SAFECOPY(first,alias);
725
	p=strchr(first,' ');
726 727
	if(p) {
		*p=0;
728
		SAFECOPY(last,p+1); 
rswindell's avatar
rswindell committed
729
	}
730 731
	else
		last[0]=0;
732
	SAFECOPY(handle,user->handle);
733
	strupr(handle);
734
	SAFECOPY(sysop,cfg.sys_op);
735
	strupr(sysop);
736
	SAFECOPY(sysname,cfg.sys_name);
737
	strupr(sysname);
738
	if((unique && user->pass[0]
739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762
			&& (strstr(pass,user->pass) || strstr(user->pass,pass)))
		|| (name[0]
			&& (strstr(pass,name) || strstr(name,pass)))
		|| strstr(pass,alias) || strstr(alias,pass)
		|| strstr(pass,first) || strstr(first,pass)
		|| (last[0]
			&& (strstr(pass,last) || strstr(last,pass)))
		|| strstr(pass,handle) || strstr(handle,pass)
		|| (user->zipcode[0]
			&& (strstr(pass,user->zipcode) || strstr(user->zipcode,pass)))
		|| (sysname[0]
			&& (strstr(pass,sysname) || strstr(sysname,pass)))
		|| (sysop[0]
			&& (strstr(pass,sysop) || strstr(sysop,pass)))
		|| (cfg.sys_id[0]
			&& (strstr(pass,cfg.sys_id) || strstr(cfg.sys_id,pass)))
		|| (cfg.node_phone[0] && strstr(pass,cfg.node_phone))
		|| (user->phone[0] && strstr(user->phone,pass))
		|| !strncmp(pass,"QWER",3)
		|| !strncmp(pass,"ASDF",3)
		|| !strncmp(pass,"!@#$",3)
		)
		{
		bputs(text[PasswordObvious]);
763
		return(false); 
rswindell's avatar
rswindell committed
764
	}
765
	return(!trashcan(pass,"password"));
766 767 768 769 770 771 772
}

/****************************************************************************/
/* Displays information about sub-board subnum								*/
/****************************************************************************/
void sbbs_t::subinfo(uint subnum)
{
773
	char str[MAX_PATH+1];
774 775 776 777 778

	bputs(text[SubInfoHdr]);
	bprintf(text[SubInfoLongName],cfg.sub[subnum]->lname);
	bprintf(text[SubInfoShortName],cfg.sub[subnum]->sname);
	bprintf(text[SubInfoQWKName],cfg.sub[subnum]->qwkname);
779 780
	if(cfg.sub[subnum]->maxmsgs)
		bprintf(text[SubInfoMaxMsgs],cfg.sub[subnum]->maxmsgs);
781 782 783 784 785
	if(cfg.sub[subnum]->misc&SUB_QNET)
		bprintf(text[SubInfoTagLine],cfg.sub[subnum]->tagline);
	if(cfg.sub[subnum]->misc&SUB_FIDO)
		bprintf(text[SubInfoFidoNet]
			,cfg.sub[subnum]->origline
786
			,smb_faddrtoa(&cfg.sub[subnum]->faddr,str));
787
	SAFEPRINTF2(str,"%s%s.msg",cfg.sub[subnum]->data_dir,cfg.sub[subnum]->code);
788 789 790 791 792 793 794 795 796
	if(fexist(str) && yesno(text[SubInfoViewFileQ]))
		printfile(str,0);
}

/****************************************************************************/
/* Displays information about transfer directory dirnum 					*/
/****************************************************************************/
void sbbs_t::dirinfo(uint dirnum)
{
797
	char str[MAX_PATH+1];
798 799 800 801 802 803

	bputs(text[DirInfoHdr]);
	bprintf(text[DirInfoLongName],cfg.dir[dirnum]->lname);
	bprintf(text[DirInfoShortName],cfg.dir[dirnum]->sname);
	if(cfg.dir[dirnum]->exts[0])
		bprintf(text[DirInfoAllowedExts],cfg.dir[dirnum]->exts);
804 805
	if(cfg.dir[dirnum]->maxfiles)
		bprintf(text[DirInfoMaxFiles],cfg.dir[dirnum]->maxfiles);
806
	SAFEPRINTF2(str,"%s%s.msg",cfg.dir[dirnum]->data_dir,cfg.dir[dirnum]->code);
807 808 809 810
	if(fexist(str) && yesno(text[DirInfoViewFileQ]))
		printfile(str,0);
}

811 812 813
/****************************************************************************/
/* Searches the file <name>.can in the TEXT directory for matches			*/
/* Returns TRUE if found in list, FALSE if not.								*/
deuce's avatar
deuce committed
814
/* Displays bad<name>.msg in text directory if found.						*/
815
/****************************************************************************/
816
bool sbbs_t::trashcan(const char *insearchof, const char *name)
817
{
818
	char str[MAX_PATH+1];
819 820
	bool result;

821
	result=::trashcan(&cfg, insearchof, name)
rswindell's avatar
rswindell committed
822
		? true:false; // This is a dumb bool conversion to make BC++ happy
823
	if(result) {
824
		sprintf(str,"%sbad%s.msg",cfg.text_dir,name);
825
		if(fexistcase(str)) {
826
			printfile(str,0);
827 828
			mswait(500); // give time for tx buffer to clear before disconnect
		}
829 830 831 832
	}
	return(result);
}

833
char* sbbs_t::timestr(time_t intime)
834
{
835
	return(::timestr(&cfg,(time32_t)intime,timestr_output));
836 837
}

838 839 840 841 842
char* sbbs_t::datestr(time_t t)
{
	return unixtodstr(&cfg, (time32_t)t, datestr_output);
}

843 844 845 846 847 848 849 850 851 852 853
void sbbs_t::sys_info()
{
	char	tmp[128];
	uint	i;
	stats_t stats;

	bputs(text[SiHdr]);
	getstats(&cfg,0,&stats);
	bprintf(text[SiSysName],cfg.sys_name);
	bprintf(text[SiSysID],cfg.sys_id);	/* QWK ID */
	for(i=0;i<cfg.total_faddrs;i++)
854
		bprintf(text[SiSysFaddr],smb_faddrtoa(&cfg.faddr[i],tmp));
855 856
	if(cfg.sys_psname[0])				/* PostLink/PCRelay */
		bprintf(text[SiSysPsite],cfg.sys_psname,cfg.sys_psnum);
857 858
	if(cfg.sys_location[0])
		bprintf(text[SiSysLocation],cfg.sys_location);
859
	bprintf(text[TiNow],timestr(now),smb_zonestr(sys_timezone(&cfg),NULL));
860 861
	if(cfg.sys_op[0])
		bprintf(text[SiSysop],cfg.sys_op);
862 863
	bprintf(text[SiSysNodes],cfg.sys_nodes);
//	bprintf(text[SiNodeNumberName],cfg.node_num,cfg.node_name);
864 865
	if(cfg.node_phone[0])
		bprintf(text[SiNodePhone],cfg.node_phone);
866 867 868 869 870
	bprintf(text[SiTotalLogons],ultoac(stats.logons,tmp));
	bprintf(text[SiLogonsToday],ultoac(stats.ltoday,tmp));
	bprintf(text[SiTotalTime],ultoac(stats.timeon,tmp));
	bprintf(text[SiTimeToday],ultoac(stats.ttoday,tmp));
	ver();
871 872
	const char* fname = "../system";
	if(menu_exists(fname) && text[ViewSysInfoFileQ][0] && yesno(text[ViewSysInfoFileQ])) {
873
		CLS;
874
		menu(fname);
875
	}
876 877
	fname = "logon";
	if(menu_exists(fname) && text[ViewLogonMsgQ][0] && yesno(text[ViewLogonMsgQ])) {
878
		CLS;
879
		menu(fname);
880 881 882 </