// Filename: menu.C // Contents: the methods for the menu object // Author: Greg Shaw // Created: 7/22/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 _MENU_C_ #define _MENU_C_ #include "bbshdr.h" // Function: can_view // Purpose: return true if the user has access based on the information // passed in // Input: acl - the access level of the user // flags - the flags of the user // am - the access level modifier for the user's acccess level // fm - the flags modifier // Output: true if user has access // Author: Greg Shaw // Created: 7/27/93 int Menu::can_view(int acl, int flags, char am, char fm) { int uacl; // user's acl int uflags; // user's flags uacl = user.u_acl(); uflags = user.u_flags(); if (!((uacl >= acl && am == '>' ) || (uacl < acl && am == '<') || (acl == uacl && am == '='))) return(0); // no access if (flags != 0) { if ((flags & uflags) && fm == '=') return(1); if (!(flags & uflags) && fm == '!') return(1); return(0); } return(1); // access }; // Function: get_chat_msg // Purpose: get a chat message from the chat object (if connected) // Input: none // Output: chat message is read into internal space // Author: Greg Shaw // Created: 7/22/93 int Menu::get_chat_msg(void) { int x; if (x = msg_avail(0), x <0) // message avail? connected = 0; else if (x > 0 && receive(chat_msg) == -1) connected = 0; return(0); }; // Function: constructor // Purpose: initialize values to sane states // Input: none // Output: (internal object changes) // Author: Greg Shaw // Created: 7/22/93 Menu::Menu() { prompt = userprompt(); menu_path[0] = 0; // erase menu path numitems = 0; // no items yet connected = 0; // not connected socknum = 0; // no socket yet last_try = 0L; // haven't tried yet chat_msg[0] = 0;// no chat message yet }; // Function: open // Purpose: read the commands for the menu from the menu file // Input: path - the path to the menu file // Output: the menu is read into the object or a non-zero result is returned // Author: Greg Shaw // Created: 7/22/93 int Menu::open(char *path) { FILE *infile; // input file char tmpstr[255]; // temporary string char state; // state of input char num; // offset into word char comnum; // command number in array char c; // input char // open_chat(); // attempt to connect to chat server if (strcpy(tmpstr,getenv("BBSDIR")), tmpstr == NULL) { sprintf(tmpstr,"BBSDIR env var not set for %s",username()); ap_log(tmpstr); return(-1); } strcat(tmpstr,"/menus/"); // add slash strcat(tmpstr,path); // add path if (infile = bopen(tmpstr,"r"), infile == NULL) { sprintf(tmpstr,"Unable to open menu file %s",path); ap_log(tmpstr); return(-1); } comnum = 0; // start at 0 while (!feof(infile)) { state = 0; num = 0; c = 0; while (c != '\r' && c != '\n' && !feof(infile)) { c = fgetc(infile); if (c != '|' && c != '\r' && c != '\n') tmpstr[num++] = c; // add char else { tmpstr[num] = 0; // add null state++; switch(state) { case 1: // command number if (sscanf(tmpstr,"%d",&items[comnum].com_type) != 1 ) continue; // we've hit end of menu file break; case 2: // hot key if (num != 0) { items[comnum].key = tmpstr[0]; } else items[comnum].key = 0; break; case 3: // access level if (num != 0) // empty? { if (sscanf(tmpstr,"%d",&items[comnum].acl) != 1) { sprintf(tmpstr,"menu.acl: %s has an error.",path); ap_log(tmpstr); bclose(infile); return(-1); } } else items[comnum].acl = 0; break; case 4: // access level modifier if (num != 0) // modifier not null? { if (tmpstr[0] != '>' && tmpstr[0] != '=' & tmpstr[0] != '<') { sprintf(tmpstr,"menu.aclmo: %s has an error.",path); ap_log(tmpstr); bclose(infile); return(-1); } else items[comnum].acl_mod = tmpstr[0]; } else items[comnum].acl_mod = '>'; // default to break; case 5: // flags if (num != 0) // flags not null? { if (sscanf(tmpstr,"%d",&items[comnum].flags) != 1) { sprintf(tmpstr,"menu.flags: %s has an error.",path); ap_log(tmpstr); bclose(infile); return(-1); } } else items[comnum].flags = 0; // no flags is default break; case 6: // flags mod if (num != 0) // modifier not null? { if (tmpstr[0] != '=' && tmpstr[0] != '!') { sprintf(tmpstr,"menu.flagsmod: %s has an error.",path); ap_log(tmpstr); bclose(infile); return(-1); } else items[comnum].flags_mod = tmpstr[0]; } else items[comnum].flags_mod = '='; // default to = break; case 7: // misc text strcpy(items[comnum].misc,tmpstr); break; case 8: // command text - skip to end of line if (items[comnum].com_type != 0) // don't care about text out commands comnum++; if (comnum > 49) // at the end? { ap_log("menu: menu has too many items (> 50)"); bclose(infile); return(-1); } while (c != '\r' && c != '\n' && !feof(infile)) c = fgetc(infile); break; default: // error sprintf(tmpstr,"Invalid switch %d in menu open.",state); ap_log(tmpstr); } num = 0; // start at next word } } } numitems = comnum; bclose(infile); return(0); }; // Function: open_chat // Purpose: attempt to open a connection to the chat process // Inputs: none // Outputs: connected changes state if connection successful // Author: Greg Shaw // Created: 7/23/93 int Menu::open_chat(void) { time_t now; // current time char hname[30]; // this host's name (where chat runs) // attempt to connect to chat object if (!connected) { if (time(&now), now - last_try > 10) // more than 10 secs? { if (gethostname(hname,29), hname == NULL) { ap_log("menu.open: Unable to get current host name"); } else { if (two_connect(hname,CHAT_MASTER_PORT) == 0) { // got new socket connected = 1; } } } } return(0); }; // Function: run // Purpose: run the menu // Input: (from user) // Output: the command that has been selected by the user is returned // Author: Greg Shaw // Created: 7/25/93 Menuitem *Menu::run(char *path) { char c,d; // dumb char char line[255]; // line char valkeys[150]; // valid keys in menu char timeleft[50]; // amount of time left to user char offset; // offset into string char numbracks; // number of |'s found char boogie; // get out of function -- guy has selected char tmpstr[255]; // stupid string FILE *infile; // menu file int x; // counter int charsfound; // number of chars found after command info int acl; // acl int flags; // flags int inactivity; // how long to wait before inactivity logoff char am; // acl mod char fm; // flags mod long tl; // timeleft time_t now; // current time time_t rightnow; // current time clear(); // clear screen if possible // if (connected) // connect to chat obj // get_chat_msg(); // get chat message (if available) // if (strlen(chat_msg) != 0) // message not null // sstrcr(chat_msg); // send message if (strcpy(tmpstr,getenv("BBSDIR")), tmpstr == NULL) { sprintf(tmpstr,"BBSDIR env var not set for %s",username()); ap_log(tmpstr); return(NULL); } strcat(tmpstr,"/menus/"); // add slash strcat(tmpstr,path); // add path if (infile = bopen(tmpstr,"r"), infile == NULL) { sprintf(tmpstr,"Unable to open menu file %s",path); ap_log(tmpstr); } boogie = 0; while (!feof(infile) && !boogie) { numbracks = 0; offset = 0; // offset into line while (numbracks < 7 && !feof(infile)) // nuke all of the command info { c = fgetc(infile); if (c != '|' && c != '\r' && c != '\n') { line[offset++] = c; } else // got info. process { line[offset] = 0; if (c == '|') { numbracks++; switch(numbracks) { case 1: // command number continue; break; case 2: // hot key case 7: // misc text break; case 3: // access level if (offset != 0) // empty? { sscanf(line,"%d",&acl); } else acl = 0; break; case 4: // access level modifier if (offset != 0) // modifier not null? { am = line[0]; } else am = '>'; // default to > break; case 5: // flags if (offset != 0) // flags not null? { sscanf(line,"%d",&flags); } else flags = 0; // no flags is default break; case 6: // flags mod if (offset != 0) // modifier not null? { fm = line[0]; } else fm = '='; // default to = break; default: // error ap_log("Invalid switch in menu run."); } } offset = 0; } } // ok, that's gone. Now the meat is left. if (!can_view(acl, flags, am, fm)) // no access, skip. { while (c = fgetc(infile), c != '\r' && c != '\n' && !feof(infile)); acl = 32767; // avoid lockup if stray \r or \n at end of file continue; } charsfound = 0; offset=0; while (d = fgetc(infile), d != '\r' && d != '\n' && !feof(infile)) { if (offset % 50 == 0 && offset > 0) { tmpstr[offset] = 0; sstr(tmpstr); offset = 0; tmpstr[offset++] = d; } else tmpstr[offset++] = d; charsfound++; } if (charsfound > 0) { tmpstr[offset] = 0; sstr(tmpstr); cr(); } if (c = valid_char(), c != -1) // check for char and return true { bclose(infile); if (c == 100) // 100 means he hit return only (for screen refresh) return(NULL); else return(&items[c]);// if hot key for menu item } } bclose(infile); // ok, he didn't hit anything. Give him a prompt. if (showcoms()) // show command keys? { // build string with valid keys offset = 0; valkeys[offset++] = '['; for (x=0; x inactivity) { sstrcr(INACTIVITYTIMEOUT); items[0].com_type = -1; // boot the user ap_log(INACTIVITYTIMEOUT); return(&items[0]); } } cr(); if (c == 100) // 100 means he hit return only (for screen refresh) return(NULL); else return(&items[c]); // if hot key for menu item }; // Function: valid_char // Purpose: look for a character from the user. If available, check // char against list, return array index into list if found. // Input: none // Output: the array index of the matching command record // Author: Greg Shaw int Menu::valid_char(void) { char c; char x; c = 0; if (char_avail(0,0) || char_avail(1,1)) c = gch(0); if (c > 0) // error or zero for no char { for (x=0; x < numitems; x++) { if ( c == items[x].key && can_view(items[x].acl, items[x].flags, items[x].acl_mod, items[x].flags_mod)) return(x); else if (c == '\r' || c == '\n') return(100); } } return(-1); }; #endif // _MENU_C_