logon.cpp 22.3 KB
Newer Older
1 2 3 4 5 6
/* Synchronet user logon 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
 *																			*
 * 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"
#include "cmdshell.h"
24
#include "filedat.h"
25

26
extern "C" void client_on(SOCKET sock, client_t* client, BOOL update);
27 28 29 30 31 32 33 34

/****************************************************************************/
/* Called once upon each user logging on the board							*/
/* Returns 1 if user passed logon, 0 if user failed.						*/
/****************************************************************************/
bool sbbs_t::logon()
{
	char	str[256],c;
35
	char 	tmp[512];
36
	int 	file;
37
	uint	i,j,mailw,mailr;
38
	long	kmode;
39 40 41 42 43
	ulong	totallogons;
	node_t	node;
	struct	tm	tm;

	now=time(NULL);
44
	if(localtime_r(&now,&tm)==NULL)
45 46 47 48 49 50
		return(false);

	if(!useron.number)
		return(false);

	client.user=useron.alias;
51
	client.usernum = useron.number;
52
	client_on(client_socket,&client,TRUE /* update */);
53

54
#ifdef JAVASCRIPT
55
	js_create_user_objects(js_cx, js_glob);
56 57
#endif

58
	if(useron.rest&FLAG('Q'))
59
		sys_status ^= SS_QWKLOGON;
60 61
	if(SYSOP && !(cfg.sys_misc&SM_R_SYSOP)) {
		hangup();
62
		return(false);
63
	}
rswindell's avatar
rswindell committed
64

65 66
	if(useron.rest&FLAG('G')) {     /* Guest account */
		useron.misc=(cfg.new_misc&(~ASK_NSCAN));
67 68
		useron.rows = TERM_ROWS_AUTO;
		useron.cols = TERM_COLS_AUTO;
69
		useron.misc &= ~TERM_FLAGS;
70
		useron.misc|=autoterm;
rswindell's avatar
rswindell committed
71
		if(!(useron.misc&(ANSI|PETSCII)) && text[AnsiTerminalQ][0] && yesno(text[AnsiTerminalQ]))
72
			useron.misc|=ANSI;
73 74
		if((useron.misc&ANSI) && text[MouseTerminalQ][0] && yesno(text[MouseTerminalQ]))
			useron.misc|=MOUSE;
75 76
		if((useron.misc&RIP) || !(cfg.uq&UQ_COLORTERM)
			|| (useron.misc&(ANSI|PETSCII) && yesno(text[ColorTerminalQ])))
77
			useron.misc|=COLOR;
78
		if(!(useron.misc&(NO_EXASCII|PETSCII)) && !yesno(text[ExAsciiTerminalQ]))
79 80 81
			useron.misc|=NO_EXASCII;
		for(i=0;i<cfg.total_xedits;i++)
			if(!stricmp(cfg.xedit[i]->code,cfg.new_xedit)
rswindell's avatar
rswindell committed
82
				&& chk_ar(cfg.xedit[i]->ar,&useron,&client))
83 84 85 86 87 88
				break;
		if(i<cfg.total_xedits)
			useron.xedit=i+1;
		else
			useron.xedit=0;
		useron.prot=cfg.new_prot;
89 90
		useron.shell=cfg.new_shell; 
	}
91

rswindell's avatar
rswindell committed
92
	if(!chk_ar(cfg.node_ar,&useron,&client)) {
93
		bputs(text[NoNodeAccess]);
94
		safe_snprintf(str, sizeof(str), "(%04u)  %-25s  Insufficient node access"
95
			,useron.number,useron.alias);
96
		logline(LOG_NOTICE,"+!",str);
97
		hangup();
98 99
		return(false); 
	}
100 101 102 103 104 105

	getnodedat(cfg.node_num,&thisnode,1);
	if(thisnode.misc&NODE_LOCK) {
		putnodedat(cfg.node_num,&thisnode);	/* must unlock! */
		if(!SYSOP && !(useron.exempt&FLAG('N'))) {
			bputs(text[NodeLocked]);
106
			safe_snprintf(str, sizeof(str), "(%04u)  %-25s  Locked node logon attempt"
107
				,useron.number,useron.alias);
108
			logline(LOG_NOTICE,"+!",str);
109
			hangup();
110 111
			return(false); 
		}
112 113 114
		if(yesno(text[RemoveNodeLockQ])) {
			getnodedat(cfg.node_num,&thisnode,1);
			logline("S-","Removed Node Lock");
115 116
			thisnode.misc&=~NODE_LOCK; 
		}
117
		else
118 119
			getnodedat(cfg.node_num,&thisnode,1); 
	}
120

rswindell's avatar
rswindell committed
121 122 123
	if(useron.exempt&FLAG('H'))
		console|=CON_NO_INACT;

124 125 126 127 128
	if((useron.exempt&FLAG('Q') && useron.misc&QUIET))
		thisnode.status=NODE_QUIET;
	else
		thisnode.status=NODE_INUSE;
	action=thisnode.action=NODE_LOGN;
129
	thisnode.connection=node_connection;
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
	thisnode.misc&=~(NODE_ANON|NODE_INTR|NODE_MSGW|NODE_POFF|NODE_AOFF);
	if(useron.chat&CHAT_NOACT)
		thisnode.misc|=NODE_AOFF;
	if(useron.chat&CHAT_NOPAGE)
		thisnode.misc|=NODE_POFF;
	thisnode.useron=useron.number;
	putnodedat(cfg.node_num,&thisnode);

	getusrsubs();
	getusrdirs();

	if(useron.misc&CURSUB && !(useron.rest&FLAG('G'))) {
		for(i=0;i<usrgrps;i++) {
			for(j=0;j<usrsubs[i];j++) {
				if(!strcmp(cfg.sub[usrsub[i][j]]->code,useron.cursub))
145 146
					break; 
			}
147 148 149
			if(j<usrsubs[i]) {
				curgrp=i;
				cursub[i]=j;
150 151 152
				break; 
			} 
		}
153 154 155 156 157 158 159
		for(i=0;i<usrlibs;i++) {
			for(j=0;j<usrdirs[i];j++)
				if(!strcmp(cfg.dir[usrdir[i][j]]->code,useron.curdir))
					break;
			if(j<usrdirs[i]) {
				curlib=i;
				curdir[i]=j;
160 161 162 163
				break; 
			} 
		} 
	}
164

165
	if((useron.misc & AUTOTERM)
166
		// User manually-enabled PETSCII, but they're logging in with an ANSI (auto-detected) terminal
167 168 169
		|| ((useron.misc & PETSCII) && (autoterm & ANSI))) {
		useron.misc &= ~(ANSI|RIP|CHARSET_FLAGS);
		useron.misc |= (AUTOTERM | autoterm);
170
	}
171

rswindell's avatar
rswindell committed
172
	if(!chk_ar(cfg.shell[useron.shell]->ar,&useron,&client)) {
173
		useron.shell=cfg.new_shell;
rswindell's avatar
rswindell committed
174
		if(!chk_ar(cfg.shell[useron.shell]->ar,&useron,&client)) {
175
			for(i=0;i<cfg.total_shells;i++)
rswindell's avatar
rswindell committed
176
				if(chk_ar(cfg.shell[i]->ar,&useron,&client))
177 178
					break;
			if(i==cfg.total_shells)
179 180 181
				useron.shell=0; 
		} 
	}
182 183 184 185

	logon_ml=useron.level;
	logontime=time(NULL);
	starttime=logontime;
186
	useron.logontime=(time32_t)logontime;
187 188
	last_ns_time=ns_time=useron.ns_time;
	// ns_time-=(useron.tlast*60); /* file newscan time == last logon time */
189
	delfiles(cfg.temp_dir,ALLFILES);
190
	safe_snprintf(str, sizeof(str), "%smsgs/n%3.3u.msg",cfg.data_dir,cfg.node_num);
191
	remove(str);            /* remove any pending node messages */
192
	safe_snprintf(str, sizeof(str), "%smsgs/n%3.3u.ixb",cfg.data_dir,cfg.node_num);
193 194
	remove(str);			/* remove any pending node message indices */

195
	if(!SYSOP && online==ON_REMOTE && !(sys_status&SS_QWKLOGON)) {
196
		rioctl(IOCM|ABORT);	/* users can't abort anything */
197 198
		rioctl(IOCS|ABORT); 
	}
199

200
	bputs(text[LoggingOn]);
201 202 203 204
	if(useron.rows != TERM_ROWS_AUTO)
		rows = useron.rows;
	if(useron.cols != TERM_COLS_AUTO)
		cols = useron.cols;
205
	update_nodeterm();
206
	if(tm.tm_mon + 1 == getbirthmonth(&cfg, useron.birth) && tm.tm_mday == getbirthday(&cfg, useron.birth)
207
		&& !(useron.rest&FLAG('Q'))) {
208 209 210 211 212
		if(text[HappyBirthday][0]) {
			bputs(text[HappyBirthday]);
			pause();
			CLS;
		}
213 214
		user_event(EVENT_BIRTHDAY); 
	}
215
	useron.ltoday++;
216 217

	gettimeleft();
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257

	/* Inform the user of what's in their batch upload queue */
	{
		str_list_t ini = batch_list_read(&cfg, useron.number, XFER_BATCH_UPLOAD);
		str_list_t filenames = iniGetSectionList(ini, NULL);
		for(size_t i = 0; filenames[i] != NULL; i++) {
			const char* filename = filenames[i];
			file_t f = {{}};
			if(batch_file_get(&cfg, ini, filename, &f)) {
				bprintf(text[FileAddedToUlQueue], f.name, i + 1, cfg.max_batup);
				smb_freefilemem(&f);
			} else
				batch_file_remove(&cfg, useron.number, XFER_BATCH_UPLOAD, filename);
		}
		iniFreeStringList(ini);
		iniFreeStringList(filenames);
	}

	/* Inform the user of what's in their batch download queue */
	{
		str_list_t ini = batch_list_read(&cfg, useron.number, XFER_BATCH_DOWNLOAD);
		str_list_t filenames = iniGetSectionList(ini, NULL);
		for(size_t i = 0; filenames[i] != NULL; i++) {
			const char* filename = filenames[i];
			file_t f = {{}};
			if(batch_file_load(&cfg, ini, filename, &f)) {
				char tmp2[256];
				getfilesize(&cfg, &f);
				bprintf(text[FileAddedToBatDlQueue]
					,f.name, i + 1, cfg.max_batdn
					,ultoac((ulong)f.cost,tmp)
					,ultoac((ulong)f.size,tmp2)
					,sectostr((ulong)f.size / (ulong)cur_cps,str));
				smb_freefilemem(&f);
			} else
				batch_file_remove(&cfg, useron.number, XFER_BATCH_DOWNLOAD, filename);
		}
		iniFreeStringList(ini);
		iniFreeStringList(filenames);
	}
258
	if(!(sys_status&SS_QWKLOGON)) { 	 /* QWK Nodes don't go through this */
259

260
		if(cfg.sys_pwdays && useron.pass[0]
261 262 263 264
			&& (ulong)logontime>(useron.pwmod+((ulong)cfg.sys_pwdays*24UL*60UL*60UL))) {
			bprintf(text[TimeToChangePw],cfg.sys_pwdays);

			c=0;
265
			while(c < MAX(RAND_PASS_LEN, cfg.min_pwlen)) { 				/* Create random password */
266
				str[c]=sbbs_random(43)+'0';
267
				if(IS_ALPHANUMERIC(str[c]))
268
					c++;
269
			}
270 271 272 273 274
			str[c]=0;
			bprintf(text[YourPasswordIs],str);

			if(cfg.sys_misc&SM_PWEDIT && yesno(text[NewPasswordQ]))
				while(online) {
275
					bprintf(text[NewPasswordPromptFmt], cfg.min_pwlen, LEN_PASS);
276
					getstr(str,LEN_PASS,K_UPPER|K_LINE|K_TRIM);
277
					truncsp(str);
278
					if(chkpass(str,&useron,true))
279
						break;
280 281
					CRLF; 
				}
282 283 284 285

			while(online) {
				if(cfg.sys_misc&SM_PWEDIT) {
					CRLF;
286 287
					bputs(text[VerifyPassword]); 
				}
288 289 290
				else {
					if(!text[NewUserPasswordVerify][0])
						break;
291
					bputs(text[NewUserPasswordVerify]);
292
				}
293
				console|=CON_R_ECHOX;
294
				getstr(tmp,LEN_PASS*2,K_UPPER);
295 296
				console&=~(CON_R_ECHOX|CON_L_ECHOX);
				if(strcmp(str,tmp)) {
297
					bputs(text[Wrong]); // Should be WrongPassword instead?
298 299 300 301
					continue; 
				}
				break; 
			}
302
			SAFECOPY(useron.pass,str);
303 304
			useron.pwmod=time32(NULL);
			putuserrec(&cfg,useron.number,U_PWMOD,8,ultoa((ulong)useron.pwmod,str,16));
305
			bputs(text[PasswordChanged]);
306 307
			pause(); 
		}
308 309 310
		if(useron.ltoday>cfg.level_callsperday[useron.level]
			&& !(useron.exempt&FLAG('L'))) {
			bputs(text[NoMoreLogons]);
311
			safe_snprintf(str, sizeof(str), "(%04u)  %-25s  Out of logons"
312
				,useron.number,useron.alias);
313
			logline(LOG_NOTICE,"+!",str);
314
			hangup();
315 316
			return(false); 
		}
317 318
		if(useron.rest&FLAG('L') && useron.ltoday>1) {
			bputs(text[R_Logons]);
319
			safe_snprintf(str, sizeof(str), "(%04u)  %-25s  Out of logons"
320
				,useron.number,useron.alias);
321
			logline(LOG_NOTICE,"+!",str);
322
			hangup();
323 324
			return(false); 
		}
325
		kmode=(cfg.uq&UQ_NOEXASC)|K_TRIM;
326 327 328
		if(!(cfg.uq&UQ_NOUPRLWR))
			kmode|=K_UPRLWR;

329 330 331 332 333 334 335 336
		if(!(useron.rest&FLAG('G'))) {
			if(!useron.name[0] && ((cfg.uq&UQ_ALIASES && cfg.uq&UQ_REALNAME)
				|| cfg.uq&UQ_COMPANY))
				while(online) {
					if(cfg.uq&UQ_ALIASES && cfg.uq&UQ_REALNAME)
						bputs(text[EnterYourRealName]);
					else
						bputs(text[EnterYourCompany]);
337
					getstr(useron.name,LEN_NAME,kmode);
338
					if(cfg.uq&UQ_ALIASES && cfg.uq&UQ_REALNAME) {
339
						if(trashcan(useron.name,"name") || !useron.name[0]
340
							|| !strchr(useron.name,' ')
341 342 343
							|| strchr(useron.name,0xff)
							|| (cfg.uq&UQ_DUPREAL
								&& userdatdupe(useron.number,U_NAME,LEN_NAME
344
								,useron.name,0,0)))
345 346
							bputs(text[YouCantUseThatName]);
						else
347 348
							break; 
					}
349
					else
350 351
						break; 
				}
352
			if(cfg.uq&UQ_HANDLE && !useron.handle[0]) {
353
				SAFECOPY(useron.handle, useron.alias);
354 355 356
				while(online) {
					bputs(text[EnterYourHandle]);
					if(!getstr(useron.handle,LEN_HANDLE
357
						,K_LINE|K_EDIT|K_AUTODEL|kmode)
358 359 360
						|| strchr(useron.handle,0xff)
						|| (cfg.uq&UQ_DUPHAND
							&& userdatdupe(useron.number,U_HANDLE,LEN_HANDLE
361
							,useron.handle,0,0))
362
						|| trashcan(useron.handle,"name"))
363 364
						bputs(text[YouCantUseThatName]);
					else
365 366 367
						break; 
				} 
			}
368 369 370
			if(cfg.uq&UQ_LOCATION && !useron.location[0])
				while(online) {
					bputs(text[EnterYourCityState]);
371
					if(getstr(useron.location,LEN_LOCATION,kmode))
372 373
						break; 
				}
374 375 376
			if(cfg.uq&UQ_ADDRESS && !useron.address[0])
				while(online) {
					bputs(text[EnterYourAddress]);
377
					if(getstr(useron.address,LEN_ADDRESS,kmode))
378 379
						break; 
				}
380 381 382
			if(cfg.uq&UQ_ADDRESS && !useron.zipcode[0])
				while(online) {
					bputs(text[EnterYourZipCode]);
383
					if(getstr(useron.zipcode,LEN_ZIPCODE,K_UPPER|kmode))
384 385
						break; 
				}
386
			if(cfg.uq&UQ_PHONE && !useron.phone[0]) {
387 388 389 390
				if(text[CallingFromNorthAmericaQ][0])
					i=yesno(text[CallingFromNorthAmericaQ]);
				else
					i=0;
391 392 393 394 395
				while(online) {
					bputs(text[EnterYourPhoneNumber]);
					if(i) {
						if(gettmplt(useron.phone,cfg.sys_phonefmt
							,K_LINE|(cfg.uq&UQ_NOEXASC))<strlen(cfg.sys_phonefmt))
396 397
							 continue; 
					} else {
398
						if(getstr(useron.phone,LEN_PHONE
399
							,K_UPPER|(cfg.uq&UQ_NOEXASC)|K_TRIM)<5)
400 401
							continue; 
					}
402
					if(!trashcan(useron.phone,"phone"))
403 404 405
						break; 
				} 
			}
406
			if(!(cfg.uq&UQ_NONETMAIL) && !useron.netmail[0]) {
407 408
				while(online) {
					bputs(text[EnterNetMailAddress]);
409
					if(getstr(useron.netmail,LEN_NETMAIL,K_EDIT|K_AUTODEL|K_LINE|K_TRIM)
410
						&& !trashcan(useron.netmail,"email"))
411 412
						break;
				}
413
				if(useron.netmail[0] && cfg.sys_misc&SM_FWDTONET && !noyes(text[ForwardMailQ]))
414 415 416 417 418
					useron.misc|=NETMAIL;
				else 
					useron.misc&=~NETMAIL;
			}
			if(cfg.new_sif[0]) {
419
				safe_snprintf(str, sizeof(str), "%suser/%4.4u.dat",cfg.data_dir,useron.number);
420
				if(flength(str)<1L)
421 422
					create_sif_dat(cfg.new_sif,str); 
			} 
423 424 425
		}
	}	
	if(!online) {
426
		safe_snprintf(str, sizeof(str), "(%04u)  %-25s  Unsuccessful logon"
427
			,useron.number,useron.alias);
428
		logline(LOG_NOTICE,"+!",str);
429 430
		return(false); 
	}
431
	SAFECOPY(useron.modem,connection);
rswindell's avatar
rswindell committed
432 433
	SAFECOPY(useron.ipaddr, client_ipaddr);
	SAFECOPY(useron.comp, client_name);
434 435 436 437 438 439
	useron.logons++;
	putuserdat(&cfg,&useron);
	getmsgptrs();
	sys_status|=SS_USERON;          /* moved from further down */

	if(useron.rest&FLAG('Q')) {
440
		safe_snprintf(str, sizeof(str), "(%04u)  %-25s  QWK Network Connection"
441 442
			,useron.number,useron.alias);
		logline("++",str);
443 444
		return(true); 
	}
445 446 447 448 449

	/********************/
	/* SUCCESSFUL LOGON */
	/********************/
	totallogons=logonstats();
450
	safe_snprintf(str, sizeof(str), "(%04u)  %-25s  %sLogon %lu - %u"
451
		,useron.number,useron.alias, (sys_status&SS_FASTLOGON) ? "Fast-":"", totallogons,useron.ltoday);
452 453
	logline("++",str);

454
	if(!(sys_status&SS_QWKLOGON) && cfg.logon_mod[0])
455 456 457
		exec_bin(cfg.logon_mod,&main_csi);

	if(thisnode.status!=NODE_QUIET && (!REALSYSOP || cfg.sys_misc&SM_SYSSTAT)) {
458
		safe_snprintf(str, sizeof(str), "%slogon.lst",cfg.data_dir);
459 460
		if((file=nopen(str,O_WRONLY|O_CREAT|O_APPEND))==-1) {
			errormsg(WHERE,ERR_OPEN,str,O_RDWR|O_CREAT|O_APPEND);
461 462
			return(false); 
		}
463
		getuserrec(&cfg,useron.number,U_NOTE,LEN_NOTE,useron.note);
464
		getuserrec(&cfg,useron.number,U_LOCATION,LEN_LOCATION,useron.location);
465
		safe_snprintf(str, sizeof(str), text[LastFewCallersFmt],cfg.node_num
466
			,totallogons,useron.alias
467
			,cfg.sys_misc&SM_LISTLOC ? useron.location : useron.note
468
			,tm.tm_hour,tm.tm_min
469
			,connection,useron.ltoday > 999 ? 999 : useron.ltoday);
470
		write(file,str,strlen(str));
471 472
		close(file); 
	}
473

474 475
	if(cfg.sys_logon[0]) {				/* execute system logon event */
		lprintf(LOG_DEBUG, "executing logon event: %s", cfg.sys_logon);
476
		external(cmdstr(cfg.sys_logon,nulstr,nulstr,NULL),EX_STDOUT); /* EX_SH */
477
	}
478

479
	if(sys_status&SS_QWKLOGON)
480 481 482
		return(true);

	sys_status|=SS_PAUSEON;	/* always force pause on during this section */
483 484
	mailw=getmail(&cfg,useron.number,/* Sent: */FALSE, /* attr: */0);
	mailr=getmail(&cfg,useron.number,/* Sent: */FALSE, /* attr: */MSG_READ);
485 486 487 488 489 490 491 492 493

	if(!(cfg.sys_misc&SM_NOSYSINFO)) {
		bprintf(text[SiSysName],cfg.sys_name);
		//bprintf(text[SiNodeNumberName],cfg.node_num,cfg.node_name);
		bprintf(text[LiUserNumberName],useron.number,useron.alias);
		bprintf(text[LiLogonsToday],useron.ltoday
			,cfg.level_callsperday[useron.level]);
		bprintf(text[LiTimeonToday],useron.ttoday
			,cfg.level_timeperday[useron.level]+useron.min);
494
		bprintf(text[LiMailWaiting],mailw, mailw-mailr);
495
		bprintf(text[LiSysopIs]
496
			, text[sysop_available(&cfg) ? LiSysopAvailable : LiSysopNotAvailable]);
497
		newline();
498 499
	}

500
	if(sys_status&SS_EVENT)
501
		bprintf(text[ReducedTime],timestr(event_time));
502 503 504 505 506 507 508
	getnodedat(cfg.node_num,&thisnode,1);
	thisnode.misc&=~(NODE_AOFF|NODE_POFF);
	if(useron.chat&CHAT_NOACT)
		thisnode.misc|=NODE_AOFF;
	if(useron.chat&CHAT_NOPAGE)
		thisnode.misc|=NODE_POFF;
	putnodedat(cfg.node_num,&thisnode);
509

510 511 512 513 514 515
	getsmsg(useron.number); 		/* Moved from further down */
	SYNC;
	c=0;
	for(i=1;i<=cfg.sys_nodes;i++)
		if(i!=cfg.node_num) {
			getnodedat(i,&node,0);
516 517 518
			if(!(cfg.sys_misc&SM_NONODELIST)
				&& (node.status==NODE_INUSE
					|| ((node.status==NODE_QUIET || node.errors) && SYSOP))) {
519 520 521
				if(!c)
					bputs(text[NodeLstHdr]);
				printnodedat(i,&node);
522 523
				c=1; 
			}
524 525
			if(node.status==NODE_INUSE && i!=cfg.node_num && node.useron==useron.number
				&& !SYSOP && !(useron.exempt&FLAG('G'))) {
526 527
				SAFEPRINTF2(str,"(%04u)  %-25s  On two nodes at the same time"
					,useron.number,useron.alias);
528
				logline(LOG_NOTICE,"+!",str);
529 530
				bputs(text[UserOnTwoNodes]);
				hangup();
531 532
				return(false); 
			}
533 534 535
			if(thisnode.status!=NODE_QUIET
				&& (node.status==NODE_INUSE || node.status==NODE_QUIET)
				&& !(node.misc&NODE_AOFF) && node.useron!=useron.number) {
536
				safe_snprintf(str, sizeof(str), text[NodeLoggedOnAtNbps]
537 538 539
					,cfg.node_num
					,thisnode.misc&NODE_ANON ? text[UNKNOWN_USER] : useron.alias
					,connection);
540
				putnmsg(&cfg,i,str); 
541 542
			} 
		}
543 544 545 546 547 548 549

	if(cfg.sys_exp_warn && useron.expire && useron.expire>now /* Warn user of coming */
		&& (useron.expire-now)/(1440L*60L)<=cfg.sys_exp_warn) /* expiration */
		bprintf(text[AccountWillExpireInNDays],(useron.expire-now)/(1440L*60L));

	if(criterrs && SYSOP)
		bprintf(text[CriticalErrors],criterrs);
550 551 552 553
	if((i=getuserxfers(&cfg, /* from: */NULL, useron.number)) != 0)
		bprintf(text[UserXferForYou],i,i>1 ? "s" : nulstr); 
	if((i=getuserxfers(&cfg, useron.alias, /* to: */0)) != 0)
		bprintf(text[UnreceivedUserXfer],i,i>1 ? "s" : nulstr);
554 555 556 557
	SYNC;
	sys_status&=~SS_PAUSEON;	/* Turn off the pause override flag */
	if(online==ON_REMOTE)
		rioctl(IOSM|ABORT);		/* Turn abort ability on */
558
	if(text[ReadYourMailNowQ][0] && mailw) {
559
		if((mailw == mailr && !noyes(text[ReadYourMailNowQ]))
560
			|| (mailw != mailr && yesno(text[ReadYourMailNowQ])))
561
			readmail(useron.number,MAIL_YOUR);
562
	}
563
	if(usrgrps && useron.misc&ASK_NSCAN && text[NScanAllGrpsQ][0] && yesno(text[NScanAllGrpsQ]))
564
		scanallsubs(SCAN_NEW);
565
	if(usrgrps && useron.misc&ASK_SSCAN && text[SScanAllGrpsQ][0] && yesno(text[SScanAllGrpsQ]))
566
		scanallsubs(SCAN_TOYOU|SCAN_UNREAD);
567 568 569 570
	return(true);
}

/****************************************************************************/
571 572 573
/* Checks the system dsts.dab to see if it is a new day, if it is, all the  */
/* nodes' and the system's csts.dab are added to, and the dsts.dab's daily  */
/* stats are cleared. Also increments the logon values in dsts.dab if       */
574 575 576 577
/* applicable.                                                              */
/****************************************************************************/
ulong sbbs_t::logonstats()
{
578
    char str[MAX_PATH+1];
579 580
    int dsts,csts;
    uint i;
deuce's avatar
deuce committed
581 582
    time32_t update32_t=0;
    time_t update_t=0;
deuce's avatar
deuce committed
583
	time32_t now32;
584
    stats_t stats;
585
	node_t	node;
586
	struct tm tm, update_tm;
587

588
	sys_status&=~SS_DAILY;
589
	memset(&stats,0,sizeof(stats));
590
	safe_snprintf(str, sizeof(str), "%sdsts.dab",cfg.ctrl_dir);
591 592
	if((dsts=nopen(str,O_RDWR))==-1) {
		errormsg(WHERE,ERR_OPEN,str,O_RDWR);
593 594
		return(0L); 
	}
deuce's avatar
deuce committed
595 596
	read(dsts,&update32_t,4);			/* Last updated         */
	update_t=update32_t;
597
	read(dsts,&stats.logons,4);		/* Total number of logons on system */
598
	close(dsts);
599
	now=time(NULL);
600
	now32=(time32_t)now;
601
	if(update_t>now+(24L*60L*60L)) /* More than a day in the future? */
602
		errormsg(WHERE,ERR_CHK,"Daily stats time stamp",(ulong)update_t);
603
	if(localtime_r(&update_t,&update_tm)==NULL)
604
		return(0);
605
	if(localtime_r(&now,&tm)==NULL)
606
		return(0);
607 608
	if((tm.tm_mday>update_tm.tm_mday && tm.tm_mon==update_tm.tm_mon)
		|| tm.tm_mon>update_tm.tm_mon || tm.tm_year>update_tm.tm_year) {
609

610
		safe_snprintf(str, sizeof(str), "New Day - Prev: %s ",timestr(update_t));
611 612 613
		logentry("!=",str);

		sys_status|=SS_DAILY;       /* New Day !!! */
614
		safe_snprintf(str, sizeof(str), "%slogon.lst",cfg.data_dir);    /* Truncate logon list */
615 616
		if((dsts=nopen(str,O_TRUNC|O_CREAT|O_WRONLY))==-1) {
			errormsg(WHERE,ERR_OPEN,str,O_TRUNC|O_CREAT|O_WRONLY);
617 618
			return(0L); 
		}
619 620 621 622 623
		close(dsts);
		for(i=0;i<=cfg.sys_nodes;i++) {
			if(i) {     /* updating a node */
				getnodedat(i,&node,1);
				node.misc|=NODE_EVENT;
624 625
				putnodedat(i,&node); 
			}
626
			safe_snprintf(str, sizeof(str), "%sdsts.dab",i ? cfg.node_path[i-1] : cfg.ctrl_dir);
627 628
			if((dsts=nopen(str,O_RDWR))==-1) /* node doesn't have stats yet */
				continue;
629
			safe_snprintf(str, sizeof(str), "%scsts.dab",i ? cfg.node_path[i-1] : cfg.ctrl_dir);
630 631 632
			if((csts=nopen(str,O_WRONLY|O_APPEND|O_CREAT))==-1) {
				close(dsts);
				errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_APPEND|O_CREAT);
633 634
				continue; 
			}
635
			lseek(dsts,8L,SEEK_SET);        /* Skip time and logons */
deuce's avatar
deuce committed
636
			write(csts,&now32,4);
637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657
			read(dsts,&stats.ltoday,4);
			write(csts,&stats.ltoday,4);
			lseek(dsts,4L,SEEK_CUR);        /* Skip total time on */
			read(dsts,&stats.ttoday,4);
			write(csts,&stats.ttoday,4);
			read(dsts,&stats.uls,4);
			write(csts,&stats.uls,4);
			read(dsts,&stats.ulb,4);
			write(csts,&stats.ulb,4);
			read(dsts,&stats.dls,4);
			write(csts,&stats.dls,4);
			read(dsts,&stats.dlb,4);
			write(csts,&stats.dlb,4);
			read(dsts,&stats.ptoday,4);
			write(csts,&stats.ptoday,4);
			read(dsts,&stats.etoday,4);
			write(csts,&stats.etoday,4);
			read(dsts,&stats.ftoday,4);
			write(csts,&stats.ftoday,4);
			close(csts);
			lseek(dsts,0L,SEEK_SET);        /* Go back to beginning */
deuce's avatar
deuce committed
658
			write(dsts,&now32,4);             /* Update time stamp  */
659 660 661 662 663 664 665 666 667 668 669 670 671 672
			lseek(dsts,4L,SEEK_CUR);        /* Skip total logons */
			stats.ltoday=0;
			write(dsts,&stats.ltoday,4);  /* Logons today to 0 */
			lseek(dsts,4L,SEEK_CUR);     /* Skip total time on */
			stats.ttoday=0;              /* Set all other today variables to 0 */
			write(dsts,&stats.ttoday,4);        /* Time on today to 0 */
			write(dsts,&stats.ttoday,4);        /* Uploads today to 0 */
			write(dsts,&stats.ttoday,4);        /* U/L Bytes today    */
			write(dsts,&stats.ttoday,4);        /* Download today     */
			write(dsts,&stats.ttoday,4);        /* Download bytes     */
			write(dsts,&stats.ttoday,4);        /* Posts today        */
			write(dsts,&stats.ttoday,4);        /* Emails today       */
			write(dsts,&stats.ttoday,4);        /* Feedback today     */
			write(dsts,&stats.ttoday,2);        /* New users Today    */
673 674 675
			close(dsts); 
		} 
	}
676

677
	if(cfg.node_num==0)	/* called from event_thread() */
678 679
		return(0);

680 681 682 683 684 685 686
	if(thisnode.status==NODE_QUIET)       /* Quiet users aren't counted */
		return(0);

	if(REALSYSOP && !(cfg.sys_misc&SM_SYSSTAT))
		return(0);

	for(i=0;i<2;i++) {
687
		safe_snprintf(str, sizeof(str), "%sdsts.dab",i ? cfg.ctrl_dir : cfg.node_dir);
688 689
		if((dsts=nopen(str,O_RDWR))==-1) {
			errormsg(WHERE,ERR_OPEN,str,O_RDWR);
690 691
			return(0L); 
		}
692 693 694 695 696 697 698 699
		lseek(dsts,4L,SEEK_SET);        /* Skip time stamp */
		read(dsts,&stats.logons,4);
		read(dsts,&stats.ltoday,4);
		stats.logons++;
		stats.ltoday++;
		lseek(dsts,4L,SEEK_SET);        /* Rewind back and overwrite */
		write(dsts,&stats.logons,4);
		write(dsts,&stats.ltoday,4);
700 701
		close(dsts); 
	}
702 703 704 705
	return(stats.logons);
}