784 lines
14 KiB
C
784 lines
14 KiB
C
/*****************************************************************************
|
|
*
|
|
* $Id$
|
|
* Purpose ...............: Display and handle the menus.
|
|
*
|
|
*****************************************************************************
|
|
* Copyright (C) 1997-2004
|
|
*
|
|
* Michiel Broek FIDO: 2:280/2802
|
|
* Beekmansbos 10
|
|
* 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, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
|
*****************************************************************************/
|
|
|
|
#include "../config.h"
|
|
#include "../lib/mbselib.h"
|
|
#include "../lib/mbse.h"
|
|
#include "../lib/users.h"
|
|
#include "oneline.h"
|
|
#include "mail.h"
|
|
#include "bbslist.h"
|
|
#include "change.h"
|
|
#include "chat.h"
|
|
#include "file.h"
|
|
#include "funcs.h"
|
|
#include "input.h"
|
|
#include "misc.h"
|
|
#include "timeout.h"
|
|
#include "menu.h"
|
|
#include "page.h"
|
|
#include "pinfo.h"
|
|
#include "bye.h"
|
|
#include "timecheck.h"
|
|
#include "whoson.h"
|
|
#include "language.h"
|
|
#include "offline.h"
|
|
#include "email.h"
|
|
#include "door.h"
|
|
#include "dispfile.h"
|
|
#include "userlist.h"
|
|
#include "timestats.h"
|
|
#include "logentry.h"
|
|
#include "morefile.h"
|
|
#include "lastcallers.h"
|
|
#include "signature.h"
|
|
|
|
|
|
extern pid_t mypid;
|
|
|
|
|
|
/*
|
|
* Menu stack, 50 levels deep.
|
|
*/
|
|
char Menus[50][15];
|
|
int MenuLevel;
|
|
int MenuError;
|
|
|
|
|
|
void InitMenu()
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 50; i++)
|
|
memset(Menus[i], 0, 51);
|
|
MenuLevel = 0;
|
|
MenuError = 0;
|
|
sprintf(Menus[0], "%s", CFG.default_menu);
|
|
}
|
|
|
|
|
|
|
|
void menu()
|
|
{
|
|
FILE *pMenuFile;
|
|
int iFoundKey = FALSE, Key, IsANSI;
|
|
char *Input, *Semfile, *sMenuPathFileName, buf[81];
|
|
|
|
Input = calloc(PATH_MAX, sizeof(char));
|
|
sMenuPathFileName = calloc(PATH_MAX, sizeof(char));
|
|
|
|
/*
|
|
* Loop forever, this is what a BBS should do until a user logs out.
|
|
*/
|
|
while (TRUE) {
|
|
|
|
WhosDoingWhat(BROWSING, NULL);
|
|
|
|
/*
|
|
* Open menufile, first users language menu, if it fails
|
|
* try to open the default menu.
|
|
*/
|
|
sprintf(sMenuPathFileName,"%s/%s", lang.MenuPath, Menus[MenuLevel]);
|
|
if ((pMenuFile = fopen(sMenuPathFileName, "r")) == NULL) {
|
|
sprintf(sMenuPathFileName,"%s/%s", CFG.bbs_menus, Menus[MenuLevel]);
|
|
pMenuFile = fopen(sMenuPathFileName,"r");
|
|
if (pMenuFile != NULL)
|
|
Syslog('+', "Menu %s (Default)", Menus[MenuLevel]);
|
|
} else {
|
|
Syslog('+', "Menu %s (%s)", Menus[MenuLevel], lang.Name);
|
|
}
|
|
|
|
if (pMenuFile == NULL) {
|
|
clear();
|
|
WriteError("Can't open menu file: %s", sMenuPathFileName);
|
|
MenuError++;
|
|
|
|
/*
|
|
* Is this the last attempt to open the default menu?
|
|
*/
|
|
if (MenuError == 10) {
|
|
WriteError("FATAL ERROR: Too many menu errors");
|
|
printf("Too many menu errors, notifying Sysop\n\n");
|
|
sleep(3);
|
|
die(MBERR_CONFIG_ERROR);
|
|
}
|
|
|
|
/*
|
|
* Switch back to the default menu
|
|
*/
|
|
MenuLevel = 0;
|
|
strcpy(Menus[0], CFG.default_menu);
|
|
} else {
|
|
/*
|
|
* Display Menu Text Fields and Perform all autoexec menus in order of menu file.
|
|
* First check if there are any ANSI menus, if not, send a clearscreen first.
|
|
*/
|
|
IsANSI = FALSE;
|
|
while (fread(&menus, sizeof(menus), 1, pMenuFile) == 1) {
|
|
if ( Le_Access(exitinfo.Security, menus.MenuSecurity) && (UserAge >= le_int(menus.Age))){
|
|
if ((le_int(menus.MenuType) == 5) || (le_int(menus.MenuType) == 19) || (le_int(menus.MenuType) == 20))
|
|
IsANSI = TRUE;
|
|
}
|
|
}
|
|
fseek(pMenuFile, 0, SEEK_SET);
|
|
if (! IsANSI)
|
|
clear();
|
|
|
|
while (fread(&menus, sizeof(menus), 1, pMenuFile) == 1) {
|
|
if ( Le_Access(exitinfo.Security, menus.MenuSecurity) && (UserAge >= le_int(menus.Age))){
|
|
if (menus.AutoExec) {
|
|
DoMenu( le_int(menus.MenuType) );
|
|
}
|
|
DisplayMenu( );
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check if the BBS closed down for Zone Mail Hour or
|
|
* system shutdown. If so, we run the Goodbye show.
|
|
*/
|
|
if (CheckStatus() == FALSE) {
|
|
fclose(pMenuFile);
|
|
Syslog('+', "Kicking user out, the BBS is closed.");
|
|
sleep(3);
|
|
Good_Bye(MBERR_OK);
|
|
}
|
|
|
|
/*
|
|
* Check the upsdown semafore
|
|
*/
|
|
Semfile = calloc(PATH_MAX, sizeof(char));
|
|
sprintf(Semfile, "%s/sema/upsdown", getenv("MBSE_ROOT"));
|
|
if (file_exist(Semfile, R_OK) == 0) {
|
|
fclose(pMenuFile);
|
|
Syslog('+', "Kicking user out, upsdown semafore detected");
|
|
printf("System power failure, closing the bbs\n\n");
|
|
free(Semfile);
|
|
sleep(3);
|
|
Good_Bye(MBERR_OK);
|
|
}
|
|
free(Semfile);
|
|
|
|
/*
|
|
* Check if SysOp wants to chat to user everytime user gets prompt.
|
|
*/
|
|
if (CFG.iChatPromptChk) {
|
|
sprintf(buf, "CISC:1,%d", mypid);
|
|
if (socket_send(buf) == 0) {
|
|
strcpy(buf, socket_receive());
|
|
if (strcmp(buf, "100:1,1;") == 0) {
|
|
Syslog('+', "Forced sysop/user chat");
|
|
Chat(exitinfo.Name, (char *)"#sysop");
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check users timeleft
|
|
*/
|
|
TimeCheck();
|
|
alarm_on();
|
|
|
|
if (exitinfo.HotKeys) {
|
|
fflush(stdout);
|
|
Key = Getone();
|
|
sprintf(Input, "%c", Key);
|
|
printf("\n");
|
|
} else {
|
|
colour(CFG.InputColourF, CFG.InputColourB);
|
|
GetstrC(Input, 80);
|
|
}
|
|
|
|
if ((strcmp(Input, "")) != 0) {
|
|
|
|
fseek(pMenuFile, 0, SEEK_SET);
|
|
|
|
while (fread(&menus, sizeof(menus), 1, pMenuFile) == 1) {
|
|
|
|
if ((strcmp(tu(Input), menus.MenuKey)) == 0) {
|
|
if ((Le_Access(exitinfo.Security, menus.MenuSecurity)) && (UserAge >= le_int(menus.Age))) {
|
|
Syslog('b', "Menu[%d] %d=(%s), Opt: '%s'", MenuLevel, le_int(menus.MenuType),
|
|
menus.TypeDesc, menus.OptionalData);
|
|
if (le_int(menus.MenuType) == 13) {
|
|
/*
|
|
* Terminate call, cleanup here
|
|
*/
|
|
free(Input);
|
|
free(sMenuPathFileName);
|
|
fclose(pMenuFile);
|
|
}
|
|
DoMenu(le_int(menus.MenuType));
|
|
iFoundKey = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fclose(pMenuFile);
|
|
|
|
} /* If menu open */
|
|
} /* while true */
|
|
}
|
|
|
|
|
|
|
|
void DoMenu(int Type)
|
|
{
|
|
int Strlen, i, x;
|
|
char *sPrompt, *sPromptBak, *temp;
|
|
|
|
sPrompt = calloc(81, sizeof(char));
|
|
sPromptBak = calloc(81, sizeof(char));
|
|
temp = calloc(81, sizeof(char));
|
|
|
|
TimeCheck();
|
|
|
|
switch(Type) {
|
|
case 0: /* Display Prompt Line Only */
|
|
break;
|
|
|
|
case 1:
|
|
/* Goto another menu */
|
|
strncpy(Menus[MenuLevel], menus.OptionalData, 14);
|
|
break;
|
|
|
|
case 2:
|
|
/* Gosub another menu */
|
|
if (MenuLevel < 49) {
|
|
MenuLevel++;
|
|
strncpy(Menus[MenuLevel], menus.OptionalData, 14);
|
|
} else
|
|
Syslog('?', "More than 50 menu levels");
|
|
break;
|
|
|
|
case 3:
|
|
/* Return from gosub */
|
|
if (MenuLevel > 0)
|
|
MenuLevel--;
|
|
break;
|
|
|
|
case 4:
|
|
/* Return to top menu */
|
|
MenuLevel = 0;
|
|
break;
|
|
|
|
case 5:
|
|
/* Display .a?? file with controlcodes */
|
|
DisplayFile(menus.OptionalData);
|
|
break;
|
|
|
|
case 6:
|
|
/* Show menu prompt */
|
|
Strlen = strlen(menus.OptionalData);
|
|
for (x = 0; x < Strlen; x++) {
|
|
if (menus.OptionalData[x] == '~') {
|
|
strcat(sPrompt, sUserTimeleft);
|
|
} else {
|
|
sprintf(temp, "%c", menus.OptionalData[x]);
|
|
strcat(sPrompt, temp);
|
|
}
|
|
}
|
|
strcpy(sPromptBak, sPrompt);
|
|
strcpy(sPrompt, "");
|
|
Strlen = strlen(sPromptBak);
|
|
for (x = 0; x < Strlen; x++) {
|
|
if (*(sPromptBak + x) == '@')
|
|
strcat(sPrompt, sAreaDesc);
|
|
else if (*(sPromptBak + x) == '^')
|
|
strcat(sPrompt, sMsgAreaDesc);
|
|
else if (*(sPromptBak + x) == '#')
|
|
sprintf(sPrompt, "%s%s", sPrompt, (char *) GetLocalHM());
|
|
else {
|
|
sprintf(temp, "%c", *(sPromptBak + x));
|
|
strcat(sPrompt, temp);
|
|
}
|
|
}
|
|
if (le_int(menus.ForeGnd) || le_int(menus.BackGnd))
|
|
pout(le_int(menus.ForeGnd), le_int(menus.BackGnd), sPrompt);
|
|
else
|
|
pout(WHITE, BLACK, sPrompt);
|
|
break;
|
|
|
|
case 7:
|
|
/* Run external program */
|
|
if (strlen(menus.DoorName) && !menus.HideDoor) {
|
|
memset(temp, 0, sizeof(temp));
|
|
strcpy(temp, menus.DoorName);
|
|
ExtDoor(menus.OptionalData, menus.NoDoorsys, menus.Y2Kdoorsys, menus.Comport,
|
|
menus.NoSuid, menus.NoPrompt, menus.SingleUser, temp);
|
|
} else {
|
|
ExtDoor(menus.OptionalData, menus.NoDoorsys, menus.Y2Kdoorsys, menus.Comport,
|
|
menus.NoSuid, menus.NoPrompt, menus.SingleUser, NULL);
|
|
}
|
|
break;
|
|
|
|
case 8:
|
|
/* Show product information */
|
|
cr();
|
|
break;
|
|
|
|
case 9:
|
|
/* display todays callers */
|
|
LastCallers(menus.OptionalData);
|
|
break;
|
|
|
|
case 10:
|
|
/* display userlist */
|
|
UserList(menus.OptionalData);
|
|
break;
|
|
|
|
case 11:
|
|
/* display time statistics */
|
|
TimeStats();
|
|
break;
|
|
|
|
case 12:
|
|
/* page sysop for chat */
|
|
Page_Sysop(menus.OptionalData);
|
|
break;
|
|
|
|
case 13:
|
|
/* terminate call */
|
|
free(sPrompt);
|
|
free(sPromptBak);
|
|
free(temp);
|
|
Good_Bye(MBERR_OK);
|
|
break;
|
|
|
|
case 14:
|
|
/* make a log entry */
|
|
LogEntry(menus.OptionalData);
|
|
break;
|
|
|
|
case 15:
|
|
/* print text to screen */
|
|
if (exitinfo.Security.level >= le_int(menus.MenuSecurity.level)) {
|
|
for (i = 0; i < strlen(menus.OptionalData); i++)
|
|
if (*(menus.OptionalData + i) == '@')
|
|
*(menus.OptionalData + i) = '\n';
|
|
printf("%s\n", menus.OptionalData);
|
|
}
|
|
break;
|
|
|
|
case 16:
|
|
/* who's currently online */
|
|
WhosOn(menus.OptionalData);
|
|
Pause();
|
|
break;
|
|
|
|
case 17:
|
|
/* comment to sysop */
|
|
SysopComment((char *)"Comment to Sysop");
|
|
break;
|
|
|
|
case 18:
|
|
/* send on-line message */
|
|
SendOnlineMsg(menus.OptionalData);
|
|
break;
|
|
|
|
case 19:
|
|
/* display Textfile with more */
|
|
MoreFile(menus.OptionalData);
|
|
break;
|
|
|
|
case 20:
|
|
/* display a?? file with controlcode and wait for enter */
|
|
DisplayFileEnter(menus.OptionalData);
|
|
break;
|
|
|
|
case 21:
|
|
/* display menuline only */
|
|
break;
|
|
|
|
case 22:
|
|
/* Chat with any user */
|
|
Chat(NULL, NULL);
|
|
break;
|
|
|
|
case 101:
|
|
FileArea_List(menus.OptionalData);
|
|
break;
|
|
|
|
case 102:
|
|
File_List();
|
|
break;
|
|
|
|
case 103:
|
|
ViewFile(NULL);
|
|
break;
|
|
|
|
case 104:
|
|
Download();
|
|
break;
|
|
|
|
case 105:
|
|
File_RawDir(menus.OptionalData);
|
|
break;
|
|
|
|
case 106:
|
|
KeywordScan();
|
|
break;
|
|
|
|
case 107:
|
|
FilenameScan();
|
|
break;
|
|
|
|
case 108:
|
|
NewfileScan(TRUE);
|
|
break;
|
|
|
|
case 109:
|
|
Upload();
|
|
break;
|
|
|
|
case 110:
|
|
EditTaglist();
|
|
break;
|
|
|
|
case 111: /* View file in homedir */
|
|
break;
|
|
|
|
case 112:
|
|
DownloadDirect(menus.OptionalData, TRUE);
|
|
break;
|
|
|
|
case 113:
|
|
Copy_Home();
|
|
break;
|
|
|
|
case 114:
|
|
List_Home();
|
|
break;
|
|
|
|
case 115:
|
|
Delete_Home();
|
|
break;
|
|
|
|
/* 116 Unpack file in homedir */
|
|
|
|
/* 117 Pack files in homedir */
|
|
|
|
case 118:
|
|
Download_Home();
|
|
break;
|
|
|
|
case 119:
|
|
Upload_Home();
|
|
break;
|
|
|
|
case 201:
|
|
MsgArea_List(menus.OptionalData);
|
|
break;
|
|
|
|
case 202:
|
|
Post_Msg();
|
|
break;
|
|
|
|
case 203:
|
|
Read_Msgs();
|
|
break;
|
|
|
|
case 204:
|
|
CheckMail();
|
|
break;
|
|
|
|
case 205:
|
|
QuickScan_Msgs();
|
|
break;
|
|
|
|
case 206:
|
|
Delete_Msg();
|
|
break;
|
|
|
|
case 207:
|
|
MailStatus();
|
|
break;
|
|
|
|
case 208:
|
|
OLR_TagArea();
|
|
break;
|
|
|
|
case 209:
|
|
OLR_UntagArea();
|
|
break;
|
|
|
|
case 210:
|
|
OLR_ViewTags();
|
|
break;
|
|
|
|
case 211:
|
|
OLR_RestrictDate();
|
|
break;
|
|
|
|
case 212:
|
|
OLR_Upload();
|
|
break;
|
|
|
|
case 213:
|
|
OLR_DownBW();
|
|
break;
|
|
|
|
case 214:
|
|
OLR_DownQWK();
|
|
break;
|
|
|
|
case 215:
|
|
OLR_DownASCII();
|
|
break;
|
|
|
|
case 216:
|
|
Read_Email();
|
|
break;
|
|
|
|
case 217:
|
|
Write_Email();
|
|
break;
|
|
|
|
case 218:
|
|
Trash_Email();
|
|
break;
|
|
|
|
case 219:
|
|
Choose_Mailbox(menus.OptionalData);
|
|
break;
|
|
|
|
case 220:
|
|
QuickScan_Email();
|
|
break;
|
|
|
|
case 221:
|
|
DisplayRules();
|
|
break;
|
|
|
|
case 301:
|
|
Chg_Protocol();
|
|
break;
|
|
|
|
case 302:
|
|
Chg_Password();
|
|
break;
|
|
|
|
case 303:
|
|
Chg_Location();
|
|
break;
|
|
|
|
case 304:
|
|
Chg_Graphics();
|
|
break;
|
|
|
|
case 305:
|
|
Chg_VoicePhone();
|
|
break;
|
|
|
|
case 306:
|
|
Chg_DataPhone();
|
|
break;
|
|
|
|
case 307:
|
|
Chg_News();
|
|
break;
|
|
|
|
case 308:
|
|
Chg_ScreenLen();
|
|
break;
|
|
|
|
case 309:
|
|
Chg_DOB();
|
|
break;
|
|
|
|
case 310:
|
|
Chg_Language(FALSE);
|
|
break;
|
|
|
|
case 311:
|
|
Chg_Hotkeys();
|
|
break;
|
|
|
|
case 312:
|
|
Chg_Handle();
|
|
break;
|
|
|
|
case 313:
|
|
Chg_MailCheck();
|
|
break;
|
|
|
|
case 314:
|
|
Chg_Disturb();
|
|
break;
|
|
|
|
case 315:
|
|
Chg_FileCheck();
|
|
break;
|
|
|
|
case 316:
|
|
Chg_FsMsged();
|
|
break;
|
|
|
|
case 317:
|
|
Chg_FsMsgedKeys();
|
|
break;
|
|
|
|
case 318:
|
|
Chg_Address();
|
|
break;
|
|
|
|
case 319:
|
|
signature();
|
|
break;
|
|
|
|
case 320:
|
|
Chg_OLR_ExtInfo();
|
|
break;
|
|
|
|
case 401:
|
|
Oneliner_Add();
|
|
break;
|
|
|
|
case 402:
|
|
Oneliner_List();
|
|
break;
|
|
|
|
case 403:
|
|
Oneliner_Show();
|
|
break;
|
|
|
|
case 404:
|
|
Oneliner_Delete();
|
|
break;
|
|
|
|
case 405:
|
|
Oneliner_Print();
|
|
break;
|
|
|
|
case 501:
|
|
BBS_Add();
|
|
break;
|
|
|
|
case 502:
|
|
BBS_List();
|
|
break;
|
|
|
|
case 503:
|
|
BBS_Show();
|
|
break;
|
|
|
|
case 504:
|
|
BBS_Delete();
|
|
break;
|
|
|
|
case 506:
|
|
BBS_Search();
|
|
break;
|
|
|
|
default:
|
|
Enter(1);
|
|
pout(15, 0, (char *) Language(339));
|
|
Enter(2);
|
|
Syslog('?', "Option: %s -> Unknown Menu Type: %d on %s", menus.MenuKey, Type, Menus[MenuLevel]);
|
|
Pause();
|
|
}
|
|
|
|
free(sPrompt);
|
|
free(sPromptBak);
|
|
free(temp);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Display the Menu Display Text to the User,
|
|
* if the sysop puts a ';' (semicolon) at the end of the menu prompt,
|
|
* the CR/LR combination will not be sent
|
|
*/
|
|
void DisplayMenu(void)
|
|
{
|
|
int maxdpos, dpos, escaped, skipCRLF, highlight;
|
|
|
|
/* Anything to process, if not; save CPU time, return */
|
|
if (( strlen( menus.Display ) == 0 ) && (le_int(menus.MenuType) != 21)) {
|
|
return;
|
|
}
|
|
|
|
/* Send Display string, formated with ANSI codes as required */
|
|
/* --- basically this with brains: printf("%s\n", menus.Display); */
|
|
maxdpos = strlen(menus.Display);
|
|
escaped = 0;
|
|
skipCRLF = 0;
|
|
highlight = 0;
|
|
|
|
colour( le_int(menus.ForeGnd), le_int(menus.BackGnd) );
|
|
|
|
for ( dpos = 0; dpos < maxdpos ; dpos++ ){
|
|
switch ( menus.Display[ dpos ] ) {
|
|
case ';': /* Semicolon, if not escaped and last char, not CRLF at end of line */
|
|
if ( ( dpos + 1 ) == maxdpos ) {
|
|
skipCRLF=1;
|
|
} else {
|
|
printf("%c",menus.Display[ dpos ]);
|
|
}
|
|
break;
|
|
|
|
case '\\': if ( !escaped ) {
|
|
escaped = 1;
|
|
} else {
|
|
escaped = 0;
|
|
printf("%c",menus.Display[ dpos ]);
|
|
}
|
|
break;
|
|
|
|
case '^': /* Highlight Toggle */
|
|
|
|
if ( !escaped ) {
|
|
if ( highlight == 0 ) {
|
|
highlight = 1;
|
|
colour( le_int(menus.HiForeGnd), le_int(menus.HiBackGnd));
|
|
} else {
|
|
highlight = 0 ;
|
|
colour( le_int(menus.ForeGnd), le_int(menus.BackGnd) );
|
|
}
|
|
} else {
|
|
escaped=0;
|
|
printf("%c",menus.Display[ dpos ]);
|
|
}
|
|
break;
|
|
|
|
default: /* all other characters */
|
|
printf("%c",menus.Display[ dpos ]);
|
|
}
|
|
}
|
|
|
|
if ( !skipCRLF ) {
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
|
|
|