/************************************************************************ * This file contains infrequently used (or used once) routines for the * overlay version of The Metal/Z-MSG * * Name: MEINFREQ.C * * Copyright (c) 1984, 1985, 1986 Tim Gary * All rights reserved. * ************************************************************************ * * 1.50xx 08/13/86 Fixed for user.phone kludge * 1.50xx 03/26/86 Totalmsg count fixed in msgalert.. * 1.50xx 03/17/86 Group stuff fixed? * 1.50xx 03/08/86 Read group file during message function.. * 1.50xx 03/06/86 Faster summary file lookup method eanabled.. * 1.50xx 03/01/86 Gearing up for groups.. Clear tagged/mail flags.. * 1.40xx 02/28/86 msg[].reply form deleted.. * 1.40xx 02/04/86 Hashed user file support added, display down/upload vals * 1.40xx 01/28/86 User city added back in.. * 1.40xx 01/26/86 Mods for new user/message format.. * 1.31a 10/13/85 Release version. Changes: * Better help for user function. Password length bug fixed. * 1.30xx 08/17/85 New inculde files and variable name bbs stuff.. * 1.30xx 06/09/85 No more allocation for msg.. * 1.30xx 05/25/85 Put msg allocation here also...(see also menter!) * 1.30xx 05/02/85 last_date/time extern defs deleted. * 1.30xx 03/03/85 Z3 Stuff looked into in this file. * 1.20b 01/18/85 Stats changes to conform to last_time, last_date. * 1.20b 01/09/85 Few more cosmetics.. * 1.20b 01/07/85 Fixed misc routines, added count of msgs user's left.. * 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" /* CPMIO header file for i/o operations.*/ #include "megen.h" /* general defines */ #include "meglob.h" /* global variable definitions */ #include "meovfn.h" /* overlay function numbers */ #include "mefiles.h" /* file names */ #include "ctype.h" /********************************************************** * 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; { #ifdef Z3 if (O.ZCPR==3) *(z3env->wheel)=0; /* turn off ZCPR3 wheel */ else /* fall through to next if */ #endif if (O.ZCPR) *O.SECURELOC=0; /* if zcpr 1 or 2, turn off hazzards */ #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 printf("\n%s.\n%s\n",O.BBSNAME,O.VERSION); /* 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.height; /* reset height */ if (O.RTC) 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 */ /* setup timeout values for different people (different stats) */ *tout=user.type_ptr->timeout; *maxuser=user.type_ptr->maxuser; *nulls=user.nulls; /* setup users nulls */ if (msg==0) { register char *zero=0; send("\nAllocation ERROR: Memory full.\n"); if (user.status==SYSOP) send("\n** Use the Configuration program and decrease total # of msgs **\n"); else send("\n** Sorry, but the BBS is in need of repair. Please try it later! **"); hangup(YES); } stats(0); /* display user number/message stats */ 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() { register FILE *lastcalr; unsigned trec,tlast; char tdate[9],ttime[9],*sp; unsigned *uptr; if ((lastcalr=open(LASTCALR,F_RD | F_UNLOCK))==NULL) /* open for read only */ { send("\nERROR: 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); sp=index(bufloc(lastcalr),0x1a)+1; /* find ^Z and skip */ uptr=sp; /* point to values.. */ trec=uptr[0]; tlast=uptr[1]; strcpy(tdate,sp+4); strcpy(ttime,sp+14); dateasc(tdate,&last_date); timeasc(ttime,&last_time); /* convert back to internal format */ 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.number=trec; /* since it's different in the file */ user.lastread=tlast; /* get lastread back */ user.type_ptr=get_tp(user.status); /* get pointer to type */ height=user.height; /* get height setup */ } /************************************************ * All new and improved msg summary builder... * * Will use messages file alone and skip bad * * sectors that it finds... * ************************************************/ msg_alert(n) int 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 */ int from_you; /* count of messages left by you and still on sys */ from_you=flag=msgcount=privmsgs=mindex=fmsg=lmsg=0; fileflag=TRUE; if (!n) send("\n[Checking for your Mail]\n"); /* white lie, this is later */ /* First we read the groups file if there is one */ read_groups(); 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].group=mptr->group; msg[mindex].flags=(getrec(summary)-1)>>5; /* set seek info */ if (mptr->status==DEADMSG) msg[mindex].parent=0; #ifdef DEBUG printf("\nnum %u seek %u parent %u",mptr->number,mptr->seek,mptr->parent); #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->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; } msg[mindex].flags|=MAIL; /* init mail */ printf("%5u %s%s%s\n", mptr->number,mptr->sender, mptr->number>user.lastread ? " [new]" : " ", mptr->status==PRIVMSG ? " [private]" : ""); } if (mptr->status!=DEADMSG) { ++msgcount; if (thisis(mptr->sender)) from_you++; } 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 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 && from_you) printf("\n[%d active messages left by you!]",from_you); if (!n && !flag) send("\n[Sorry, you have no Mail]"); if (summary && fileflag) { send("\n[One moment please. Be sure to do a message purge BEFORE anything else!]\n"); for (flag=0; flag0 ? atoi(temp)-1 : 0); while (showuser(temp,n)!=ERROR); if (users!=NULL) close(users); if (n==PRINT) height=theight; } showuser(sstr,mode) register char *sstr; int mode; { char temp[120]; char tb[81]; usr *up; up=bufloc(users); if (read(users,1)!=128) return ERROR; if (breakkey()) return ERROR; /* stop? */ if (up->file_info&DEADUSER) return NULL; sprintf(tb,"%s$$%s$$%s",up->name,up->city,up->phone); upcase(tb); /* make upper case only */ if (isdigit(*sstr)) { if (atoi(sstr) >= getrec(users)) 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 [%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,up->phone); else { mode=NOPRINT; *temp='\0'; } sprintf(buffer,"\n%-5u %s %s From %s",getrec(users),up->name,temp,up->city); if (send(buffer)==ERROR) return ERROR; if (mode==PRINT) { print(buffer); /* send to list device */ print("\r"); } sprintf(buffer,"\n\\---- Called %u time(s). Last message was %u on %s %s%s\n", up->calls,up->lastread,ascdate(up->date), O.RTC!=NOCLOCK ? "at " : "",O.RTC!=NOCLOCK ? asctime(up->time) : ""); 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("\nEnter the number next to what you wish to change:\n"); sprintf(buffer,"\ \n(1) Experience=%s (2) Bell=%s (3) Nulls=%d\ \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.flags&EXPERT) ? "EXPERT" : "NOVICE", (user.flags&BELL) ? "ON" : "OFF",(int)user.nulls, (user.login) ? "Skip BBS " : "Enter BBS", (user.flags&READNEW) ? "Read" : "Don't read", user.height,user.width); send(buffer); } /******************** * Save users stuff * ********************/ saveuser(n) register unsigned n; { char temp[10]; disuser(); /* display the user */ do { if (user.flags&EXPERT) sprintf(buffer,"\nChange :"); else sprintf(buffer,"\nEnter number to change (Return to End, '?' to redisplay menu) :"); ask(buffer,temp,9,UP); switch (*temp) { case '1': user.flags^=EXPERT; /* XOR toggle */ if (user.flags&EXPERT) send("\n[Expert mode]"); else send("\n[Novice mode]"); break; case '2': user.flags^=BELL; if (user.flags&BELL) send("\n[Bell ON]"); else send("\n[Bell OFF]"); break; case '3': ask("\nNumber of nulls (0-9)? ",buffer,5,UP); if ((*temp>='0') && (*temp<='9') && *buffer!='\0') { *nulls=*buffer-'0'; user.nulls=*buffer-'0'; } else send("\n[Nulls NOT changed]"); break; case '4': if ( !(user.type_ptr->maxuser) ) { send("\nYou don't have access to the Operating System..."); break; } user.login^=1; /* for now.. */ if (!user.login) send("\nYou will now enter the message system when you call."); else send("\nYou will now enter the Operating System instead of the BBS when you call."); break; case '5': user.flags^=READNEW; if (user.flags&READNEW) send("\n[AUTO read of messages ON]"); else send("\n[AUTO read of messages OFF]"); break; case '6': do ask ("\nEnter new password, or RETURN if no change -> ",buffer,PASSLEN+2,UP+NOECHO+NUMBER); /* no spaces, or number for first char */ while (isspc(buffer) || isdigit(*buffer)); if (strlen(buffer)>PASSLEN) { buffer[PASSLEN]='\0'; printf("\nWARNING: Password truncated to %d characters.\n",PASSLEN); } if (*buffer!='\0') { ask("\nNow enter it again for verification -> ",buffer+50,PASSLEN,UP+NOECHO+NUMBER); if (!strcmp(buffer,buffer+50)) strcpy(user.pass,buffer); else send("[Incorrect. Password was NOT changed]\n"); } else send("\n[Password NOT changed]"); break; case '7': ask("\nTerminal Height (0=no pause)? ",buffer,5,UP); if (*buffer!='\0') user.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.width=atoi(buffer); } else send("\n[Width not changed]"); break; case '\0': break; case '?': send("\nChoose the number of the item you wish to change\nfrom the following selections.\n"); 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[2],temp_date[3]; send("\n[Saving]"); n=user.lastread; user.lastread=nextmsg ? nextmsg-1 : 0; movmem(user.time,temp_time,2); movmem(user.date,temp_date,3); movmem(time,user.time,2); movmem(date,user.date,3); putuser(user.number); /* write new user info back to file */ movmem(temp_time,user.time,2); movmem(temp_date,user.date,3); user.lastread=n; /* restore last read msg number */ } } /* saveuser */ /* write user specified to correct place in users file, 0=write to current possition in the OPEN users file */ putuser(un) register unsigned un; { register usr *up; register int flag; if ((users=open(USERFILE,F_RW | F_LOCK))==NULL) return ERROR; /* else, open it */ up=bufloc(users); setarec(users,un); read(users,0); user.number=up->number; movmem(&user,bufloc(users),128); /* get user vars */ user.number=un; write(users,0); /* write record, no increment... */ close(users); /* either method called closes the users file */ return NULL; /* NULL=all's well */ } /************************* * Display message stats * *************************/ stats(n) { sprintf(buffer,"\nYou're caller number %u.\n\ You've called %u time(s), last one being on %s%s%s.\n\n",callnum,user.calls, ascdate(last_date),O.RTC!=NOCLOCK ? " at " : "", O.RTC!=NOCLOCK ? asctime(last_time) : ""); if (send(buffer)==ERROR) return; if (user.uploads || user.downloads) { sprintf(buffer,"You have downloaded %u files, and uploaded %u.\n\n", user.download,user.uploads); if (send(buffer)==ERROR) return; } sprintf(buffer,"There are %d active messages.",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 */