// Filename: 	User.c
// Contents:	the methods for the User object
// Author:		Greg Shaw
// Created:		6/1/93

/*
This file 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, or (at your option) any
later version.

In addition to the permissions in the GNU General Public License, the
Free Software Foundation gives you unlimited permission to link the
compiled version of this file with other programs, and to distribute
those programs without any restriction coming from the use of this
file.  (The General Public License restrictions do apply in other
respects; for example, they cover modification of the file, and
distribution when not linked into another program.)

This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */

#ifndef _USER_C_
#define _USER_C_

#include "bbshdr.h"

// Function:	append
// Purpose:	append a new user record to the user file
// Input:	object attributes
// Output:	(file is written)
// Author:	Greg Shaw
// Created:	7/20/93

int User::append(void)
{
	FILE	*ofile;
	char	finame[255];		// filename
	char	line[255];		// one line in file (255 max)
	char	bbspath[225];	// bbs path

	if (strcpy(bbspath,getenv("BBSDIR")), bbspath == NULL)
	{
		sprintf(finame,"user.save: BBSDIR env var not set for %s",login_name);
		ap_log(finame);
		return(-1);
	}
	strcpy(line,bbspath);
	strcat(line,"/admin/userlog");
	if (ofile = bopen(line,"a"), ofile == NULL)
	{
		sprintf(line,"user.save: Unable to open userlog file ");
		ap_log(line);
		return(-1);
	}	
	//[A login_name firstname lastname state city]
	fprintf(ofile,"[A %s %s %s %s %s %s ]\n", login_name, fname, lname, alias, state, city);
	//[B terminal_type last_logon #_logins downloads uploads card_color]
	fprintf(ofile,"[B %s %ld %d %d %d %s ]\n", uterm, 
		last_login, logins, downloads, uploads, card->colr);
	//[C private_msgs public_msgs credited_time has_color editor lines cols]
	fprintf(ofile,"[C %d %d %d %d %s %d %d ]\n",priv_msgs,pub_msgs,
		credited, has_color, editor, lines, cols);
	//[D flags access_level timelimit timeused_last_call anniversary kused ]
	fprintf(ofile,"[D %lx %d %d %d %ld %d ]\n",flags, acl, timelimit, timeused, anniversary, kused);
	bclose(ofile);
	return(0);
};

// Function:	change_acl
// Purpose:		change the user's access level (possibly permanently)
// Input:		acl - the timlit to change to
//				perm - permanent or not 
// Output:		none
// Author:		Greg Shaw
// Created:		6/8/93

int User::change_acl(int acl, char perm)
{
	if (perm)
		acl = acl;
	else
		tmpacl = acl;
	return(0);
}

// Function:	change_flags
// Purpose:		change the user's timelimit (possibly permanently)
// Input:		flags - the flags to change to
//				perm - permanent or not 
//			or - or into user flags or and into user flags
// Output:		none
// Author:		Greg Shaw
// Created:		6/9/93

int User::change_flags(unsigned long fl, char perm, char or)
{
	if (perm)
		if (or)
			flags |= fl;
		else
			flags &= fl;
	else
		if (or)
			tmpflags |= fl;
		else
			tmpflags &= fl;
	return(0);
}

// Function:	change_tl
// Purpose:		change the user's timelimit (possibly permanently)
// Input:		tl - the timlit to change to
//				perm - permanent or not 
// Output:		none
// Author:		Greg Shaw
// Created:		6/8/93

int User::change_tl(int tl, char perm)
{
	if (perm)
		timelimit = tl;
	else
		tmptl = tl;
	return(0);
}

// Function:	check_card
// Purpose:		check the user's access information vs. the card color he has
// Input:		none
// Output:		(user may be changed)
// Author:		Greg Shaw

int User::check_card(void)
{
	if (card = cardinfo(card_color), card == NULL)
		return(-1);
	if (acl < card->acl)	// only update info if card better
		acl = card->acl;
	if (timelimit < card->tl)
		timelimit = card->tl;
	flags |= card->flags;
	return(0);
};

// Function:	delete_user
// Purpose:	delete a user from the BBS
// Input:	name - the login name of the user to delete
// Output:	none
// Author:	Greg Shaw
// Created:	4/11/94

int User::delete_user(char *name)
{
};

// Function:	display_info
// Purpose:	display the user's information 
// Input:	logon - has the user just logged on?  (it gives 'welcome' message
// Output:	user information is formatted and printed.
// Author:	Greg Shaw
// Created:	7/2793

int User::display_info(int logon)
{
	char 	tmpstr[255];	// string
	char	*str2;	// used for time
	double	udratio;	// upload/download ratio

	clear();
	if (logon)
		sprintf(tmpstr,WELCOMEBACK,fname,lname,city,state);
	else
		sprintf(tmpstr,YOUARE,fname,lname,city,state);
	sstrcr(tmpstr);
	str2 = ctime(&login_time);
	str2[strlen(str2)-1] = 0;	// chop \n
	cr();
	sstrcr(USERINFORMATION);
	sstr("    ");
	sprintf(tmpstr,ONSINCE,str2);
	sstrcr(tmpstr);
	str2 = ctime(&last_login);
	str2[strlen(str2)-1] = 0;	// chop \n
	sstr("    ");
	sprintf(tmpstr,LOGINSLAST,logins,str2);
	sstrcr(tmpstr);
	sstr("    ");
	sprintf(tmpstr,ALIASEDITOR,alias,editor);
	sstrcr(tmpstr);
	sstr("    ");
	sprintf(tmpstr,TERMINALINFO,uterm,has_color?COLOR:MONOCHROME,lines,cols);
	sstrcr(tmpstr);
	cr();
	sprintf(tmpstr,CARDINFORMATION,card->colr);
	sstrcr(tmpstr);
	sstr("    ");
	sprintf(tmpstr,TIMELIMITINFO,timelimit,waittime());
	sstrcr(tmpstr);
	sstr("    ");
	sprintf(tmpstr,CREDITEDTIME,credited);
	sstrcr(tmpstr);
	sstr("    ");
	if (card->kbytes < 0)	// unlimited download?
		sprintf(tmpstr,DOWNLOADCAPACITY1);
	else
		sprintf(tmpstr,DOWNLOADCAPACITY2,card->kbytes);
	sstrcr(tmpstr);
	cr();
	sstrcr(FILETRANSFERS);
	sstr("    ");
	sprintf(tmpstr,PRIORDOWNLOADS,downloads);
	sstrcr(tmpstr);
	sstr("    ");
	sprintf(tmpstr,PRIORUPLOADS,uploads);
	sstrcr(tmpstr);
	if (downloads > 0)
		udratio = (double)uploads/downloads;
	else
		udratio = uploads;
	sstr("    ");
	sprintf(tmpstr,RESULTRATIO,udratio);
	sstrcr(tmpstr);
	cr();
	sstrcr(LASTCALL);
	sstr("    ");
	sprintf(tmpstr,TIMEUSED,timeused);
	sstrcr(tmpstr);
	sstr("    ");
	sprintf(tmpstr,DOWNLOADSIZE,kused);
	sstrcr(tmpstr);
	waitcr();
	return(0);
};

// Function:	export
// Purpose:	export the user's environment variables
// Input:	none
// Output:	(environment vars are exported)
// Author:	Greg Shaw
// Created:	7/2793

int User::export(void)
{
	char tmpmsg[100];
	char *outmsg;

	sprintf(tmpmsg,"EDITOR=%s",editor);
	if (outmsg = (char *) malloc(strlen(tmpmsg)+1), outmsg == NULL)
	{
		ap_log("Unable to malloc more environment space.");
	}
	strcpy(outmsg,tmpmsg);
	if (putenv(outmsg) != 0)
		ap_log("Unable to export variable.");
	sprintf(tmpmsg,"VISUAL=%s",editor);
	if (outmsg = (char *) malloc(strlen(tmpmsg)+1), outmsg == NULL)
	{
		ap_log("Unable to malloc more environment space.");
	}
	strcpy(outmsg,tmpmsg);
	if (putenv(outmsg) != 0)
		ap_log("Unable to export variable.");
	sprintf(tmpmsg,"TERM=%s",uterm);
	if (outmsg = (char *) malloc(strlen(tmpmsg)+1), outmsg == NULL)
	{
		ap_log("Unable to malloc more environment space.");
	}
	strcpy(outmsg,tmpmsg);
	if (putenv(outmsg) != 0)
		ap_log("Unable to export variable.");
	sprintf(tmpmsg,"LINES=%s",lines);
	if (outmsg = (char *) malloc(strlen(tmpmsg)+1), outmsg == NULL)
	{
		ap_log("Unable to malloc more environment space.");
	}
	strcpy(outmsg,tmpmsg);
	if (putenv(outmsg) != 0)
		ap_log("Unable to export variable.");
	sprintf(tmpmsg,"COLUMNS=%s",cols);
	if (outmsg = (char *) malloc(strlen(tmpmsg)+1), outmsg == NULL)
	{
		ap_log("Unable to malloc more environment space.");
	}
	strcpy(outmsg,tmpmsg);
	if (putenv(outmsg) != 0)
		ap_log("Unable to export variable.");
	return(0);
};


// Function:	get
// Purpose:		get the user's info from the user list
// Input:		none
// Output:		object is loaded or an error is returned
// Author:		Greg Shaw
// Created:		7/13/93
// Notes:		the user file is a plain text file (to allow editing).  
//				its format is such:
//					[A login_name firstname lastname]
//					[B terminal_type last_logon #_logins downloads uploads card color]
//					[C private_msgs public_msgs credited_time has_color editor lines cols]
//					[D flags access_level timelimit timeused_last_call]
//				the above format includes the brackets and lines (for reference)

int User::get(char *name)
{
	FILE	*ufile;
	char	*u;
	char	finame[255];		// filename
	char	line[255];		// one line in file (255 max)
	char	logname[10];	// user login name
	char	found;			// user found?
	char	linenum;		// used to look for appropriate line
	char	c;				// input char
	unsigned char	of;		// offset into line
	int	x;
	struct passwd *userent;	// user entry in password file

	if (name == NULL)
		strcpy(logname,username());		// get user's login information	
	else	
		strcpy(logname,name);
	if (strcpy(finame,getenv("BBSDIR")), fname == NULL)
	{
		sprintf(finame,"user.get: BBSDIR environment variable not set for %s",logname);
		ap_log(finame);
		return(-1);
	}
	strcat(finame,"/admin/userlog");
	linenum = 0;		// look for first line first
	if (ufile = bopen(finame,"r"), ufile != NULL)
	{
		found = 0;
		while (!found && !feof(ufile))
		{
			of = 0;
			while (c = fgetc(ufile), c != '\r' && c != '\n' && !feof(ufile))
				if (c != ']')	// skip trailing left bracket
				line[of++] = c;
			line[of] = 0;	// add null
			switch(linenum)
			{
			case 0:	// first line
				if (line[0] == '[' && line[1] == 'A')	// got line 1?
				{
					x = sscanf(&line[2],"%s %s %s %s %s %s",login_name,
						fname, lname, alias, state, city);
					if (u = strchr(city,']'), u != NULL)
					{	// convert any left brackets to null
						u++;
						u[0] = 0;
					}
					if (strcmp(login_name,logname) == 0)
					{
						linenum++;		// get next line
					}
				}
				break;
			case 1:	// second line
				if (line[0] == '[' && line[1] == 'B')	// got line 2?
				{
					if (sscanf(&line[2],"%s %ld %d %d %d %s",uterm,
						&last_login, &logins, &downloads, &uploads,
						card->colr) != 6)
					{
						ap_log("user.get: bad read from user file.  Corrupted?");
						sprintf(finame,"user.get: bad user record was %s, line B",login_name);
						ap_log(finame);
						return(-1);
					}
					linenum++;		// get next line
					if (!strcmp(card->colr,"red"))
						card_color = 0;
					if (!strcmp(card->colr,"blue"))
						card_color = 1;
					if (!strcmp(card->colr,"green"))
						card_color = 2;
					if (!strcmp(card->colr,"white"))
						card_color = 3;
					if (!strcmp(card->colr,"grey"))
						card_color = 4;
					if (!strcmp(card->colr,"pink"))
						card_color = 5;
					if (!strcmp(card->colr,"yellow"))
						card_color = 6;
					if (!strcmp(card->colr,"black"))
						card_color = 7;
				}
				break;
			case 2:	// third line
				if (line[0] == '[' && line[1] == 'C')	// got line 3?
				{
					if (sscanf(&line[2],"%d %d %d %d %s %d %d",&priv_msgs,&pub_msgs,
						&credited, &has_color, editor, &lines, &cols) != 7)
					{
						ap_log("user.get: bad read from user file.  Corrupted?");
						sprintf(finame,"user.get: bad user record was %s, line C",login_name);
						ap_log(finame);
						return(-1);
					}
					linenum++;		// get next line
				}
				break;
			case 3:	// fourth line
				if (line[0] == '[' && line[1] == 'D')	// got line 4?
				{
					if (sscanf(&line[2],"%lx %d %d %d %ld %d",&flags,
						&acl, &timelimit, &timeused, &anniversary,&kused) != 6)
					{
						ap_log("user.get: bad read from user file.  Corrupted?");
						sprintf(finame,"user.get: bad user record was %s, line D",login_name);
						ap_log(finame);
						return(-1);
					}
					linenum++;		// get next line
				}
				break;
			}	
			if (linenum == 4)	// got him.
			{
				found++;
				bclose(ufile);
				logins++;
				if (name != NULL && (login_time - last_login)/60 < waittime())
				{
					if ((timelimit - timeused) < 5)
					{
						clear();
						sstrcr(NOUNUSEDTIME);
						sprintf(finame,TOOSOONERROR,waittime());
						sstrcr(finame);
						cr();
						cr();
						waitcr();
						sstrcr(THANKSFORCALLING);
						exit(0);
					}
				}
				else
				{
					kused = 0;	// start all counters over
					timeused = 0;
					credited = 0;
				}
				tmpflags = flags;
				tmpacl = acl;
				tmptl = timelimit;
				if (name == NULL)
				{
					sprintf(line,"Logon for %s %s",fname,lname);
					ap_log(line);
					export();	// export his environment variables
					check_card();	// check his access level vs. card
				}
				return(1);	// return 1 for new user only
			}
		}
	}
	bclose(ufile);	// close just in case
	// didn't find him in user file.  Need to get his information
	if (name != NULL) // error - unable to find user in userlog
	{
		sprintf(line,"Unable to find %s in userlog.",name);
		ap_log(line);
		return(0);
	}	
	strcpy(login_name,logname);		// get login name	
	sstrcr(UNABLETOFINDUSER);
	sstr(WOULDLIKETOREGISTER);
	if (!yesno())
	{
		fflush(stdout);
		sprintf(finame,"user.get: %s decided not to register for bbs.",logname);
		ap_log(finame);
		return(-1);
	}
	cr();
	if (userent = getpwnam((char *)username()), userent == NULL)
	{
		sprintf(finame,"user.get: Unable to get user %s's password entry!",logname);
		ap_log(finame);
		return(-1);
	}
	sscanf(userent->pw_gecos,"%s %s",fname,lname);	// get user name
	getinfo(1);	// get user information
	export();	// export his environment variables
	check_card();	// check his access level vs. card
	append();
	sprintf(line,"Logon for %s %s",fname,lname);
	ap_log(line);
	return(0);
}

// Function:	getinfo
// Purpose:		prompt the user for information to setup the user object
// Input:		firsttime - is this the first logon by user?
// Output:		(user questions)
// Author:		Greg Shaw
// Created:		7/25/93

int User::getinfo(char firsttime)
{
	char	loop;			// loop counter
	char	done;			// loop counter
	char	entered;		// entered anything?
	char	tmpstr[255];
	char	anotherstr[50];		// another string
	char	finame[255];		// filename
	char	logname[10];	// user login name

	loop = 1;
	entered = 0;
	while (loop)
	{
		clear();		// clear screen
		if (!firsttime || entered)
		{
			cr();
			cr();
			cr();
			sstrcr(ENTERFOLLOWING);
			cr();
			sprintf(finame,LOGINNAME,login_name);
			sstrcr(finame);
			sprintf(finame,REALNAME,fname,lname);
			sstrcr(finame);
			sprintf(finame,ALIASNAME,alias);
			sstrcr(finame);
			sprintf(finame,CALLINGFROM,city,state);
			sstrcr(finame);
			sprintf(finame,TERMINALTYPE,uterm);
			sstrcr(finame);
			sprintf(finame,TERMINALCAPABILITIES,has_color?YES:NO);
			sstrcr(finame);
			sprintf(finame,EDITOR,editor);
			sstrcr(finame);
			sprintf(finame,LINESCOLUMNS,lines,cols);
			sstrcr(finame);
			cr();
			sstr(CORRECT);
			if (yesno())
				loop = 0;
		}
		if (loop)	// still looping?
		{
			if (!firsttime)
				sstrcr(XTOKEEPENTRY);
			strcpy(logname,username());		// get user's login information	
			done = 0;
			while (!done)
			{
				sstrcr(USERINFOCITY0);
				sstrcr(USERINFOCITY1);
				sstr(USERINFOCITY2);
				if (gstr(tmpstr,20), strcmp(tmpstr,"") == 0)
					continue;
				if (!strcmp(tmpstr,"x"))
				{
					if (firsttime)		// no empty entries for first time
						continue;
				}
				else
					strcpy(city,tmpstr);
				done++;
			}
			cr();
			done = 0;
			while (!done)
			{
				sstrcr(USERINFOSTATE0);
				sstr(USERINFOSTATE1);
				if (gstr(tmpstr,2), strcmp(tmpstr,"") == 0)
					continue;
				if (!strcmp(tmpstr, "x"))
				{
					if (firsttime)		// no empty entries for first time
						continue;
				}
				else
					strcpy(state,tmpstr);
				done++;
			}
			cr();
			done = 0;
			while (!done)
			{
				sstrcr(USERINFOTERM0);
				sstrcr(USERINFOTERM1);
				sstrcr(USERINFOTERM2);
				sstrcr(USERINFOTERM3);
				cr();
				sstrcr(USERINFOTERM4);
				sstrcr(USERINFOTERM5);
				sstrcr(USERINFOTERM6);
				sstrcr(USERINFOTERM7);
				sstrcr(USERINFOTERM8);
				cr();
				sstrcr(USERINFOTERM9);
				sstrcr(USERINFOTERM10);
				sstrcr(USERINFOTERM11);
				sstrcr(USERINFOTERM12);
				sstrcr(USERINFOTERM13);
				cr();
				sstrcr(USERINFOTERM14);
				sstr(USERINFOTERM15);
				if (gstr(tmpstr,20), strcmp(tmpstr,"") == 0)
					continue;
				if (!strcmp(tmpstr,"x"))
				{
					if (firsttime)		// no empty entries for first time
						continue;
				}
				else
					strcpy(uterm,tmpstr);
				done++;
			}
			cr();
			cr();
			sstr(USERINFOCOLOR0);
			if (yesno())
				has_color = 1;
			else
				has_color = 0;
			cr();
			cr();
			if (strcpy(finame,getenv("BBSDIR")), finame == NULL)
			{
				sprintf(finame,"user.get: BBSDIR env var not set for %s",logname);
				ap_log(finame);
				return(-1);
			}
			strcat(finame,"/text/editors");
			sprintf(tmpstr,"Viewing %s",finame);
			sysopstrcr(tmpstr);
			display_file(finame,1);		// display file with paging
			cr();
			cr();
			done = 0;
			while (!done)
			{
				sstrcr(USERINFOEDITOR0);
				sstr(USERINFOEDITOR1);
				if (gstr(tmpstr,14), strcmp(tmpstr,"") == 0)
					continue;
				if (!strcmp(tmpstr,"x"))
				{
					if (firsttime)		// no empty entries for first time
						continue;
				}
				else
					strcpy(editor,tmpstr);
				done++;
			}
			cr();
			cr();
			sstrcr(USERINFOALIAS0);
			sstrcr(USERINFOALIAS1);
			sstr(USERINFOALIAS2);
			if (yesno())
				strcpy(alias,logname);
			else 
			{
				done = 0;
				while (!done)
				{
					sstrcr(USERINFOALIAS3);
					sstr(USERINFOALIAS4);
					if (gstr(tmpstr,20), strcmp(tmpstr,"") == 0)
						continue;
					if (!strcmp(tmpstr,"x"))
					{
						if (firsttime)		// no empty entries for first time
							continue;
					}
					else
						if (sscanf(tmpstr,"%s%s",alias,anotherstr) != 1)
							continue;
					done++;
				}
			}
			cr();
			cr();
			done = 0;
			while (!done)
			{
				sstrcr(USERINFOLINES0);
				sstrcr(USERINFOLINES1);
				sstr(USERINFOLINES2);
				if (gstr(tmpstr,5), strcmp(tmpstr,"") == 0)
					continue;
				if (tmpstr[0] == 'x')
				{
					lines = 24;
				}
				else
					sscanf(tmpstr,"%d",&lines);
				done++;
			}
			cr();
			cr();
			done = 0;
			while (!done)
			{
				sstrcr(USERINFOCOLUMNS0);
				sstrcr(USERINFOCOLUMNS1);
				sstr(USERINFOCOLUMNS2);
				if (gstr(tmpstr,5), strcmp(tmpstr,"") == 0)
					continue;
				if (tmpstr[0] == 'x')
				{
					cols = 80;
				}
				else
					sscanf(tmpstr,"%d",&cols);
				done++;
			}
			entered++;
		}
	}
	export();
	return(0);
};

// Function:	inactive_list
// Purpose:	list the inactive (people who haven't called lately) users
// Input:	none
// Output:	A list of users who haven't called in a specified time
// Author:	Greg Shaw
// Created:	4/3/94

int User::inactive_list(void)
{
	char	tmpstr[255];
	char	line[150];
	char	c;
	char	key[MAX_FILENAMELENGTH+1];
	char	uname[10];
	char	fullname[50];
	char	fname[15];
	char	lname[15];
	char	tmp[2][15];
	char	state[50];
	char	city[50];
	char	llogon[10];
	char	from[50];
	char	*sptr;
	int	logins;
	int	uls,dls;
	time_t	laston;
	time_t	today;
	struct tm *tmdata;
	int	off;
	int	found;
	int	days;
	FILE	*infile;
	
	
	clear();
	time(&today);
	// get number of days inactive to search for
	sstrcr(USERSEARCH1);
	sstrcr(USERSEARCH2);
	sstrcr(USERSEARCH3);
	cr();
	sstr(USERSEARCH4);
	gstr(key,MAX_FILENAMELENGTH);
	if (key[0] == 0 || sscanf(key,"%d",&days) != 1)
		return(0);
	sprintf(tmpstr,"%s/admin/userlog",getenv("BBSDIR"));		
	if (infile = bopen(tmpstr,"r"), infile == NULL)
	{
		ap_log("Unable to open userlog for read.");
		return(0);
	}
	found = 0;
	sstr(USERSEARCH5);
	while (!feof(infile))
	{
		off = 0;
		while (c = fgetc(infile), c != '\n' && c != '\r' && !feof(infile))
			line[off++] = c;
		line[off] = 0;
		if (line[0] == '[')
		{
			if (line[1] == 'A')
			{
				sscanf(&line[2],"%s %s %s %s %s %s %s %s", uname, fname, lname, alias, state, city,tmp[0], tmp[1]);
				strcat(city,tmp[0]);
				strcat(city,tmp[1]);
				if (sptr = strchr(city,']'), sptr != NULL)
					sptr[0] = 0;
			} else if (line[1] == 'B')
			{
				sscanf(&line[2],"%*s %ld %d %d %d %*s",&laston, &logins,&uls,&dls);
				sprintf(fullname,"%s %s",fname,lname);
				sprintf(from,"%s, %s",city,state);
				tmdata = localtime(&laston);
				strftime(llogon, 12, "%b %d,%Y", tmdata);
				if ((today - laston)/86400 >= days)
				{
					sprintf(tmpstr,"%-15s %-15s %s   %d    %d",fullname,from,llogon,uls,dls);
					sstrcr(tmpstr);
					found++;
				}
				if (found == 17)
				{
					found = 0;
					waitcr();
					sstr(CONTINUELISTING);
					if (!yesno())
					{
						bclose(infile);
						return(0);
					}
				}
			}
		}
	}
	cr();
	sstrcr(NOMOREFOUND);
	bclose(infile);
	waitcr();
	return(0);
};

// Function:	inactive_delete
// Purpose:	delete inactive users on the BBS
// Input:	none
// Output:	A list of users who haven't called in a specified time
// Author:	Greg Shaw
// Created:	4/21/94

int User::inactive_delete(void)
{
	char	tmpstr[255];
	char	line[150];
	char	c,b;
	char	key[MAX_FILENAMELENGTH+1];
	char	uname[10];
	char	fullname[50];
	char	fname[15];
	char	lname[15];
	char	tmp[2][15];
	char	state[50];
	char	city[50];
	char	llogon[10];
	char	from[50];
	char	*sptr;
	int	x;
	int	logins;
	int	uls,dls;
	time_t	laston;
	time_t	today;
	struct tm *tmdata;
	int	off;
	int	found;
	int	days;
	FILE	*infile;
	FILE	*outfile;
	
	
	clear();
	time(&today);
	// get number of days inactive to search for
	sstrcr(SEARCHTODELETE1);
	sstrcr(SEARCHTODELETE2);
	sstrcr(SEARCHTODELETE3);
	cr();
	sstr(SEARCHTODELETE4);
	gstr(key,MAX_FILENAMELENGTH);
	if (key[0] == 0 || sscanf(key,"%d",&days) != 1)
		return(0);
	sprintf(tmpstr,"Will delete users %d days.",days);
	sstrcr(tmpstr);
	cr();
	sstrcr(SEARCHTODELETE5);
	sstr(SEARCHTODELETE6);
	while (b = tolower(gch(1)), b != 'a' && b != 'i');
	cr();
	if (b == 'i')	// interactively
	{
		sstrcr(PROMPTENABLED);
		waitcr();
	}
	sprintf(tmpstr,"%s/admin/userlog",getenv("BBSDIR"));		
	if (infile = bopen(tmpstr,"r"), infile == NULL)
	{
		ap_log("Unable to open userlog for read.");
		sstrcr(NOOPENREAD);
		waitcr();
		return(0);
	}
	strcat(tmpstr,".new"); // get 'new' filename
	if (outfile = bopen(tmpstr,"w"), outfile == NULL)
	{
		ap_log("Unable to open userlog.new for write.");
		sstrcr(NOOPENWRITE);
		waitcr();
		return(0);
	}
	found = 0;
	while (!feof(infile))
	{
		off = 0;
		while (c = fgetc(infile), c != '\n' && c != '\r' && !feof(infile))
			line[off++] = c;
		line[off] = 0;
		if (line[0] == '[')
		{
			if (line[1] == 'A')
			{
				sscanf(&line[2],"%s %s %s %s %s %s %s %s", uname, fname, lname, alias, state, city,tmp[0], tmp[1]);
				strcat(city,tmp[0]);
				strcat(city,tmp[1]);
				if (sptr = strchr(city,']'), sptr != NULL)
					sptr[0] = 0;
			} else if (line[1] == 'B')
			{
				if (sscanf(&line[2],"%s %ld %d %d %d %s",uterm, &laston, &logins,&uls,&dls,card->colr) != 6)
				{
					sprintf(tmpstr,"Error found in line B userlog in entry %s %s",fname,lname);
					ap_log(tmpstr);
					sstrcr("Error found in userlog.  Clean aborted.");
					waitcr();
					return(0);
				}
				sprintf(fullname,"%s %s",fname,lname);
				sprintf(from,"%s, %s",city,state);
				tmdata = localtime(&laston);
				strftime(llogon, 12, "%b %d,%Y", tmdata);
				if ((today - laston)/86400 >= days)
				{
					sprintf(tmpstr,"%-15s %-15s %s   %d    %d",fullname,from,llogon,uls,dls);
					sstrcr(tmpstr);
					if (b == 'i')	// interactive?
					{
						sstr(DELETEUSER);
						if (yesno())
							continue;
					}
					else 
						continue;
				}
				for (x=0; x<2; x++)
					if (strlen(tmp[x]) < 2)
						tmp[x][0] = 0;
				// save info and next two lines
				fprintf(outfile,"[A %s %s %s %s %s %s %s %s ]\n", uname, fname, lname, alias, state, city, tmp[0], tmp[1]);
				fprintf(outfile,"%s\n",line);
				x = 0;
				while (x < 2)
				{
					if (c = fgetc(infile), c == '\n' || c == '\r')
						x++;
					fputc(c,outfile);
				}
			}
		}
	}
	cr();
	bclose(outfile);
	sprintf(tmpstr,"%s/admin/userlog",getenv("BBSDIR"));		
	sprintf(line,"%s/admin/userlog.old",getenv("BBSDIR"));
	rename(tmpstr,line);
	sprintf(tmpstr,"%s/admin/userlog.new",getenv("BBSDIR"));		
	sprintf(line,"%s/admin/userlog",getenv("BBSDIR"));
	rename(tmpstr,line);
	waitcr();
	return(0);
};

// Function:	list
// Purpose:	return a user record 
// Input:	path - the path to the user file 
// Output:	a list of users on the bbs - 
// Author:	Greg Shaw
// Created:	6/8/93

int User::list(int search, int sysop)
{
	char	tmpstr[255];
	char	line[150];
	char	c;
	char	key[MAX_FILENAMELENGTH+1];
	char	uname[10];
	char	alias[25];
	char	fname[15];
	char	lname[15];
	char	tmp[2][15];
	char	state[50];
	char	city[50];
	char	*sptr;
	int	logins;
	time_t	laston;
	int	off;
	int	found;
	FILE	*infile;
	
	
	clear();
	sprintf(tmpstr,"%s/admin/userlog",getenv("BBSDIR"));		
	if (infile = bopen(tmpstr,"r"), infile == NULL)
	{
		ap_log("Unable to open userlog for read.");
		return(0);
	}
	if (search)
	{
		sstrcr(SEARCHFORUSER);
		cr();		
		sstr(SEARCHFORCHARS);
		gstr(key,MAX_FILENAMELENGTH);
		if (key[0] == 0)
			return(0);
		// search for characters in userlog
		found = 0;
		while (!feof(infile))
		{
			off = 0;
			while (c = fgetc(infile), c != '\n' && c != '\r' && !feof(infile))
				line[off++] = c;
			line[off] = 0;
			if (line[0] == '[')
			{
				if (line[1] == 'A')
				{
					sscanf(&line[2],"%s %s %s %s %s %s %s %s", uname, fname, lname, alias, state, city,tmp[0], tmp[1]);
					strcat(city,tmp[0]);
					strcat(city,tmp[1]);
					if (sptr = strchr(city,']'), sptr != NULL)
						sptr[0] = 0;
					if (strstr(line,key) != NULL)
					{
						sprintf(tmpstr,NAMEFROM,fname,lname,city,state);
						sstrcr(tmpstr);
						sprintf(tmpstr,LOGINALIAS,uname,alias);
						sstrcr(tmpstr);
						found++;
					}
				} else if (found && line[1] == 'B')
				{
					sscanf(&line[2],"%*s %ld %d %*d %*d %*s",&laston, &logins);
					sptr = ctime(&laston);
					sptr[strlen(sptr)-1] = 0;	// chop \n
					sprintf(tmpstr,NUMLOGONS,logins,sptr);
					sstrcr(tmpstr);
					waitcr();
					if (sysop)
					{
						sstr(CONTINUEEDITDELETE);
						while (c = toupper(gch(1)), c != 'D' && c != 'C' && c != 'E');
						if (c == 'D')
						{
							bclose(infile);
							delete_user(uname);
							return(0);
						}
						else if (c == 'E')
						{
							bclose(infile);
							if (get(uname))
							{
								check_card();
								sysop_edit();
							}
							else
							{
								sprintf(tmpstr,"Unable to get %s for sysop edit.",uname);
								ap_log(tmpstr);
							}
							return(0);
						}
					}
					else 
					{
						sstr(CONTINUESEARCH);
						if (!yesno())
						{
							bclose(infile);
							return(0);
						}
					}
					found = 0;
				}
			}
		}
		bclose(infile);
	}
	else
	{
		found = 0;
		while (!feof(infile))
		{
			off = 0;
			while (c = fgetc(infile), c != '\n' && c != '\r' && !feof(infile))
				line[off++] = c;
			if (line[0] == '[')
			{
				if (line[1] == 'A')
				{
					sscanf(&line[2],"%s %s %s %s %s %s %s %s", uname, fname, lname, alias, state, city,tmp[0], tmp[1]);
					strcat(city,tmp[0]);
					strcat(city,tmp[1]);
					if (sptr = strchr(city,']'), sptr != NULL)
						sptr[0] = 0;
					sprintf(tmpstr,"%s %s from %s, %s",fname,lname,city,state);
					sstrcr(tmpstr);
					sprintf(tmpstr,LOGINALIAS,uname,alias);
					sstrcr(tmpstr);
				} else if (line[1] == 'B')
				{
					sscanf(&line[2],"%*s %ld %d %*d %*d %*s",&laston, &logins);
					sptr = ctime(&laston);
					sptr[strlen(sptr)-1] = 0;	// chop \n
					sprintf(tmpstr,NUMLOGONS,logins,sptr);
					sstrcr(tmpstr);
					cr();
					if (found == 6)
					{
						found = 0;
						waitcr();
						sstr(CONTINUELISTING);
						if (!yesno())
						{
							bclose(infile);
							return(0);
						}
					}
					found++;
				}
			}
		}
		cr();
	}
	cr();
	sstrcr(NOMOREFOUND);
	waitcr();
	return(0);
}

// Function:	mailavail
// Purpose:	return true if mail for the user is available
// Input:	none
// Output:	1 for mail.  0 for no mail
// Author:		Greg Shaw
// Created:		8/10/93

int User::mailavail(void)
{
	struct stat fistat;	// file status record
	char	tmpstr[255];	// tmpstr
	time_t	now = 0L;		// current time
	static time_t	then = 0L;	// previous check time

	if (!checkmail())	// check?  
		return(0);	// no, just exit
	time(&now);
	if (abs(now - then) > mailchecktime())	// seconds elapsed?
	{
		sprintf(tmpstr,"%s/%s",mailspool(),login_name);
		if (stat(tmpstr,&fistat) == 0 && S_ISREG(fistat.st_mode))
		{
			if (mail_check == 0)	// just check size the first time
			{
					mail_check = fistat.st_mtime;// save modification time
					if (mail_size = fistat.st_size, mail_size > 0)
						return(1);
			}
			else // check date of last mail update 
			{
				if (fistat.st_mtime != mail_check &&
				fistat.st_size > mail_size)	// new mail (mailbox bigger)
				{
					return(1);
				}
				mail_check = fistat.st_mtime;
				mail_size = fistat.st_size;
			}
		}
	}
	return(0);
};

// Function:	save
// Purpose:		save the current User to the User file
// Input:		path - the path to the User file
// Output:		returns non-zero on failure
// Author:		Greg Shaw
// Created:		6/5/93

int User::save(char *name)
{
	FILE	*ufile;
	FILE	*ofile;
	char	finame[255];		// filename
	char	line[255];		// one line in file (255 max)
	char	bbspath[225];	// bbs path
	char	logname[10];	// user login name
	char	found;			// user found?
	char	linenum;		// used to look for appropriate line
	char	c;				// input character
	char	*u;
	unsigned char	of;		// offset into line
	int	x;
	time_t	now;

	last_login = login_time;	// set to new login time
	time(&now);
	timeused += (now - login_time)/60;	// update time used field.
	if (name == NULL)
		strcpy(logname,username());		// get user's log information	
	else
		strcpy(logname,name);
	if (strcpy(bbspath,getenv("BBSDIR")), bbspath == NULL)
	{
		sprintf(finame,"user.save: BBSDIR env var not set for %s",logname);
		ap_log(finame);
		return(-1);
	}
	strcpy(line,bbspath);
	strcat(line,"/admin/nuserlog");
	if (ofile = bopen(line,"w"), ofile == NULL)
	{
		sprintf(line,"user.save: Unable to open new userlog file: %s",logname);
		ap_log(line);
		return(-1);
	}	
	chmod(line,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH); // change permissions
	strcpy(finame,bbspath);
	strcat(finame,"/admin/userlog");
	linenum = 0;		// look for first line first
	if (ufile = bopen(finame,"r"), ufile == NULL)
	{
		// create the bugger so that you can continue
		ufile = bopen(finame,"w");
		bclose(ufile);
		if (ufile = bopen(finame,"r"), ufile == NULL)
		{	// still can't open the file!  AARGH!
			sprintf(line,"user.save: Unable to open userlog file.",logname);
			ap_log(line);
			return(-1);
		}
	}
	else
	{
		found = 0;
		while (!found && !feof(ufile))
		{
			// get first line
			of = 0;
			while (c = fgetc(ufile), c != '\r' && c != '\n' && !feof(ufile))
				if (c != ']')	// skip trailing left bracket
					line[of++] = c;
			line[of] = 0;	// add null
			if (!feof(ufile) && of > 1)	// end of file, skip.
			{
				switch(linenum)
				{
				case 0:	// first line
					if (line[0] == '[' && line[1] == 'A')	// got line 1?
					{
						x = sscanf(&line[2],"%s %s %s %s %s %s",login_name,
							fname, lname, alias, state, city);
						if (u = strchr(city,']'), u != NULL)
						{	// convert any left brackets to null
							u++;
							u[0] = 0;
						}
						if (strcmp(login_name,logname) == 0)
						{
							linenum++;		// get next line
							fprintf(ofile,"[A %s %s %s %s %s %s ]\n", login_name, fname, lname, alias, state, city);
						}
						else
							fprintf(ofile,"%s]\n",line);
	//					[A login_name firstname lastname state city]
					}
					else
						fprintf(ofile,"%s]\n",line);
					break;
				case 1:	// second line
					if (line[0] == '[' && line[1] == 'B')	// got line 2?
					{
							fprintf(ofile,"[B %s %ld %d %d %d %s ]\n", uterm, 
								last_login, logins, downloads, uploads, card->colr);
	//					[B terminal_type last_logon #_logins downloads uploads]
						linenum++;		// get next line
					}
					else
						fprintf(ofile,"%s]\n",line);
					break;
				case 2:	// third line
					if (line[0] == '[' && line[1] == 'C')	// got line 3?
					{
						fprintf(ofile,"[C %d %d %d %d %s %d %d]\n",priv_msgs,
							pub_msgs, credited, has_color, editor, lines, cols);
						linenum++;		// save next line
	//					[C private_msgs public_msgs credited_time has_color editor lines cols]
					}
					else
						fprintf(ofile,"%s]\n",line);
					break;
				case 3:	// fourth line
					if (line[0] == '[' && line[1] == 'D')	// got line 4?
					{
						fprintf(ofile,"[D %lx %d %d %d %ld %d ]\n",
							flags, acl, timelimit, timeused,anniversary,kused);
	//					[D flags access_level timelimit timeused_last_call anniversary kused ]
						linenum++;		// save next line
					}
					else
						fprintf(ofile,"%s]\n",line);
					break;
				}	
				if (linenum == 4)	// got him.
				{
					found++;
				}
			}
		}
		// Ok, got the guy.  copy the rest of the file
		while (!feof(ufile))
		{
			c = fgetc(ufile);
			if (!feof(ufile))
				fputc(c,ofile);
		}
	}
	// now rename the userfile to old userfile
	bclose(ufile);
	bclose(ofile);
	strcpy(line,bbspath);
	strcat(line,"/admin/userlog.old");
	if (rename(finame, line) != 0)
	{
		sprintf(finame,"user.save: unable to rename userlog to userlog.old");
		ap_log(finame);
		return(-1);
	}	
	strcpy(line,bbspath);
	strcat(line,"/admin/nuserlog");
	strcpy(finame,bbspath);
	strcat(finame,"/admin/userlog");
	if (rename(line, finame) != 0)
	{
		sprintf(finame,"user.save: unable to rename new userlog to userlog",logname);
		ap_log(finame);
		return(-1);
	}	
	chmod(finame,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH); // change permissions
	return(0);
}

// Function:		sysop_edit
// Purpose:		allow the sysop to edit a user
// Input:		firsttime - is this the first logon by user?
// Output:		(user questions)
// Author:		Greg Shaw
// Created:		4/11/94

int User::sysop_edit(void)
{
	char 	c;
	char	loop;			// loop counter
	char	changed;		// changed anything?
	char	tmpstr[255];
	char	str1[50], str2[50];
	int	selected;		// which selected?
	int	tmp;
	int	x;
	struct tm *tmdata;		// time stuff

	loop = 1;
	changed = 0;
	while (loop)
	{
		clear();		// clear screen
		cr();
		cr();
		cr();
		sstrcr(CURRENTUSER);
		cr();
		sprintf(tmpstr,LOGINFULLNAME,login_name,fname,lname,city,state);
		sstrcr(tmpstr);
		sprintf(tmpstr,ALIASDOWNLOADS,alias, downloads, uploads, logins);
		sstrcr(tmpstr);
		sprintf(tmpstr,ACLFLAGS,acl, flags, timelimit);
		sstrcr(tmpstr);
		sprintf(tmpstr,TERMTYPECOLOR,uterm,card->colr,lines,cols);
		sstrcr(tmpstr);
		tmdata = localtime(&anniversary);
		strftime(str1,49,"%c",tmdata);
		tmdata = localtime(&last_login);
		strftime(str2,49,"%c",tmdata);
		sprintf(tmpstr,FIRSTLOGON,str1);
		sstrcr(tmpstr);
		sprintf(tmpstr,LASTLOGON,str2,timeused);
		sstrcr(tmpstr);
		sstr(ISTHISCORRECT);
		if (yesno())
		{
			if (changed)
			{
				sstrcr(SAVEUSERINFO);
				save(login_name); 
			}
			return(0);
		}
		cr();
		clear();
		sstrcr(EDITFOLLOWING);
		sstrcr(EDITUSER1);
		sstrcr(EDITUSER2);
		sstrcr(EDITUSER3);
		sstrcr(EDITUSER4);
		sstrcr(EDITUSER5);
		sstrcr(EDITUSER6);
		sstrcr(EDITUSER7);
		sstrcr(EDITUSER8);
		sstrcr(RETURNTOEXIT);
		cr();
		sstr("Edit which? ");
		gstr(str1,3);
		selected = 0;
		if (sscanf(str1,"%d",&selected) != 1 || (selected < 1 || selected > 15))
			continue;
		switch(selected)
		{
		case 1:	//  get login name
			sstrcr(LOGINERROR);
			sstrcr(SECURITYHOLE);
			sstrcr(RETURNTOEXIT);
			waitcr();
			break;  // not done at this time (requires
				// modification of passwd file)
		case 2: // get first name
			sprintf(tmpstr,CURRENTFIRSTNAME,fname);	
			sstrcr(tmpstr);
			cr();
			sstrcr(RETURNTOEXIT);
			cr();
			sstr(CHANGEFIRSTNAME);
			gstr(str1,20);
			if (sscanf(str1,"%s",str2) != 1)
			{
				sstrcr(NOTCHANGED);
				waitcr();
				continue;
			}
			strcpy(fname,str2);
			changed++;
			break;
		case 3: // get last name
			sprintf(tmpstr,CURRENTLASTNAME,lname);	
			sstrcr(tmpstr);
			cr();
			sstrcr(RETURNTOEXIT);
			cr();
			sstr(CHANGELASTNAME);
			gstr(str1,20);
			if (sscanf(str1,"%s",str2) != 1)
			{
				sstrcr(NOTCHANGED);
				waitcr();
				continue;
			}
			strcpy(lname,str2);
			changed++;
			break;
		case 4: // get city
			sprintf(tmpstr,CURRENTCITY,city);	
			sstrcr(tmpstr);
			cr();
			sstrcr(RETURNTOEXIT);
			cr();
			sstr(CHANGECITY);
			gstr(str1,20);
			if (sscanf(str1,"%s",str2) != 1)
			{
				sstrcr(NOTCHANGED);
				waitcr();
				continue;
			}
			strcpy(city,str2);
			changed++;
			break;
		case 5: // get state
			sprintf(tmpstr,CURRENTSTATE,state);	
			sstrcr(tmpstr);
			cr();
			sstrcr(RETURNTOEXIT);
			cr();
			sstr(CHANGESTATE);
			gstr(str1,14);
			if (sscanf(str1,"%s",str2) != 1)
			{
				sstrcr(NOTCHANGED);
				waitcr();
				continue;
			}
			strcpy(state,str2);
			changed++;
			break;
		case 6: // get alias
			sprintf(tmpstr,CURRENTALIAS,alias);	
			sstrcr(tmpstr);
			cr();
			sstrcr(RETURNTOEXIT);
			cr();
			sstr(CHANGEALIAS);
			gstr(str1,20);
			if (sscanf(str1,"%s",str2) != 1)
			{
				sstrcr(NOTCHANGED);
				waitcr();
				continue;
			}
			strcpy(alias,str2);
			changed++;
			break;
		case 7: // get downloads
			sprintf(tmpstr,CURRENTDOWNLOADS,downloads);	
			sstrcr(tmpstr);
			cr();
			sstrcr(RETURNTOEXIT);
			cr();
			sstr(CHANGEDOWNLOADS);
			gstr(str1,4);
			if (sscanf(str1,"%d",&tmp) != 1)
			{
				sstrcr(NOTCHANGED);
				waitcr();
				continue;
			}
			downloads = tmp;
			changed++;
			break;
		case 8: // get uploads
			sprintf(tmpstr,CURRENTUPLOADS,uploads);	
			sstrcr(tmpstr);
			cr();
			sstrcr(RETURNTOEXIT);
			cr();
			sstr(CHANGEUPLOADS);
			gstr(str1,4);
			if (sscanf(str1,"%d",&tmp) != 1)
			{
				sstrcr(NOTCHANGED);
				waitcr();
				continue;
			}
			uploads = tmp;
			changed++;
			break;
		case 9: // get access level
			sprintf(tmpstr,CURRENTACL,acl);	
			sstrcr(tmpstr);
			cr();
			sstrcr(RETURNTOEXIT);
			cr();
			sstr(CHANGEACL);
			gstr(str1,5);
			if (sscanf(str1,"%d",&tmp) != 1)
			{
				sstrcr(NOTCHANGED);
				waitcr();
				continue;
			}
			acl = tmp;
			changed++;
			break;
		case 10: // get flags
			sstrcr(CURRENTFLAGS);
			for (x=0; x<32; x++)
			{
				if (x%8 == 0 && x != 0)
					cr();
				sprintf(tmpstr,"%.2d:%d ",x,flags&1<<x?1:0);
				sstr(tmpstr);
			}
			cr();
			sstrcr(RETURNTOEXIT);
			cr();
			sstr(SETORCLEAR);
			gstr(str1,2);
			for (c=0; c<strlen(str1); c++)
				str1[c] = tolower(str1[c]);
			if (strchr(str1,'s') != NULL)
			{
				sstr(SETFLAG);
				gstr(str1,3);
				if (sscanf(str1,"%d",&tmp) != 1 || (tmp < 0 || tmp > 31))
				{
					sstrcr(NOTCHANGED);
					waitcr();
					continue;
				} 
				flags |= 1<<tmp;
			} 
			else if (strchr(str1,'c') != NULL)
			{
				sstr(CLEARFLAG);
				gstr(str1,3);
				if (sscanf(str1,"%d",&tmp) != 1 || (tmp < 0 || tmp > 31))
				{
					sstrcr(NOTCHANGED);
					waitcr();
					continue;
				} 
				flags &= ~(1<<tmp);
			}
			else
			{
				sstrcr(NOTCHANGED);
				waitcr();
				continue;
			} 
			changed++;
			break;
		case 11: // get timelimit
			sprintf(tmpstr,CURRENTTIMELIMIT,timelimit);	
			sstrcr(tmpstr);
			cr();
			sstrcr(RETURNTOEXIT);
			cr();
			sstr(CHANGETIMELIMIT);
			gstr(str1,5);
			if (sscanf(str1,"%d",&tmp) != 1)
			{
				sstrcr(NOTCHANGED);
				waitcr();
				continue;
			}
			timelimit = tmp;
			changed++;
			break;
		case 12: // get terminal types
			sprintf(tmpstr,CURRENTTERMTYPE,uterm);	
			sstrcr(tmpstr);
			cr();
			sstrcr(RETURNTOEXIT);
			cr();
			sstr(CHANGETYPE);
			gstr(str1,20);
			if (sscanf(str1,"%s",str2) != 1)
			{
				sstrcr(NOTCHANGED);
				waitcr();
				continue;
			}
			strcpy(uterm,str2);
			changed++;
			break;
		case 13: // get card color
			sprintf(tmpstr,CURRENTCARDCOLOR,card->colr);	
			sstrcr(tmpstr);
			cr();
			sstrcr(RETURNTOEXIT);
			cr();
			sstr(CHANGECOLOR);
			gstr(str1,10);
			if (sscanf(str1,"%s",str2) != 1)
			{
				sstrcr(NOTCHANGED);
				waitcr();
				continue;
			}
			for (c = 0; c < strlen(str2); c++) // convert to lower case
				str2[c] = tolower(str2[c]);
			if (!strcmp(str2,"red"))
				card_color = 0;
			else if (!strcmp(str2,"blue"))
				card_color = 1;
			else if (!strcmp(str2,"green"))
				card_color = 2;
			else if (!strcmp(str2,"white"))
				card_color = 3;
			else if (!strcmp(str2,"grey"))
				card_color = 4;
			else if (!strcmp(str2,"pink"))
				card_color = 5;
			else if (!strcmp(str2,"yellow"))
				card_color = 6;
			else if (!strcmp(str2,"black"))
				card_color = 7;
			else
			{
				sstrcr(COLORBAD);
				sstrcr(NOTCHANGED);
				waitcr();
				continue;
			}
			check_card();
			changed++;
			break;
		case 14: // get lines
			sprintf(tmpstr,CURRENTLINES,lines);	
			sstrcr(tmpstr);
			cr();
			sstrcr(RETURNTOEXIT);
			cr();
			sstr(CHANGELINES);
			gstr(str1,4);
			if (sscanf(str1,"%d",&tmp) != 1)
			{
				sstrcr(NOTCHANGED);
				waitcr();
				continue;
			}
			lines = tmp;
			changed++;
			break;
		case 15: // get columns
			sprintf(tmpstr,CURRENTCOLUMNS,cols);	
			sstrcr(tmpstr);
			cr();
			sstrcr(RETURNTOEXIT);
			cr();
			sstr(CHANGECOLUMNS);
			gstr(str1,4);
			if (sscanf(str1,"%d",&tmp) != 1)
			{
				sstrcr(NOTCHANGED);
				waitcr();
				continue;
			}
			cols = tmp;
			changed++;
			break;
		}
	}
	return(0);
};
// Function:	constructor
// Purpose:		initialize all object variables
// Input:		none
// Output:		(object is initialized)
// Author:		Greg Shaw
// Created:		6/1/93

User::User()
{
	card = NULL;
	if (card_color = def_card(), card_color == -1)
		ap_log("Unable to get default card color.");
	if (card_color != -1 && (card = cardinfo(card_color), card == NULL))
		ap_log("Unable to get card information.");
	fname[0] = 0;
	lname[0] = 0;
	alias[0] = 0;
	login_name[0] = 0;
	editor[0] = 0;
	city[0] = 0;
	state[0] = 0;
	uterm[0] = 0;
	time(&last_login);
	time(&login_time);
	time(&anniversary);
	mail_check = 0;
	logins = 1;
	lines = 24;
	cols = 80;
	downloads = 0;
	uploads = 0;
	priv_msgs = 0;
	pub_msgs = 0;
	credited = 0;
	flags = 0;
	tmpflags = 0;
	acl = card->acl;
	tmpacl = acl;
	timelimit = card->tl;
	tmptl = timelimit;
	credited = 0;
	timeused = 0;
	kused = 0;
	has_color = 0;
}

// Function:	destructor
// Purpose:		clean up the object
// Input:		none
// Output:		none ( null destructor at this point )
// Author:		Greg Shaw
// Created:		6/1/93

User::~User()
{
}
#endif // _USER_C_
