Skip to content
Snippets Groups Projects
userdat.c 122 KiB
Newer Older
	if(!VALID_CFG(cfg) || birth==NULL)
		return(0);

	if(!atoi(birth) || !atoi(birth+3))	/* Invalid */
		return(0);

	now=time(NULL);
	tm.tm_mon++;	/* convert to 1 based */
	int year = getbirthyear(birth);
	int age = (1900 + tm.tm_year) - year;
	int mon = getbirthmonth(cfg, birth);
	int day = getbirthday(cfg, birth);
	if(mon < 1 || mon > 12 || day < 1 || day > 31)
		return 0;
	if(mon > tm.tm_mon || (mon == tm.tm_mon && day > tm.tm_mday))
/****************************************************************************/
/* Converts from MM/DD/YYYYY, DD/MM/YYYY, or YYYY/MM/DD to YYYYMMDD			*/
/****************************************************************************/
char* parse_birthdate(scfg_t* cfg, const char* birthdate, char* out, size_t maxlen)
{
	if (cfg->sys_date_fmt == YYMMDD)
		safe_snprintf(out, maxlen, "%.4s%.2s%.2s", birthdate, birthdate + 5, birthdate + 8);
	else if (cfg->sys_date_fmt == DDMMYY)
		safe_snprintf(out, maxlen, "%.4s%.2s%.2s", birthdate + 6, birthdate + 3, birthdate);
	else
		safe_snprintf(out, maxlen, "%.4s%.2s%.2s", birthdate + 6, birthdate, birthdate + 3);
	return out;
}

/****************************************************************************/
/* Converts from user birth date to MM/DD/YYYYY, DD/MM/YYYY, or YYYY/MM/DD	*/
/****************************************************************************/
char* format_birthdate(scfg_t* cfg, const char* birthdate, char* out, size_t maxlen)
{
	if(maxlen < 1)
		return NULL;
	*out = '\0';
	if(*birthdate) {
		if (cfg->sys_date_fmt == YYMMDD)
			safe_snprintf(out, maxlen, "%04u%c%02u%c%02u"
				, getbirthyear(birthdate)
				, cfg->sys_date_sep
				, getbirthmonth(cfg, birthdate)
				, cfg->sys_date_sep
				, getbirthday(cfg, birthdate));
		else if (cfg->sys_date_fmt == DDMMYY)
			safe_snprintf(out, maxlen, "%02u%c%02u%c%04u"
				, getbirthday(cfg, birthdate)
				, cfg->sys_date_sep
				, getbirthmonth(cfg, birthdate)
				, cfg->sys_date_sep
				, getbirthyear(birthdate));
			safe_snprintf(out, maxlen, "%02u%c%02u%c%04u"
				, getbirthmonth(cfg, birthdate)
				, cfg->sys_date_sep
				, getbirthday(cfg, birthdate)
				, cfg->sys_date_sep
				, getbirthyear(birthdate));
/****************************************************************************/
/****************************************************************************/
char* birthdate_format(scfg_t* cfg, char* buf, size_t size)
	switch (cfg->sys_date_fmt) {
		case MMDDYY: snprintf(buf, size, "MM%cDD%cYYYY", cfg->sys_date_sep, cfg->sys_date_sep); return buf;
		case DDMMYY: snprintf(buf, size, "DD%cMM%cYYYY", cfg->sys_date_sep, cfg->sys_date_sep); return buf;
		case YYMMDD: snprintf(buf, size, "YYYY%cMM%cDD", cfg->sys_date_sep, cfg->sys_date_sep); return buf;
/****************************************************************************/
/****************************************************************************/
char* birthdate_template(scfg_t* cfg, char* buf, size_t size)
{
	if (cfg->sys_date_fmt == YYMMDD)
		snprintf(buf, size, "nnnn%cnn%cnn", cfg->sys_date_sep, cfg->sys_date_sep);
	else
		snprintf(buf, size, "nn%cnn%cnnnn", cfg->sys_date_sep, cfg->sys_date_sep);
	return buf;
}

/****************************************************************************/
/****************************************************************************/
int opennodedat(scfg_t* cfg)
{
	char	fname[MAX_PATH+1];

	if(!VALID_CFG(cfg))
		return -1;

	SAFEPRINTF(fname, "%snode.dab", cfg->ctrl_dir);
	return nopen(fname, O_RDWR|O_DENYNONE);
}

/****************************************************************************/
/****************************************************************************/
int opennodeext(scfg_t* cfg)
{
	char	fname[MAX_PATH+1];

	if(!VALID_CFG(cfg))
		return -1;

	SAFEPRINTF(fname, "%snode.exb", cfg->ctrl_dir);
	return nopen(fname, O_RDWR|O_DENYNONE);
}

/****************************************************************************/
/* Reads the data for 1-based node number 'number' into the node structure	*/
/****************************************************************************/
int getnodedat(scfg_t* cfg, uint number, node_t *node, bool lockit, int* fdp)
	int		count=0;
	if(!VALID_CFG(cfg)
		|| node==NULL || number<1 || number>cfg->sys_nodes)
	memset(node,0,sizeof(node_t));
	if(fdp != NULL && *fdp > 0)
		file = *fdp;
	else {
		if((file = opennodedat(cfg)) == -1)
			return errno;
	}
	if(filelength(file)>=(long)(number*sizeof(node_t))) {
		number--;	/* make zero based */
		for(count=0;count<LOOP_NODEDAB;count++) {
			if(count)
				mswait(100);
			(void)lseek(file,(long)number*sizeof(node_t),SEEK_SET);
				&& lock(file,(long)number*sizeof(node_t),sizeof(node_t))!=0)
				continue;
			rd=read(file,node,sizeof(node_t));
				unlock(file,(long)number*sizeof(node_t),sizeof(node_t));
			if(rd==sizeof(node_t))
	if(fdp==NULL || count==LOOP_NODEDAB)
		CLOSE_OPEN_FILE(file);
	if(fdp!=NULL)
	if(count==LOOP_NODEDAB)
		return(-2);

	return(0);
}

/****************************************************************************/
/* Write the data from the structure 'node' into node.dab  					*/
/****************************************************************************/
int putnodedat(scfg_t* cfg, uint number, node_t* node, bool closeit, int file)
	if(!VALID_CFG(cfg)
		|| node==NULL || number<1 || number>cfg->sys_nodes) {

	number--;	/* make zero based */
	for(attempts=0;attempts<LOOP_USERDAT;attempts++) {
		(void)lseek(file,(long)number*sizeof(node_t),SEEK_SET);
		if((wr=write(file,node,sizeof(node_t)))==sizeof(node_t))
			break;
		wrerr=errno;	/* save write error */
		mswait(((attempts + 1) / 10) * 100);
	}
	unlock(file,(long)number*sizeof(node_t),sizeof(node_t));
	if(wr!=sizeof(node_t))
		return(wrerr);
/****************************************************************************/
/****************************************************************************/
bool set_node_status(scfg_t* cfg, int nodenum, enum node_status status)
	int file = -1;
	if(getnodedat(cfg, nodenum, &node, /* lockit: */true, &file) != 0)
		return false;
	return putnodedat(cfg, nodenum, &node, /* closeit: */true, file) == 0;
}

/****************************************************************************/
/****************************************************************************/
bool set_node_misc(scfg_t* cfg, int nodenum, uint misc)
	int file = -1;
	if(getnodedat(cfg, nodenum, &node, /* lockit: */true, &file) != 0)
		return false;
	return putnodedat(cfg, nodenum, &node, /* closeit: */true, file) == 0;
}

/****************************************************************************/
/****************************************************************************/
bool set_node_lock(scfg_t* cfg, int nodenum, bool set)
	int file = -1;
	if(getnodedat(cfg, nodenum, &node, /* lockit: */true, &file) != 0)
		return false;
	if(set)
		node.misc |= NODE_LOCK;
	else
		node.misc &= ~NODE_LOCK;
	return putnodedat(cfg, nodenum, &node, /* closeit: */true, file) == 0;
}

/****************************************************************************/
/****************************************************************************/
bool set_node_interrupt(scfg_t* cfg, int nodenum, bool set)
	int file = -1;
	if(getnodedat(cfg, nodenum, &node, /* lockit: */true, &file) != 0)
		return false;
	if(set)
		node.misc |= NODE_INTR;
	else
		node.misc &= ~NODE_INTR;
	return putnodedat(cfg, nodenum, &node, /* closeit: */true, file) == 0;
}

/****************************************************************************/
/****************************************************************************/
bool set_node_down(scfg_t* cfg, int nodenum, bool set)
	int file = -1;
	if(getnodedat(cfg, nodenum, &node, /* lockit: */true, &file) != 0)
		return false;
	if(set)
		node.misc |= NODE_DOWN;
	else
		node.misc &= ~NODE_DOWN;
	return putnodedat(cfg, nodenum, &node, /* closeit: */true, file) == 0;
}

/****************************************************************************/
/****************************************************************************/
bool set_node_rerun(scfg_t* cfg, int nodenum, bool set)
	int file = -1;
	if(getnodedat(cfg, nodenum, &node, /* lockit: */true, &file) != 0)
		return false;
	if(set)
		node.misc |= NODE_RRUN;
	else
		node.misc &= ~NODE_RRUN;
	return putnodedat(cfg, nodenum, &node, /* closeit: */true, file) == 0;
}

/****************************************************************************/
/****************************************************************************/
bool set_node_errors(scfg_t* cfg, int nodenum, uint errors)
	int file = -1;
	if(getnodedat(cfg, nodenum, &node, /* lockit: */true, &file) != 0)
		return false;
	return putnodedat(cfg, nodenum, &node, /* closeit: */true, file) == 0;
/****************************************************************************/
/* Packs the password 'pass' into 5bit ASCII inside node_t. 32bits in 		*/
/* node.extaux, and the other 8bits in the upper byte of node.aux			*/
/****************************************************************************/
void packchatpass(char *pass, node_t *node)
	if(pass==NULL || node==NULL)
		return;

	node->aux&=~0xff00;		/* clear the password */
	node->extaux=0L;
	if((j=strlen(pass))==0) /* there isn't a password */
		return;
	node->aux|=(int)((pass[0]-64)<<8);  /* 1st char goes in low 5bits of aux */
	if(j==1)	/* password is only one char, we're done */
		return;
	node->aux|=(int)((pass[1]-64)<<13); /* low 3bits of 2nd char go in aux */
	node->extaux|=(long)((pass[1]-64)>>3); /* high 2bits of 2nd char go extaux */
	bits=2;
	for(i=2;i<j;i++) {	/* now process the 3rd char through the last */
		node->extaux|=(long)((long)(pass[i]-64)<<bits);
	}
}

/****************************************************************************/
/* Unpacks the password 'pass' from the 5bit ASCII inside node_t. 32bits in */
/* node.extaux, and the other 8bits in the upper byte of node.aux			*/
/****************************************************************************/
char* unpackchatpass(char *pass, node_t* node)
	if(pass==NULL || node==NULL)
		return(NULL);

	pass[0]=(node->aux&0x1f00)>>8;
	pass[1]=(char)(((node->aux&0xe000)>>13)|((node->extaux&0x3)<<3));
	bits=2;
	for(i=2;i<8;i++) {
		pass[i]=(char)((node->extaux>>bits)&0x1f);
	}
	pass[8]=0;
	for(i=0;i<8;i++)
		if(pass[i])
			pass[i]+=64;
	return(pass);
}

static char* node_connection_desc(ushort conn, char* str)
{
	switch(conn) {
		case NODE_CONNECTION_LOCAL:
			strcpy(str,"Locally");
			break;
		case NODE_CONNECTION_TELNET:
			strcpy(str,"via telnet");
			break;
		case NODE_CONNECTION_RLOGIN:
			strcpy(str,"via rlogin");
			break;
		case NODE_CONNECTION_SSH:
			strcpy(str,"via ssh");
			break;
		case NODE_CONNECTION_SFTP:
			strcpy(str,"via sftp");
			break;
		case NODE_CONNECTION_RAW:
			strcpy(str,"via raw");
			break;
char* getnodeext(scfg_t* cfg, int num, char* buf)
{
	int f;

	if(!VALID_CFG(cfg) || num < 1)
		return "";
	(void)lseek(f, (num-1) * 128, SEEK_SET);
	if(read(f, buf, 128) != 128)
		memset(buf, 0, 128);
	close(f);
	buf[127] = 0;
	return buf;
}

char* nodestatus(scfg_t* cfg, node_t* node, char* buf, size_t buflen, int num)
	if(node==NULL) {
		strncpy(buf,"(null)",buflen);
		return(buf);
            SAFECOPY(str,"Waiting for connection");
            break;
        case NODE_OFFLINE:
            strcpy(str,"Offline");
            break;
        case NODE_NETTING:	/* Obsolete */
				,node_connection_desc(node->connection, tmp));
		case NODE_LOGOUT:
			SAFEPRINTF(str,"Logging out %s", username(cfg,node->useron,tmp));
			break;
            SAFECOPY(str,"Waiting for all nodes to become inactive");
            SAFEPRINTF(str,"Waiting for node %d to finish external event"
            SAFECOPY(str,"Running external event");
            SAFEPRINTF(str,"New user applying for access %s"
				,node_connection_desc(node->connection, tmp));
			if(node->misc & NODE_EXT) {
				getnodeext(cfg, num, str);
				break;
			}
            username(cfg,node->useron,str);
            strcat(str," ");
            switch(node->action) {
                case NODE_MAIN:
                    strcat(str,"at main menu");
                    break;
                case NODE_RMSG:
                    strcat(str,"reading messages");
                    break;
                case NODE_RMAL:
                    strcat(str,"reading mail");
                    break;
                case NODE_RSML:
                    strcat(str,"reading sent mail");
                    break;
                case NODE_RTXT:
                    strcat(str,"reading text files");
                    break;
                case NODE_PMSG:
                    strcat(str,"posting message");
                    break;
                case NODE_SMAL:
                    strcat(str,"sending mail");
                    break;
                case NODE_AMSG:
                    strcat(str,"posting auto-message");
                    break;
                case NODE_XTRN:
                        strcat(str,"at external program menu");
						break;
					}
					user.number = node->useron;
					getuserdat(cfg, &user);
					xtrnnum = getxtrnnum(cfg, user.curxtrn);
					if(is_valid_xtrnnum(cfg, xtrnnum))
						sprintf(str+strlen(str),"running %s"
							,cfg->xtrn[xtrnnum]->name);
					else if(*user.curxtrn != '\0')
						sprintf(str+strlen(str),"running external program %s"
							,user.curxtrn);
					else
						sprintf(str+strlen(str),"running external program #%d"
                    break;
                case NODE_DFLT:
                    strcat(str,"changing defaults");
                    break;
                case NODE_XFER:
                    strcat(str,"at transfer menu");
                    break;
                case NODE_RFSD:
                    sprintf(str+strlen(str),"retrieving from device #%d",node->aux);
                    break;
                case NODE_DLNG:
                    strcat(str,"downloading");
                    break;
                case NODE_ULNG:
                    strcat(str,"uploading");
                    break;
                case NODE_BXFR:
                    strcat(str,"transferring bidirectional");
                    break;
                case NODE_LFIL:
                    strcat(str,"listing files");
                    break;
                case NODE_LOGN:
                    strcat(str,"logging on");
                    break;
                case NODE_LCHT:
                    strcat(str,"in local chat with sysop");
                    break;
                case NODE_MCHT:
                    if(node->aux) {
                        sprintf(str+strlen(str),"in multinode chat channel %d"
                            ,node->aux&0xff);
                        if(node->aux&0x1f00) { /* password */
                            strcat(str,"* ");
                            unpackchatpass(str+strlen(str),node);
                        }
                    }
                    else
                        strcat(str,"in multinode global chat channel");
                    break;
                case NODE_PAGE:
                    sprintf(str+strlen(str)
						,"paging node %u for private chat",node->aux);
                    break;
                case NODE_PCHT:
                    if(node->aux==0)
                        sprintf(str+strlen(str)
							,"in local chat with %s"
							,cfg->sys_op);
                    else
                        sprintf(str+strlen(str)
							,"in private chat with node %u"
                            ,node->aux);
                    break;
                case NODE_GCHT:
                    strcat(str,"chatting with The Guru");
                    break;
                case NODE_CHAT:
                    strcat(str,"in chat section");
                    break;
                case NODE_TQWK:
                    strcat(str,"transferring QWK packet");
                    break;
                case NODE_SYSP:
                    strcat(str,"performing sysop activities");
                    break;
                default:
rswindell's avatar
rswindell committed
                    sprintf(str+strlen(str),"%d",node->action);
			sprintf(str+strlen(str)," %s",node_connection_desc(node->connection, tmp));
            if(node->action==NODE_DLNG) {
                if((node->aux/60)>=12) {
                    if(node->aux/60==12)
                        hour=12;
                    else
                        hour=(node->aux/60)-12;
                    mer="pm";
                } else {
                    if((node->aux/60)==0)    /* 12 midnite */
                        hour=12;
                    else hour=node->aux/60;
                    mer="am";
                }
                sprintf(str+strlen(str), " ETA %02d:%02d %s"
                    ,hour,node->aux-((node->aux/60)*60),mer);
            }
	}
    if(node->misc&(NODE_LOCK|NODE_POFF|NODE_AOFF|NODE_MSGW|NODE_NMSG)) {
        strcat(str," (");
        if(node->misc&NODE_AOFF)
            strcat(str,"A");
        if(node->misc&NODE_LOCK)
            strcat(str,"L");
        if(node->misc&NODE_POFF)
            strcat(str,"P");
        strcat(str,")");
	}
    if(((node->misc
        &(NODE_ANON|NODE_UDAT|NODE_INTR|NODE_RRUN|NODE_EVENT|NODE_DOWN))
        || node->status==NODE_QUIET)) {
        strcat(str," [");
        if(node->misc&NODE_ANON)
            strcat(str,"A");
        if(node->misc&NODE_INTR)
            strcat(str,"I");
        if(node->misc&NODE_RRUN)
            strcat(str,"R");
        if(node->misc&NODE_UDAT)
            strcat(str,"U");
        if(node->status==NODE_QUIET)
            strcat(str,"Q");
        if(node->misc&NODE_EVENT)
            strcat(str,"E");
        if(node->misc&NODE_DOWN)
            strcat(str,"D");
        if(node->misc&NODE_LCHAT)
            strcat(str,"C");
        if(node->misc&NODE_FCHAT)
            strcat(str,"F");
        strcat(str,"]");
	if(node->errors)
		sprintf(str+strlen(str)
			," %d error%c",node->errors, node->errors>1 ? 's' : '\0' );

	strncpy(buf,str,buflen);

	return(buf);

/****************************************************************************/
/* Displays the information for node number 'number' contained in 'node'    */
/****************************************************************************/
void printnodedat(scfg_t* cfg, uint number, node_t* node)
	printf("Node %2d: %s\n",number,nodestatus(cfg,node,status,sizeof(status),number));
/****************************************************************************/
uint finduserstr(scfg_t* cfg, uint usernumber, enum user_field fnum
						 ,const char* str, bool del, bool next, void (*progress)(void*, int, int), void* cbdata)
	if(!VALID_CFG(cfg) || str == NULL)
	if((file=openuserdat(cfg, /* for_modify: */false)) == -1)
	int last = (int)filelength(file) / USER_RECORD_LINE_LEN;
	if(usernumber && next)
		progress(cbdata, unum, last);
	for(;unum <= last && found == 0; unum++) {
			progress(cbdata, unum, last);
		if(usernumber && unum == usernumber)
			continue;
		char userdat[USER_RECORD_LEN + 1];
		if(readuserdat(cfg, unum, userdat, sizeof(userdat), file, /* leave_locked: */false) == 0) {
			char* field[USER_FIELD_COUNT];
			split_userdat(userdat, field);
			if(stricmp(field[fnum], str) == 0) {
				if(del || !(ahtou32(field[USER_MISC]) & (DELETED|INACTIVE)))
					found = unum;
		progress(cbdata, unum, last);
	return found;
}

/****************************************************************************/
/* Creates a short message for 'usernumber' that contains 'strin'           */
/****************************************************************************/
int putsmsg(scfg_t* cfg, int usernumber, char *strin)
{
    char str[256];
    int file,i;
    node_t node;

	if(!VALID_CFG(cfg) || !VALID_USER_NUMBER(usernumber) || strin==NULL)
	SAFEPRINTF2(str,"%smsgs/%4.4u.msg",cfg->data_dir,usernumber);
	if((file=nopen(str,O_WRONLY|O_CREAT|O_APPEND))==-1) {
	}
	i=strlen(strin);
	if(write(file,strin,i)!=i) {
		close(file);
	for(i=1;i<=cfg->sys_nodes;i++) {     /* flag node if user on that msg waiting */
		getnodedat(cfg,i,&node,/* lockit: */false, &file);
		if(node.useron==usernumber
			&& (node.status==NODE_INUSE || node.status==NODE_QUIET)
			&& !(node.misc&NODE_MSGW)) {
			if(getnodedat(cfg,i,&node, /* lockit: */true, &file)==0) {
				putnodedat(cfg,i,&node, /* closeit: */false, file);
/****************************************************************************/
/* Returns any short messages waiting for user number, buffer must be freed */
/****************************************************************************/
char* getsmsg(scfg_t* cfg, int usernumber)
	if(!VALID_CFG(cfg) || !VALID_USER_NUMBER(usernumber))
	for(i=1;i<=cfg->sys_nodes;i++) {	/* clear msg waiting flag */
		getnodedat(cfg,i,&node, /* lockit: */false, &file);
		if(node.useron==usernumber
			&& (node.status==NODE_INUSE || node.status==NODE_QUIET)
			&& node.misc&NODE_MSGW) {
			if(getnodedat(cfg,i,&node, /* lockit: */true, &file) == 0) {
				putnodedat(cfg,i,&node, /* closeit: */false, file);
	return readsmsg(cfg, usernumber);
}

/****************************************************************************/
/* Returns any short messages waiting for user number, buffer must be freed */
/****************************************************************************/
char* readsmsg(scfg_t* cfg, int usernumber)
{
	char	str[MAX_PATH+1], *buf;
    int		file;
    long	length;

	if(!VALID_CFG(cfg) || !VALID_USER_NUMBER(usernumber))
	SAFEPRINTF2(str,"%smsgs/%4.4u.msg",cfg->data_dir,usernumber);
	if(flength(str)<1L)
		return(NULL);
	if((file=nopen(str,O_RDWR))==-1)
		return(NULL);
	if(length < 0 || (buf=(char *)malloc(length+1))==NULL) {
	if(read(file,buf,length)!=length || chsize(file, 0) != 0) {
		close(file);
		free(buf);
		return(NULL);
	}
	close(file);
	buf[length]=0;
	SAFEPRINTF2(str, "%smsgs/%4.4u.last.msg", cfg->data_dir, usernumber);
	backup(str, 19, /* rename: */true);
	if((file = nopen(str, O_WRONLY|O_CREAT|O_APPEND)) != -1) {
		int wr = write(file, buf, length);
		if(wr != length) {
			free(buf);
			return NULL;
		}
char* getnmsg(scfg_t* cfg, int node_num)
	if(!VALID_CFG(cfg) || node_num<1)
		return(NULL);

	if(getnodedat(cfg,node_num,&node, /* lockit: */true, &file) == 0) {
		node.misc&=~NODE_NMSG;          /* clear the NMSG flag */
		putnodedat(cfg,node_num,&node, /* closeit: */true, file);
	SAFEPRINTF2(str,"%smsgs/n%3.3u.msg",cfg->data_dir,node_num);
	if(flength(str)<1L)
		return(NULL);
	if((file=nopen(str,O_RDWR))==-1)
	if(length < 1) {
	}
	if((buf=(char *)malloc(length+1))==NULL) {
		close(file);
	if(read(file,buf,length)!=length || chsize(file, 0) != 0) {
		close(file);
		free(buf);
		return(NULL);
	}
	close(file);
	buf[length]=0;

	return(buf);	/* caller must free */
}

/****************************************************************************/
/* Creates a short message for node 'num' that contains 'strin'             */
/****************************************************************************/
int putnmsg(scfg_t* cfg, int num, char *strin)
	if(!VALID_CFG(cfg) || num<1 || strin==NULL)
		return(-1);

	SAFEPRINTF2(str,"%smsgs/n%3.3u.msg",cfg->data_dir,num);
	if((file=nopen(str,O_WRONLY|O_CREAT))==-1)
	(void)lseek(file,0L,SEEK_END);	/* Instead of opening with O_APPEND */
	i=strlen(strin);
	if(write(file,strin,i)!=i) {
		close(file);
	getnodedat(cfg,num,&node, /* lockit: */false, &file);
	if((node.status==NODE_INUSE || node.status==NODE_QUIET)
		&& !(node.misc&NODE_NMSG)) {
		if(getnodedat(cfg,num,&node, /* lockit: */true, &file) == 0) {
			putnodedat(cfg,num,&node, /* closeit: */false, file);
/* Return node's client's socket descriptor or negative on error */
int getnodeclient(scfg_t* cfg, uint number, client_t* client, time_t* done)
{
	SOCKET sock = INVALID_SOCKET;
	char path[MAX_PATH + 1];
	char value[INI_MAX_VALUE_LEN];
	FILE* fp;

	if(!VALID_CFG(cfg)
		|| client == NULL || number < 1 || number > cfg->sys_nodes)
		return -1;

	memset(client, 0, sizeof(*client));
	client->size = sizeof(client);
	SAFEPRINTF(path, "%sclient.ini", cfg->node_path[number - 1]);
	fp = iniOpenFile(path, /* for_modify: */false);
	if(fp == NULL)
		return -2;
	sock = iniReadShortInt(fp, ROOT_SECTION, "sock", 0);
	client->port = iniReadShortInt(fp, ROOT_SECTION, "port", 0);
	client->time = iniReadInteger(fp, ROOT_SECTION, "time", 0);
	client->usernum = iniReadInteger(fp, ROOT_SECTION, "user", 0);
	SAFECOPY(client->addr, iniReadString(fp, ROOT_SECTION, "addr", "<none>", value));
	SAFECOPY(client->host, iniReadString(fp, ROOT_SECTION, "host", "<none>", value));
	SAFECOPY(client->protocol, iniReadString(fp, ROOT_SECTION, "prot", "<unknown>", value));
	SAFECOPY(client->user, iniReadString(fp, ROOT_SECTION, "name", "<unknown>", value));
	*done = iniReadInteger(fp, ROOT_SECTION, "done", client->time);
static bool ar_exp(scfg_t* cfg, uchar **ptrptr, user_t* user, client_t* client)
	bool	result,not,or,equal;
	uint	i,n,artype=AR_LEVEL,age;
rswindell's avatar
rswindell committed
	const char*	p;

	for(;(**ptrptr);(*ptrptr)++) {

		if((**ptrptr)==AR_ENDNEST)
			break;

		not=or=equal = false;

		if((**ptrptr)==AR_OR) {
			or=1;
		if((**ptrptr)==AR_NOT) {
			not=1;

		if((**ptrptr)==AR_EQUAL) {
			equal=1;

		if((result && or) || (!result && !or))
			break;

		if((**ptrptr)==AR_BEGNEST) {
			(*ptrptr)++;
rswindell's avatar
rswindell committed
			if(ar_exp(cfg,ptrptr,user,client))
				result=!not;
			else
				result=not;
			while((**ptrptr)!=AR_ENDNEST && (**ptrptr)) /* in case of early exit */
				(*ptrptr)++;
			if(!(**ptrptr))
				break;

		artype=(**ptrptr);
		switch(artype) {
			case AR_ANSI:				/* No arguments */
rswindell's avatar
rswindell committed
			case AR_PETSCII:
			case AR_ASCII:
			case AR_UTF8:
			case AR_CP437:
			case AR_RIP:
			case AR_WIP:
			case AR_LOCAL:
			case AR_EXPERT:
			case AR_SYSOP:
			case AR_GUEST:
			case AR_QNODE:
			case AR_QUIET:
			case AR_OS2:
			case AR_DOS:
			case AR_WIN32:
			case AR_UNIX:
			case AR_LINUX:
			case AR_ACTIVE:
			case AR_INACTIVE:
			case AR_DELETED:
				break;
			default:
				(*ptrptr)++;

		n=(**ptrptr);
		i=(*(short *)*ptrptr);
		switch(artype) {
			case AR_LEVEL:
				if(user==NULL
					|| (equal && user->level!=n)