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

data.cpp 9.7 KB
Newer Older
rswindell's avatar
rswindell committed
1
/* Synchronet (oh, so old) data access routines */
2 3 4 5 6

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
rswindell's avatar
rswindell committed
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 27 28 29 30 31 32 33
 *																			*
 * 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.	*
 ****************************************************************************/

/**************************************************************/
/* Functions that store and retrieve data from disk or memory */
/**************************************************************/

#include "sbbs.h"

/****************************************************************************/
/* Looks for close or perfect matches between str and valid usernames and  	*/
/* numbers and prompts user for near perfect matches in names.				*/
/* Returns the number of the matched user or 0 if unsuccessful				*/
/* Called from functions main_sec, useredit and readmailw					*/
/****************************************************************************/
Rob Swindell's avatar
Rob Swindell committed
34
uint sbbs_t::finduser(const char* name, bool silent_failure)
35 36
{
	int file,i;
Rob Swindell's avatar
Rob Swindell committed
37 38
	char buf[256],ynq[25],c,pass=1;
	char path[MAX_PATH + 1];
39
	long l,length;
40 41
	FILE *stream;

Rob Swindell's avatar
Rob Swindell committed
42 43
	SKIP_WHITESPACE(name);
	i=atoi(name);
44
	if(i>0) {
Rob Swindell's avatar
Rob Swindell committed
45 46
		username(&cfg, i, buf);
		if(buf[0] && strcmp(buf,"DELETED USER"))
47 48
			return(i); 
	}
Rob Swindell's avatar
Rob Swindell committed
49 50
	SAFEPRINTF(path,"%suser/name.dat",cfg.data_dir);
	if(flength(path)<1L)
51
		return(0);
Rob Swindell's avatar
Rob Swindell committed
52 53
	if((stream=fnopen(&file,path,O_RDONLY))==NULL) {
		errormsg(WHERE,ERR_OPEN,path,O_RDONLY);
54 55
		return(0); 
	}
56
	SAFEPRINTF3(ynq, "%c%c%c", yes_key(), no_key(), quit_key());
57
	length=(long)filelength(file);
58 59 60 61
	while(pass<3) {
		fseek(stream,0L,SEEK_SET);	/* seek to beginning for each pass */
		for(l=0;l<length;l+=LEN_ALIAS+2) {
			if(!online) break;
Rob Swindell's avatar
Rob Swindell committed
62
			fread(buf,LEN_ALIAS+2,1,stream);
63
			for(c=0;c<LEN_ALIAS;c++)
Rob Swindell's avatar
Rob Swindell committed
64 65
				if(buf[c]==ETX) break;
			buf[c]=0;
66 67
			if(!c)		/* deleted user */
				continue;
Rob Swindell's avatar
Rob Swindell committed
68
			if(pass==1 && matchusername(&cfg, name, buf)) {
69
				fclose(stream);
70 71
				return((l/(LEN_ALIAS+2))+1); 
			}
Rob Swindell's avatar
Rob Swindell committed
72 73
			if(pass==2 && strcasestr(buf, name)) {
				bprintf(text[DoYouMeanThisUserQ], buf
74 75 76 77
					,(uint)(l/(LEN_ALIAS+2))+1);
				c=(char)getkeys(ynq,0);
				if(sys_status&SS_ABORT) {
					fclose(stream);
78 79
					return(0); 
				}
80
				if(c==yes_key()) {
81
					fclose(stream);
82 83
					return((l/(LEN_ALIAS+2))+1); 
				}
84
				if(c==quit_key()) {
85
					fclose(stream);
Rob Swindell's avatar
Rob Swindell committed
86
					sys_status |= SS_ABORT;
87 88 89 90 91 92
					return(0); 
				} 
			} 
		}
		pass++; 
	}
rswindell's avatar
rswindell committed
93 94
	if(!silent_failure)
		bputs(text[UnknownUser]);
95 96 97 98
	fclose(stream);
	return(0);
}

99 100 101
/****************************************************************************/
/* Return date/time that the specified event should run next				*/
/****************************************************************************/
Rob Swindell's avatar
Rob Swindell committed
102
extern "C" time_t getnexteventtime(event_t* event)
103 104 105
{
	struct tm tm;
	time_t	t = time(NULL);
106
	time_t	now = t;
107 108 109 110

	if(event->misc & EVENT_DISABLED)
		return 0;

111
	if((event->days & 0x7f) == 0 || event->freq != 0)
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
		return 0;

	if(localtime_r(&t, &tm) == NULL)
		return 0;

	tm.tm_hour = event->time / 60;
	tm.tm_min = event->time % 60;
	tm.tm_sec = 0;
	tm.tm_isdst = -1;	/* Do not adjust for DST */
	t = mktime(&tm);

	if(event->last >= t)
		t += 24 * 60 * 60; /* already ran today, so add 24hrs */

	do {
127 128
		if(t > now + (1500 * 24 * 60 * 60)) /* Handle crazy configs, e.g. Feb-29, Apr-31 */
			return 0;
129 130 131 132 133 134 135 136 137 138 139 140
		if(localtime_r(&t, &tm) == NULL)
			return 0;
		if((event->days & (1 << tm.tm_wday))
			&& (event->mdays == 0 || (event->mdays & (1 << tm.tm_mday)))
			&& (event->months == 0 || (event->months & (1 << tm.tm_mon))))
			break;
		t += 24 * 60 * 60;
	} while(t > 0);

	return t;
}

141
/****************************************************************************/
142 143
/* Return time of next forced timed event									*/
/* 'event' may be NULL														*/
144
/****************************************************************************/
Rob Swindell's avatar
Rob Swindell committed
145
extern "C" time_t getnextevent(scfg_t* cfg, event_t* event)
146 147
{
    int     i;
148
	time_t	event_time=0;
149 150
	time_t	thisevent;

151 152 153
	for(i=0;i<cfg->total_events;i++) {
		if(!cfg->event[i]->node || cfg->event[i]->node>cfg->sys_nodes
			|| cfg->event[i]->misc&EVENT_DISABLED)
154
			continue;
155
		if(!(cfg->event[i]->misc&EVENT_FORCE)
156
			|| (!(cfg->event[i]->misc&EVENT_EXCL) && cfg->event[i]->node!=cfg->node_num))
157 158
			continue;

159 160
		thisevent = getnexteventtime(cfg->event[i]);
		if(thisevent <= 0)
rswindell's avatar
rswindell committed
161
			continue;
162

163
		if(!event_time || thisevent<event_time) {
164 165 166
			event_time=thisevent;
			if(event!=NULL)
				*event=*cfg->event[i];
167
		}
168
	}
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185

	return event_time;
}

/****************************************************************************/
/* Fills the timeleft variable with the correct value. Hangs up on the      */
/* user if their time is up.                                                */
/* Called from functions main_sec and xfer_sec                              */
/****************************************************************************/
ulong sbbs_t::gettimeleft(bool handle_out_of_time)
{
    char    str[128];
	char 	tmp[512];
	event_t	nextevent;

	now=time(NULL);

186
	timeleft = (ulong)::gettimeleft(&cfg, &useron, starttime);
187 188 189 190 191 192

	/* Timed event time reduction handler */
	event_time=getnextevent(&cfg, &nextevent);
	if(event_time)
		event_code=nextevent.code;

193
	if(event_time && now+(time_t)timeleft>event_time) {    /* less time, set flag */
194 195 196
		if(event_time<now)
			timeleft=0;
		else
197
			timeleft=(ulong)(event_time-now); 
198
		if(!(sys_status&SS_EVENT)) {
199
			lprintf(LOG_NOTICE,"Node %d Time reduced (to %s) due to upcoming event (%s) on %s"
200
				,cfg.node_num,sectostr(timeleft,tmp),event_code,timestr(event_time));
201 202
			sys_status|=SS_EVENT;
		}
203 204
	}

205
	if((long)timeleft<0)  /* timeleft can't go negative */
206 207 208 209
		timeleft=0;
	if(thisnode.status==NODE_NEWUSER) {
		timeleft=cfg.level_timepercall[cfg.new_level];
		if(timeleft<10*60L)
210 211
			timeleft=10*60L; 
	}
212

213 214 215
	if(handle_out_of_time && !gettimeleft_inside)			/* The following code is not recursive */
	{
		gettimeleft_inside=1;
216

217
		if(!timeleft && !SYSOP && !(sys_status&SS_LCHAT)) {
218
			logline(LOG_NOTICE,nulstr,"Ran out of time");
219 220
			SAVELINE;
			if(sys_status&SS_EVENT)
221
				bprintf(text[ReducedTime],timestr(event_time));
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
			bputs(text[TimesUp]);
			if(!(sys_status&(SS_EVENT|SS_USERON)) && useron.cdt>=100L*1024L
				&& !(cfg.sys_misc&SM_NOCDTCVT)) {
				SAFEPRINTF(tmp,text[Convert100ktoNminQ],cfg.cdt_min_value);
				if(yesno(tmp)) {
					logline("  ","Credit to Minute Conversion");
					useron.min=adjustuserrec(&cfg,useron.number,U_MIN,10,cfg.cdt_min_value);
					useron.cdt=adjustuserrec(&cfg,useron.number,U_CDT,10,-(102400L));
					SAFEPRINTF(str,"Credit Adjustment: %ld",-(102400L));
					logline("$-",str);
					SAFEPRINTF(str,"Minute Adjustment: %u",cfg.cdt_min_value);
					logline("*+",str);
					RESTORELINE;
					gettimeleft();
					gettimeleft_inside=0;
					return timeleft; 
				} 
			}
			if(cfg.sys_misc&SM_TIME_EXP && !(sys_status&SS_EVENT)
				&& !(useron.exempt&FLAG('E'))) {
												/* set to expired values */
				bputs(text[AccountHasExpired]);
244
				SAFEPRINTF2(str,"%s #%u Expired",useron.alias,useron.number);
245 246 247 248 249 250 251 252 253 254
				logentry("!%",str);
				if(cfg.level_misc[useron.level]&LEVEL_EXPTOVAL
					&& cfg.level_expireto[useron.level]<10) {
					useron.flags1=cfg.val_flags1[cfg.level_expireto[useron.level]];
					useron.flags2=cfg.val_flags2[cfg.level_expireto[useron.level]];
					useron.flags3=cfg.val_flags3[cfg.level_expireto[useron.level]];
					useron.flags4=cfg.val_flags4[cfg.level_expireto[useron.level]];
					useron.exempt=cfg.val_exempt[cfg.level_expireto[useron.level]];
					useron.rest=cfg.val_rest[cfg.level_expireto[useron.level]];
					if(cfg.val_expire[cfg.level_expireto[useron.level]])
255
						useron.expire=(time32_t)now
256 257 258
							+(cfg.val_expire[cfg.level_expireto[useron.level]]*24*60*60);
					else
						useron.expire=0;
259 260
					useron.level=cfg.val_level[cfg.level_expireto[useron.level]]; 
				}
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
				else {
					if(cfg.level_misc[useron.level]&LEVEL_EXPTOLVL)
						useron.level=cfg.level_expireto[useron.level];
					else
						useron.level=cfg.expired_level;
					useron.flags1&=~cfg.expired_flags1; /* expired status */
					useron.flags2&=~cfg.expired_flags2; /* expired status */
					useron.flags3&=~cfg.expired_flags3; /* expired status */
					useron.flags4&=~cfg.expired_flags4; /* expired status */
					useron.exempt&=~cfg.expired_exempt;
					useron.rest|=cfg.expired_rest;
					useron.expire=0; 
				}
				putuserrec(&cfg,useron.number,U_LEVEL,2,ultoa(useron.level,str,10));
				putuserrec(&cfg,useron.number,U_FLAGS1,8,ultoa(useron.flags1,str,16));
				putuserrec(&cfg,useron.number,U_FLAGS2,8,ultoa(useron.flags2,str,16));
				putuserrec(&cfg,useron.number,U_FLAGS3,8,ultoa(useron.flags3,str,16));
				putuserrec(&cfg,useron.number,U_FLAGS4,8,ultoa(useron.flags4,str,16));
279
				putuserrec(&cfg,useron.number,U_EXPIRE,8,ultoa((ulong)useron.expire,str,16));
280 281 282 283
				putuserrec(&cfg,useron.number,U_EXEMPT,8,ultoa(useron.exempt,str,16));
				putuserrec(&cfg,useron.number,U_REST,8,ultoa(useron.rest,str,16));
				if(cfg.expire_mod[0])
					exec_bin(cfg.expire_mod,&main_csi);
284 285 286
				RESTORELINE;
				gettimeleft();
				gettimeleft_inside=0;
287
				return timeleft; 
288
			}
289 290
			SYNC;
			hangup(); 
291
		}
292
		gettimeleft_inside=0;
293
	}
294
	return timeleft;
295
}