/*****************************************************************************
 *
 * File ..................: bbs/funcs4.c
 * Purpose ...............: Misc functions, also for some utils.
 * Last modification date : 13-Nov-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_LANG
#define	DB_USERS
#define DB_TTY

#include "../include/libs.h"
#include "../include/mbse.h"
#include "../include/structs.h"
#include "../include/records.h"
#include "../common/common.h"
#include "funcs4.h"
#include "misc.h"
#include "timeout.h"
#include "language.h"


extern	pid_t mypid;		/* Original pid				   */



void UserCity(char *user, char *city)
{
	SockS("AUSR:3,%d,%s,%s;", mypid, user, city);
}



void UserSilent(int flag)
{
	SockS("ADIS:2,%d,%d;", mypid, flag);
}



int CheckStatus()
{
	static	char buf[81];
	char	resp[81];

	if (!ttyinfo.honor_zmh)
		return TRUE;

	sprintf(buf, "SBBS:0;");
	if (socket_send(buf) == 0) {
		strcpy(buf, socket_receive());
		strncpy(resp, buf, 4);
		if (strncmp(buf, "100:", 4) == 0)
			return TRUE;

		strcpy(resp, strtok(buf, ":"));
		strcpy(resp, strtok(NULL, ",")); 
		printf("\n\n\007*** %s ***\n\n\n", strtok(NULL, ";")); 
	} 
	fflush(stdout);
	return FALSE;
}



/*
 * Get a character string with cursor position
 */
void GetstrP(char *sStr, int iMaxLen, int Position)
{
	unsigned char	ch = 0;
	int		iPos = Position;

	if ((ttyfd = open("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) {
		perror("open 1");
		return;
	}
	Setraw();

	alarm_on();

	while (ch != KEY_ENTER) {

		fflush(stdout);
		ch = Readkey();

		if ((ch == KEY_BACKSPACE) || (ch == KEY_DEL) || (ch == KEY_RUBOUT)) {
			if (iPos > 0) {
				printf("\b \b");
				sStr[--iPos] = '\0';
			} else
				putchar('\007');
		}

		if (ch > 31 && ch < 127) {
			if (iPos <= iMaxLen) {
				iPos++;
				sprintf(sStr, "%s%c", sStr, ch);
				printf("%c", ch);
			} else
				putchar('\007');
		}
	}

	Unsetraw();
	close(ttyfd);
	printf("\n");
}



/*
 * Get a character string
 */
void GetstrC(char *sStr, int iMaxlen)
{
	unsigned char	ch = 0;
	int		iPos = 0;

	fflush(stdout);
	if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) {
		perror("open 6");
		return;
	}
	Setraw();

	strcpy(sStr, "");
	alarm_on();

	while (ch != 13) {

		fflush(stdout);
		ch = Readkey();

		if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) {
			if (iPos > 0) {
				printf("\b \b");
				sStr[--iPos] = '\0';
			} else
				putchar('\007');
		}

		if (ch > 31 && ch < 127) {
			if (iPos <= iMaxlen) {
				iPos++;
				sprintf(sStr, "%s%c", sStr, ch);
				printf("%c", ch);
			} else
				putchar('\007');
		}
	}

	Unsetraw();
	close(ttyfd);
	printf("\n");
}



/*
 *  get a string, don't allow spaces (for Unix accounts)
 */
void GetstrU(char *sStr, int iMaxlen)
{
	unsigned char	ch = 0;
	int		iPos = 0;

	fflush(stdout);
	if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) {
		perror("open 6");
		return;
	}
	Setraw();

	strcpy(sStr, "");
	alarm_on();

	while (ch != 13) {

		fflush(stdout);
		ch = Readkey();

		if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) {
			if (iPos > 0) {
				printf("\b \b");
				sStr[--iPos] = '\0';
			} else
				putchar('\007');
		}

		if (ch > 32 && ch < 127) {
			if (iPos <= iMaxlen) {
				iPos++;
				sprintf(sStr, "%s%c", sStr, ch);
				printf("%c", ch);
			} else
				putchar('\007');
		}
	}

	Unsetraw();
	close(ttyfd);
	printf("\n");
}



/*
 * Get a phone number, only allow digits, + and - characters.
 */
void GetPhone(char *sStr, int iMaxlen)
{
	unsigned char	ch = 0; 
	int		iPos = 0;

	fflush(stdout);

	if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) {
		perror("open 5");
		return;
	}
	Setraw();

	strcpy(sStr, "");
	alarm_on();

	while (ch != 13) {

		fflush(stdout);
		ch = Readkey();

		if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) { 
			if (iPos > 0) {
				printf("\b \b");
				sStr[--iPos]='\0';
			} else
				putchar('\007');
		}

		if ((ch >= '0' && ch <= '9') || (ch == '-') || (ch == '+')) {
			if (iPos <= iMaxlen) {
				iPos++;
				sprintf(sStr, "%s%c", sStr, ch);
				printf("%c", ch);
			} else 
				putchar('\007');
		}
	}

	Unsetraw();                                           
	close(ttyfd);
	printf("\n");
}



/*
 * Get a number, allow digits, spaces, minus sign, points and comma's
 */
void Getnum(char *sStr, int iMaxlen)
{
	unsigned char	ch = 0; 
	int		iPos = 0;

	fflush(stdout);

	if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) {
		perror("open 5");
		return;
	}
	Setraw();

	strcpy(sStr, "");
	alarm_on();

	while (ch != 13) {

		fflush(stdout);
		ch = Readkey();

		if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) {
			if (iPos > 0) {
				printf("\b \b");
				sStr[--iPos]='\0';
			} else
				putchar('\007');
		}

		if ((ch >= '0' && ch <= '9') || (ch == '-') || (ch == ' ') \
		     || (ch == ',') || (ch == '.')) {

			if (iPos <= iMaxlen) {
				iPos++;
				sprintf(sStr, "%s%c", sStr, ch);
				printf("%c", ch);
			} else
				putchar('\007');
		}
	}

	Unsetraw();
	close(ttyfd);
	printf("\n");
}



/*
 * This function gets the date from the user checking the length and
 * putting two minus signs in the right places
 */
void GetDate(char *sStr, int iMaxlen)
{
	unsigned char	ch = 0; 
	int		iPos = 0;

	fflush(stdout);

	strcpy(sStr, "");

	if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) {
		perror("open 4");
		return;
	}
	Setraw();

	alarm_on();
	while (ch != 13) {

		fflush(stdout);
		ch = Readkey();

		if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) {
			if (iPos > 0)
				printf("\b \b");
			else
				putchar('\007');

			if (iPos == 3 || iPos == 6) {
				printf("\b \b"); 
				--iPos;
			}

			sStr[--iPos]='\0';
		}

		if (ch >= '0' && ch <= '9') {
			if (iPos < iMaxlen) {
				iPos++;
				sprintf(sStr, "%s%c", sStr, ch);
				printf("%c", ch);
				if (iPos == 2 || iPos == 5) {
					printf("-");
					sprintf(sStr, "%s-", sStr);
					iPos++;
				}
			} else
				putchar('\007');
		}
	}

	Unsetraw();
	close(ttyfd);
	printf("\n");
}



/*
 * Get a string, capitalize only if set in config.
 */
void Getname(char *sStr, int iMaxlen)
{
	unsigned char	ch = 0; 
	int		iPos = 0, iNewPos = 0;

	fflush(stdout);

	strcpy(sStr, "");

	if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) {
		perror("open 2");
		return;
	}
	Setraw();
	alarm_on();

	while (ch != 13) {

		fflush(stdout);
		ch = Readkey();

		if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) {
			if (iPos > 0) {
				printf("\b \b");
				sStr[--iPos]='\0';
			} else
				putchar('\007');
		}

		if (ch > 31 && (ch < 127)) {
			if (iPos < iMaxlen) {
				iPos++;
				if (iPos == 1 && CFG.iCapUserName)
					ch = toupper(ch);

				if (ch == 32) {
					iNewPos = iPos;
					iNewPos++;
				}

				if (iNewPos == iPos && CFG.iCapUserName)
					ch = toupper(ch);
				else
					if (CFG.iCapUserName)
						ch = tolower(ch);

				if (iPos == 1 && CFG.iCapUserName)
					ch = toupper(ch);

				sprintf(sStr, "%s%c", sStr, ch);
				printf("%c", ch);
			} else
				putchar('\007');
		}
	}

	Unsetraw();
	close(ttyfd);
	printf("\n");
}



/*
 * Get a Fidonet style username, always capitalize.
 */
void GetnameNE(char *sStr, int iMaxlen)         
{                                              
	unsigned char	ch = 0; 
	int		iPos = 0, iNewPos = 0;

	fflush(stdout);

	strcpy(sStr, "");

	if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) {
		perror("open 2");
		return;
	}
	Setraw();
	alarm_on();

	while (ch != 13) {

		fflush(stdout);
		ch = Readkey();

		if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) {
			if (iPos > 0) {
				printf("\b \b");
				sStr[--iPos]='\0';
			} else 
				putchar('\007');
		}

		if (ch > 31 && ch < 127) {
			if (iPos < iMaxlen) {
				iPos++;

				if (iPos == 1)
					ch = toupper(ch);

				if (ch == 32) {
					iNewPos = iPos;
					iNewPos++;
				}

				if (iNewPos == iPos)
					ch = toupper(ch);
				else
					ch = tolower(ch);

				if (iPos == 1)
					ch = toupper(ch);

				sprintf(sStr, "%s%c", sStr, ch);
				printf("%c", ch);
			} else
				putchar('\007');
		}
	}

	Unsetraw();
	close(ttyfd);
	printf("\n");
}



/*
 * Function will Scan Users Database for existing phone numbers. If
 * found, it will write a log entry to the logfile. The user WILL NOT
 * be notified about the same numbers
 */
int TelephoneScan(char *Number)
{
	FILE	*fp;
	int	Status = FALSE;
	char	*temp, *temp1;
	struct	userhdr	uhdr;
	struct	user	u;

	temp  = calloc(81, sizeof(char));
	temp1 = calloc(81, sizeof(char));
 
	strcpy(temp1, exitinfo.sUserName);

	sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT"));
	if(( fp = fopen(temp,"rb")) != NULL) {
		fread(&uhdr, sizeof(uhdr), 1, fp);

 		while (fread(&u, uhdr.recsize, 1, fp) == 1) {
			if (strcmp(u.sUserName, temp1) != 0)
	 			if ((strlen(u.sVoicePhone) && (strcmp(u.sVoicePhone, Number) == 0i)) || \
				    (strlen(u.sDataPhone) &&  (strcmp(u.sDataPhone, Number) == 0))) {
					Status = TRUE;
 					break;
 				}
 		}
		free(temp);
		free(temp1);
		fclose(fp);
	}
	return Status;
}



void Pause()
{
	int	i, x;
	char	*string;

	string = malloc(81);

	/* Press (Enter) to continue: */
	sprintf(string, "\r%s", (char *) Language(375));
	colour(CFG.CRColourF, CFG.CRColourB);
	printf(string);
	
	do {
		fflush(stdout);
		fflush(stdin);
		alarm_on();
		i = Getone();
	} while ((i != '\r') && (i != '\n'));

	x = strlen(string);
	for(i = 0; i < x; i++)
		printf("\b");
	for(i = 0; i < x; i++)
		printf(" ");
	for(i = 0; i < x; i++)
		printf("\b");
	fflush(stdout);

	free(string);
}



/*
 * Function to check if UserName exists and returns a 0 or 1
 */
int CheckName(char *Name)
{
	FILE	*fp;
	int	Status = FALSE;
	char	*temp, *temp1;
	struct	userhdr	ushdr;
	struct	user	us;

	temp   = calloc(81, sizeof(char));
	temp1  = calloc(81, sizeof(char));

	strcpy(temp1, tl(Name));

	sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT"));
	if ((fp = fopen(temp,"rb")) != NULL) {
		fread(&ushdr, sizeof(ushdr), 1, fp);

 		while (fread(&us, ushdr.recsize, 1, fp) == 1) {
			strcpy(temp, tl(us.sUserName));

			if((strcmp(temp, temp1)) == 0) {
				Status = TRUE;
				break;
			}
 		}
		free(temp);
		free(temp1);
		fclose(fp);
	}
	return Status;
}



/*
 * This function returns the date in the following format:
 * DD-Mon HH:MM:SS (Day-Month Time)
 * The users language is used.
 */
char *logdate()
{
	static char Logdate[15];

	time(&Time_Now);
	l_date = localtime(&Time_Now);
	sprintf(Logdate,"%02d-%s %02d:%02d:%02d", l_date->tm_mday, GetMonth(l_date->tm_mon+1),
			l_date->tm_hour, l_date->tm_min, l_date->tm_sec);
	return(Logdate);
}



/*
 * Function will ask user to create a unix login
 * Name cannot be longer than 8 characters
 */
char *NameGen(char *FidoName)
{
	char		*sUserName;
	struct passwd	*pw;

	sUserName = calloc(10, sizeof(char));

	Syslog('+', "NameGen(%s)", FidoName);
	setpwent();
	while ((strcmp(sUserName, "") == 0 || 
               (pw = getpwnam(sUserName)) != NULL) ||
	       (strlen(sUserName) < 3)) {
		colour(12, 0);
		printf("\n%s\n\n", (char *) Language(381));
		colour(15, 0);
		/* Please enter a login name (Maximum 8 characters) */
		printf("\n%s\n", (char *) Language(383));
		/* ie. John Doe, login = jdoe */
		printf("%s\n", (char *) Language(384));
		colour(10, 0);
		/* login > */
		printf("%s", (char *) Language(385));
		fflush(stdout);
		fflush(stdin);
		GetstrU(sUserName, 7);

		setpwent();
		if (pw = getpwnam(tl(sUserName)), pw != NULL) {
			/* That login name already exists, please choose another one. */
			colour(12, 0);
			printf("\n%s\n", (char *) Language(386));
			setpwent();
		}
	}
	return tl(sUserName);
}



/*
 * Function will create the users name in the passwd file
 */
char *NameCreate(char *Name, char *Comment)
{
	char	*PassEnt;

	PassEnt = calloc(256, sizeof(char));

	/*
	 * Call mbuseradd, this is a special setuid root program to create
	 * unix acounts and home directories.
	 */
	sprintf(PassEnt, "%s/bin/mbuseradd %d %s \"%s\" %s",
		bbs_path, getgid(), Name, Comment, CFG.bbs_usersdir);
	Syslog('b', "%s", PassEnt);
	fflush(stdout);
	fflush(stdin);

	if (system(PassEnt) != 0) {
		WriteError("Failed to create unix account");
		ExitClient(1);
	} 

	colour(14, 0);
	/* Your "Unix Account" is created, you may use it the next time you call */
	printf("\n%s\n", (char *) Language(382));
	Syslog('+', "Created Unix account %s for %s", Name, Comment);

	free(PassEnt);
	return Name;
}



/*
 * Function will check and create a home directory for the user if
 * needed. It will also change into the users home directory when
 * they login.
 */
char *ChangeHomeDir(char *Name)
{
	char	*temp;
	static	char temp1[81];

	temp  = calloc(81, sizeof(char));

	/*
	 * set umask bits to zero's then reset with mkdir
	 */
	umask(00000);
	
	/*
	 * First check to see if users home directory exists
	 * else try create directory, as set in CFG.bbs_usersdir
	 */
	if ((access(CFG.bbs_usersdir, R_OK)) != 0) {
		WriteError("$FATAL: Access to %s failed", CFG.bbs_usersdir);
		ExitClient(1);
	}

	sprintf(temp1, "%s/%s", CFG.bbs_usersdir, Name);
//	Syslog('b', "Checking %s", temp1);

	/*
	 * Then check to see if users directory exists in the home dir
	 */
	if ((access(temp1, R_OK)) != 0) {
		WriteError("$FATAL: Users homedir %s doesn't exist", temp1);
		ExitClient(1);
	}

	/*
	 * Change to users home directory
	 */
	if (chdir(temp1) != 0) {
		WriteError("$FATAL: Can't change to users home dir, aborting: %s", temp1);
		ExitClient(1);
	}

	/*
	 * Check subdirectories, create them if they don't exist.
	 */
	sprintf(temp, "%s/wrk", temp1);
	CheckDir(temp);
	sprintf(temp, "%s/tag", temp1);
	CheckDir(temp);
	sprintf(temp, "%s/upl", temp1);
	CheckDir(temp);
	sprintf(temp, "%s/tmp", temp1);
	CheckDir(temp);
	
	free(temp);
	return temp1;
}



void CheckDir(char *dir)
{
	if ((access(dir, R_OK) != 0)) {
		Syslog('+', "Creating %s", dir);
		if (mkdir(dir, 0770))
			WriteError("$Can't create %s", dir);
	}
}



/*
 * Function will check /etc/passwd for users fidonet login name.
 * This will allow users to login in with there full name instead of
 * their login name, to cut out confusion between unix accounts
 * and normal bbs logins.
 */
int Check4UnixLogin(char *UsersName)
{
	unsigned	UID = -1;  /* Set to -1 incase user is not found */
	struct passwd	*pw;

	while ((pw = getpwent())) {
		#ifdef linux
			if(strcmp(pw->pw_gecos, UsersName) == 0) {
		#else
			if(strcmp(pw->pw_comment, UsersName) == 0) {
		#endif
				UID = pw->pw_uid;
				break;
			}
	}

	return UID;
}



/*
 * Function to check if User Handle exists and returns a 0 or 1
 */
int CheckHandle(char *Name)
{
	FILE	*fp;
	int	Status = FALSE;
	char	*temp, *temp1;
	struct	userhdr	uhdr;
	struct	user	u;

	temp   = calloc(81, sizeof(char));
	temp1  = calloc(81, sizeof(char));

	strcpy(temp1, tl(Name));

	sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT"));
	if(( fp = fopen(temp,"rb")) != NULL) {
		fread(&uhdr, sizeof(uhdr), 1, fp);

 		while (fread(&u, uhdr.recsize, 1, fp) == 1) {
			strcpy(temp, tl(u.sHandle));

			if((strcmp(temp, temp1)) == 0) {
				Status = TRUE;
				break;
			}
 		}
		free(temp);
		free(temp1);
		fclose(fp);
	}

	return Status;
}



/*
 * Function will check for unwanted user names
 */
int BadNames(char *Username)
{
	FILE	*fp;
	short	iFoundName = FALSE;
	char	*temp, *String, *User;

	temp   = calloc(81, sizeof(char));
	String = calloc(81, sizeof(char));
	User   = calloc(81, sizeof(char));

	strcpy(User, tl(Username));

	sprintf(temp, "%s/etc/badnames.ctl", getenv("MBSE_ROOT"));
	if(( fp = fopen(temp, "r")) != NULL) {
		while((fgets(String, 80, fp)) != NULL) {
			strcpy(String, tl(String));
			Striplf(String);
			if((strstr(User, String)) != NULL) {
				printf("\nSorry that name is not acceptable on this system\n");
				iFoundName = TRUE;
				break;
			}
		}
		fclose(fp);
	}
	return iFoundName;
}



/*
 * Function will find where MBSE is located on system and load
 * the file $MBSE_ROOT/etc/config.data in memory.
 */
void FindMBSE()
{
	FILE		*pDataFile;
	char		*p, *FileName;
	struct passwd	*pw;

        FileName = calloc(81, sizeof(char));

	/*
	 * Check if the environment is set, if not, then we create the
	 * environment from the passwd file.
	 */
	if (getenv("MBSE_ROOT") == NULL) {
		pw = getpwnam("mbse");
		p = xstrcpy((char *)"MBSE_ROOT=");
		p = xstrcat(p, pw->pw_dir);
		putenv(p);
	}

	if (getenv("MBSE_ROOT") == NULL) {
		printf("FATAL ERROR: Environment variable MBSE_ROOT not set\n");
		exit(1);
	}
	strcpy(bbs_path, getenv("MBSE_ROOT"));
	sprintf(FileName, "%s/etc/config.data", bbs_path);

	if(( pDataFile = fopen(FileName, "rb")) == NULL) {
		printf("FATAL ERROR: Can't open %s for reading!\n", FileName);
		printf("Please run mbsetup to create configuration file.\n");
		printf("Or check that your environment variable MBSE_ROOT is set to the BBS Path!\n");
		exit(1);
	}

	fread(&CFG, sizeof(CFG), 1, pDataFile);
	free(FileName);
	fclose(pDataFile);
}




/* 
 * Returns Mmm in the users language.
 */
char *GetMonth(int Month)
{
	static char	month[10];

	switch (Month) {
		case 1:
			strcpy(month, *(mLanguage + 398));
			break;
		case 2:                    
			strcpy(month, *(mLanguage + 399));      
			break;                    
		case 3:                    
			strcpy(month, *(mLanguage + 400));      
			break;                    
		case 4:                    
			strcpy(month, *(mLanguage + 401));      
			break;                    
		case 5:                    
			strcpy(month, *(mLanguage + 402));      
			break;                    
		case 6:                    
			strcpy(month, *(mLanguage + 403));      
			break;                    
		case 7:                    
			strcpy(month, *(mLanguage + 404));      
			break;                    
		case 8:                    
			strcpy(month, *(mLanguage + 405));      
			break;                    
		case 9:                    
			strcpy(month, *(mLanguage + 406));      
			break;                    
		case 10:                    
			strcpy(month, *(mLanguage + 407));      
			break;                    
		case 11:                    
			strcpy(month, *(mLanguage + 408));      
			break;                    
		case 12:
			strcpy(month, *(mLanguage + 409));
			break;
		default:                        
			strcpy(month, "Unknown");      
	}                                              

	return(month);
}



/* Returns DD-Mmm-YYYY */
char *GLCdateyy()
{
	static	char	GLcdateyy[15];
	char	ntime[15];

	time(&Time_Now);
	l_date = localtime(&Time_Now);

	sprintf(GLcdateyy,"%02d-",
	  l_date->tm_mday);

	sprintf(ntime,"-%02d", l_date->tm_year+1900);
	strcat(GLcdateyy, GetMonth(l_date->tm_mon+1));
	strcat(GLcdateyy,ntime);

	return(GLcdateyy);
}


