// Filename:	bbs.C
// Contents:	the main bbs program (main)
// Author:	Greg Shaw
// Created:	7/28/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 _BBS_C_
#define _BBS_C_

#include "bbshdr.h"

// the user object is defined globally so that the menu object can access
// it via extern 
moncon	mon_obj;
User	user;

// Function:	getout
// Purpose:	get out of the bbs system.  Quick and dirty
// Author:	Greg Shaw
// Created:	8/16/93

void getout(int sig)
{
	char	tmpstr[255];	// temporary string
	static	int inalready=0;	// if already in, don't do again
	
	if (sig == SIGINT)	// don't exit on interrupt
		return;
	if (!inalready)
	{
		sprintf(tmpstr,"Got signal %d",sig);
		user.ap_log(tmpstr);
		inalready++;
		user.save(NULL);
		sprintf(tmpstr,"(hangup - %s) Logoff for %s %s",sys_siglist[sig],user.fname,user.lname);
		user.ap_log(tmpstr);
		if (mon_obj.watching())
		{
			sprintf(tmpstr,"Logoff for %s %s.\n",user.fname,user.lname);
			mon_obj.send(tmpstr);
		}
		exit(0);	// exit to OS
		inalready = 0;
	}
}

main()		// no command line inputs at this time
{
	char	tmpstr[255];	// temporary string
	char	*bbsdir;	// bbs 'home' directory 
	char	curmenu[MENU_NAME_LEN];	// current menu 
	char	prevmenu[MENU_NAME_LEN];	// previous menu (should a menu not be found) 
	char	menustack[MENU_STACK_SIZE][MENU_NAME_LEN]; 
	int	stacktop;	// current stack top 
	int	bootuser;	// kick user out?
	int	x;		// counter 
	int	done;		// done inside bbs? 
	int	newuser;	// is it a the first logon for this user? 
	int	credit;		// credited minutes for upload
	float	uldlratio;	// download/upload ratio
	files	fileobj;	// files upload/download object
	Menu	menu;
	Menuitem *result;	// result of menu run
	time_t	now;		// current time
	time_t	timeatlogoff;	// time to log user off (when in external)
	struct tm *tnow;	// current time (structure)
	User	tmpuser;	// temporary user object for sysop editing


	// get the user (or get user's information)
	stacktop = 0;	// stack empty
	bootuser = 0;
	if (newuser = user.get(NULL), newuser == -1)
	{
		menu.ap_log("Unable to get user.");
		return(0);
	}
	// turn on signal handlers so that hangup and such caught
	for (x=1; x<15; x++)
		signal(x,&getout);
	if (mon_obj.watching())
	{
		sprintf(tmpstr,"Logon for %s %s.\n",user.fname,user.lname);
		mon_obj.send(tmpstr);
	}
	// display welcome text file
	if (bbsdir = getenv("BBSDIR"), bbsdir == NULL)
	{
		printf("BBSDIR environment variable not set.\r\n");
		return(0);
	}
	strcpy(tmpstr,bbsdir);		// get bbsdir
	strcat(tmpstr,"/text/welcome");	// get 'welcome file path'
	menu.display_file(tmpstr,0);
	user.display_info(1);	// display user info with 'Welcome back' msg.
	if (!newuser)
	{
		strcpy(tmpstr,bbsdir);		// get bbsdir
		strcat(tmpstr,"/text/newuser.msg");// get newuser file path
		menu.display_file(tmpstr,1); // display newuser file 
	}		
	for (x=1; x<4; x++)	// display all system messages if applicable
	{
		if (!(user.sys_msg_once(x) && ((1<<x | SYSMSGFLAGS) & user.u_flags())))
		{	// not sys_msg_once so show him system message
			sprintf(tmpstr,"%s/text/system%d.msg",bbsdir,x);
			menu.display_file(tmpstr,1);
		}
	}
	// check for mail
	if (user.mailavail())
	{
		user.cr();
		user.sstrcr(YOUHAVEMAIL);
		user.cr();
		user.waitcr();
		// add something here for reading mail at logon
	}
	strcpy(prevmenu,"main");
	strcpy(curmenu,"main");
	if (menu.open("main") != 0)
	{
		menu.ap_log("Unable to open main menu.\r\n");
		return(0);
	}
	if (user.showfortune())
	{
		user.sysint("fortune",0,0);
		menu.waitcr();
	}
	done = 0;
	while (!done)
	{
		if (user.mailavail())// new mail?
		{
			user.clear();
			user.sstrcr(YOUHAVEMAIL);
			user.cr();
			user.waitcr();
			// add something here to read mail
		}
		if (user.u_uploads() == 0)
			uldlratio = (float)user.u_downloads()/(float)-1;
		else	
			uldlratio = (float)user.u_downloads()/(float)user.u_uploads();
		while (result = menu.run(curmenu), result == NULL); // run menu till something selected
		switch(result->com_type)
		{
		default:
		case -1:	// boot the user due to timeout or out of time
			done++;
			bootuser++;
			break;
		case 0:	// do nothing
			break;
		case 1:	// logout of bbs
			user.cr();
			user.sstr(LOGOFF);
			if (user.yesno())
				done++;
			break;
		case 2:	// branch to (another) menu
			strcpy(prevmenu,curmenu);
			strcpy(curmenu,result->misc);	// get new menu name
			if (menu.open(curmenu) != 0)
			{
				sprintf(tmpstr,"Unable to open menu %s.",result->misc);
				menu.ap_log(tmpstr);
				strcpy(curmenu,prevmenu);	// get new menu name
				if (menu.open(curmenu) != 0)
				{
					sprintf(tmpstr,"PANIC: Unable to open menu %s.",prevmenu);
					menu.er_log(tmpstr);
				}
			}
			else
			{
				strcpy(menustack[stacktop++],prevmenu);// get new menu name
			}
			break;
		case 3:	// exit to previous menu
			if (stacktop > 0)
			{
				strcpy(prevmenu,curmenu);
				strcpy(curmenu,menustack[--stacktop]);
				if (menu.open(curmenu) != 0)
				{
					sprintf(tmpstr,"Unable to open menu %s.",result->misc);
					menu.ap_log(tmpstr);
					strcpy(curmenu,prevmenu);	// get last menu
					if (menu.open(curmenu) != 0)
					{
						sprintf(tmpstr,"PANIC: Unable to open menu %s.",prevmenu);
						menu.er_log(tmpstr);
					}
				}
			}
			break;
		case 4:	// search userlog for user information
			user.list(1,0);
			break;
		case 5:	// list users in userlog
			user.list(0,0);
			break;
		case 6:	// display user information and access level
			user.display_info(0);	// display user info w/o 'Welcome back' msg.
			break;
		case 7: // modify user setup
			user.getinfo(0);
			break;
		case 8: // chat with sysop (via talk)
			user.clear();
			time(&now);
			tnow = localtime(&now);
			x = tnow->tm_hour * 100;
			x += tnow->tm_min;
			if (user.chat_avail(x))
			{
				user.sstrcr(ATTEMPTCHAT);
				user.cr();
				user.sstrcr(CTRLCTOEXIT);
				user.waitcr();
				sprintf(tmpstr,"%s %s",user.talkprog(), user.sysop());
				user.sysint(tmpstr,0,0);
			}
			else
			{
				user.sstrcr(SYSOPNOTAVAIL);
				user.sstrcr(PLEASELEAVEFEEDBACK);
				user.waitcr();
			}
			break;
		case 9:	// transfer to a new root menu (reset menu stack)
			strcpy(prevmenu,curmenu);
			strcpy(curmenu,result->misc);	// get new menu name
			if (menu.open(curmenu) != 0)
			{
				sprintf(tmpstr,"Unable to open menu %s.",result->misc);
				menu.ap_log(tmpstr);
				strcpy(curmenu,prevmenu);	// get new menu name
				if (menu.open(curmenu) != 0)
				{
					sprintf(tmpstr,"PANIC: Unable to open menu %s.",prevmenu);
					menu.er_log(tmpstr);
				}
			}
			else
			{	// successful change -- this is the new
				// 'top' menu -- nuke menu stack
				stacktop = 0;
			}
			break;
		case 10:	// display file, paged
			sprintf(tmpstr,"%s/text/%s",bbsdir,result->misc);
			menu.display_file(tmpstr,1);
			break;
		case 11:	// display file, not paged
			sprintf(tmpstr,"%s/text/%s",bbsdir,result->misc);
			menu.display_file(tmpstr,0);
			break;
		case 21:	// call shell to launch external
			menu.clear();
			time(&now);
			timeatlogoff = (user.u_timelimit() * 60) - 
				(now - user.user_logon()) + now;	
				// compute time to log user off if in external
			sprintf(tmpstr,"Executing %s\n",result->misc);
			mon_obj.send(tmpstr);
			strcpy(tmpstr,result->misc);
			if (user.sysint(tmpstr,timeatlogoff,0) == NUKEHIM)
			{
				done++;
				bootuser++;
				continue;
			}
			user.waitcr();
			break;
		case 25:	// list new files with option to download
			fileobj.waitmsg();	// print 'please wait' message
			if (!fileobj.open(result->misc,user.usercard()))
			{
				x =
				fileobj.list(1,user.usercard(),&user.kused,
					user.last_logon(),uldlratio,
					user.u_timelimit(), user.user_logon());
				if (x > 0)
					user.inc_downloads(x);			
			}
			break;
		case 26:	// list new files without option to download
			fileobj.waitmsg();	// print 'please wait' message
			if (!fileobj.open(result->misc,user.usercard()))
			{
			fileobj.list(0,user.usercard(),&user.kused,
				user.last_logon(),uldlratio,0,0);
			}
			break;
		case 27:	// list all files with option to download 
			fileobj.waitmsg();	// print 'please wait' message
			if (!fileobj.open(result->misc,user.usercard()))
			{
			x =
			fileobj.list(1,user.usercard(),&user.kused,0L,
				uldlratio,user.u_timelimit(), 
				user.user_logon());
			if (x > 0)
				user.inc_downloads(x);			
			}
			break;
		case 28:	// list all files without option to download
			fileobj.waitmsg();	// print 'please wait' message
			if (!fileobj.open(result->misc,user.usercard()))
			{
			fileobj.list(0,user.usercard(),&user.kused,0L,uldlratio,0,0);
			}
			break;
		case 29:	// search for string in files area with option
			if (!fileobj.open(result->misc,user.usercard()))
			{
			x = fileobj.search(1,user.u_timelimit(), 
				user.user_logon());
			if (x > 0)
				user.inc_downloads(x);			
			}
			break;
		case 30:	// search for string in files area w/o option
			if (!fileobj.open(result->misc,user.usercard()))
			{
			fileobj.search(0,0,0);
			}
			break;
		case 31:	// view detailed information on file
			if (!fileobj.open(result->misc,user.usercard()))
			{
			fileobj.info(NULL,NULL,NULL);
			user.waitcr();
			}
			break;
		case 32:	// download files
			if (!fileobj.open(result->misc,user.usercard()))
			{
			x = fileobj.one_download(&user.kused, uldlratio,NULL,1);
			if (x > 0)
				user.inc_downloads(x);			
			}
			break;
		case 33:	// upload files
			if (!fileobj.open(result->misc,user.usercard()))
			{
			x = fileobj.upload(user.logname(),user.editorname(), &credit);
			if (x > 0)
				user.inc_uploads(x);			
			if (credit > 0 && user.credituploads())
				user.inc_credit(x);
			}
			break;
		case 34:	// delete a file (that you uploaded)
			break;
		case 35:	// download a particular file (with ratio checking
			x = fileobj.one_download(&user.kused,uldlratio,result->misc,1);
			if (x > 0)
				user.inc_downloads(x);			
			break;
		case 36:	// download a particular file (without ratio checking
			fileobj.one_download(&user.kused,uldlratio,result->misc,0);
			break;
		// sysop specific commands follow
		case 40:	// search for users for edit/delete
			tmpuser.list(1,1);
			break;
		case 41:	// delete inactive users from the BBS
			tmpuser.inactive_delete();
			break;
		case 42:	// list inactive users
			tmpuser.inactive_list();
			break;
		case 43:	// list users for edit/delete
			tmpuser.list(0,1);
			break;
		}
	}
	// display logoff message
	menu.clear();
	strcpy(tmpstr,bbsdir);		// get bbsdir
	strcat(tmpstr,"/text/logoff");	// get logoff menu 
	if (!bootuser)
		menu.display_file(tmpstr,0);
	menu.cr();
	menu.cr();
	menu.cr();
	menu.cr();
	sprintf(tmpstr,"rocat BBS System for Unix(tm) version %s",VERSION);
	menu.sstrcr(tmpstr);
	menu.sstrcr("copyright (C) 1994 by Gregory Shaw and fmSoft, Inc.  All Rights Reserved.");
	menu.sstrcr("rocat BBS support available at The Roman Catacombs (303) 429-8914");
	user.save(NULL);
	sprintf(tmpstr,"Logoff for %s %s",user.fname,user.lname);
	user.ap_log(tmpstr);
	if (mon_obj.watching())
	{
		sprintf(tmpstr,"Logoff for %s %s.\n",user.fname,user.lname);
		mon_obj.send(tmpstr);
	}
	sleep(1);
	return(0);
};

#endif // _BBS_C_
