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

logon.cpp 22.4 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 166


	if(useron.misc&AUTOTERM) {
167
		useron.misc&=~(ANSI|RIP|PETSCII);
rswindell's avatar
rswindell committed
168
		useron.misc|=autoterm;
169 170 171 172
	} else if((useron.misc&PETSCII) && (autoterm&ANSI)) {
		// User manually-enabled PETSCII, but they're logging in with an ANSI (auto-detected) terminal
		useron.misc &= ~PETSCII;
		useron.misc |= (AUTOTERM | autoterm);
173
	}
174

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

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

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

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

	gettimeleft();
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 258 259 260

	/* 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);
	}
261
	if(!(sys_status&SS_QWKLOGON)) { 	 /* QWK Nodes don't go through this */
262

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

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

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

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

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

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

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

457
	if(!(sys_status&SS_QWKLOGON) && cfg.logon_mod[0])
458 459 460
		exec_bin(cfg.logon_mod,&main_csi);

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

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

482
	if(sys_status&SS_QWKLOGON)
483 484 485
		return(true);

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

	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);
497
		bprintf(text[LiMailWaiting],mailw, mailw-mailr);
498
		bprintf(text[LiSysopIs]
499
			, text[sysop_available(&cfg) ? LiSysopAvailable : LiSysopNotAvailable]);
500
		newline();
501 502
	}

503
	if(sys_status&SS_EVENT)
504
		bprintf(text[ReducedTime],timestr(event_time));
505 506 507 508 509 510 511
	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);
512

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

	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);
553 554 555 556
	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);
557 558 559 560
	SYNC;
	sys_status&=~SS_PAUSEON;	/* Turn off the pause override flag */
	if(online==ON_REMOTE)
		rioctl(IOSM|ABORT);		/* Turn abort ability on */
561
	if(text[ReadYourMailNowQ][0] && mailw) {
562
		if((mailw == mailr && !noyes(text[ReadYourMailNowQ]))
563
			|| (mailw != mailr && yesno(text[ReadYourMailNowQ])))
564
			readmail(useron.number,MAIL_YOUR);
565
	}
566
	if(usrgrps && useron.misc&ASK_NSCAN && text[NScanAllGrpsQ][0] && yesno(text[NScanAllGrpsQ]))
567
		scanallsubs(SCAN_NEW);
568
	if(usrgrps && useron.misc&ASK_SSCAN && text[SScanAllGrpsQ][0] && yesno(text[SScanAllGrpsQ]))
569
		scanallsubs(SCAN_TOYOU|SCAN_UNREAD);
570 571 572 573
	return(true);
}

/****************************************************************************/
574 575 576
/* 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       */
577 578 579 580
/* applicable.                                                              */
/****************************************************************************/
ulong sbbs_t::logonstats()
{
581
    char str[MAX_PATH+1];
582 583
    int dsts,csts;
    uint i;
deuce's avatar
deuce committed
584 585
    time32_t update32_t=0;
    time_t update_t=0;
deuce's avatar
deuce committed
586
	time32_t now32;
587
    stats_t stats;
588
	node_t	node;
589
	struct tm tm, update_tm;
590

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

613
		safe_snprintf(str, sizeof(str), "New Day - Prev: %s ",timestr(update_t));
614 615 616
		logentry("!=",str);

		sys_status|=SS_DAILY;       /* New Day !!! */
617
		safe_snprintf(str, sizeof(str), "%slogon.lst",cfg.data_dir);    /* Truncate logon list */
618 619
		if((dsts=nopen(str,O_TRUNC|O_CREAT|O_WRONLY))==-1) {
			errormsg(WHERE,ERR_OPEN,str,O_TRUNC|O_CREAT|O_WRONLY);
620 621
			return(0L); 
		}
622 623 624 625 626
		close(dsts);
		for(i=0;i<=cfg.sys_nodes;i++) {
			if(i) {     /* updating a node */
				getnodedat(i,&node,1);
				node.misc|=NODE_EVENT;
627 628
				putnodedat(i,&node); 
			}
629
			safe_snprintf(str, sizeof(str), "%sdsts.dab",i ? cfg.node_path[i-1] : cfg.ctrl_dir);
630 631
			if((dsts=nopen(str,O_RDWR))==-1) /* node doesn't have stats yet */
				continue;
632
			safe_snprintf(str, sizeof(str), "%scsts.dab",i ? cfg.node_path[i-1] : cfg.ctrl_dir);
633 634 635
			if((csts=nopen(str,O_WRONLY|O_APPEND|O_CREAT))==-1) {
				close(dsts);
				errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_APPEND|O_CREAT);
636 637
				continue; 
			}
638
			lseek(dsts,8L,SEEK_SET);        /* Skip time and logons */
deuce's avatar
deuce committed
639
			write(csts,&now32,4);
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660
			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
661
			write(dsts,&now32,4);             /* Update time stamp  */
662 663 664 665 666 667 668 669 670 671 672 673 674 675
			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    */
676 677 678
			close(dsts); 
		} 
	}
679

680
	if(cfg.node_num==0)	/* called from event_thread() */
681 682
		return(0);

683 684 685 686 687 688 689
	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++) {
690
		safe_snprintf(str, sizeof(str), "%sdsts.dab",i ? cfg.ctrl_dir : cfg.node_dir);
691 692
		if((dsts=nopen(str,O_RDWR))==-1) {
			errormsg(WHERE,ERR_OPEN,str,O_RDWR);
693 694
			return(0L); 
		}
695 696 697 698 699 700 701 702
		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);
703 704
		close(dsts); 
	}
705 706 707 708
	return(stats.logons);
}