/************************************************************************ * This file contains infrequently used (or used once) routines for the * overlay version of The Metal Message System. * * Name: MEINFREQ.C * Version 1.20a * * Copyright (c) 1984 Tim Gary * Delphi Data Systems * All rights reserved. * ************************************************************************ * * 1.20a 11/11/84 Ok, final cosmetic touches and release for this * series of changes. * 1.20 11/09/84 Version message changed for new mes.c file. * 1.20 11/07/84 Lastread fixed. * 1.20 11/04/84 Version change, and additions to lastcalr file info. * 1.10e 11/03/84 Added more info to the '#' command. * 1.10e 11/02/84 Msg number=parent thing deleted. New put/get counters. * 1.10e 11/01/84 Untypo'd a typo. * 1.10e 10/31/84 Added stuff for private message counts/width stuff. * 1.10d 10/21/84 First time system setup bug (from 1.10a/b/c) fixed. * 1.10c 10/12/84 Routines added to verify parent/replys to msgs. * if not found in the table, then zero'd. * 1.10b 10/04/84 Message table build from message file corrected. * 1.10b 10/03/84 Version change, touch-ups, height properly initialized. * 1.10a 09/27/84 Cosmetic fixes (U command). * 1.10a 09/09/84 Cosmetic fixes. * 1.10a 08/31/84 Created. * ************************************************************************/ #include "xpm.h" #include "hmh.h" #include "hmconfg.h" #include "ctype.h" #define TITLE "\nMetal Message System..(A Heavy BBS)\nVersion 1.20a\n" /********************************************************** * Overlay main program, dispatches to contained routines. **********************************************************/ ovmain(routine,parm) int routine,parm; { switch(routine) { case INIT: return init(parm); case MSGALERT: return msg_alert(parm); case READUSERS: return readusers(parm); case SAVEUSER: return saveuser(parm); case CALLS: return calls(parm); case STATS: return stats(parm); default: send("\nUnknown routine called for.\n"); break; } } /* ovmain */ /*************************** * INITIALIZE EVERYTHING * ***************************/ /* flag is argc and is used to tell if menter was run or not for getlastcalr */ init(flag) register int flag; { if (O.ZCPR) *O.SECURELOC=0; /* turn of all cp/m hazzards */ msg=malloc(O.MAXTOTMSGS*8+1); /* alloc message array */ if (msg==0) { send("\nFatal ERROR: Unable to allocate message table space."); exit(); } #ifdef MULTI_USER #ifdef MPM if (strncmp(id_loc,ID_STR,3)) { send("\n[Please wait]\n"); /* ovloader(OVMENTER,(char *)0,0); won't work here..*//* not setup with lastcalr.. */ } #endif #endif send(TITLE); /* display banner identifing the system */ /* done only if menter not used */ if (flag<=1) { gcntrs(0); getlastcaller(); /* get lastcalr file saved in menter.c */ } height=user.parm.height; /* reset height */ if (O.RTC!=NOCLOCK) getdate(); /* get time and date from clock board */ /* * Find out if BYE is active and setup BYE parms.. */ findbye(); /* Get bye, maxuser,tout, etc.. variables */ *maxuser=15; /* initialy so BYE lets us get to bbs files */ /* setup timeout values for different people (different stats) */ *tout=O.user_types[user.type].timeout; *nulls=user.parm.nulls-'0'; /* setup users nulls */ stats(0); /* display user number/message stats */ *(char *)O.RESETDRIVE; flag=msg_alert(0); /* check for msgs/build index */ putchar('\n'); return flag; } /* init */ /************************ * Get user from lastcalr file, file was created with menter ************************/ getlastcaller() { unsigned trec,tlast; char td[DATELEN+1],tt[TIMELEN+1]; if ((lastcalr=open(LASTCALR,F_RD | F_UNLOCK))==NULL) /* open for read only */ { send("\nSerious ERROR: No LASTCALLER FILE!"); exit(); /* exit to cpm in case it's sysop and can be fixed.. */ } #ifdef MULTI_USER #ifdef MPM trec=bdos(153,0)%16; /* get mp/m user console id */ #else trec=id_num; #endif /* MP/M */ setarec(lastcalr,trec); /* seek to console position to get caller */ #endif /* Multi_User */ read(lastcalr,0); sscanf(bufloc(lastcalr),"%*[^\032] %*1s %d %d %s %s", &trec,&tlast,td,tt); close(lastcalr); users=open(USERFILE,F_RD | F_UNLOCK); /* open for read */ setarec(users,trec); /* seek to user */ read(users,0); /* get the record */ movmem(bufloc(users),&user,128); /* copy the record into our variable */ close(users); user.lastread=tlast; /* get lastread back */ height=user.parm.height; /* get height setup */ strcpy(user.time,tt); strcpy(user.date,td); } /************************************************ * All new and improved msg summary builder... * * Will use messages file alone and skip bad * * sectors that it finds... * ************************************************/ msg_alert(n) { msg_record *mptr; /* for easy access to values in the field */ register int flag; int fileflag; /* summary or message index build */ int lines; /* line count of message */ flag=msgcount=totalmsgs=privmsgs=mindex=fmsg=lmsg=0; fileflag=TRUE; if (!n) send("\n[Checking for Mail]\n"); if ((summary=open(SUMMARY,F_RD | F_UNLOCK))!=NULL) { /* summary file opened.. */ toeof(summary); if (getrec(summary)<=1) close(summary); else { setarec(summary,1); fileflag=FALSE; } } else { /* create summary to keep things happy */ summary=open(SUMMARY,F_RW); sprintf(bufloc(summary),"0 \n"); write(summary,1); close(summary); } if (fileflag) /* summary file not opened correctly, try messages */ summary=open(MESSAGES,F_RD | F_UNLOCK); #ifdef DEBUG printf("\nBuilding message index from %s file.\n",fileflag ? "message" : "summary"); #endif mptr=bufloc(summary); /* setup buffer pointer */ while (summary && read(summary,1)==128) { msg[mindex].number=mptr->number; msg[mindex].seek=mptr->seek; msg[mindex].parent=mptr->parent; msg[mindex].reply=mptr->reply; if (mptr->status==DEADMSG) msg[mindex].parent=msg[mindex].reply=0; #ifdef DEBUG printf("\nnum %u seek %u parent %u reply %u",mptr->number,mptr->seek, mptr->parent,mptr->reply); #endif if (mptr->lines && fileflag) { /* message file skip text */ if ( (mptr->status!=PRIVMSG && mptr->status!=NORMMSG && mptr->status!=DEADMSG) || mptr->seek!=(getrec(summary)-1) ) { /* not valid record, skip till one found.. */ send("\n[Bad records found, skipping..]\n"); #ifdef DEBUG printf("\nFile seek=%u, Message stat='%c' %x hex.",getrec(summary)-1,mptr->status,mptr->status); #endif do lines=read(summary,1); while (lines==128 && (mptr->status!=NORMMSG && mptr->status!=PRIVMSG && mptr->status!=DEADMSG) || mptr->lines>O.MLINES || mptr->seek!=(getrec(summary)-1) ); setrrec(summary,-1); if (lines==128) continue; /* don't increment mindex, etc.. */ else break; } } if ( /* mptr->status!=DEADMSG && */ mptr->number) { lmsg=mptr->number; if (!fmsg) fmsg=lmsg; } if (mptr->status==PRIVMSG) privmsgs++; /* count # of private msgs */ if (!n && mptr->status!=DEADMSG && thisis(mptr->receiver)) { /* if message active and addressed to them */ if (!flag) { send("\n[You have Mail!]\n\nNumber: From:\n"); ++flag; } printf("%5u %s %s%s%s\n", mptr->number, mptr->fsend,mptr->lsend, mptr->number>user.lastread ? " [new]" : " ", mptr->status==PRIVMSG ? " [private]" : ""); } if (mptr->status!=DEADMSG) { ++msgcount; ++totalmsgs; } if (mptr->lines && fileflag) { lines=mptr->lines+1; read(summary,1); while (lines--) while (getc(summary)!='\n'); /* flush line */ } ++mindex; /* killed msg in table too, for upcoming unkill,etc. */ if (mindex>=O.MAXTOTMSGS) { printf("\nTo many msgs, (%d is max, including deleted ones)\n", O.MAXTOTMSGS); close(summary); return ERROR; } } /* while */ if (!n && !flag) send("\n[Sorry, no Mail]\n"); if (summary && fileflag) { send("\n[One moment please. Be sure to do a message purge before anything else!]\n"); for (flag=0; flagnumber==0) return NULL; sprintf(tb,"%s %s %s",up->first,up->last,up->city); upcase(tb); /* make upper case only */ if (isdigit(*sstr)) { if (atoi(sstr) > up->number) return NULL; } else if (!sindex(sstr,tb) && *sstr!='\0') return NULL; /* no match-no show */ if (user.status==SYSOP) sprintf(temp," -- '%c' (%s) pw=%s",up->status, up->status==SYSOP ? "sysop" : up->status==SPECIAL ? "special" : up->status==NORMAL ? "normal" : up->status==NOCPM ? "NO CP/M" : up->status==TWIT ? "*TWIT*" : "OTHER",up->pass); else { mode=NOPRINT; *temp='\0'; } sprintf(buffer,"\n%-5u %s %s%s from %s",up->number,up->first,up->last, temp,up->city); if (send(buffer)==ERROR) return ERROR; if (mode==PRINT) { print(buffer); /* send to list device */ print("\r"); } strcpy(temptime,up->time); timefix(temptime); sprintf(buffer,"\n\\---- Called %u time(s). Last message was %u on %s %s%s\n", up->parm.calls,up->lastread,up->date, O.RTC!=NOCLOCK ? "at " : "",O.RTC!=NOCLOCK ? temptime : ""); if (send(buffer)==ERROR) return ERROR; if (mode==PRINT) { print(buffer); /* send to list device */ print("\r"); } return NULL; /* alls done */ } /******************************* * display the user on console * *******************************/ disuser() { printf("\nYou are user #%d.\n",user.number); sprintf(buffer,"\ \n(1) Experience=%s (2) Bell=%s (3) Nulls=%c\ \n(4) %s (5) %s messages when first entering the bbs.\ \n(6) Change Password. (7) Terminal height=%d (if 0, no pause)\ \n(8) Terminal width=%d\n", (user.parm.expert==PON) ? "EXPERT" : "NOVICE", (user.parm.bell==PON) ? "ON" : "OFF",user.parm.nulls, (user.parm.jmpcpm==PON) ? "Skip BBS " : "Enter BBS", (user.parm.rp==POFF) ? "Read" : "Don't read", user.parm.height,user.parm.width); send(buffer); } /******************** * Save users stuff * ********************/ saveuser(n) register unsigned n; { char temp[10]; disuser(); /* display the user */ do { if (user.parm.expert==PON) sprintf(buffer,"\nChange :"); else sprintf(buffer,"\nEnter number to change (Return to End) :"); ask(buffer,temp,9,UP); switch (*temp) { case '1': user.parm.expert==PON ? (send("\n[Novice mode]"),user.parm.expert=POFF) : (send("\n[Expert mode]"),user.parm.expert=PON); break; case '2': user.parm.bell==PON ? (send("\n[Bell off]"),user.parm.bell=POFF) : (send("\n[Bell on]"),user.parm.bell=PON); break; case '3': ask("\nNumber of nulls (0-9)? ",buffer,5,UP); if ((*temp>='0') && (*temp<='9') && *buffer!='\0') { *nulls=*buffer-'0'; user.parm.nulls=*buffer; } else send("\n[Nulls NOT changed]"); break; case '4': if (O.user_types[user.type].maxuser==0) { send("\nYou don't have Operating System privs..."); break; } user.parm.jmpcpm==PON ? (send("\nYou will now enter the BBS when you call."), user.parm.jmpcpm=POFF) : (send("\nYou will now enter the Operating System instead of the BBS when you call.") ,user.parm.jmpcpm=PON); break; case '5': user.parm.rp==POFF ? (send("\n[AUTO read of messages OFF]"),user.parm.rp=PON) : (send("\n[AUTO read of messages ON]"),user.parm.rp=POFF); break; case '6': do ask ("\nEnter new password, or RETURN if no change -> ",buffer,PASSLEN,UP); /* no spaces, or number for first char */ while (isspc(buffer) || isdigit(*buffer)); if (*buffer!='\0') strcpy(user.pass,buffer); else send("\n[Password NOT changed]"); break; case '7': ask("\nTerminal Height (0=no pause)? ",buffer,5,UP); if (*buffer!='\0') user.parm.height=height=atoi(buffer); else send("\n[Height not changed]"); break; case '8': ask("\nTerminal width? ",buffer,5,UP); if (*buffer!='\0') { if (atoi(buffer)<20) send("\n[Must be >=20, unchanged]"); else user.parm.width=atoi(buffer); } else send("\n[Width not changed]"); break; case '\0': break; case '?': disuser(); break; default: send("\n[Invalid option]"); } /* switch */ } while (*temp!='\0'); ask("\nMake changes permanent for future calls (y/n)? ",temp,2,UP); if (*temp=='Y') { char temp_time[TIMELEN+1],temp_date[DATELEN+1]; send("\n[Saving]"); n=user.lastread; user.lastread=nextmsg ? nextmsg-1 : 0; strcpy(temp_time,user.time); strcpy(temp_date,user.date); strcpy(user.time,time); strcpy(user.date,date); putuser(user.number); /* write new user info back to file */ strcpy(user.time,temp_time); strcpy(user.date,temp_date); user.lastread=n; /* restore last read msg number */ } } /* saveuser */ /****************************************************************** * initialize the bye variable to point to location if BYE active */ findbye() { register char *p; bye=(*(char *)2)*256+*(char *)1-2; bye=(*(char *)(bye+1))*256+*(char *)bye+6; /* bye keeps mucking everyone up by changing the locations of strings */ for (p=bye; p<=bye+35; p++) if (!ustrncmp("bye",p,3)) break; if (p>=bye+25) bye=nothing; /* now for the values that we use the bye variable for.. */ maxuser=bye; tout=bye+2; nulls=bye+3; } /************************* * Display message stats * *************************/ stats(n) { char temptime[TIMELEN+1]; strcpy(temptime,user.time); /* make pretty time */ timefix(temptime); sprintf(buffer,"\nYou are caller %u (User #%u).\n\ You've called %u time(s), last one being on %s%s%s.\n\n\ There are %d active messages.",callnum,user.number,user.parm.calls, user.date,O.RTC!=NOCLOCK ? " at " : "",O.RTC!=NOCLOCK ? temptime : "", msgcount); if (send(buffer)==ERROR) return; if (privmsgs) sprintf(buffer," (%d are private)",privmsgs); else *buffer='\0'; if (send(buffer)==ERROR) return; sprintf(buffer,"\nYour last read message was %u.\n\ The current high message is %u.\n",user.lastread,nextmsg ? nextmsg-1 : 0); send(buffer); } /********************* * List callers file * *********************/ calls(n) { if (type(CALLERS)!=ERROR) /* type the callers of today */ if (user.status==SYSOP) { ask("[Purge callers file?]",buffer,2,UP); if (*buffer=='Y') { send("[Purging]"); unlink(CALLERS); } } } /* End of File */