/*****************************************************************************
 *
 * File ..................: bbs/user.c
 * Purpose ...............: Main user login procedure.  Checks for limits, 
 *                          new ratio's cats all the welcome screens, and 
 *                          does a lot of checking in general.
 * Last modification date : 05-Aug-1999
 *
 *****************************************************************************
 * Copyright (C) 1997-1999
 *   
 * Michiel Broek		FIDO:		2:2801/16
 * Beekmansbos 10		Internet:	mbroek@ux123.pttnwb.nl
 * 1971 BV IJmuiden
 * the Netherlands
 *
 * This file is part of MBSE BBS.
 *
 * This BBS 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.
 *
 * MBSE BBS 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 MBSE BBS; see the file COPYING.  If not, write to the Free
 * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *****************************************************************************/

#define	DB_USERS
#define	DB_LANG
#define	DB_LIMITS
#define	DB_FILEAREA
#define	DB_TTY

#include "../include/libs.h"
#include "../include/mbse.h"
#include "../include/structs.h"
#include "../include/records.h"
#include "../common/common.h"
#include "timeout.h"
#include "user.h"
#include "pwcheck.h"
#include "funcs.h"
#include "funcs4.h"
#include "misc.h"
#include "bye.h"
#include "file.h"
#include "mail.h"
#include "change.h"
#include "menu.h"
#include "exitinfo.h"
#include "language.h"
#include "offline.h"
#include "statetbl.h"
#include "newuser.h"


extern int	sock;


/* Non global function prototypes */

char *AskLogin(void);
static int rxemsi(void);


int	iMaxLogin = 1;
char	*ieUserName = NULL;
char	*ieHandle = NULL;
char	*ieLocation = NULL;
char	*ieVoicePhone = NULL;
char	*ieDataPhone = NULL;
long	iePassword = 0;
char	*ieBirthDate = NULL;
char	*ieTerminal = NULL;
int	ieRows = 0;
int	ieCols = 0;
int	ieNulls = 0;
int	ieDZA = FALSE;
int	ieZAP = FALSE;
int	ieZMO = FALSE;
int	ieSLK = FALSE;
int	ieKER = FALSE;
int	ieCHT = FALSE;
int	ieMNU = FALSE;
int	ieTAB = FALSE;
int	ieASCII8 = FALSE;
int	ieNEWS = FALSE;
int	ieMAIL = FALSE;
int	ieFILE = FALSE;
int	ieHOT  = FALSE;
int	ieCLR  = FALSE;
int	ieHUSH = FALSE;
int	ieMORE = FALSE;
int	ieFSED = FALSE;
int	ieXPRS = FALSE;
char	*ieSoftware = NULL;
int	ieLogin = FALSE;



/*
 * Ask for BBS Login name (Firstname Lastname) and try to
 * establish an IEMSI session if the client supports it.
 */
char *AskLogin(void);
char *AskLogin(void)
{
	char	temp[36];
	int	Count = 0, rc = 0;
	static	char GetName[36];

	do {
		/*
		 * if after the first time IEMSI failed rc will not be
		 * zero anymore so we don't check for IEMSI logon anymore.
		 */
		if (rc == 0) {
			rc = rxemsi();
			Syslog('+', "rxemsi rc=%d", rc);
		}
		if (rc) {
			/*
			 * IEMSI Aborted or other errors, so prompt user.
			 * Note that if the user didn't had an IEMSI client,
			 * rc is still 0, the name is entered in the rxemsi
			 * function.
			 */
			/* Please enter your First and Last name: */
			language(7, 0, 0);
			fflush(stdout);
			alarm_on();
			Getname(GetName, 35);
		} else {
			sprintf(GetName, "%s", ieUserName);
		}

		if ((strcmp(GetName,"")) == 0) {
			Count++;

			if(Count >= CFG.iCRLoginCount) {
				Enter(1);
				/* Disconnecting user ... */
				language(CFG.HiliteF, CFG.HiliteB, 2);
				Enter(2);
				Syslog('!', "Exceeded maximum login attempts");
				Quick_Bye(0);
			}
		}
	} while (strcmp(GetName, "") == 0);

	strcpy(temp, GetName);

	/*
	 * Secret escape name
	 */
	if ((strcasecmp(temp, "off")) == 0) {
		Syslog('+', "Quick \"off\" logout");
		Quick_Bye(0);
	}

	/*
	 * Check for singlename
	 */
	if ((strchr(GetName,' ') == NULL && !CFG.iOneName)) {
		Syslog('+', "Did not enter a full name");

		while (TRUE) {
			do {
				/* Please enter your Last name: */
				language(7, 0, 1);
				fflush(stdout);
				alarm_on();
				Getname(temp, 34 - strlen(GetName));
			} while ((strcmp(temp, "")) == 0);

			if((strcmp(temp,"")) != 0) {
				strcat(GetName," ");
				strcat(GetName,temp);
				break;
			}
		}
	}

	alarm_off();
	return GetName;
}



/*
 *  The next function is "borrowed" from Eugene M. Crossers ifcico.
 */
char *sel_brace(char *);
char *sel_brace(char *s)
{
	static char	*save;
	char		*p, *q;
	int		i;

	if (s == NULL)
		s = save;
	for (; *s && (*s != '{'); s++);
	if (*s == '\0') {
		save = s;
		return NULL;
	} else
		s++;

	for (p = s, q = s; *p; p++)
		switch(*p) {
			case '}':	if (*(p+1) == '}')
						*q++ = *p++;
					else {
						*q = '\0';
						save = p+1;
						goto exit;
					}
					break;

			case '\\':	if (*(p+1) == '\\')
						*q++ = *p++;
					else {
						sscanf(p+1, "%02x", &i);
						*q++ = i;
						p+=2;
					}
					break;

			default:	*q++ = *p;
					break;
		}
exit:
	return s;
}



int scanemsiici(char *);
int scanemsiici(char *buf)
{
	char	*p, *q;

	ieUserName = xstrcpy(sel_brace(buf));
	Syslog('i', "Username    : %s", S(ieUserName));
	ieHandle = xstrcpy(sel_brace(NULL));
	Syslog('i', "Handle      : %s", S(ieHandle));
	ieLocation = xstrcpy(sel_brace(NULL));
	Syslog('i', "Location    : %s", S(ieLocation));
	ieVoicePhone = xstrcpy(sel_brace(NULL));
	Syslog('i', "Voice Phone : %s", S(ieVoicePhone));
	ieDataPhone = xstrcpy(sel_brace(NULL));
	Syslog('i', "Data Phone  : %s", S(ieDataPhone));
	p = sel_brace(NULL);
	iePassword = StringCRC32(tu(p));
	Syslog('i', "Password    : %s (%ld)", p, iePassword);
	ieBirthDate = xstrcpy(sel_brace(NULL));
	Syslog('i', "Birthdate   : %s", S(ieBirthDate));
	p = sel_brace(NULL);
	ieTerminal = strtok(p, ",");
	ieRows = atoi(strtok(NULL, ","));
	ieCols = atoi(strtok(NULL, ","));
	ieNulls = atoi(strtok(NULL, ","));
	Syslog('i', "Terminal    : %s (%d x %d) [%d]", ieTerminal, ieRows, ieCols, ieNulls);

	p = sel_brace(NULL);
	Syslog('i', "Protocols   : %s", S(p));
	for (q = strtok(p, ","); q; q = strtok(NULL, ",")) {
		if (strcasecmp(q, "DZA") == 0)
			ieDZA = TRUE;
		else if (strcasecmp(q, "ZAP") == 0)
			ieZAP = TRUE;
		else if (strcasecmp(q, "ZMO") == 0)
			ieZMO = TRUE;
		else if (strcasecmp(q, "SLK") == 0)
			ieSLK = TRUE;
		else if (strcasecmp(q, "KER") == 0)
			ieKER = TRUE;
		else 
			Syslog('+', "Unrecognized IEMSI Protocol \"%s\"", q);
	}

	p = sel_brace(NULL);
	Syslog('i', "Capabilities: %s", S(p));
	for (q = strtok(p, ","); q; q = strtok(NULL, ",")) {
		if (strcasecmp(q, "CHT") == 0)
			ieCHT = TRUE;
		else if (strcasecmp(q, "TAB") == 0)
			ieTAB = TRUE;
		else if (strcasecmp(q, "MNU") == 0)
			ieMNU = TRUE;
		else if (strcasecmp(q, "ASCII8") == 0)
			ieASCII8 = TRUE;
		else
			Syslog('+', "Unrecognized IEMSI Capability \"%s\"", q);
	}

	p = sel_brace(NULL);
	Syslog('i', "Requests    : %s", S(p));
	for (q = strtok(p, ","); q; q = strtok(NULL, ",")) {
		if (strcasecmp(q, "NEWS") == 0)
			ieNEWS = TRUE;
		else if (strcasecmp(q, "MAIL") == 0)
			ieMAIL = TRUE;
		else if (strcasecmp(q, "FILE") == 0)
			ieFILE = TRUE;
		else if (strcasecmp(q, "HOT") == 0)
			ieHOT = TRUE;
		else if (strcasecmp(q, "CLR") == 0)
			ieCLR = TRUE;
		else if (strcasecmp(q, "HUSH") == 0)
			ieHUSH = TRUE;
		else if (strcasecmp(q, "MORE") == 0)
			ieMORE = TRUE;
		else if (strcasecmp(q, "FSED") == 0)
			ieFSED = TRUE;
		else if (strcasecmp(q, "XPRS") == 0)
			ieXPRS = TRUE;
		else
			Syslog('+', "Unrecognized IEMSI Request \"%s\"", q);
	}

	ieSoftware = xstrcpy(sel_brace(NULL));
	Syslog('i', "Software    : %s", S(ieSoftware));

	return 0;
}



char *mkiemsiisi(void);
char *mkiemsiisi(void)
{
	char	*p, cbuf[16];
	time_t	tt;

	p = xstrcpy((char *)"EMSI_ISI0000{MBSE BBS,");
	p = xstrcat(p, (char *)MBSEVersion);
	p = xstrcat(p, (char *)",Linux}{");
	p = xstrcat(p, CFG.bbs_name);
	p = xstrcat(p, (char *)"}{");
	p = xstrcat(p, CFG.location);
	p = xstrcat(p, (char *)"}{");
	p = xstrcat(p, CFG.sysop_name);
	p = xstrcat(p, (char *)"}{");
	(void)time(&tt);
	sprintf(cbuf, "%08lX", mktime(localtime(&tt)));
	p = xstrcat(p, cbuf);
	p = xstrcat(p, (char *)"}{");
	p = xstrcat(p, CFG.comment);
	p = xstrcat(p, (char *)"}{0}{}");
	sprintf(cbuf, "%04X", strlen(p+12));
	memcpy(p+8, cbuf, 4);

	Syslog('i', "Prepared \"%s\"", p);
	return p;
}



SM_DECL(rxemsi, (char *)"rxemsi")
SM_STATES
	prompt,
	getpkt,	
	chkpkt,
	chkici,
	sendnak,
	sendisi,
	human
SM_NAMES
	(char *)"prompt",
	(char *)"getpkt",
	(char *)"chkpkt",
	(char *)"chkici",
	(char *)"sendnak",
	(char *)"sendisi",
	(char *)"human"
SM_EDECL
	int		len, iemsi, newpos, tries = 0;
	char		*p, *buf = NULL;
	unsigned char	c = 0;
	unsigned short	lcrc, rcrc;
	unsigned long	llcrc, lrcrc;

	buf = calloc(2048, sizeof(char));

SM_START(prompt)

SM_STATE(prompt)
	Syslog('i', "SM: prompt");

	/*
	 * Issue EMSI_IRQ and overwrite it with the prompt.
	 */
	printf("**EMSI_IRQ8E08\r              \r");
	/* Please enter your First and Last name: */
	language(7, 0, 0);
	fflush(stdout);
	tries = 0;
	SM_PROCEED(getpkt);

SM_STATE(getpkt)
	Syslog('i', "SM: getpkt");

	fflush(stdin);
	if ((ttyfd = open("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) {
		WriteError("$Can't open /dev/tty");
		SM_ERROR;
	}
	Setraw();
	len = 0;
	iemsi = FALSE;
	newpos = 0;
	buf[0] = '\0';
	alarm_on();

	while(TRUE) {
		c = Readkey();

//		Syslog('i', "c=%s len=%d iemsi=%d", printablec(c), len, iemsi);

		if ((len == 0) && (c == '*')) {
			iemsi = TRUE;
		} else {
			if (((c == 8) || (c == KEY_DEL) || (c == 127)) && (len > 0)) {
				printf("\b \b");
				fflush(stdout);
				buf[--len] = '\0';
			}

			if (c > 31 && c < 127) {
				if ((len == 0) && (CFG.iCapUserName))
					c = toupper(c);
	
				if (c == 32) {
					newpos = len;
					newpos++;
				}

				if (!iemsi) {
					if (newpos == len && CFG.iCapUserName)
						c = toupper(c);
					else {
						if (CFG.iCapUserName)
							c = tolower(c);
					}
					printf("%c", c);
					fflush(stdout);
				}
				buf[len] = c;
				len++;
			}
		}

		if ((c == '\r') || (!iemsi && (len == 35)) || (iemsi && (len == 2047))) {
			buf[len] = '\0';
			break;
		}
	}

	Unsetraw();
	close(ttyfd);
	Syslog('i', "Buf \"%s\"", printable(buf,0));

	if (strncasecmp(buf, "EMSI_", 5)) {
		SM_PROCEED(human);
	} else {
		SM_PROCEED(chkpkt);
	}

SM_STATE(chkpkt)
	Syslog('i', "SM: chkpkt");
	if (strncasecmp(buf, "EMSI_ICI", 8) == 0) {
		SM_PROCEED(chkici)
	}
	lcrc = crc16xmodem(buf, 8);
	sscanf(buf+8, "%04hx", &rcrc);
	if (lcrc != rcrc) {
		Syslog('+', "Got IEMSI packet \"%s\" with bad crc: %04x/%04x",
			printable(buf, 0), lcrc, rcrc);
		SM_PROCEED(sendnak);
	}
	if (strncasecmp(buf, "EMSI_HBT", 8) == 0) {
		tries = 0;
		SM_PROCEED(getpkt);
	} else if (strncasecmp(buf, "EMSI_IIR61E2", 12) == 0) {
		Syslog('+', "IEMSI Interrup Request received");
		SM_ERROR;
	} else if (strncasecmp(buf, "EMSI_ACKA490", 12) == 0) {
		Syslog('+', "Established IEMSI session");
		ieLogin = TRUE;
		/*
		 * Clearup the part of the users screen where some IEMSI
		 * codes may be hanging around
		 */
		fflush(stdin);
		printf("\r                                              \r");
		fflush(stdout);
		SM_SUCCESS;
	} else if (strncasecmp(buf, "EMSI_NAKEEC3", 12) == 0) {
		Syslog('+', "IEMSI NAK received");
		SM_PROCEED(getpkt);
	} else {
		Syslog('i', "rxemsi ignores packet \"%s\"", buf);
		SM_PROCEED(getpkt);
	}

SM_STATE(chkici)
	Syslog('i', "SM: chkici");
	sscanf(buf+8, "%04x", &len);
	if (len != (strlen(buf) - 20)) {
		Syslog('+', "Bad EMSI_ICI length: %d/%d", len, strlen(buf)-20);
		SM_PROCEED(sendnak);
	}
	sscanf(buf+strlen(buf)-8, "%08lx", &lrcrc);
	*(buf+strlen(buf)-8) = '\0';
	llcrc = crc32ccitt(buf, strlen(buf));
	if (llcrc != lrcrc) {
		Syslog('+', "Got EMSI_ICI packet \"%s\" with bad crc: %08x/%08x",
			printable(buf, 0), llcrc, lrcrc);
		SM_PROCEED(sendnak);
	}
	if (scanemsiici(buf+12) == 0) {
		SM_PROCEED(sendisi);
	} else {
		WriteError("Could not parse EMSI_ICI packet \"%s\"", buf);
		SM_ERROR;
	}

SM_STATE(sendnak)
	Syslog('i', "SM: sendnak");
	if (++tries > 9) {
		Syslog('+', "too many tries getting EMSI_ICI");
		SM_ERROR;
	}
	printf((char *)"**EMSI_IRQ8E08\r");
	if (tries > 1)
		printf((char *)"**EMSI_NAKEEC3\r");
	fflush(stdout);
	SM_PROCEED(getpkt);

SM_STATE(sendisi)
	Syslog('i', "SM: sendisi");
	p = mkiemsiisi();
	printf("**%s%08lX\r", p, crc32ccitt(p, strlen(p)));
	fflush(stdout);
	free(p);
	SM_PROCEED(getpkt);

SM_STATE(human)
	printf("\n");
	fflush(stdout);
	ieUserName = xstrcpy(buf);
	Syslog('+', "Human caller (%s)", S(ieUserName));
	SM_SUCCESS;

SM_END
	free(buf);

SM_RETURN



void user()
{
	FILE		*pUsrConfig, *pLimits;
	int		i, x, z;
	int		FoundName = FALSE, iFoundLimit = FALSE;
	register int 	recno;
	int		lrecno = 0;
	long		l1, l2;
	unsigned 	crc = 0;
	char		*token;
	char		temp[84];
	char		temp1[84];
	char		sGetName[84];
	char		*FileName;
	char		*handle;
	struct passwd	*pw;
	char		*sGetPassword;
	long		offset;
	time_t		LastLogin;
	struct stat 	st;
	char		UserName[36];
	int		IsNew = FALSE;


	sGetPassword = malloc(Max_passlen+1);
	FileName     = calloc(84, sizeof(char));
	handle       = calloc(40, sizeof(char));

	recno=0;
	LoginPrompt = TRUE;

	/*
	 * If not in unix mode ask for login
	 */
	if (!iUnixMode) {
		strcpy(sGetName, AskLogin());
	} else {
		Syslog('+', "Unixmode login: %s", sUnixName);
		if ((pw = getpwnam(sUnixName)))
		#ifdef linux
			strcpy(sGetName, pw->pw_gecos);
		#else
			strcpy(sGetName, pw->pw_comment);
		#endif

		/*
		 * If there are more fields in the passwd gecos field
		 * then only get the first field.
		 */
		if (strchr(sGetName, ',') != NULL)
			strcpy(sGetName, strtok(sGetName, ","));

		if (!(CheckName(sGetName))) {
			printf("Unknown username: %s\n", sGetName);
			/* FATAL ERROR: You are not in the BBS users file.*/
			printf("%s\n", (char *) Language(389));
			/* Please run 'newuser' to create an account */
			printf("%s\n", (char *) Language(390));
			Syslog('?', "FATAL: Could not find user in BBS users file.");
			Syslog('?', "       and system is using unix accounts\n");
			ExitClient(0);
		}
	}

	if (CFG.iCapUserName || SYSOP)
		strcpy(sGetName, tlcap(sGetName));

	/*
	 * Copy username, split first and lastname.
	 */
	strcpy(UserName, tlcap(sGetName));

	if ((strchr(sGetName,' ') == NULL && !CFG.iOneName)) {
		token = strtok(sGetName, " ");
  		strcpy(FirstName, token);
  		token = strtok(NULL, "\0");
		i = strlen(token);
		for(x = 2; x < i; x++) {
			if(token[x] == ' ')
				token[x] = '\0';
		}
	 	strcpy(LastName, token);
	} else
		strcpy(FirstName, sGetName);

	Syslog('+', "%s On-Line at %s", UserName, ttyinfo.comment);

	if ((strlen(sGetName)) < 2)
		user();

	/*
	 * Check some essential files, create them if they don't exist.
	 */
 	ChkFiles();


	sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); 
	if ((pUsrConfig = fopen(temp,"r+b")) == NULL) {
		/*
		 * This should only happen once, when you build the BBS
		 */
		WriteError("Can't open users file: %s", temp);
		printf("Can't open userfile, run \"newuser\" first");
		ExitClient(0);
	}

	fread(&usrconfighdr, sizeof(usrconfighdr), 1, pUsrConfig);
	strcpy(temp1, UserName);
	while (fread(&usrconfig, usrconfighdr.recsize, 1, pUsrConfig) == 1) {
		strcpy(temp, usrconfig.sUserName);
		strcpy(handle, usrconfig.sHandle);

		if ((strcasecmp(temp, temp1) == 0 || strcasecmp(handle, temp1) == 0)) {
			FoundName = TRUE;
			break;
		} else
			recno++;
	}

	if (!FoundName) {
		Syslog('+', "Name not in user file");
		Enter(1);
		/* Scanning User File */
		language(7, 0, 3);
		Enter(1);

		usrconfig.GraphMode = FALSE;
		DisplayFile((char *)"notfound");

		Enter(1);
		/* Name entered: */
		language(7, 0, 5);
		printf("%s\n\n", UserName);
		/* Did you spell your name correctly [Y/n] */
		language(7, 0, 4);
		fflush(stdout);
		fflush(stdin);
		i = toupper(Getone());
		if (i == Keystroke(4, 0) || i == '\r') {
			if (!CFG.elite_mode) {
				/*
				 * Here we run newuser.
				 */
				Syslog('+', "Creating user ...");
				recno = newuser(UserName);
				IsNew = TRUE;
			} else {
				if (!DisplayFile((char *)"private")) {
					/* If FALSE display hard coded message */
					Enter(1);
					/* This is a PRIVATE System, Type "off" to leave */
					language(7, 0, 6);
					Enter(2);
				}

				Syslog('!', "NewUser tried to login to \"Private System\"");
				Quick_Bye(0);
			}

		} else {
			Enter(1);
			Syslog('+', "User spelt his/her name incorrectly");
			user();
		}
	}

	/*
	 * Setup users favourite language.
	 */
	Set_Language(usrconfig.iLanguage);
	Free_Language();
	InitLanguage();

	/*
	 * User logged in, tell it to the server.
	 */
	UserCity(usrconfig.sUserName, usrconfig.sLocation);

	/*
	 * See if this user is the Sysop.
	 */
	strcpy(temp, UserName);
	strcpy(temp1, CFG.sysop_name);
	if ((strcasecmp(temp1, temp)) == 0)
		SYSOP = TRUE; /* If login name is sysop, set SYSOP true */

	grecno = recno;

	offset = usrconfighdr.hdrsize + (recno * usrconfighdr.recsize);
	if (fseek(pUsrConfig, offset, 0) != 0) {
		printf("Can't move pointer there."); 
		getchar(); 
		ExitClient(1);
	}

	fread(&usrconfig, usrconfighdr.recsize, 1, pUsrConfig);
	TermInit(usrconfig.GraphMode);

	/*
	 * If UnixMode is False, else let crc = iPassword to bypass the
	 * passwd
	 */
	if (!iUnixMode && !IsNew) {
		/*
		 * Check for a blank or expired password, they do exist
		 * after upgrading from RA 2.xx due to a bug in RA (or feature)
		 */
		if (usrconfig.iPassword == 0) {
			Syslog('!', "User has blank password, asking new");
			z = 0;
			while (TRUE) {
				Enter(1);
				/* Your password is expired, enter password: */
				language(7, 0, 435);
				fflush(stdout);
				alarm_on();
				Getpass(temp);
				if ((x = strlen(temp)) >= CFG.password_length) {
					Enter(1);
					/* Please enter password again: */
					language(7, 0, 40);
					fflush(stdout);
					alarm_on();
					Getpass(temp1);
					if ((i = strcmp(temp, temp1)) != 0) {
						Enter(2);
						/* Passwords do not match */
						language(7,0,41);
						Enter(1);
					} else {
						crc = StringCRC32(tu(temp));
						usrconfig.iPassword = crc;
						break;
					}
				} else {
					z++;
					if (z == CFG.iCRLoginCount) {
						Syslog('!', "User did not enter new password");
						Enter(1);
						language(CFG.HiliteF, CFG.HiliteB, 2);
						Enter(2);
						Quick_Bye(0);
					}

					Enter(2);
					/* Your password must contain at least */
					language(7, 0, 42);
					printf("%d ", CFG.password_length);
					/* characters! Try again */
					language(7, 0, 43);
					Enter(1);
				}
			}
		} else {
			if ((ieLogin) && (iePassword == usrconfig.iPassword)) {
				crc = iePassword;
			} else {
				/* Pasword: */
				language(7, 0, 8);
				fflush(stdout);
				alarm_on();
				Getpass(sGetPassword);
				/*
				 * Password is CRC32 of uppercase string
				 */
				crc = StringCRC32(tu(sGetPassword));
			}
		}
	} else
		crc = usrconfig.iPassword;

	IsDoing("Just Logged In");

	/*
	 * If password already OK, give pause prompt so the bbs logo
	 * will stay on the users screen.
	 */
	if ((iUnixMode) || ((ieLogin) && (iePassword == usrconfig.iPassword))) {
		alarm_on();
		Pause();
	}

	if (usrconfig.Archiver[0] == '\0') {
		usrconfig.Archiver[0] = 'Z';
		usrconfig.Archiver[1] = 'I';
		usrconfig.Archiver[2] = 'P';
		Syslog('+', "Setup default archiver ZIP");
	}

 	if (usrconfig.iPassword == crc) {
		recno = 0;

		/*
		 * Check if user has an Unix account, if not create one
		 */
		if (usrconfig.Name[0] == '\0') {
			alarm_on();
			sprintf(usrconfig.Name, "%s", (char *)NameCreate(NameGen(UserName), UserName));
			sprintf(sUnixName, "%s", usrconfig.Name);
			Pause();
		}

		/*
		 * Check users date format. We do it strict as we
		 * need this to be good for several other purposes.
		 * If it is correct, the users age is set in UserAge
		 */
		if (!Test_DOB(usrconfig.sDateOfBirth)) {
			Syslog('!', "Error in Date of Birth");
			Chg_DOB();
			strcpy(usrconfig.sDateOfBirth, exitinfo.sDateOfBirth);
		}

		/*
		 * Check to see if user must expire
		 */
		sprintf(temp,"%s", (char *) GetDateDMY());
		SwapDate(temp, usrconfig.sExpiryDate);

		/* Convert Date1 & Date2 to longs for compare */
		l1 = atol(Date1);
		l2 = atol(Date2);

		if(l1 >= l2 && l2 != 0) {
			/* 
			 * If Expiry Date is the same as today expire to 
			 * Expire Sec level
			 */
			usrconfig.Security = usrconfig.ExpirySec;
			Syslog('!', "User is expired, resetting level");
			/*
			 * Show texfile to user telling him about this.
			 */
			DisplayFile((char *)"expired");
		}

		free(Date1); 
		free(Date2);

		/* 
		 * Copy limits.data into memory
		 */
		sprintf(FileName, "%s/etc/limits.data", getenv("MBSE_ROOT"));

		if(( pLimits = fopen(FileName,"rb")) == NULL) {
			perror("");
			WriteError("Can't open file: %s", FileName);
		} else {
			fread(&LIMIThdr, sizeof(LIMIThdr), 1, pLimits);

			while (fread(&LIMIT, sizeof(LIMIT), 1, pLimits) == 1) {
	 			if (LIMIT.Security == usrconfig.Security.level) {
					iFoundLimit = TRUE;
					break;
				} else
					lrecno++;
			}
			fclose(pLimits);
		}

		if(!iFoundLimit) {
			Syslog('?', "Unknown Security Level in limits.data");
			usrconfig.iTimeLeft = 0; /* Could not find limit, so set to Zero */
			usrconfig.iTimeUsed = 0; /* Set to Zero as well  */
		} else {
			/*
			 * Give user new time limit everyday
			 */
			sprintf(temp,"%s", (char *) GetDateDMY());

			if((strcmp(StrDateDMY(usrconfig.tLastLoginDate), temp)) != 0) {
				usrconfig.iTimeLeft    = LIMIT.Time; /* Copy Sec limit/time to users file */
				usrconfig.iTimeUsed    = 0;          /* Set time used today to Zero       */
				usrconfig.iConnectTime = 0;	     /* Set connect time to Zero          */

				/*
				 * Give user new bytes and files every day
				 */
				usrconfig.DownloadKToday = LIMIT.DownK;
				usrconfig.DownloadsToday = LIMIT.DownF;
			}
		} /* End of else  */

		usrconfig.iConnectTime = 0;

		/* Copy Users Protocol into Memory */
		Set_Protocol(usrconfig.sProtocol);
		tlf(usrconfig.sProtocol);

		/* 
		 * Set last login Date and Time, copy previous session
		 * values in memory.
		 */
		sprintf(LastLoginDate, "%s", StrDateDMY(usrconfig.tLastLoginDate));
		sprintf(LastLoginTime, "%s", StrTimeHMS(usrconfig.tLastLoginDate));
		LastLogin = usrconfig.tLastLoginDate;
		usrconfig.tLastLoginDate = ltime; /* Set current login to current date */
		usrconfig.iTotalCalls = ++usrconfig.iTotalCalls;

		/* 
		 * Copy last file Area in to current Area 
		 */
		SetFileArea(usrconfig.iLastFileArea);

		/*
		 * Copy Last Message Area in to Current Msg Area
		 */
		SetMsgArea(usrconfig.iLastMsgArea);

		/*
		 * If IEMSI login, update some settings
		 */
		if (ieLogin) {
			usrconfig.Cls          = ieCLR;
			usrconfig.HotKeys      = ieHOT;
			usrconfig.ieNEWS       = ieNEWS;
			usrconfig.MailScan     = ieMAIL;
			usrconfig.ieFILE       = ieFILE;
			usrconfig.Chat         = ieCHT;
			usrconfig.ieASCII8     = ieASCII8;
			usrconfig.DoNotDisturb = ieHUSH;
			usrconfig.FsMsged      = ieFSED;
		}

		/*
		 * Update user record.
		 */
		if(fseek(pUsrConfig, offset, 0) != 0)
			WriteError("Can't move pointer in file: %s", temp);
		else {
			fwrite(&usrconfig, sizeof(usrconfig), 1, pUsrConfig);
			fclose(pUsrConfig);
		}

		/*
		 * Write users structure to tmp file in ~/tmp
		 */
		InitExitinfo();
		GetLastUser();
		GetLastCallers();
		ChangeHomeDir(exitinfo.Name);

		Syslog('+', "User successfully logged into BBS");
		Syslog('+', "Level %d (%s), %d mins. left, port %s", usrconfig.Security.level, LIMIT.Description, usrconfig.iTimeLeft, pTTY);
		time(&Time2Go);
		Time2Go += usrconfig.iTimeLeft * 60;
		iUserTimeLeft = usrconfig.iTimeLeft;

		DisplayFile((char *)"welcome");

		/*
		 * The following files are only displayed if the user has
		 * turned the Bulletins on.
		 */
		if (exitinfo.ieNEWS) {
			DisplayFile((char *)"welcome1");

			sprintf(temp, "%s", (char *) GetDateDMY() );
			if ((strcmp(usrconfig.sDateOfBirth, temp)) == 0)
				DisplayFile((char *)"birthday");

			/*
			 * Displays file if it exists DD-MM.A??
			 */
			sprintf(temp, "%s", (char *) GetDateDMY());
			strcpy(temp1, "");
			strncat(temp1, temp, 5);
			sprintf(temp, "%s", temp1);
			DisplayFile(temp);
	
			/*
			 * Displays users security file if it exists
			 */
			sprintf(temp, "sec%d", usrconfig.Security.level);
			DisplayFile(temp);

			/*
			 * Display News file
			 */
			DisplayFile((char *)"news");
		}

		/*
		 * Display Onceonly file, first get the date of that
		 * file, search order is the same as in DisplayFile()
		 */
		st.st_mtime = 0;
		if (usrconfig.GraphMode) {
			sprintf(temp, "%s/onceonly.ans", lang.TextPath);
			stat(temp, &st);
			if (st.st_mtime == 0) {
				sprintf(temp, "%s/onceonly.ans", CFG.bbs_txtfiles);
				stat(temp, &st);
			}
		}
		if (st.st_mtime == 0) {
			sprintf(temp, "%s/onceonly.asc", lang.TextPath);
			stat(temp, &st);
			if (st.st_mtime == 0) {
				sprintf(temp, "%s/onceonly.asc", CFG.bbs_txtfiles);
				stat(temp, &st);
			}
		}

		if ((st.st_mtime != 0) && (LastLogin < st.st_mtime))
			DisplayFile((char *)"onceonly");
	
		LoginPrompt = FALSE;
		OLR_SyncTags();

		if (usrconfig.MailScan)
			CheckMail();

		/*
		 * We don't show new files to new users, their lastlogin
		 * date is not yet set so they would see all the files
		 * which can be boring...
		 */
		if (usrconfig.ieFILE && (!IsNew))
			NewfileScan(FALSE);

		/*
		 * Set or Reset the DoNotDisturb flag, now is the time
		 * we may be interrupted.
		 */
		UserSilent(usrconfig.DoNotDisturb);

		/*
		 * Start the menu.
		 */
        	menu();
	} else {
		free(FileName);
		free(handle);

		Syslog('+',"Login attempt: %d, password: %s", iMaxLogin, sGetPassword);
		iMaxLogin++;
		if(iMaxLogin == CFG.max_login + 1) {
			Enter(2);
			language(7, 0, 9);
			Enter(1);
			Syslog('!', "Exceeded maximum login attempts, user disconnected");
			ExitClient(1);
		}
		Enter(2);
		language(7, 0, 10);
		Enter(2);
		alarm_on();
		Pause();
		printf("\n");
		user();
	}
}


