/************************************************************************/ /* rooma.c */ /* room code fore Citadel bulletin board system */ /************************************************************************/ /************************************************************************/ /* history */ /* */ /* 83Feb24 Insert check for insufficient RAM, externs too low. */ /* 82Dec06 CrT 2.00 release. */ /* 82Nov05 CrT main() splits off to become citadel.c */ /************************************************************************/ #include "b:210ctdl.h" /************************************************************************/ /* Contents */ /* */ /* dumpRoom() tells us # new messages etc */ /* fileDir() prints out a filename for a dir listing */ /* fillMailRoom() set up Mail> from log record */ /* gotoRoom() handles "g(oto)" command for menu */ /* init() system startup initialization */ /* initCitadel() */ /* initSysop() */ /* listRooms() lists known rooms */ /* openFile() opens a .sys file */ /* readSysTab() restores system state from citadel.tab */ /* roomExists() returns slot# of named room else ERROR */ /* setSpace() set default disk and user# */ /* setUp() */ /* systat() shows current system status */ /* wildCard() expands ambiguous filenames */ /* writeSysTab() saves state of system in citadel.tab */ /* */ /************************************************************************/ /************************************************************************/ /* dumpRoom() tells us # new messages etc */ /************************************************************************/ dumpRoom() { int fileDir(); int i, count, loc, newCount, no; for (newCount=0, count=0, i=0; i count) newCount = count; mprintf(" %d messages\n ", count); if (loggedIn && newCount > 0) mprintf(" %d new\n", newCount); if ((roomBuf.rbflags & CPMDIR) && !expert) { /* list directory also: */ doCR(); wildCard(fileDir, "*.*"); } } /************************************************************************/ /* fileDir() prints out one filename and size, for a dir listing */ /************************************************************************/ fileDir(fileName) char *fileName; { struct fcb block; char tempName[NAMESIZE], tBuf[2*NAMESIZE]; outFlag = OUTOK; unspace(fileName, tempName); setFcb(&block, tempName); bdos(GETfILEsIZE, &block); /* very slow on MMS BIOS! */ FDSectCount += block.fcbRecn; sprintf(tBuf, "%s%5d ", fileName, block.fcbRecn); putWord(tBuf); mAbort(); /* chance to next(!)/pause/skip */ } /************************************************************************/ /* fillMailRoom() */ /************************************************************************/ fillMailRoom() { int i; /* mail room -- copy messages in logBuf to room: */ for (i=0; i, else FALSE */ /************************************************************************/ char gotoRoom(nam) char *nam; { int i, foundit, newStuff, nwest, roomNo; if (!strLen(nam)) { /* update log entry for current room: */ logBuf.lbgen[thisRoom] = roomBuf.rbgen << GENSHIFT; foundit = FALSE; /* leaves us in Lobby> if nothing found */ newStuff= FALSE; for (i = 0 ; i>GENSHIFT)) ) { nwest = logBuf.lbvisit[logBuf.lbgen[i] & CALLMASK]+1; if (roomTab[i].rtlastMessage - nwest < 0x8000) { if (i != thisRoom && (i != AIDEROOM || aide)) { foundit = i; newStuff= TRUE; } } } } getRoom(foundit, &roomBuf); mprintf("%s\n ", roomBuf.rbname); } else { /* non-empty room name, so now we look for it: */ if ( (roomNo = roomExists(nam)) == ERROR || (roomNo==AIDEROOM && !aide) ) { mPrintf(" ?no %s room\n", nam); } else { /* update log entry for current room: */ if (loggedIn) logBuf.lbgen[thisRoom] = roomBuf.rbgen << GENSHIFT; getRoom(roomNo, &roomBuf); /* if may have been unknown... if so, note it: */ if ((logBuf.lbgen[thisRoom] >> GENSHIFT) != roomBuf.rbgen) { logBuf.lbgen[thisRoom] = ( (roomBuf.rbgen << GENSHIFT) + (MAXVISIT -1) ); } } } setUp(FALSE); dumpRoom(); return newStuff; /* was thisRoom */ } /************************************************************************/ /* init() -- master system initialization */ /************************************************************************/ init() { char getCh(), readSysTab(), toUpper(); char *msgFile; unsigned codend(), endExt(), externs(), topOfMem(); if (!readSysTab()) exit(); setSpace(homeDisk, homeUser); /* 1K RAM might not actually be sufficient... */ if (topOfMem() - codEnd() < 1024) { printf("Not enough RAM!"); exit(); } if (codEnd() >= externs()) { printf("Externs too low!"); exit(); } #ifdef XYZZY printf("code ends ....at %u\n", codend() ); printf("externs start at %u\n", externs() ); printf("externs end at %u\n", endext() ); printf("free RAM ends at %u\n", topofmem()); #endif if (FALSE) getText(); /* dummy to force load */ exitToCpm = FALSE; /* not time to quit yet! */ sizeLTentry = sizeOf(logTab[0]); /* just had to try that feature */ outFlag = OUTOK; /* not p(ausing) */ pullMessage = FALSE; /* not pulling a message */ pulledMLoc = ERROR; /* haven't pulled one either */ pulledMId = ERROR; debug = FALSE; loggedIn = FALSE; thisRoom = LOBBY; whichIO = CONSOLE; loggedIn = FALSE; setUp(TRUE); /* we initmodem at beginning & end both...*/ modemInit(); monthTab[1] = "Jan"; monthTab[2] = "Feb"; monthTab[3] = "Mar"; monthTab[4] = "Apr"; monthTab[5] = "May"; monthTab[6] = "Jun"; monthTab[7] = "Jul"; monthTab[8] = "Aug"; monthTab[9] = "Sep"; monthTab[10]= "Oct"; monthTab[11]= "Nov"; monthTab[12]= "Dec"; if (!clock) interpret(pInitDate); /* open message files: */ msgFile = "a:ctdlmsg.sys"; *msgFile += msgDisk; openFile(msgFile, &msgfl ); openFile("ctdlroom.sys", &roomfl); openFile("ctdllog.sys", &logfl ); getRoom(0, &roomBuf); /* load Lobby> */ modemInit(); } /************************************************************************/ /* initCitadel() does not reformat data files */ /************************************************************************/ initCitadel() { whichIO = MODEM; setUp(FALSE); } /************************************************************************/ /* listRooms() lists known rooms */ /************************************************************************/ listRooms(doDull) char doDull; /* TRUE to list unchanged rooms also */ { char str[NAMESIZE+3]; char boringRooms, doBoringRooms, hasUnseenStuff, shownHidden; int i; shownHidden = FALSE; boringRooms = FALSE; mprintf("\n Rooms with unread messages:\n "); for (doBoringRooms=FALSE; doBoringRooms<=doDull; doBoringRooms++) { for (i=0; i> GENSHIFT) ) || debug ) ) { /* do only rooms with unseen messages first pass, */ /* only rooms without unseen messages second pass: */ hasUnseenStuff = ( roomTab[i].rtlastMessage - ( logBuf.lbvisit[ logBuf.lbgen[i] & CALLMASK ]+1 ) < 0x8000 ); if (!hasUnseenStuff) boringRooms = TRUE; if ( (!doBoringRooms && hasUnseenStuff) || ( doBoringRooms && !hasUnseenStuff) ) { strcpy(str, roomTab[i].rtname); if (roomTab[i].rtflags & CPMDIR) strcat(str, ":"); else strcat(str, ">"); if (! (roomTab[i].rtflags & PUBLIC)) { strcat(str, "*"); shownHidden = TRUE; } mprintf(" %s", str); } } } if (boringRooms && !doBoringRooms && doDull) { mprintf("\n No unseen msgs in:\n "); } } if (!expert && shownHidden) mprintf("\n \n * => hidden room\n "); } /************************************************************************/ /* openFile() opens one of the .sys files. */ /************************************************************************/ openFile(filename, fd) char *filename; int *fd; { /* open message file */ if ((*fd = open(filename, 2)) == ERROR) { printf("?no %s", filename); exit(); } rsrec(*fd); /* initialize for random io */ } /************************************************************************/ /* readSysTab() restores state of system from SYSTEM.TAB */ /* returns: TRUE on success, else FALSE */ /* destroys SYSTEM.TAB after read, to prevent erroneous re-use */ /* in the event of a crash. */ /************************************************************************/ readSysTab() { char getc(); char fBuf[BUFSIZ]; char *c; if(fopen("ctdlTabl.sys", fBuf) == ERROR) { printf("?no ctdlTabl.sys!"); return(FALSE); } if ( getw(fBuf) != &firstExtern || getw(fBuf) != &lastExtern ) { printf("?old ctdlTabl.sys!"); return(FALSE); } c = &firstExtern; while (c < &lastExtern) *c++ = getc(fBuf); unlink("ctdlTabl.sys"); return(TRUE); } /************************************************************************/ /* roomExists() returns slot# of named room else ERROR */ /************************************************************************/ int roomExists(room) char *room; { int i; for (i=0; i> GENSHIFT) != roomTab[i].rtgen) { /* yes -- set gen = (realgen-1) % MAXGEN */ j = (roomTab[i].rtgen + (MAXGEN-1)) % MAXGEN; logBuf.lbgen[ i ] = (j << GENSHIFT) + (MAXVISIT-1); } } else if ((logBuf.lbgen[i] >> GENSHIFT) != roomTab[i].rtgen) { /* newly created public room -- remember to visit it; */ logBuf.lbgen[i] = (roomTab[i].rtgen << GENSHIFT) +1; } } /* special kludge for Mail> room, to signal new mail: */ roomTab[MAILROOM].rtlastMessage = logBuf.lbId[MAILSLOTS-1]; /* slide lbvisit array down and change lbgen entries to match: */ for (i=(MAXVISIT-2); i; i--) { logBuf.lbvisit[i] = logBuf.lbvisit[i-1]; } logBuf.lbvisit[(MAXVISIT-1)] = oldestLo; for (i=0; i>GENSHIFT==%d; roomTab.rtgen==%d; roomBuf.rbgen==%d\n" , logBuf.lbgen[thisRoom]>>GENSHIFT, roomTab[thisRoom].rtgen, roomBuf.rbgen ); printf("lbgen&CALLMASK==%d\n", logBuf.lbgen[thisRoom]&CALLMASK); } #endif } mprintf(" %d messages,", newestLo-oldestLo +1); mprintf(" last is %u %u,\n", newestHi, newestLo ); mprintf(" %dK message space,\n", maxMSector >> 3 ); mprintf(" %d-entry log\n", MAXLOGTAB ); } /************************************************************************/ /* unspace() copies a filename, removing blanks */ /************************************************************************/ unspace(from, to) char *from, *to; { while (*to = *from++) if (*to != ' ') to++; } /************************************************************************/ /* wildCard() */ /* Adapted from YAM which borrowed from Richard Greenlaw's expander. */ /************************************************************************/ #define UFNsIZE 13 /* size of "filename.ext" plus a null. */ wildCard(fn, filename) int (*fn)(); char *filename; /* may be ambiguous. No drive or user numbers. */ { char toLower(); int strCmp(); struct fcb block, *pBlock; char *p, *q, c, byteAddr, finished; int fileCount, i, m; char tBuf[SECTSIZE]; struct { char unambig[UFNsIZE]; /* filename */ } *fp; if ( filename[1] == ':' || setFcb(&block, filename) == 255 ) { /* bad filename: */ mprintf("%s?\n ", filename); return; } bdos(SETdMA, tBuf); setSpace(roomBuf.rbdisk, roomBuf.rbuser); if ( (byteAddr=bdos(FINDfIRST, &block)) == 255) { /* no such file */ mprintf("no %s\n ", filename); setSpace(homeDisk, homeUser); return; } /* search directory for all matches: */ for ( fp=msgBuf.mbtext, fileCount=0, finished=FALSE; !finished; fp++, fileCount++, finished = ((byteAddr=bdos(FINDnEXT, &block)) == 255) ) { /* figure out where BDOS stashed our fcb: */ pBlock = tBuf + 32*(byteAddr % 4); /* "% 4"? --CrT */ p = fp; if (fp > (&msgBuf.mbtext[MAXTEXT-100])) { printf("too many files!!\n"); setSpace(homeDisk, homeUser); return; } /* copy filename from directory: */ q = pBlock; for (i=8; i; i--) *p++ = toLower(*++q & 0x7F); *p++ = '.'; /* get file extention: */ for (i=3; i; i--) *p++ = toLower(*++q & 0x7F); *p = '\0'; /* tie off with null */ } qSort(msgBuf.mbtext, fileCount, UFNsIZE, strCmp); outFlag = OUTOK; for (fp=msgBuf.mbtext; fileCount-- && outFlag!=OUTSKIP; fp++) { (*fn)(fp); } setSpace(homeDisk, homeUser); } /************************************************************************/ /* writeSysTab() saves state of system in SYSTEM.TAB */ /* returns: TRUE on success, else ERROR */ /************************************************************************/ writeSysTab() { /* extern int opsLogChar, opsLogSector, catChar, catSector; */ /* extern int lowId, highId, nextRoom; */ /* extern struct logTab, struct roomTab; */ char *c; char fBuf[BUFSIZ]; if(fcreat("ctdlTabl.sys", fBuf) == ERROR) { printf("?can't make ctdlTabl.sys"); return(ERROR); } /* write loc & len so we can detect bad ctdlTabl.sys files: */ putw(&firstExtern, fBuf); putw(&lastExtern, fBuf); c = &firstExtern; while (c < &lastExtern) putc(*c++, fBuf); fflush(fBuf); fclose(fBuf); return(TRUE); } .