Newer
Older
result=not;
else
result=!not;
break;
case AR_AGE:
if(user==NULL)
else {
age=getage(cfg,user->birth);
if((equal && age!=n) || (!equal && age<n))
result=not;
else
result=!not;
}
break;
case AR_BPS:
result=!not;
(*ptrptr)++;
break;
case AR_ANSI:
if(user==NULL || !(user->misc&ANSI))
result=not;
else result=!not;
break;
if(user==NULL || (user->misc&CHARSET_FLAGS) != CHARSET_PETSCII)
result=not;
else result=!not;
break;
case AR_ASCII:
if(user==NULL || (user->misc&CHARSET_FLAGS) != CHARSET_ASCII)
result=not;
else result=!not;
break;
case AR_UTF8:
if(user==NULL || (user->misc&CHARSET_FLAGS) != CHARSET_UTF8)
result=not;
else result=!not;
break;
case AR_CP437:
if(user==NULL || (user->misc&CHARSET_FLAGS) != CHARSET_CP437)
if(user==NULL || !(user->misc&RIP))
result=not;
else result=!not;
break;
case AR_WIP:
break;
case AR_OS2:
#ifndef __OS2__
result=not;
#else
result=!not;
#endif
break;
case AR_DOS:
#if defined(_WIN32) || defined(__linux__) || defined(__FreeBSD__)
result=!not;
#else
result=not;
#endif
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
case AR_WIN32:
#ifndef _WIN32
result=not;
#else
result=!not;
#endif
break;
case AR_UNIX:
#ifndef __unix__
result=not;
#else
result=!not;
#endif
break;
case AR_LINUX:
#ifndef __linux__
result=not;
#else
result=!not;
#endif
break;
case AR_ACTIVE:
if(user==NULL || user->misc&(DELETED|INACTIVE))
result=not;
else result=!not;
break;
case AR_INACTIVE:
if(user==NULL || !(user->misc&INACTIVE))
result=not;
else result=!not;
break;
case AR_DELETED:
if(user==NULL || !(user->misc&DELETED))
result=not;
else result=!not;
break;
if(user==NULL || !(user->misc&EXPERT))
result=not;
else result=!not;
break;
case AR_SYSOP:
result=not;
else result=!not;
break;
case AR_GUEST:
if(user==NULL || !(user->rest&FLAG('G')))
result=not;
else result=!not;
break;
case AR_QNODE:
if(user==NULL || !(user->rest&FLAG('Q')))
result=not;
else result=!not;
break;
case AR_QUIET:
result=not;
break;
case AR_LOCAL:
result=not;
break;
case AR_DAY:
now=time(NULL);
localtime_r(&now,&tm);
if((equal && tm.tm_wday!=(int)n)
|| (!equal && tm.tm_wday<(int)n))
result=not;
else
result=!not;
break;
case AR_CREDIT:
if(user==NULL
|| (equal && user_available_credits(user)!=l)
|| (!equal && user_available_credits(user)<l))
result=not;
else
result=!not;
(*ptrptr)++;
break;
case AR_NODE:
if((equal && cfg->node_num!=n) || (!equal && cfg->node_num<n))
result=not;
else
result=!not;
break;
case AR_USER:
if(user==NULL
|| (!equal && user->number<i))
result=not;
else
result=!not;
(*ptrptr)++;
break;
case AR_GROUP:
if(user==NULL)
result=not;
else {
l=getgrpnum(cfg,user->cursub);
if((equal && l!=i) || (!equal && l<i))
result=not;
else
result=!not;
}
(*ptrptr)++;
break;
case AR_SUB:
if(user==NULL)
result=not;
else {
l=getsubnum(cfg,user->cursub);
if((equal && l!=i) || (!equal && l<i))
result=not;
else
result=!not;
}
(*ptrptr)++;
break;
case AR_SUBCODE:
if(user!=NULL && findstr_in_string(user->cursub,(char *)*ptrptr)==0)
result=!not;
else
result=not;
while(*(*ptrptr))
(*ptrptr)++;
break;
case AR_LIB:
if(user==NULL)
result=not;
else {
l=getlibnum(cfg,user->curdir);
if((equal && l!=i) || (!equal && l<i))
result=not;
else
result=!not;
}
(*ptrptr)++;
break;
case AR_DIR:
if(user==NULL)
result=not;
else {
l=getdirnum(cfg,user->curdir);
if((equal && l!=i) || (!equal && l<i))
result=not;
else
result=!not;
}
(*ptrptr)++;
break;
case AR_DIRCODE:
if(user!=NULL && findstr_in_string(user->curdir,(char *)*ptrptr)==0)
result=!not;
else
result=not;
while(*(*ptrptr))
(*ptrptr)++;
break;
case AR_EXPIRE:
now=time(NULL);
|| user->expire==0
|| now+((long)i*24L*60L*60L)>user->expire)
result=not;
else
result=!not;
(*ptrptr)++;
break;
case AR_RANDOM:
n=xp_random(i+1);
if((equal && n!=i) || (!equal && n<i))
result=not;
else
result=!not;
(*ptrptr)++;
break;
case AR_LASTON:
now=time(NULL);
if(user==NULL || (now-user->laston)/(24L*60L*60L)<(long)i)
result=not;
else
result=!not;
(*ptrptr)++;
break;
case AR_LOGONS:
if(user==NULL
|| (equal && user->logons!=i)
|| (!equal && user->logons<i))
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
result=not;
else
result=!not;
(*ptrptr)++;
break;
case AR_MAIN_CMDS:
result=not;
(*ptrptr)++;
break;
case AR_FILE_CMDS:
result=not;
(*ptrptr)++;
break;
case AR_TLEFT:
result=not;
break;
case AR_TUSED:
result=not;
break;
case AR_TIME:
now=time(NULL);
localtime_r(&now,&tm);
if((tm.tm_hour*60)+tm.tm_min<(int)i)
result=not;
else
result=!not;
(*ptrptr)++;
break;
case AR_PCR:
if(user==NULL)
result=not;
else if(user->logons>user->posts
&& (!user->posts || 100/((float)user->logons/user->posts)<(long)n))
result=not;
else
result=!not;
break;
case AR_UDR: /* up/download byte ratio */
if(user==NULL)
else {
l=user->dlb;
if(!l) l=1;
if(user->dlb>user->ulb
&& (!user->ulb || 100/((float)l/user->ulb)<n))
result=not;
else
result=!not;
}
break;
case AR_UDFR: /* up/download file ratio */
if(user==NULL)
else {
i=user->dls;
if(!i) i=1;
if(user->dls>user->uls
&& (!user->uls || 100/((float)i/user->uls)<n))
result=not;
else
result=!not;
}
if(user==NULL || (equal && user->uls!=i) || (!equal && user->uls<i))
result=not;
else
result=!not;
(*ptrptr)++;
break;
case AR_ULK:
if(user==NULL || (equal && user->ulb/1024!=i) || (!equal && user->ulb/1024<i))
result=not;
else
result=!not;
(*ptrptr)++;
break;
case AR_ULM:
if(user==NULL || (equal && user->ulb/(1024*1024)!=i) || (!equal && user->ulb/(1024*1024)<i))
result=not;
else
result=!not;
(*ptrptr)++;
break;
case AR_DLS:
if(user==NULL || (equal && user->dls!=i) || (!equal && user->dls<i))
result=not;
else
result=!not;
(*ptrptr)++;
break;
case AR_DLK:
if(user==NULL || (equal && user->dlb/1024!=i) || (!equal && user->dlb/1024<i))
result=not;
else
result=!not;
(*ptrptr)++;
break;
case AR_DLM:
if(user==NULL || (equal && user->dlb/(1024*1024)!=i) || (!equal && user->dlb/(1024*1024)<i))
result=not;
else
result=!not;
(*ptrptr)++;
break;
if(user==NULL
|| (!equal && !(user->flags1&FLAG(n)))
|| (equal && user->flags1!=FLAG(n)))
result=not;
else
result=!not;
break;
case AR_FLAG2:
if(user==NULL
|| (!equal && !(user->flags2&FLAG(n)))
|| (equal && user->flags2!=FLAG(n)))
result=not;
else
result=!not;
break;
case AR_FLAG3:
if(user==NULL
|| (!equal && !(user->flags3&FLAG(n)))
|| (equal && user->flags3!=FLAG(n)))
result=not;
else
result=!not;
break;
case AR_FLAG4:
if(user==NULL
|| (!equal && !(user->flags4&FLAG(n)))
|| (equal && user->flags4!=FLAG(n)))
result=not;
else
result=!not;
break;
case AR_REST:
if(user==NULL
|| (!equal && !(user->rest&FLAG(n)))
|| (equal && user->rest!=FLAG(n)))
result=not;
else
result=!not;
break;
case AR_EXEMPT:
if(user==NULL
|| (!equal && !(user->exempt&FLAG(n)))
|| (equal && user->exempt!=FLAG(n)))
result=not;
else
result=!not;
break;
case AR_SEX:
if(user==NULL || user->sex!=n)
result=not;
else
result=!not;
case AR_SHELL:
|| user->shell>=cfg->total_shells
|| !findstr_in_string(cfg->shell[user->shell]->code,(char*)*ptrptr))
result=not;
else
result=!not;
while(*(*ptrptr))
(*ptrptr)++;
break;
case AR_PROT:
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
if(client!=NULL)
p=client->protocol;
else if(user!=NULL)
p=user->modem;
else
p=NULL;
if(!findstr_in_string(p,(char*)*ptrptr))
result=not;
else
result=!not;
while(*(*ptrptr))
(*ptrptr)++;
break;
case AR_HOST:
if(client!=NULL)
p=client->host;
else if(user!=NULL)
p=user->comp;
else
p=NULL;
if(!findstr_in_string(p,(char*)*ptrptr))
result=not;
else
result=!not;
while(*(*ptrptr))
(*ptrptr)++;
break;
case AR_IP:
if(client!=NULL)
p=client->addr;
else if(user!=NULL)
else
p=NULL;
if(!findstr_in_string(p,(char*)*ptrptr))
result=not;
else
result=!not;
while(*(*ptrptr))
(*ptrptr)++;
break;
case AR_TERM:
result=!not;
while(*(*ptrptr))
(*ptrptr)++;
break;
case AR_ROWS:
case AR_COLS:
result=!not;
break;
bool chk_ar(scfg_t* cfg, uchar *ar, user_t* user, client_t* client)
{
uchar *p;
if(ar==NULL)
if(!VALID_CFG(cfg))

Rob Swindell
committed
/****************************************************************************/
/* Does the Access Requirement String (ARS) parse and check */
/****************************************************************************/
bool chk_ars(scfg_t* cfg, char *ars, user_t* user, client_t* client)

Rob Swindell
committed
{
uchar ar_buf[LEN_ARSTR + 1];
return chk_ar(cfg, arstr(NULL, ars, cfg, ar_buf), user, client);
}
/****************************************************************************/
/* Returns 0 on success, non-zero on failure. */
/****************************************************************************/
char* getuserstr(scfg_t* cfg, int usernumber, enum user_field fnum, char *str, size_t size)
char* field[USER_FIELD_COUNT];
char userdat[USER_RECORD_LEN + 1];
int file;
if(!VALID_CFG(cfg) || !VALID_USER_NUMBER(usernumber) || !VALID_USER_FIELD(fnum) || str == NULL)
return NULL;
memset(str, 0, size);
if((file = openuserdat(cfg, /* for_modify: */false)) == -1)
return str;
if(readuserdat(cfg, usernumber, userdat, sizeof(userdat), file, /* leave_locked: */false) == 0) {
split_userdat(userdat, field);
safe_snprintf(str, size, "%s", field[fnum]);
dirtyuserdat(cfg, usernumber);
return str;
uint32_t getuserhex32(scfg_t* cfg, int usernumber, enum user_field fnum)
if(getuserstr(cfg, usernumber, fnum, str, sizeof(str)) == NULL)
return 0;
return ahtou32(str);
}
uint32_t getuserdec32(scfg_t* cfg, int usernumber, enum user_field fnum)
{
char str[32];
if(getuserstr(cfg, usernumber, fnum, str, sizeof(str)) == NULL)
return 0;
return strtoul(str, NULL, 10);
}
uint64_t getuserdec64(scfg_t* cfg, int usernumber, enum user_field fnum)
{
char str[32];
if(getuserstr(cfg, usernumber, fnum, str, sizeof(str)) == NULL)
return 0;
return strtoull(str, NULL, 10);
uint32_t getusermisc(scfg_t* cfg, int usernumber)
{
return getuserhex32(cfg, usernumber, USER_MISC);
}
uint32_t getuserchat(scfg_t* cfg, int usernumber)
{
return getuserhex32(cfg, usernumber, USER_CHAT);
}
uint32_t getusermail(scfg_t* cfg, int usernumber)
{
return getuserhex32(cfg, usernumber, USER_MAIL);
}
uint32_t getuserqwk(scfg_t* cfg, int usernumber)
{
return getuserhex32(cfg, usernumber, USER_QWK);
}
uint32_t getuserflags(scfg_t* cfg, int usernumber, enum user_field fnum)
{
char str[LEN_FLAGSTR + 1];
if(getuserstr(cfg, usernumber, fnum, str, sizeof(str)) == NULL)
return 0;
return aftou32(str);
}
/****************************************************************************/
/* Returns 0 on success, non-zero on failure. */
/****************************************************************************/
int putuserstr(scfg_t* cfg, int usernumber, enum user_field fnum, const char *str)
{
char* field[USER_FIELD_COUNT];
char userdat[USER_RECORD_LEN + 1];
int file;
int retval;
if(!VALID_CFG(cfg) || !VALID_USER_NUMBER(usernumber) || !VALID_USER_FIELD(fnum) || str == NULL)
return -1;
if(strchr(str, USER_FIELD_SEPARATOR) != NULL)
return -2;
if((file = openuserdat(cfg, /* for_modify: */true)) == -1)
return errno;
retval = readuserdat(cfg, usernumber, userdat, sizeof(userdat), file, /* leave_locked: */true);
if(retval == 0) {
split_userdat(userdat, field);
field[fnum] = (char*)str;
if(!seekuserdat(file, usernumber))
retval = -4;
else
writeuserfields(cfg, field, file);
unlockuserdat(file, usernumber);
}
close(file);
if(retval == 0)
dirtyuserdat(cfg, usernumber);
return retval;
}
int putuserdatetime(scfg_t* cfg, int usernumber, enum user_field fnum, time32_t t)
return putuserstr(cfg, usernumber, fnum, format_datetime(t, str, sizeof(str)));
}
int putuserflags(scfg_t* cfg, int usernumber, enum user_field fnum, uint32_t flags)
{
char str[128];
return putuserstr(cfg, usernumber, fnum, u32toaf(flags, str));
}
int putuserhex32(scfg_t* cfg, int usernumber, enum user_field fnum, uint32_t value)
{
char str[128];
return putuserstr(cfg, usernumber, fnum, ultoa(value, str, 16));
}
int putuserdec32(scfg_t* cfg, int usernumber, enum user_field fnum, uint32_t value)
{
char str[128];
return putuserstr(cfg, usernumber, fnum, ultoa(value, str, 10));
}
int putuserdec64(scfg_t* cfg, int usernumber, enum user_field fnum, uint64_t value)
{
char str[128];
SAFEPRINTF(str, "%" PRIu64, value);
return putuserstr(cfg, usernumber, fnum, str);
}
int putusermisc(scfg_t* cfg, int usernumber, uint32_t value)
{
return putuserhex32(cfg, usernumber, USER_MISC, value);
}
int putuserchat(scfg_t* cfg, int usernumber, uint32_t value)
{
return putuserhex32(cfg, usernumber, USER_CHAT, value);
}
int putusermail(scfg_t* cfg, int usernumber, uint32_t value)
{
return putuserhex32(cfg, usernumber, USER_MAIL, value);
}
int putuserqwk(scfg_t* cfg, int usernumber, uint32_t value)
{
return putuserhex32(cfg, usernumber, USER_QWK, value);
/****************************************************************************/
/* Updates user 'usernumber's numeric field value by adding 'adj' to it */
/* returns the new value. */
/****************************************************************************/
uint64_t adjustuserval(scfg_t* cfg, int usernumber, enum user_field fnum, int64_t adj)
{
char value[256];
char userdat[USER_RECORD_LEN + 1];
int file;
bool valid = true;
uint64_t val = 0;
if(!VALID_CFG(cfg) || !VALID_USER_NUMBER(usernumber) || !VALID_USER_FIELD(fnum))
return 0;
if((file = openuserdat(cfg, /* for_modify: */true)) == -1)
return 0;
if(readuserdat(cfg, usernumber, userdat, sizeof(userdat), file, /* leave_locked: */true) == 0) {
char* field[USER_FIELD_COUNT];
split_userdat(userdat, field);
val = strtoull(field[fnum], NULL, 10);
switch(user_field_len(fnum)) {
case sizeof(uint64_t):
if(adj < 0 && val < (uint64_t)-adj) // don't go negative
val = 0;
else if(adj > 0 && val + adj < val)
val = UINT64_MAX;
else
val += (uint64_t)adj;
SAFEPRINTF(value, "%" PRIu64, val);
break;
case sizeof(uint32_t):
if(adj < 0 && val < (uint32_t)-adj) // don't go negative
val = 0;
else if(adj > 0 && val + adj < val)
val = UINT32_MAX;
else
val += (uint32_t)adj;
break;
case sizeof(uint16_t):
if(adj < 0 && val < (uint16_t)-adj) // don't go negative
val = 0;
else if(adj > 0 && val + adj < val)
val = UINT16_MAX;
else
val += (uint16_t)adj;
SAFEPRINTF(value, "%u", (uint)val);
break;
case sizeof(uint8_t):
if(adj < 0 && val < (uint8_t)-adj) // don't go negative
val = 0;
else if(adj > 0 && val + adj < val)
val = UINT8_MAX;
else
val += (uint8_t)adj;
SAFEPRINTF(value, "%u", (uint)val);
break;
default:
valid = false;
break;
}
if(valid) {
field[fnum] = value;
if(seekuserdat(file, usernumber))
writeuserfields(cfg, field, file);
}
}
unlockuserdat(file, usernumber);
close(file);
dirtyuserdat(cfg, usernumber);
return val;
}
/****************************************************************************/
/* Returns user's available credits, handling integer overflow */
/****************************************************************************/
uint64_t user_available_credits(user_t* user)
{
uint64_t result;
if(user == NULL)
return 0;
result = user->cdt + user->freecdt;
if(result < user->cdt)
return UINT64_MAX;
return result;
}
/****************************************************************************/
/* Subtract credits from the current user online, accounting for the new */
/* "free credits" field. */
/****************************************************************************/
void subtract_cdt(scfg_t* cfg, user_t* user, uint64_t amt)
return;
if(user->freecdt) {
if(amt > user->freecdt) { /* subtract both credits and */
mod=amt-user->freecdt; /* free credits */
putuserstr(cfg, user->number, USER_FREECDT, "0");
user->cdt = adjustuserval(cfg, user->number, USER_FREECDT, -mod);
} else { /* subtract just free credits */
putuserstr(cfg, user->number, USER_FREECDT, _ui64toa(user->freecdt, tmp, 10));
else { /* no free credits */
if(amt > INT64_MAX)
amt = INT64_MAX;
user->cdt = adjustuserval(cfg, user->number, USER_CDT, -(int64_t)amt);
bool user_posted_msg(scfg_t* cfg, user_t* user, int count)
{
if(user==NULL)
user->posts =(ushort)adjustuserval(cfg, user->number, USER_POSTS, count);
user->ptoday=(ushort)adjustuserval(cfg, user->number, USER_PTODAY, count);
if(user->rest & FLAG('Q'))
}
bool user_sent_email(scfg_t* cfg, user_t* user, int count, bool feedback)
{
if(user==NULL)
if(feedback)
user->fbacks=(ushort)adjustuserval(cfg, user->number, USER_FBACKS, count);
else
user->emails=(ushort)adjustuserval(cfg, user->number, USER_EMAILS, count);
user->etoday=(ushort)adjustuserval(cfg, user->number, USER_ETODAY, count);
}
bool user_downloaded(scfg_t* cfg, user_t* user, int files, off_t bytes)
{
if(user==NULL)
user->dls=(ushort)adjustuserval(cfg, user->number, USER_DLS, files);
user->dlb=adjustuserval(cfg, user->number, USER_DLB, bytes);
}
#ifdef SBBS
bool user_downloaded_file(scfg_t* cfg, user_t* user, client_t* client,

Rob Swindell
committed
int dirnum, const char* filename, off_t bytes)
{
if(!loadfile(cfg, dirnum, filename, &f, file_detail_normal))
if(!bytes)
bytes = getfilesize(cfg, &f);
if(dirnum == cfg->user_dir) {
str_list_t dest_user_list = strListSplitCopy(NULL, f.to_list, ",");
char usernum[16];
SAFEPRINTF(usernum, "%u", user->number);
int i = strListFind(dest_user_list, usernum, /* case-sensitive: */true);
if(i >= 0) {
strListFastDelete(dest_user_list, i, /* count: */1);
char tmp[512];
smb_hfield_replace_str(&f, RECIPIENTLIST, strListCombine(dest_user_list, tmp, sizeof(tmp), ","));
}
if(strListCount(dest_user_list) < 1) {
char path[MAX_PATH + 1];
if(remove(getfilepath(cfg, &f, path)) == 0)
removed = removefile(cfg, dirnum, f.name);
}
strListFree(&dest_user_list);
}
f.hdr.times_downloaded++;
f.hdr.last_downloaded = time32(NULL);
if(!removed && !updatefile(cfg, &f)) {
smb_freefilemem(&f);
/**************************/
/* Update Uploader's Info */
/**************************/
user_t uploader = {0};
uploader.number=matchuser(cfg, f.from, true /*sysop_alias*/);
if(uploader.number
&& uploader.number != user->number
&& getuserdat(cfg, &uploader) == 0
&& (uint32_t)uploader.firston < f.hdr.when_imported.time) {
uint64_t l = f.cost;
if(!(cfg->dir[dirnum]->misc&DIR_CDTDL)) /* Don't give credits on d/l */
l=0;
uint64_t mod=(uint64_t)(l*(cfg->dir[dirnum]->dn_pct/100.0));
adjustuserval(cfg, uploader.number, USER_CDT, mod);
if(cfg->text != NULL && !(cfg->dir[dirnum]->misc&DIR_QUIET)) {
char str[256];
char tmp[128];
char prefix[128]="";
u64toac(mod,tmp,',');
const char* alias = user->alias[0] ? user->alias : cfg->text[UNKNOWN_USER];
char username[64];
if(client != NULL && is_user_sysop(&uploader)) {
if(client->host[0] != '\0' && strcmp(client->host, STR_NO_HOSTNAME) != 0)
SAFEPRINTF2(username,"%s [%s]", alias, client->host);
else
SAFEPRINTF2(username,"%s [%s]", alias, client->addr);
} else
SAFECOPY(username, alias);
if(strcmp(cfg->dir[dirnum]->code, "TEMP") == 0 || bytes < getfilesize(cfg, &f))
SAFECOPY(prefix, cfg->text[Partially]);
if(client != NULL) {
SAFECAT(prefix, client->protocol);
SAFECAT(prefix, "-");
}
/* Inform uploader of downloaded file */
if(mod == 0)
SAFEPRINTF3(str, cfg->text[FreeDownloadUserMsg]
,getfname(filename)
,prefix
,username);
else
SAFEPRINTF4(str, cfg->text[DownloadUserMsg]
,getfname(filename)
,prefix
,username, tmp);
putsmsg(cfg, uploader.number, str);
}
}
/****************************/
/* Update Downloader's Info */
/****************************/
user_downloaded(cfg, user, /* files: */1, bytes);
if(!is_download_free(cfg, dirnum, user, client))
subtract_cdt(cfg, user, f.cost);
bool result = true;
if(!(cfg->dir[dirnum]->misc&DIR_NOSTAT))
result = inc_download_stats(cfg, /* files: */1, bytes);
smb_freefilemem(&f);
return result;
}
#endif
bool user_uploaded(scfg_t* cfg, user_t* user, int files, off_t bytes)
{
if(user==NULL)
user->uls=(ushort)adjustuserval(cfg, user->number, USER_ULS, files);
user->ulb=adjustuserval(cfg, user->number, USER_ULB, bytes);
}
bool user_adjust_credits(scfg_t* cfg, user_t* user, int64_t amount)
{
if(user==NULL)
if(amount<0) /* subtract */
subtract_cdt(cfg, user, -amount);
else /* add */
user->cdt=adjustuserval(cfg, user->number, USER_CDT, amount);
}
bool user_adjust_minutes(scfg_t* cfg, user_t* user, long amount)
{
if(user==NULL)
user->min=(uint32_t)adjustuserval(cfg, user->number, USER_MIN, amount);
}

rswindell
committed
/****************************************************************************/
/****************************************************************************/
bool logoutuserdat(scfg_t* cfg, user_t* user, time_t now, time_t logontime)
{
char str[128];
struct tm tm, tm_now;
if(now==0)
now=time(NULL);
tused=(now-logontime)/60;
user->tlast=(ushort)(tused > USHRT_MAX ? USHRT_MAX : tused);
putuserdatetime(cfg,user->number, USER_LASTON, (time32_t)now);
putuserstr(cfg,user->number, USER_TLAST, ultoa(user->tlast,str,10));
adjustuserval(cfg,user->number, USER_TIMEON, user->tlast);
adjustuserval(cfg,user->number, USER_TTODAY, user->tlast);
/* Convert time_t to struct tm */
if(localtime_r(&now,&tm_now)==NULL)