Newer
Older
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
if(!chk_ar(cfg,cfg->lib[cfg->dir[dirnum]->lib]->ar,user,client))
return FALSE;
if(!chk_ar(cfg,cfg->dir[dirnum]->ar,user,client))
return FALSE;
return TRUE;
}
/****************************************************************************/
/* Determine if the specified user can or cannot upload files to the dirnum */
/* 'reason' is an (optional) pointer to a text.dat item number, indicating */
/* the reason the user cannot post, when returning FALSE. */
/****************************************************************************/
BOOL can_user_upload(scfg_t* cfg, uint dirnum, user_t* user, client_t* client, uint* reason)
{
if(reason!=NULL)
*reason=NoAccessDir;
if(!can_user_access_dir(cfg, dirnum, user, client))
return FALSE;
if(reason!=NULL)
*reason=R_Upload;
if(user->rest&FLAG('U')) /* upload restriction? */
return FALSE;
if(user->rest&FLAG('T')) /* transfer restriction? */
return FALSE;
if(!(user->exempt&FLAG('U')) /* upload exemption */
&& !is_user_dirop(cfg, dirnum, user, client)) {
if(reason!=NULL)
*reason=CantUploadHere;
if(!chk_ar(cfg, cfg->dir[dirnum]->ul_ar, user, client))
return FALSE;
}
return TRUE;
}
/****************************************************************************/
/* Determine if the specified user can or cannot download files from dirnum */
/* 'reason' is an (optional) pointer to a text.dat item number, indicating */
/* the reason the user cannot post, when returning FALSE. */
/****************************************************************************/
BOOL can_user_download(scfg_t* cfg, uint dirnum, user_t* user, client_t* client, uint* reason)
{
if(reason!=NULL)
*reason=NoAccessDir;
if(!can_user_access_dir(cfg, dirnum, user, client))
return FALSE;
if(reason!=NULL)
*reason=CantDownloadFromDir;
if(!chk_ar(cfg,cfg->dir[dirnum]->dl_ar,user,client))
return FALSE;
if(reason!=NULL)
*reason=R_Download;
if(user->rest&FLAG('D')) /* download restriction? */
return FALSE;
if(user->rest&FLAG('T')) /* transfer restriction? */
return FALSE;
return TRUE;
}
/****************************************************************************/
/* Determine if the specified user can or cannot send email */
/* 'reason' is an (optional) pointer to a text.dat item number */
/* usernumber==0 for netmail */
/****************************************************************************/
BOOL can_user_send_mail(scfg_t* cfg, enum smb_net_type net_type, uint usernumber, user_t* user, uint* reason)
{
if(reason!=NULL)
*reason=R_Email;
if(user==NULL || user->number==0)
return FALSE;
if(net_type==NET_NONE && usernumber>1 && user->rest&FLAG('E')) /* local mail restriction? */
return FALSE;
if(reason!=NULL)
*reason=NoNetMailAllowed;
if(net_type!=NET_NONE && user->rest&FLAG('M')) /* netmail restriction */
return FALSE;
if(net_type==NET_FIDO && !(cfg->netmail_misc&NMAIL_ALLOW)) /* Fido netmail globally disallowed */
return FALSE;
if(net_type==NET_INTERNET && !(cfg->inetmail_misc&NMAIL_ALLOW)) /* Internet mail globally disallowed */
return FALSE;
if(reason!=NULL)
*reason=R_Feedback;
if(net_type==NET_NONE && usernumber==1 && user->rest&FLAG('S')) /* feedback restriction? */
return FALSE;
if(reason!=NULL)
*reason=TooManyEmailsToday;
if(user->etoday>=cfg->level_emailperday[user->level] && !(user->exempt&FLAG('M')))
return FALSE;
return TRUE;
}
/****************************************************************************/
/* Determine if the specified user is a sub-board operator */
/****************************************************************************/
BOOL is_user_subop(scfg_t* cfg, uint subnum, user_t* user, client_t* client)
{
if(user==NULL)
return FALSE;
if(!can_user_access_sub(cfg, subnum, user, client))
return FALSE;
if(user->level>=SYSOP_LEVEL)
return TRUE;
return cfg->sub[subnum]->op_ar[0]!=0 && chk_ar(cfg,cfg->sub[subnum]->op_ar,user,client);
}
/****************************************************************************/
/* Determine if the specified user is a directory operator */
/****************************************************************************/
BOOL is_user_dirop(scfg_t* cfg, uint dirnum, user_t* user, client_t* client)
{
if(user==NULL)
return FALSE;
if(!can_user_access_dir(cfg, dirnum, user, client))
return FALSE;
if(user->level >= SYSOP_LEVEL)
return TRUE;
return cfg->dir[dirnum]->op_ar[0]!=0 && chk_ar(cfg,cfg->dir[dirnum]->op_ar,user,client);
/****************************************************************************/
/* Determine if downloads from the specified directory are free for the */
/* specified user */
/****************************************************************************/
BOOL is_download_free(scfg_t* cfg, uint dirnum, user_t* user, client_t* client)
{
if(!VALID_CFG(cfg))
return(FALSE);
if(dirnum>=cfg->total_dirs)
return(FALSE);
if(cfg->dir[dirnum]->misc&DIR_FREE)
return(TRUE);
if(user==NULL)
return(FALSE);
if(user->exempt&FLAG('D'))
return(TRUE);
return(FALSE);
BOOL is_host_exempt(scfg_t* cfg, const char* ip_addr, const char* host_name)
{
char exempt[MAX_PATH+1];
SAFEPRINTF2(exempt, "%s%s", cfg->ctrl_dir, strIpFilterExemptConfigFile);
return findstr(ip_addr, exempt) || findstr(host_name, exempt);
}
/****************************************************************************/
/* Add an IP address (with comment) to the IP filter/trashcan file */
/* ToDo: Move somewhere more appropriate (filter.c?) */
/****************************************************************************/
BOOL filter_ip(scfg_t* cfg, const char* prot, const char* reason, const char* host
,const char* ip_addr, const char* username, const char* fname)
{
char ip_can[MAX_PATH+1];
char exempt[MAX_PATH+1];
char tstr[64];
FILE* fp;
time_t now = time(NULL);
if(ip_addr==NULL)
return(FALSE);
SAFEPRINTF2(exempt, "%s%s", cfg->ctrl_dir, strIpFilterExemptConfigFile);
if(findstr(ip_addr, exempt))
return(FALSE);
if(findstr(host, exempt))
return(FALSE);
SAFEPRINTF(ip_can,"%sip.can",cfg->text_dir);
if(fname==NULL)
fname=ip_can;
if(findstr(ip_addr, fname)) /* Already filtered? */
return(TRUE);
if((fp=fopen(fname,"a"))==NULL)
return(FALSE);
fprintf(fp, "\n; %s %s ", prot, reason);
if(username != NULL)
fprintf(fp, "by %s ", username);
fprintf(fp,"on %.24s\n", ctime_r(&now, tstr));
if(host!=NULL)
fprintf(fp,"; Hostname: %s\n",host);
fclose(fp);
return(TRUE);
}
/****************************************************************************/
/* Note: This function does not account for timed events! */
/****************************************************************************/
time_t gettimeleft(scfg_t* cfg, user_t* user, time_t starttime)
{
time_t now;
long tleft;
time_t timeleft;
now=time(NULL);
if(user->exempt&FLAG('T')) { /* Time online exemption */
timeleft=cfg->level_timepercall[user->level];
if(timeleft<10) /* never get below 10 minutes for exempt users */
timeleft*=60; /* convert to seconds */
}
else {
tleft=(((long)cfg->level_timeperday[user->level]-user->ttoday)
+user->textra)*60L;
if(tleft<0) tleft=0;
if(tleft>cfg->level_timepercall[user->level]*60)
tleft=cfg->level_timepercall[user->level]*60;
tleft+=user->min*60L;
if(tleft>0x7fffL)
timeleft=0x7fff;
else
return(timeleft);
}
/*************************************************************************/
/* Check a supplied name/alias and see if it's valid by our standards. */
/*************************************************************************/
BOOL check_name(scfg_t* cfg, const char* name)
{
char tmp[512];
size_t len;
len=strlen(name);
if(len<1)
return FALSE;
if ( name[0] <= ' ' /* begins with white-space? */
|| name[len-1] <= ' ' /* ends with white-space */
|| !IS_ALPHA(name[0])
|| !stricmp(name,cfg->sys_id)
|| strchr(name,0xff)
|| matchuser(cfg,name,TRUE /* sysop_alias */)
|| trashcan(cfg,name,"name")
|| alias(cfg,name,tmp)!=name
)
return FALSE;
return TRUE;
/****************************************************************************/
/* Login attempt/hack tracking */
/****************************************************************************/
/****************************************************************************/
link_list_t* loginAttemptListInit(link_list_t* list)
{
return listInit(list, LINK_LIST_MUTEX);
}
/****************************************************************************/
BOOL loginAttemptListFree(link_list_t* list)
{
return listFree(list);
}
/****************************************************************************/
/* Returns negative value on failure */
/****************************************************************************/
long loginAttemptListCount(link_list_t* list)
if(!listLock(list))
return -1;
count = listCountNodes(list);
listUnlock(list);
return count;
}
/****************************************************************************/
/* Returns number of items (attempts) removed from the list */
/* Returns negative value on failure */
/****************************************************************************/
long loginAttemptListClear(link_list_t* list)
long count;
if(!listLock(list))
return -1;
count=listCountNodes(list);
count-=listFreeNodes(list);
listUnlock(list);
return count;
}
/****************************************************************************/
static list_node_t* login_attempted(link_list_t* list, const union xp_sockaddr* addr)
{
list_node_t* node;
login_attempt_t* attempt;
if(list==NULL)
return NULL;
for(node=list->first; node!=NULL; node=node->next) {
attempt=node->data;
if(attempt->addr.addr.sa_family != addr->addr.sa_family)
continue;
if(memcmp(&attempt->addr.in.sin_addr, &addr->in.sin_addr, sizeof(addr->in.sin_addr)) == 0)
return node;
if(memcmp(&attempt->addr.in6.sin6_addr, &addr->in6.sin6_addr, sizeof(addr->in6.sin6_addr)) == 0)
return node;
}
return NULL;
}
/****************************************************************************/
/* Returns negative value on failure */
/****************************************************************************/
long loginAttempts(link_list_t* list, const union xp_sockaddr* addr)
long count=0;
if(addr->addr.sa_family != AF_INET && addr->addr.sa_family != AF_INET6)
return 0;
if(!listLock(list))
return -1;
if((node=login_attempted(list, addr))!=NULL)
count = ((login_attempt_t*)node->data)->count - ((login_attempt_t*)node->data)->dupes;
listUnlock(list);
return count;
/****************************************************************************/
void loginSuccess(link_list_t* list, const union xp_sockaddr* addr)
{
list_node_t* node;
if(addr->addr.sa_family != AF_INET && addr->addr.sa_family != AF_INET6)
return;
listLock(list);
if((node=login_attempted(list, addr)) != NULL)
listRemoveNode(list, node, /* freeData: */TRUE);
listUnlock(list);
}
/****************************************************************************/
/* Returns number of *unique* login attempts (excludes consecutive dupes) */
/****************************************************************************/
ulong loginFailure(link_list_t* list, const union xp_sockaddr* addr, const char* prot, const char* user, const char* pass)
{
list_node_t* node;
login_attempt_t* attempt=&first;
ulong count=0;
if(addr->addr.sa_family != AF_INET && addr->addr.sa_family != AF_INET6)
return 0;
if(list==NULL)
return 0;
if(!listLock(list))
return 0;
if((node=login_attempted(list, addr)) != NULL) {
attempt=node->data;
/* Don't count consecutive duplicate attempts (same name and password): */
if((user!=NULL && strcmp(attempt->user,user)==0) && (pass!=NULL && strcmp(attempt->pass,pass)==0))
}
SAFECOPY(attempt->prot,prot);
attempt->time=time32(NULL);
memcpy(&attempt->addr, addr, sizeof(*addr));
if(user != NULL)
SAFECOPY(attempt->user, user);
memset(attempt->pass, 0, sizeof(attempt->pass));
if(pass != NULL)
SAFECOPY(attempt->pass, pass);
attempt->count++;
if(node==NULL)
listPushNodeData(list, attempt, sizeof(login_attempt_t));
listUnlock(list);
return count;
}
#if !defined(NO_SOCKET_SUPPORT)
ulong loginBanned(scfg_t* cfg, link_list_t* list, SOCKET sock, const char* host_name
,struct login_attempt_settings settings, login_attempt_t* details)
char ip_addr[128];
list_node_t* node;
login_attempt_t* attempt;
BOOL result = FALSE;
time32_t now = time32(NULL);
union xp_sockaddr client_addr;
union xp_sockaddr server_addr;
socklen_t addr_len;
char exempt[MAX_PATH+1];
SAFEPRINTF2(exempt, "%s%s", cfg->ctrl_dir, strIpFilterExemptConfigFile);
if(list==NULL)
return 0;
addr_len=sizeof(server_addr);
if((result=getsockname(sock, &server_addr.addr, &addr_len)) != 0)
return 0;
addr_len=sizeof(client_addr);
if((result=getpeername(sock, &client_addr.addr, &addr_len)) != 0)
return 0;
/* Don't ban connections from the server back to itself */
if(inet_addrmatch(&server_addr, &client_addr))
return 0;
if(inet_addrtop(&client_addr, ip_addr, sizeof(ip_addr)) != NULL
&& findstr(ip_addr, exempt))
return 0;
if(host_name != NULL
&& findstr(host_name, exempt))
return 0;
if(!listLock(list))
return 0;
node = login_attempted(list, &client_addr);
listUnlock(list);
if(node == NULL)
return 0;
attempt = node->data;
if(((settings.tempban_threshold && (attempt->count - attempt->dupes) >= settings.tempban_threshold)
|| trashcan(cfg, attempt->user, "name")) && now < (time32_t)(attempt->time + settings.tempban_duration)) {
if(details != NULL)
*details = *attempt;
return settings.tempban_duration - (now - attempt->time);
/****************************************************************************/
/* Message-new-scan pointer/configuration functions */
/****************************************************************************/
BOOL getmsgptrs(scfg_t* cfg, user_t* user, subscan_t* subscan, void (*progress)(void*, int, int), void* cbdata)
{
char path[MAX_PATH+1];
uint i;
int file;
long length;
FILE* stream;
/* Initialize to configured defaults */
for(i=0;i<cfg->total_subs;i++) {
subscan[i].ptr=subscan[i].sav_ptr=0;
subscan[i].last=subscan[i].sav_last=0;
subscan[i].cfg=0xff;
if(!(cfg->sub[i]->misc&SUB_NSDEF))
subscan[i].cfg&=~SUB_CFG_NSCAN;
if(!(cfg->sub[i]->misc&SUB_SSDEF))
subscan[i].cfg&=~SUB_CFG_SSCAN;
subscan[i].sav_cfg=subscan[i].cfg;
if(user->number == 0)
return 0;
if(user->rest&FLAG('G'))
return initmsgptrs(cfg, subscan, cfg->guest_msgscan_init, progress, cbdata);
/* New way: */
SAFEPRINTF2(path,"%suser/%4.4u.subs", cfg->data_dir, user->number);
FILE* fp = fnopen(NULL, path, O_RDONLY|O_TEXT);
if (fp != NULL) {
str_list_t ini = iniReadFile(fp);
for(i = 0; i < cfg->total_subs; i++) {
if(progress != NULL)
progress(cbdata, i, cfg->total_subs);
str_list_t keys = iniGetSection(ini, cfg->sub[i]->code);
if(keys == NULL)
continue;
subscan[i].ptr = iniGetLongInt(keys, NULL, "ptr" , subscan[i].ptr);
subscan[i].last = iniGetLongInt(keys, NULL, "last" , subscan[i].last);
subscan[i].cfg = iniGetShortInt(keys, NULL, "cfg" , subscan[i].cfg);
subscan[i].cfg &= (SUB_CFG_NSCAN|SUB_CFG_SSCAN|SUB_CFG_YSCAN); // Sanitize the 'cfg' value
subscan[i].sav_ptr = subscan[i].ptr;
subscan[i].sav_last = subscan[i].last;
subscan[i].sav_cfg = subscan[i].cfg;
iniFreeStringList(keys);
iniRemoveSection(&ini, cfg->sub[i]->code);
}
iniFreeStringList(ini);
fclose(fp);
if(progress != NULL)
progress(cbdata, i, cfg->total_subs);
return TRUE;
}
/* Old way: */
SAFEPRINTF2(path,"%suser/ptrs/%4.4u.ixb", cfg->data_dir, user->number);
if((stream=fnopen(&file,path,O_RDONLY))==NULL) {
if(fexist(path))
return(FALSE); /* file exists, but couldn't be opened? */
return initmsgptrs(cfg, subscan, cfg->new_msgscan_init, progress, cbdata);
}
length=(long)filelength(file);
for(i=0;i<cfg->total_subs;i++) {
if(progress != NULL)
progress(cbdata, i, cfg->total_subs);
if(length>=(cfg->sub[i]->ptridx+1)*10L) {
fseek(stream,(long)cfg->sub[i]->ptridx*10L,SEEK_SET);
fread(&subscan[i].ptr,sizeof(subscan[i].ptr),1,stream);
fread(&subscan[i].last,sizeof(subscan[i].last),1,stream);
fread(&subscan[i].cfg,sizeof(subscan[i].cfg),1,stream);
}
subscan[i].sav_ptr=subscan[i].ptr;
subscan[i].sav_last=subscan[i].last;
subscan[i].sav_cfg=subscan[i].cfg;
if(progress != NULL)
progress(cbdata, i, cfg->total_subs);
fclose(stream);
return(TRUE);
}
/****************************************************************************/
/* Writes to data/user/####.subs the msgptr array for the current user */
/* Pass usernumber value of 0 to indicate "Guest" login */
/****************************************************************************/
BOOL putmsgptrs(scfg_t* cfg, user_t* user, subscan_t* subscan)
uint i;
time_t now = time(NULL);
BOOL result = TRUE;
if(user->number==0 || (user->rest&FLAG('G'))) /* Guest */
return(TRUE);
fixmsgptrs(cfg, subscan);
SAFEPRINTF2(path,"%suser/%4.4u.subs", cfg->data_dir, user->number);
FILE* fp = fnopen(NULL, path, O_RDWR|O_CREAT|O_TEXT);
if (fp == NULL)
return FALSE;
str_list_t new = strListInit();
str_list_t ini = iniReadFile(fp);
ini_style_t ini_style = { .key_prefix = "\t", .section_separator = "" };
BOOL modified = FALSE;
for(i=0; i < cfg->total_subs; i++) {
str_list_t keys = iniGetSection(ini, cfg->sub[i]->code);
if(subscan[i].sav_ptr==subscan[i].ptr
&& subscan[i].sav_cfg==subscan[i].cfg
&& keys != NULL && *keys != NULL)
iniAppendSectionWithKeys(&new, cfg->sub[i]->code, keys, &ini_style);
else {
iniSetLongInt(&new, cfg->sub[i]->code, "ptr", subscan[i].ptr, &ini_style);
iniSetLongInt(&new, cfg->sub[i]->code, "last", subscan[i].last, &ini_style);
iniSetHexInt(&new, cfg->sub[i]->code, "cfg", subscan[i].cfg, &ini_style);
iniSetDateTime(&new, cfg->sub[i]->code, "updated", /* include_time: */TRUE, now, &ini_style);
modified = TRUE;
}
if(keys != NULL) {
iniRemoveSection(&ini, cfg->sub[i]->code);
iniFreeStringList(keys);
}
}
if(modified || strListCount(ini))
result = iniWriteFile(fp, new);
strListFree(&new);
iniFreeStringList(ini);
fclose(fp);
return result;
BOOL newmsgs(smb_t* smb, time_t t)
{
char index_fname[MAX_PATH + 1];
SAFEPRINTF(index_fname, "%s.sid", smb->file);
return fdate(index_fname) >= t;
}
/****************************************************************************/
/* Initialize new-msg-scan pointers (e.g. for new users) */
/* If 'days' is specified as 0, just set pointer to last message (faster) */
/****************************************************************************/
BOOL initmsgptrs(scfg_t* cfg, subscan_t* subscan, unsigned days, void (*progress)(void*, int, int), void* cbdata)
{
uint i;
smb_t smb;
idxrec_t idx;
time_t t = time(NULL) - (days * 24 * 60 * 60);
for(i=0;i<cfg->total_subs;i++) {
if(progress != NULL)
progress(cbdata, i, cfg->total_subs);
/* This value will be "fixed" (changed to the last msg) when saving */
subscan[i].ptr = ~0;
if(days == 0)
continue;
ZERO_VAR(smb);
SAFEPRINTF2(smb.file,"%s%s",cfg->sub[i]->data_dir,cfg->sub[i]->code);
if(!newmsgs(&smb, t))
continue;
smb.retry_time=cfg->smb_retry_time;
smb.subnum=i;
if(smb_open_index(&smb) != SMB_SUCCESS)
memset(&idx, 0, sizeof(idx));
smb_getlastidx(&smb, &idx);
subscan[i].ptr = idx.number;
if(idx.time >= t && smb_getmsgidx_by_time(&smb, &idx, t) >= SMB_SUCCESS)
subscan[i].ptr = idx.number - 1;
smb_close(&smb);
}
if(progress != NULL)
progress(cbdata, i, cfg->total_subs);
return TRUE;
}
/****************************************************************************/
/* Insure message new-scan pointers are within the range of the msgs in */
/* the sub-board. */
/****************************************************************************/
BOOL fixmsgptrs(scfg_t* cfg, subscan_t* subscan)
{
uint i;
smb_t smb;
for(i=0;i<cfg->total_subs;i++) {
if(subscan[i].ptr == 0)
continue;
if(subscan[i].ptr < ~0 && subscan[i].sav_ptr == subscan[i].ptr)
continue;
ZERO_VAR(smb);
SAFEPRINTF2(smb.file,"%s%s",cfg->sub[i]->data_dir,cfg->sub[i]->code);
smb.retry_time=cfg->smb_retry_time;
smb.subnum=i;
if(smb_open_index(&smb) != SMB_SUCCESS) {
subscan[i].ptr = 0;
continue;
}
idxrec_t idx;
memset(&idx, 0, sizeof(idx));
smb_getlastidx(&smb, &idx);
if(subscan[i].ptr > idx.number)
subscan[i].ptr = idx.number;
if(subscan[i].last > idx.number)
subscan[i].last = idx.number;
static char* sysop_available_semfile(scfg_t* scfg)
{
static char semfile[MAX_PATH+1];
SAFEPRINTF(semfile, "%ssysavail.chat", scfg->ctrl_dir);
return semfile;
}
BOOL sysop_available(scfg_t* scfg)
{
return fexist(sysop_available_semfile(scfg));
}
BOOL set_sysop_availability(scfg_t* scfg, BOOL available)
{
if(available)
return ftouch(sysop_available_semfile(scfg));
return remove(sysop_available_semfile(scfg)) == 0;
}
static char* sound_muted_semfile(scfg_t* scfg)
{
static char semfile[MAX_PATH+1];
SAFEPRINTF(semfile, "%ssound.mute", scfg->ctrl_dir);
return semfile;
}
BOOL sound_muted(scfg_t* scfg)
{
return fexist(sound_muted_semfile(scfg));
}
BOOL set_sound_muted(scfg_t* scfg, BOOL muted)
{
if(muted)
return ftouch(sound_muted_semfile(scfg));
return remove(sound_muted_semfile(scfg)) == 0;
}
/************************************/
/* user .ini file get/set functions */
/************************************/
static FILE* user_ini_open(scfg_t* scfg, unsigned user_number, BOOL create)
{
char path[MAX_PATH+1];
SAFEPRINTF2(path, "%suser/%04u.ini", scfg->data_dir, user_number);
return iniOpenFile(path, create);
}
BOOL user_get_property(scfg_t* scfg, unsigned user_number, const char* section, const char* key, char* value, size_t maxlen)
{
FILE* fp;
char buf[INI_MAX_VALUE_LEN];
fp = user_ini_open(scfg, user_number, /* create: */FALSE);
if(fp == NULL)
return FALSE;
char* result = iniReadValue(fp, section, key, NULL, buf);
if(result != NULL)
safe_snprintf(value, maxlen, "%s", result);
iniCloseFile(fp);
return result != NULL;
}
BOOL user_set_property(scfg_t* scfg, unsigned user_number, const char* section, const char* key, const char* value)
{
FILE* fp;
str_list_t ini;
fp = user_ini_open(scfg, user_number, /* create: */TRUE);
if(fp == NULL)
return FALSE;
ini = iniReadFile(fp);
ini_style_t ini_style = { .key_prefix = "\t", .section_separator = "", .value_separator = " = " };
char* result = iniSetValue(&ini, section, key, value, &ini_style);
iniWriteFile(fp, ini);
iniFreeStringList(ini);
iniCloseFile(fp);
return result != NULL;
}
BOOL user_set_time_property(scfg_t* scfg, unsigned user_number, const char* section, const char* key, time_t value)
{
FILE* fp;
str_list_t ini;
fp = user_ini_open(scfg, user_number, /* create: */TRUE);
if(fp == NULL)
return FALSE;
ini = iniReadFile(fp);
ini_style_t ini_style = { .key_prefix = "\t", .section_separator = "", .value_separator = " = " };
char* result = iniSetDateTime(&ini, section, key, /* include_time */TRUE, value, &ini_style);
iniWriteFile(fp, ini);
iniFreeStringList(ini);
iniCloseFile(fp);
return result != NULL;
}
#endif /* !NO_SOCKET_SUPPORT */
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
/****************************************************************************/
/* Returns user number or 0 on failure or "user not found". */
/****************************************************************************/
int lookup_user(scfg_t* cfg, link_list_t* list, const char *inname)
{
if(inname == NULL || *inname == 0)
return 0;
if(list->first == NULL) {
user_t user;
int userdat = openuserdat(cfg, /* modify */FALSE);
if(userdat < 0)
return 0;
for(user.number = 1; ;user.number++) {
if(fgetuserdat(cfg, &user, userdat) != 0)
break;
if(user.misc&DELETED)
continue;
listPushNodeData(list, &user, sizeof(user));
}
close(userdat);
}
for(list_node_t* node = listFirstNode(list); node != NULL; node = node->next) {
if(matchusername(cfg, ((user_t*)node->data)->alias, inname))
return ((user_t*)node->data)->number;
}
for(list_node_t* node = listFirstNode(list); node != NULL; node = node->next) {
if(matchusername(cfg, ((user_t*)node->data)->name, inname))
return ((user_t*)node->data)->number;
}
return 0;
}
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
/* Returns the directory index of a virtual lib/dir path (e.g. main/games/filename) */
int getdir_from_vpath(scfg_t* cfg, const char* p, user_t* user, client_t* client, BOOL include_upload_only)
{
char* tp;
char path[MAX_PATH+1];
uint dir;
uint lib;
SAFECOPY(path,p);
p=path;
if(*p=='/')
p++;
if(!strncmp(p,"./",2))
p+=2;
tp=strchr(p,'/');
if(tp) *tp=0;
for(lib=0;lib<cfg->total_libs;lib++) {
if(!chk_ar(cfg,cfg->lib[lib]->ar,user,client))
continue;
if(!stricmp(cfg->lib[lib]->vdir,p))
break;
}
if(lib>=cfg->total_libs)
return(-1);
if(tp!=NULL)
p=tp+1;
tp=strchr(p,'/');
if(tp) *tp=0;
for(dir=0;dir<cfg->total_dirs;dir++) {
if(cfg->dir[dir]->lib!=lib)
continue;
if((!include_upload_only || (dir!=cfg->sysop_dir && dir!=cfg->upload_dir))
&& !chk_ar(cfg,cfg->dir[dir]->ar,user,client))
continue;
if(!stricmp(cfg->dir[dir]->vdir,p))
break;
}
if(dir>=cfg->total_dirs)
return(-1);
return(dir);
}