/************************************************************* * Configuration program for Metal version 1.20a * and HMH.H version 1.10c * * FILE: MECONFIG.C version 1.20a * * Copyright (c) 1984 Tim Gary * Delphi Data Systems * All rights reserved. * * * This is the configuration program which enables you to * setup the message system without recompiling. * ************************************************************* * * 1.20a 11/04/84 CCS stuff deleted. * 1.10d 10/21/84 Sysop pass bug fixed. * 1.10c 10/18/84 New config format (from hmh.h)... * 1.10b 10/04/84 Cosmetic changes for new version of Metal. * 1.01a 7/15/84 Fixed minor bug in menu routine. * 1.01a 7/10/84 Fixed some bugs introduced in 1.06 changes. * 1.01a 7/02/84 Multi_User Id location added as option. * 1.01a 6/10/84 Aztec c 1.06 changes made. Added CCS Clock * stuff. Got rid of * all the USER/DRIVE stuff, since files now * include that in their name. * 1.0c 5/17/84 Hayes clock support added. * 1.0b 4/18/84 Added default user status in 'usertypes'. * 1.0b 4/14/84 (continue fixing things) * 1.0b 4/13/84 Extensive changes to internal format. Menu * changes, addition of message parm options, * and save configuration function. The save- * perm function has been made general, and * is grouped under one command. * 1.0a 2/07/84 Cosmetic and functional additions/fixes. * 1.0 1/22/84 Provide for pre-release version 3.0a changes. * First working version of this !!! * *************************************************************/ #define MAIN #include "xpm.h" /* cpmio header file */ #include "hmh.h" /* METAL bbs header file */ #include "hmconfg.h" /* config/options defines */ #include "ctype.h" #define TITLE "Metal Configuration, Version 1.20a\nCopyright 1984 Tim Gary Delphi Data Systems\n\n" #define CHAR 1 /* flag to return a 1 byte number */ #define INT 2 /* flag to return an int (2 bytes) */ #define HEX 4 /* flag to make it a hex number */ /* new menu function declarations.. */ struct menutype { char *itemdesc; /* description string */ int (*func)(); /* pointer to function */ }; int finishup(),usertypes(),privatesys(),mfiles(),maxtry(),clock(), byestuff(),zcprstuff(),location(),printer(),fiveinch(),statline(), sysopstuff(),getconf(),savem(),msgstuff(),saveconf(); struct menutype main_menu[] = { "Return to operating system (optionally save configuration file)",finishup, "Edit user types",usertypes, "Private/Public system setup",privatesys, "Files: Names and locations",mfiles, "Maximum tries user gets before being logged out",maxtry, "Real time clock setup",clock, "BYE parameters",byestuff, "Operating system setup (ZCPR)",zcprstuff, "Location of system (Sign-on message)",location, "Printer log option",printer, "Five inch drive timer reset",fiveinch, "25th status line setup",statline, "Sysop name and password",sysopstuff, "Message-base options (max messages, etc..)",msgstuff, "Save current configuration in configuration file for later use",saveconf, "Recall a previously saved configuration file",getconf, "Permanently save current configuration in METAL or MECONFIG", savem, 0,0 /* mark end of menu */ }; /********************* * Main program loop * *********************/ main() { char *menu(); int (*fn)(); send(TITLE); height=0; /* no screen pause */ getconf(); /* see if he has a config file to use, and get it if so */ while (1) { send("\n-=<(| Configuration Menu |)>=-\n"); fn=menu(main_menu); /* endless loop */ (*fn)(); } } /* main program loop */ /***********************************************************************/ /****************************************************************** * display menu, and get response. Return pointer to the function * ******************************************************************/ char *menu(menu_table) /* really returns pointer to function, but how the hell do you declare that? */ struct menutype *menu_table; { struct menutype *mp; register int i; char n; n=255; /* so that RETURN will look like invalid entry */ /* for (items=0,mp=menu_table; mp->itemdesc; ++items,++mp); */ /* get items count */ do { for (i=0,mp=menu_table; mp->itemdesc; i++,++mp) { sprintf(buffer,"\n%2d. %s.",i+1,mp->itemdesc); if (send(buffer)==ERROR) break; /* so you can cheat if you know the item number already */ } asknum("\n\nSelect",&n,0,CHAR); } while (n>i /* tems */ || n==0); for (mp=menu_table; n-1; --n,++mp); return mp->func; } /********************************************* * Get file/drive/user seting the user and * * drive up for an open, and returning a * * string pointer to the filename. * *********************************************/ char *getfile(str) /* prints prompt string 'str' */ char *str; { static char fname[18]; /* static so value don't go away on return! */ ask(str,fname,17,UP); /* ask for file name */ if (*fname=='\0') return NULL; /* signal nothing entered */ return fname; } /******************************** * get config file from disk if * * he has one to get.. else all * * defaults are used ... * ********************************/ getconf() { FILE *config; /* config file */ char *addr; /* address pointer to variable block */ char *fn; /* file name */ while (1) { if ((fn=getfile("Configuration file name? "))==NULL) break; if ((*fn=='?') || (!ustrcmp("help",fn))) /* help wanted */ { send("If you have a configuration file saved from running this program\n"); send("previously, you may retrieve it here.\n"); } config=open(fn,F_RD | F_UNLOCK); /* open for read */ if (config==NULL) { /* error, file not found */ send("Can't find that file.\n"); continue; /* ask again */ } uread(config,O.zippo,O.zappo-O.zippo); /* unix style read.. */ send("Configuration file loaded.\n"); close(config); break; /* and exit */ } /* endless while loop */ } /* get config */ /************************************* * Finish up by saving config. file * * and possibly making changes to the* * metal and menter files themselves * *************************************/ finishup() { while (1) { ask("\nSave current configuration in seperate configuration file? ",buffer,2,UP); if ( (*buffer=='\0') || (*buffer=='?') || !ustrcmp("help",buffer)) { send("\nYou may save the current configuration in a file that may be read\n at a later time with MECONFIG. This saves reconfiguring several\n options over again.\n"); continue; } if (*buffer!='Y') break; /* nope, so forget it */ else { saveconf(); /* save configuration file */ break; } } send("\nEntering CP/M."); exit(); } /************************************** * save current configuration in file * * that getconf() can read later on.. * **************************************/ saveconf() { register FILE *mfile; /* metal/menter file descriptor */ register char *addr; /* address used to write config */ char *fn; while (1) { /* seemingly endless loop */ if ((fn=getfile("File name to save configuration under? "))==0) break; mfile=open(fn,F_RW | F_LOCK); /* open for write */ if (mfile==NULL) { /* couldn't open file */ send("Unable to open file, invalid drive, disk full, or write protected. Try again.\n\n"); continue; /* ask filename again */ } send("Saving.\n"); for (addr=O.zippo; addr<=O.zappo+128; addr+=128) { movmem(addr,bufloc(mfile),128); write(mfile,1); /* write/increment pos */ } close(mfile); break; } /* endless while */ } /********************************************* * Save config in metal or menter, or most * * any other file by that matter............ * *********************************************/ savem() { FILE *fil; char *addr,*addr2; char *fn; do { if ((fn=getfile("Save configuration permanently in which METAL Message system file? "))==NULL) break; if (*fn=='?' || !ustrcmp("help",fn)) { /* help person out */ send("\nTo make the options you have changed permanent (operational),\n\ you must save the configuration in the appropriate COM files.\n"); send("METAL.COM and MECONFIG.COM or any\n\ other compiled Aztec C program which includes HMH.H (source vers.)\nare valid files.\n"); continue; } if (!index(fn,'.')) strcat(fn,".COM"); fil=open(fn,F_RW | F_LOCK); /* open for r/w */ send("[Searching...]\n"); toeof(fil); /* go to end of file */ if (getrec(fil)==0 || fil==NULL) { send("\n<>\n"); close(fil); unlink(fn); /* cleanup open's mess */ return; } setrrec(fil,-1); read(fil,0); movmem(bufloc(fil),buffer,128); do { setrrec(fil,-1); movmem(buffer,buffer+128,128); read(fil,0); movmem(bufloc(fil),buffer,128); printf("Record %d\r",getrec(fil)); for (addr=buffer; addr0); if (getrec(fil)<=0) { send("\nNothing found to replace..\n"); break; } send("\nFound option area, saving."); /* we have the address in the buffer of zilch */ if (addr>=buffer+128) { addr2=(buffer+256)-addr; movmem(O.zippo,bufloc(fil)+(addr-(buffer+128)),addr2); setrrec(fil,-1); } else { addr2=(buffer+128)-addr; movmem(O.zippo,bufloc(fil)+(addr-buffer),addr2); } write(fil,1); /* write portion of record+incr. */ putchar('.'); for (addr=O.zippo+(int)addr2; addr+128\n"); } while (0); /* one-shot loop */ } /* savem */ /******************************** * Get number (as a char) 0-255 * ********************************/ asknum(str,nptr,max,flag) register char *str,flag; int *nptr; register int max; { char ts[10]; char *cptr; int tint; /* temp int */ cptr=nptr; /* make a char pointer to the same thing as int */ sprintf(buffer,"%s? ",str); do { ask(buffer,ts,10,UP); if ( !(flag&HEX) ) { if (isdigit(*ts)) { if (max!=0) if (atoi(ts)>max) { printf("Maximum value is %d.\n",max); continue; } return (flag&INT ? (*nptr=atoi(ts)) : (*cptr=atoi(ts))); } } else /* wants a hex char */ { if (*ts=='\0') break; sscanf(ts,"%x",&tint); if (max!=0) if (tint>max) { printf("Maximum value is %xH.\n",max); continue; } return (flag&INT ? (*nptr=tint) : (*cptr=tint)); } } while (*ts!='\0'); return (*nptr); } /********************* * Get string, etc.. * *********************/ askstr(outstr,str,max) register char *outstr; char *str,max; { char ts[MAXLINE+1]; sprintf(ts,"%s? ",outstr); ask(ts,ts,max,UPLOW); if (*ts!='\0') strcpy(str,ts); } /*********************** * Get yes/no question * ***********************/ askyesno(outstr,yn) register char *outstr; char *yn; { char ts[2]; sprintf(buffer,"%s (YES/NO)? ",outstr); do { ask(buffer,ts,1,UP); if (*ts=='\0') break; if (*ts=='Y') { *yn=YES; break; } if (*ts=='N') { *yn=NO; break; } } while (1); /* crumby way to do this */ } /***************************** * Edit avaliable user types * *****************************/ usertypes() { u_types *uptr; /* pointer to user structure */ send("Alter User types and parameters.\n\n"); printf("Default user status='%c'\n\n",O.DSTATUS); ask("New default status character (see doc) ? ",buffer,1,UPLOW); if ( (*buffer!='\0') && (index("+snxXabc",*buffer)) ) O.DSTATUS=*buffer; for (uptr=O.user_types; uptr->type; uptr++) { printf("\nUser Char\t Maxuser\t Timeout\t Kill Msgs?\n '%c'\t\t %d\ \t\t %d mins. \t %s\n\nMaster CPM privs?\t Read priv. msgs?\t Post Messages?\n\ %s \t\t %s \t\t %s\n\n", uptr->type,uptr->maxuser,uptr->timeout, uptr->killflag==YES ? "YES" : "NO", uptr->zcprflag==YES ? "YES" : "NO", uptr->readpriv==YES ? "YES" : "NO", uptr->postmsg==YES ? "YES" : "NO"); ask("Alter this user? ",buffer,2,UP); if (*buffer=='Y') { asknum("Max CP/M user number (0-15)",&uptr->maxuser,15,CHAR); asknum("Timeout (minutes)",&uptr->timeout,0,CHAR); askyesno("Can this user kill msgs",&uptr->killflag); askyesno("Does the user have MASTER CP/M Privs", &uptr->zcprflag); askyesno("Can the user read private msgs",&uptr->readpriv); askyesno("Can the user post messages",&uptr->postmsg); } } /* for */ } /* user types */ /************************ * Private system stuff * ************************/ privatesys() { send("Make system PRIVATE/PUBLIC.\n\n"); printf("System is now %s. Password is %s (applies only if PRIVATE system).\n", O.PRIVATE ? "PRIVATE" : "PUBLIC",O.PRIVPASS); askyesno("Make system Private",&O.PRIVATE); if (O.PRIVATE) askstr("System Password",O.PRIVPASS,PASSLEN); upcase(O.PRIVPASS); } /********************************* * Alter file names/drives/users * *********************************/ mfiles() { register int ind; send("Alter filenames of BBS files.\n\n"); for (ind=0; O.files[ind][0]!='\0'; ind++) { sprintf(buffer,"\nFile %s :: new name ( if no change) ", O.files[ind]); askstr(buffer,O.files[ind],17); } } /*********************************** * Get max # of tries till hang-up * ***********************************/ maxtry() { printf("Maximum tries before logout=%d.\n",O.MAXTRIES); asknum("New value (0-255)",&O.MAXTRIES,255,CHAR); } /********************** * Change clock setup * **********************/ clock() { send("Change clock setup.\n\n"); printf("Currently #%d selected.\n",O.RTC); send("0) NO Clock (or incompatible one)\n1) CompuPro SS1 Clock\n2) Hayes Chronograph\n"); /* 3) CCS Clock board\n"); */ send("Note: a port address>255 will enable memory mapped I/O\n"); asknum("\nNew setup",&O.RTC,3,CHAR); if (O.RTC!=NOCLOCK) { printf("%xH is the clock comand/status port, %xH is data.\n",O.CLKCMD,O.CLKDATA); if (O.RTC!=COMPUPRO /* && O.RTC!=CCS */ ) printf("%xH is the output status mask, %xH is the input status mask\n",(unsigned)O.CLKOMASK,(unsigned)O.CLKIMASK); asknum("New command port (IN HEX!)",&O.CLKCMD,0,HEX|INT); asknum("New Data port (IN HEX!)",&O.CLKDATA,0,HEX|INT); if (O.RTC!=COMPUPRO /* && O.RTC!=CCS */ ) { asknum("New output status mask (IN HEX!)",&O.CLKOMASK,0,HEX|CHAR); asknum("New input status mask (IN HEX!)",&O.CLKIMASK,0,HEX|CHAR); } } } /************************************** * BYE stuff... if ask for CaSe/NULLS * **************************************/ byestuff() { send("Setup for BYE.\n\n"); printf("Current setting:\n\tBYE %s ask for NULLS.\n", O.ASKNULLS ? "DOES" : "DOES NOT" ); askyesno("Is BYE set to ask for NULLS when you login",&O.ASKNULLS); } /********************************* * ZCPR setup, WHEEL LOC/No ZCPR * *********************************/ zcprstuff() { send("Operating System setup.\n\n"); #ifndef MULTI_USER printf("Currently setup%s to use ZCPR.\n",O.ZCPR ? "" : " NOT"); askyesno("Is ZCPR to be used",&O.ZCPR); if (O.ZCPR) { printf("Wheel byte currently at %xH\n",O.SECURELOC); asknum("New location (IN HEX!)",&O.SECURELOC,0,HEX|INT); } #else #ifndef MPM printf("Location of 4 char id string currently at %xH\n",O.id_loc); asknum("New location (IN HEX!)",&O.id_loc); #endif #endif } /************************************ * Location change.. up to 80 chars * ************************************/ location() { send("Change Metal site location (sign-on msg).\n\nCurrently is: "); send(O.WHERE); send("\n"); askstr("Enter new location/phone (up to 80 chars)",O.WHERE,80); } /***************** * Printer log ? * *****************/ printer() { send("Change printer log option.\n\n"); printf("Printer log is %s.\n",O.PRTLOG ? "ON" : "OFF"); askyesno("Log callers/comments to printer",&O.PRTLOG); } /************************ * Fiveinch drive thing * ************************/ fiveinch() { send("Set peek location for slow 5 inch drives.\n\n"); printf("Current location is %xH\n",O.RESETDRIVE); asknum("New location (IN HEX!)? ",&O.RESETDRIVE,0,HEX|INT); } /************************** * 25th status line stuff * **************************/ statline() { register int n; /* temp loop variable */ char tbuf[MAXLINE]; send("Setup for 25th status line.\n\n"); printf("Currently 25th line %s setup.",O.STATUSLINE ? "IS" : "IS NOT"); if (O.STATUSLINE) { printf("\nOutput STATUS port=%xH\nOutput DATA port=%xH\nOutput status mask=%xH\n",O.OSTAT,O.ODATA,O.OSMASK); printf("Hex values to move cursor to 25th line:\n"); for (n=0; O.TO25[n] && n<15; ++n) printf("%2xH ",O.TO25[n]); printf("\nHex values to return cursor to where it was before it got to the 25th line:\n"); for (n=0; O.FROM25[n] && n<15; ++n) printf("%2xH ",O.FROM25[n]); } askyesno("\n\nDo you have a 25th status line on your terminal",&O.STATUSLINE); if (O.STATUSLINE) /* only do this if he has one, else it doesn't apply */ { send("\nNote: If you have a non-I/O mapped screen with 25th line capability\n\ you may enter the address of your BIOS output routine in place of the\n"); send("Output Data port below. Make sure the Status port, and Status mask are set\nto Zero in this case!\n\n"); asknum("Output Status port (IN HEX!)",&O.OSTAT,0,HEX|INT); asknum("Output Data port (IN HEX!)",&O.ODATA,0,HEX|INT); asknum("Output status ready mask (IN HEX!)",&O.OSMASK,255,HEX|CHAR); send("String to get TO 25th line. (Up to 15 chars. 0 for end of string).\n"); for (n=0; n<15; n++) { sprintf(tbuf,"Hex Byte %2d (was %2xH): New value (IN HEX!)", n+1,O.TO25[n]); asknum(tbuf,&O.TO25[n],255,HEX|CHAR); if (!O.TO25[n]) break; /* done */ } O.TO25[15]='\0'; /* make sure it's terminated */ send("String to get FROM 25th line. (Up to 15 chars. 0 for end of string).\n"); for (n=0; n<15; n++) { sprintf(tbuf,"Hex Byte %2d (was %2xH): New value (IN HEX!)", n+1,O.FROM25[n]); asknum(tbuf,&O.FROM25[n],255,HEX|CHAR); if (!O.FROM25[n]) break; /* done */ } O.FROM25[15]='\0'; /* make sure it's terminated */ } /* block for status line check */ } /* statusline */ /******************************************************************* * Message-base options.. MAXMSGS, MAXTOTMSGS, MLINES, MAXMSGLINE * *******************************************************************/ msgstuff() { send("Message-base options.\n\n"); printf("Currently:\n\tMaximum active messages allowed is %d\n\tMaximum TOTAL messages allowed (killed+active) is %d\n\tMaximum lines per message is %d\n\tMaximum message line length is %d\n\n",O.MAXMSGS,O.MAXTOTMSGS,O.MLINES,O.MAXMSGLINE); while (1) { asknum("Maximum active messages allowed",&O.MAXMSGS,2000,INT); asknum("Maxumum TOTAL active and killed msgs allowed",&O.MAXTOTMSGS,3000,INT); if (O.MAXMSGS>O.MAXTOTMSGS) { send("\nMaximum TOTAL messages MUST BE >= Maximum active msgs!!!\n"); continue; } else break; } asknum("Maxumum lines per message",&O.MLINES,MAXMLINES,INT); asknum("Maximum characters per message line",&O.MAXMSGLINE,MAXLINE,CHAR); } /********************* * Sysop name, etc.. * *********************/ sysopstuff() { send("Change sysop name/password.\n\n"); printf("Sysop's name is %s %s, and password is %s\n\n", O.SOFIRST,O.SOLAST,O.SOPASS); sepstr=' '; askstr("New Sysop name",O.SOFIRST,FNAMELEN); sepstr='\0'; capstr(O.SOFIRST); askstr("New Last name",O.SOLAST,LNAMELEN); capstr(O.SOLAST); askstr("New Password",O.SOPASS,PASSLEN); upcase(O.SOPASS); } /* EOF MECONFIG.C */