// This may look like C code, but it is really -*- C++ -*- // ------------------------------------------------------------------ // The Goldware Library // Copyright (C) 1990-1999 Odinn Sorensen // Copyright (C) 1999-2000 Alex. S. Aganichev // ------------------------------------------------------------------ // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library 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 // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public // License along with this program; if not, write to the Free // Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, // MA 02111-1307, USA // ------------------------------------------------------------------ // $Id$ // ------------------------------------------------------------------ // Hudson / Goldbase msgbase handling // ------------------------------------------------------------------ // ------------------------------------------------------------------ template void _HudsArea::data_open() { wide = (HudsWide*) (__HUDSON ? (void *)hudsonwide : (void *)goldbasewide); } // ------------------------------------------------------------------ template void _HudsArea::data_close() { } // ------------------------------------------------------------------ template void _HudsWide::exit() { if(__HUDSON) { delete hudsonwide->user; throw_release(hudsonwide->msgidxptr); } else { delete goldbasewide->user; throw_release(goldbasewide->msgidxptr); } } // ------------------------------------------------------------------ template void _HudsWide::init() { GFTRK("HudsInit"); if (WideDebug) WideLog->printf("- Begin init for %s.", path); isopen = 0; islocked = false; timesposted = 0; msgidxsize = 0; msgidxptr = NULL; pmscan = NULL; scn = NULL; // Open complete msgbase, create if none exists if (not fexist(AddPath(path, __HUDSON ? "msghdr" HUDS_EXT : "msghdr" GOLD_EXT))) { WideLog->printf("* Creating new msgbase at %s", path); raw_open(O_CREAT); if (fhinf.FileLength() == 0) { memset(&msginfo, 0, sizeof(HudsInfo)); fhinf.Write(&msginfo, sizeof(HudsInfo)); } if (fhlrd.FileLength() == 0) { memset(lastrec, 0, sizeof(HudsLast)); fhlrd.Write(lastrec, sizeof(HudsLast)); } } else { raw_open(); } // Lock msgbase to ensure data integrity lock(); // Check if MSGTXT.BBS is approaching dangerous size if (__HUDSON and (fhtxt.FileLength() > sizewarn)) HudsSizewarn(); // Check for mismatch between the header and the index files uint _hdrsize = fhhdr.FileLength()/sizeof(HudsHdr); uint _idxsize = fhidx.FileLength()/sizeof(HudsIdx); uint _toisize = fhtoi.FileLength()/sizeof(HudsToIdx); if ((_hdrsize != _idxsize) or (_hdrsize != _toisize)) { raw_close(); HGWarnRebuild(); WideLog->ErrIndex(); WideLog->printf("! The %s msgbase files do not have the same number of records.", __HUDSON ? HUDS_NAME : GOLD_NAME); WideLog->printf(": %smsghdr%s (%u records).", path, __HUDSON ? HUDS_EXT : GOLD_EXT, _hdrsize); WideLog->printf(": %smsgidx%s (%u records).", path, __HUDSON ? HUDS_EXT : GOLD_EXT, _idxsize); WideLog->printf(": %smsgtoidx%s (%u records).", path, __HUDSON ? HUDS_EXT : GOLD_EXT, _toisize); WideLog->printf("+ Advice: You need to run a msgbase index rebuild utility."); IndexErrorExit(); } // Detect USERS.BBS format unless user has configured it if(__HUDSON and (ra2usersbbs == 0)) { // Get size of USERS.BBS int len = fhusr.FileLength(); // Does size match Hudson format? int hudsmatch = (len % sizeof(HudsUsers)) == 0; if(hudsmatch) ra2usersbbs = 1; // Does size match RA2 format? int ra2match = (len % sizeof(RA2Users)) == 0; if(ra2match) ra2usersbbs = 2; // If it matches both of them if (hudsmatch and ra2match) { // Check version in CONFIG.RA to make sure Path rapath, file; char* ptr = getenv("RA"); if (ptr) AddBackslash(strcpy(rapath, ptr)); MakePathname(file, rapath, "messages.ra"); gfile fh(file, O_RDONLY|O_BINARY, WideSharemode, S_STDRD); if (fh.isopen()) { word VersionID = 0; fh.Read(&VersionID, sizeof(word)); if (VersionID >= 0x200) ra2usersbbs = 2; else ra2usersbbs = 1; } } // If it does not match either of them if(not hudsmatch and not ra2match) { WideLog->ErrIndex(); WideLog->printf("! The users.bbs file has an incorrect size."); WideLog->printf(": %susers.bbs, %u bytes.", path, len); WideLog->printf(": Should be %u bytes if it's in RA2 format.", (uint)((len/sizeof(RA2Users))*sizeof(RA2Users))); WideLog->printf(": Should be %u bytes if it's in Hudson format.", (uint)((len/sizeof(HudsUsers))*sizeof(HudsUsers))); if(ra2usersbbs) WideLog->printf(": It appears to be in %s format.", (ra2usersbbs == 2) ? "RA2" : "Hudson"); WideLog->printf("+ Advice: Run a userbase packing utility."); IndexErrorExit(); } } if (__HUDSON) { if (ra2usersbbs == 2) { if (WideDebug) WideLog->printf("- Using a RA2 format userbase."); user = new RA2User; } else { if(WideDebug) WideLog->printf("- Using a Hudson format userbase."); user = new HudsonUser; } } else user = new GoldbaseUser; throw_new(user); // Open RA2 files if (__HUDSON and (ra2usersbbs == 2)) { RA2User* _user2 = (RA2User*)user; test_open(fhuix, "usersidx.bbs", O_CREAT); test_open(fhuxi, "usersxi.bbs", O_CREAT); _user2->idxfh = &fhuix; _user2->xifh = &fhuxi; } // Find user const char* _username = WideUsername[0]; if (userno == -1) { user->gufh = fhusr.fh; user->find(_username); if(not user->found) { WideLog->printf("* User \"%s\" not found in %susers%s.", _username, path, __HUDSON ? HUDS_EXT : GOLD_EXT); user->add(_username); WideLog->printf("* Now added with user number %u.", user->index); } userno = user->index; } if(WideDebug) WideLog->printf("- Using user record number %u.", userno); // Close RA2 files if (__HUDSON and (ra2usersbbs == 2)) { fhuix.Close(); fhuxi.Close(); } // Unlock and close unlock(); raw_close(); if(WideDebug) WideLog->printf("- End init for %s.", path); GFTRK(0); } // ------------------------------------------------------------------ template void _HudsWide::save_lastread(board_t board, msgn_t msgno) { GFTRK("HudsSaveLast"); // Update lastread record msgn_t _lastread = lastrec[board-1] = msgno; fhlrd.LseekSet(userno*sizeof(HudsLast)); fhlrd.Write(lastrec, sizeof(HudsLast)); // Update user record user->gufh = fhusr.fh; user->moveto(userno); if (user->lastread() < _lastread) user->lastread(_lastread); if (timesposted) { user->inctimesposted(timesposted); timesposted = 0; } GFTRK(0); } // ------------------------------------------------------------------ template void _HudsArea::open() { GFTRK("HudsOpen"); data_open(); wide->isopen++; if(wide->isopen == 1) { wide->raw_open(); wide->refresh(); wide->timesposted = 0; } if(wide->isopen > 2) { WideLog->ErrTest(); goto error; } isopen++; if(isopen > 2) { WideLog->ErrTest(); goto error; } scan(); goto done; error: WideLog->printf("! Trying to open a %s msgbase more than twice.", __HUDSON ? HUDS_NAME : GOLD_NAME); WideLog->printf(": %s, board %u.", echoid(), board()); WideLog->printf("+ Info: This indicates a serious bug."); WideLog->printf("+ Advice: Report to the Author immediately."); TestErrorExit(); done: GFTRK(0); } // ------------------------------------------------------------------ template void _HudsArea::close() { GFTRK("HudsClose"); if(isopen) { if(isopen == 1) { wide->save_lastread((board_t)board(), (msgn_t)Msgn->CvtReln(lastread)); Msgn->Reset(); } isopen--; } else { WideLog->ErrTest(); goto error; } if(wide->isopen) { if(wide->isopen == 1) { if(wide->islocked) wide->unlock(); wide->raw_close(); throw_release(wide->msgidxptr); } wide->isopen--; } else { WideLog->ErrTest(); goto error; } goto done; error: WideLog->printf("! Trying to close an already closed %s msgbase.", __HUDSON ? HUDS_NAME : GOLD_NAME); WideLog->printf(": %s, board %u.", echoid(), board()); WideLog->printf("+ Info: This indicates a potentially serious bug."); WideLog->printf("+ Advice: Report to the Author immediately."); TestErrorExit(); done: data_close(); GFTRK(0); } // ------------------------------------------------------------------ template void _HudsArea::suspend() { GFTRK("HudsSuspend"); wide->save_lastread((board_t)board(), (msgn_t)Msgn->CvtReln(lastread)); wide->raw_close(); GFTRK(0); } // ------------------------------------------------------------------ template void _HudsArea::resume() { GFTRK("HudsResume"); wide->raw_open(); GFTRK(0); } // ------------------------------------------------------------------