// 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;
Chat   chatobj;             // chat object interface

// 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 (sig == SIGPIPE)         // closed pipe
		return;                 // don't track
	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
	// current menu
	char   curmenu[MENU_NAME_LEN];
	// previous menu (should a menu not be found)
	char   prevmenu[MENU_NAME_LEN];
	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;                // current menu
	MenuItem *result;           // result of menu run
	time_t now;                 // current time
	struct tm *tnow;            // current time (structure

	time_t timeatlogoff;        // time to log user off (when in external)
	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
	// get 'welcome file path'
	strcat(tmpstr,"/text/welcome");
	menu.display_file(tmpstr,0);
	user.display_info(1);       // display user info with 'Welcome back' msg.
	if (!newuser)
	{
		strcpy(tmpstr,bbsdir);  // get bbsdir
		// get newuser file path
		strcat(tmpstr,"/text/newuser.msg");
		// display newuser file
		menu.display_file(tmpstr,1);
	}
	for (x=1; x<4; x++)         // display all system messages if applicable
	{
		if (!(user.sys_msg_once(x) && (((x*MSGFLAGS) & 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);
			if (user.sys_msg_once(x))
			{                   // save it so he doesn't see it again
				user.change_flags(x*MSGFLAGS,1,1);
			}
		}
	}
	// check for mail
	if (user.mailavail())
	{
		user.cr();
		user.sstrcrl("YOUHAVEMAIL");
		user.cr();
		user.waitcr();
		// add something here for reading mail at logon
	}
	strcpy(prevmenu,"main");
	strcpy(curmenu,"main");
	if (menu.build("main",1) != 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_scr();
			user.sstrcrl("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();
		// run menu till something selected
		while (result = menu.run(), result == NULL);
		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.sstrl("LOGOFF");
				if (user.yesno())
					done++;
				break;
			case 2:             // branch to (another) menu
				strcpy(prevmenu,curmenu);
				// get new menu name
				strcpy(curmenu,result->misc);
				// log menu access?
				if (menu.log_menu_accesses())
				{
					sprintf(tmpstr,"menu: %s",result->misc);
					menu.ap_log(tmpstr);
				}
				if (menu.build(curmenu,1) != 0)
				{
					sprintf(tmpstr,"Unable to open menu %s.",result->misc);
					menu.ap_log(tmpstr);
					// get new menu name
					strcpy(curmenu,prevmenu);
					if (menu.build(curmenu,1) != 0)
					{
						sprintf(tmpstr,"PANIC: Unable to open menu %s.",prevmenu);
						menu.er_log(tmpstr);
					}
				}
				else
				{
					// get new menu name
					strcpy(menustack[stacktop++],prevmenu);
				}
				break;
			case 3:             // exit to previous menu
				if (stacktop > 0)
				{
					strcpy(prevmenu,curmenu);
					strcpy(curmenu,menustack[--stacktop]);
					if (menu.build(curmenu,1) != 0)
					{
						sprintf(tmpstr,"Unable to open menu %s.",result->misc);
						menu.ap_log(tmpstr);
						// get last menu
						strcpy(curmenu,prevmenu);
						if (menu.build(curmenu,1) != 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
				// display user info w/o 'Welcome back' msg.
				user.display_info(0);
				break;
			case 7:             // modify user setup
				user.check_info();
				break;
			case 8:             // chat with sysop (via talk)
				sprintf(tmpstr,"%s wanted to chat with the sysop",user.logname());
				user.ap_log(tmpstr);
				user.clear_scr();
				time(&now);
				tnow = localtime(&now);
				x = tnow->tm_hour * 100;
				x += tnow->tm_min;
				if (user.chat_avail(x))
				{
					user.sstrcrl("ATTEMPTCHAT");
					user.cr();
					user.sstrcrl("CTRLCTOEXIT");
					user.waitcr();
					sprintf(tmpstr,"%s %s",user.talkprog(), user.sysop());
					user.sysint(tmpstr,0,0);
				}
				else
				{
					user.sstrcrl("SYSOPNOTAVAIL");
					user.sstrcrl("PLEASELEAVEFEEDBACK");
					user.waitcr();
				}

				break;
			case 9:             // transfer to a new root menu (reset menu stack)
				strcpy(prevmenu,curmenu);
				// get new menu name
				strcpy(curmenu,result->misc);
				if (menu.build(curmenu,1) != 0)
				{
					sprintf(tmpstr,"Unable to open menu %s.",result->misc);
					menu.ap_log(tmpstr);
					// get new menu name
					strcpy(curmenu,prevmenu);
					if (menu.build(curmenu,1) != 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 12:            // transfer to another menu directly
				strcpy(prevmenu,curmenu);
				// get new menu name
				strcpy(curmenu,result->misc);
				if (menu.build(curmenu,1) != 0)
				{
					sprintf(tmpstr,"Unable to open menu %s.",result->misc);
					menu.ap_log(tmpstr);
					// get new menu name
					strcpy(curmenu,prevmenu);
					if (menu.build(curmenu,1) != 0)
					{
						sprintf(tmpstr,"PANIC: Unable to open menu %s.",prevmenu);
						menu.er_log(tmpstr);
					}
				}
				// nothing goes on stack.
				break;
			case 13:            // chat with sysop (alternative method)
				sprintf(tmpstr,"%s wanted to chat with the sysop",user.logname());
				user.ap_log(tmpstr);
				time(&now);
				tnow = localtime(&now);
				x = tnow->tm_hour * 100;
				x += tnow->tm_min;
				if (user.chat_avail(x))
					chatobj.private_connect(user.sysop(),0);
				else
				{
					user.sstrcrl("SYSOPNOTAVAIL");
					user.sstrcrl("PLEASELEAVEFEEDBACK");
					user.waitcr();
				}
				break;
			case 21:            // call shell to launch external
				menu.clear_scr();
				time(&now);
				timeatlogoff = (user.u_timelimit() * 60) -
				(now - user.user_logon() + (user.prevtimeused()*60))
				+ 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
				// print 'please wait' message
				fileobj.waitmsg();
				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(),
					user.prevtimeused());
					if (x > 0)
						user.inc_downloads(x);
				}
				break;
			case 26:            // list new files without option to download
				// print 'please wait' message
				fileobj.waitmsg();
				if (!fileobj.open(result->misc,user.usercard()))
				{
					fileobj.list(0,user.usercard(),&user.kused,
					user.last_logon(),uldlratio,0,0,0);
				}
				break;
			case 27:            // list all files with option to download
				// print 'please wait' message
				fileobj.waitmsg();
				if (!fileobj.open(result->misc,user.usercard()))
				{
					x =
					fileobj.list(1,user.usercard(),&user.kused,0L,
					uldlratio,user.u_timelimit(),
					user.user_logon(),
					user.prevtimeused());
					if (x > 0)
						user.inc_downloads(x);
				}
				break;
			case 28:            // list all files without option to download
				// print 'please wait' message
				fileobj.waitmsg();
				if (!fileobj.open(result->misc,user.usercard()))
				{
					fileobj.list(0,user.usercard(),&user.kused,0L,uldlratio,0,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(),
					user.prevtimeused());
					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,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;
			case 37:            // upload a file without adding to a files section
				fileobj.one_upload(user.logname(),result->misc);
				break;
			case 38:            // upload a file without adding to a files section
					// upload to /bbs/tmp/$LOGNAME
				fileobj.one_upload(user.logname(),NULL);
				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;
			case 70:            // display chat server status
				chatobj.admin_info(0);
				break;
			case 71:            // display private chat server status
				chatobj.admin_info(1);
				break;
			case 72:            // display broadcast server status
				chatobj.admin_info(2);
				break;
			case 73:            // display info on all rooms
				chatobj.room_info();
				break;
			case 74:            // display info on one room
				if (sscanf(result->misc,"%d",&x) != 1)
				{
					menu.ap_log("Unable to determine chat room number.");
				}
				else
					chatobj.room_users(x);
				break;
			case 75:            // send a broadcast to all users
				chatobj.broadcast(0);
				break;
			case 76:            // send a broadcast to one user
				chatobj.broadcast(1);
				break;
			case 77:            // change a club password
				if (sscanf(result->misc,"%d",&x) != 1)
				{
					menu.ap_log("Unable to determine chat room number.");
				}
				else
					chatobj.change_club_password(x);
				break;
			case 78:            // connect to a club
				if (sscanf(result->misc,"%d",&x) != 1)
				{
					menu.ap_log("Unable to determine chat room number.");
				}
				else
					chatobj.club_connect(x);
				break;
			case 79:            // connect to a dynamic room
				chatobj.dynamic_connect();
				break;
			case 80:            // connect to a public room
				if (sscanf(result->misc,"%d",&x) != 1)
				{
					menu.ap_log("Unable to determine chat room number.");
				}
				else
					chatobj.room_connect(x);
				break;
			case 81:            // connect to another person privately
				chatobj.private_connect(NULL,0);
				break;
			case 82:            // create a dynamic room
				chatobj.room_create();
				break;
			case 83:            // edit your kill file
				chatobj.edit_kill();
				break;
			case 84:            // break into chat with a user (sysop initiated)
				chatobj.private_connect(NULL,1);
		}
	}
	// display logoff message
	menu.clear_scr();
	strcpy(tmpstr,bbsdir);      // get bbsdir
	// get logoff menu
	strcat(tmpstr,"/text/logoff");
	if (!bootuser)
		menu.display_file(tmpstr,0);
	menu.cr();
	menu.cr();
	menu.cr();
	menu.cr();
	sprintf(tmpstr,"\\f6rocat BBS System for Unix(tm) version \\f4%s\\n",VERSION);
	menu.sstrcr_c(tmpstr);
	menu.sstrcr_c("\\f6copyright \\f7(C)\\f6 1994-1995 by Gregory Shaw and fmSoft, Inc.  All Rights Reserved.\\n");
	menu.sstrcr_c("\\f6rocat BBS support is available at The Roman Catacombs \\f4(303) 429-8914\\n");
	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_






