This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
deb-goldedplus/goldlib/gmb3/gmohuds2.cpp
Alexander S. Aganichev 4934ba030c none
2001-04-15 19:24:44 +00:00

728 lines
21 KiB
C++

// 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 <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::raw_close() {
GFTRK("HudsRawClose");
if(fhtxt != -1) ::close(fhtxt); fhtxt = -1;
if(fhhdr != -1) ::close(fhhdr); fhhdr = -1;
if(fhidx != -1) ::close(fhidx); fhidx = -1;
if(fhinf != -1) ::close(fhinf); fhinf = -1;
if(fhlrd != -1) ::close(fhlrd); fhlrd = -1;
if(fhtoi != -1) ::close(fhtoi); fhtoi = -1;
if(fhusr != -1) ::close(fhusr); fhusr = -1;
GFTRK(NULL);
}
// ------------------------------------------------------------------
template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
int _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::test_open(char* __file, int __oaccess) {
GFTRK("HudsTestOpen");
int _fh;
long _tries = 0;
__oaccess |= O_RDWR|O_BINARY;
do {
Path _testfn;
strcpy(_testfn, AddPath(path, __file));
int _omode = (__oaccess & O_CREAT) ? S_STDRW : S_STDRD;
_fh = ::sopen(_testfn, __oaccess, WideSharemode, _omode);
if(_fh == -1) {
if(errno == ENOENT) {
if(_tries == 0) {
__oaccess |= O_CREAT;
_tries++;
continue;
}
}
// Request the other program to unlock
if(errno != ENOENT)
TouchFile(AddPath(path, "mbunlock.now"));
// Tell the world
if(PopupLocked(++_tries, false, _testfn) == false) {
// User requested to exit
WideLog->ErrOpen();
raw_close();
WideLog->printf("! A %s msgbase file could not be opened.", __HUDSON ? HUDS_NAME : GOLD_NAME);
WideLog->printf(": %s.", _testfn);
WideLog->ErrOSInfo();
OpenErrorExit();
}
}
} while(_fh == -1);
// Remove the popup window
if(_tries)
PopupLocked(0, 0, NULL);
GFTRK(NULL);
return _fh;
}
// ------------------------------------------------------------------
template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::raw_open(int __oaccess, int __all) {
GFTRK("HudsRawOpen");
fhidx = test_open(__HUDSON ? "msgidx" HUDS_EXT : "msgidx" GOLD_EXT, __oaccess);
fhinf = test_open(__HUDSON ? "msginfo" HUDS_EXT : "msginfo" GOLD_EXT, __oaccess);
fhlrd = test_open(__HUDSON ? "lastread" HUDS_EXT : "lastread" GOLD_EXT, __oaccess);
fhtoi = test_open(__HUDSON ? "msgtoidx" HUDS_EXT : "msgtoidx" GOLD_EXT, __oaccess);
if(__all) {
fhhdr = test_open(__HUDSON ? "msghdr" HUDS_EXT : "msghdr" GOLD_EXT, __oaccess);
fhtxt = test_open(__HUDSON ? "msgtxt" HUDS_EXT : "msgtxt" GOLD_EXT, __oaccess);
fhusr = test_open(__HUDSON ? "users" HUDS_EXT : "users" GOLD_EXT, __oaccess);
}
GFTRK(NULL);
}
// ------------------------------------------------------------------
template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::raw_open_scan() {
GFTRK("HudsRawOpenScan");
raw_open(0, false);
GFTRK(NULL);
}
// ------------------------------------------------------------------
template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::refresh() {
GFTRK("HudsRefresh");
// (Re)Allocate memory to hold the complete MSGIDX.BBS/DAT
msgidxsize = filelength(fhidx);
msgidxptr = (HudsIdx*)throw_realloc(msgidxptr, (uint)(msgidxsize+sizeof(HudsIdx)));
// Load MSGIDX.BBS/DAT
lseek(fhidx, 0, SEEK_SET);
read(fhidx, msgidxptr, (uint)msgidxsize);
// Load MSGINFO.BBS/DAT
lseek(fhinf, 0, SEEK_SET);
read(fhinf, &msginfo, sizeof(HudsInfo));
// Load LASTREAD.BBS/DAT
lseek(fhlrd, (long)userno*(long)sizeof(HudsLast), SEEK_SET);
read(fhlrd, lastrec, sizeof(HudsLast));
GFTRK(NULL);
}
// ------------------------------------------------------------------
template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::open() {
GFTRK("HudsWideOpen");
isopen = 1;
iswideopen = true;
ispmscanned = false;
iswidescanned = false;
raw_open_scan();
lock();
GFTRK(NULL);
}
// ------------------------------------------------------------------
template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::close() {
GFTRK("HudsWideClose");
unlock();
raw_close();
throw_release(msgidxptr);
throw_release(pmscan);
throw_release(scn);
iswideopen = false;
isopen = 0;
GFTRK(NULL);
}
// ------------------------------------------------------------------
template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::lock() {
GFTRK("HudsLock");
if(not islocked and WideCanLock) {
long _tries = 0;
// Try to get the lock
while(::lock(fhinf, sizeof(HudsInfo)+1, 1) == -1) {
// Tell the world
if(PopupLocked(++_tries, true, AddPath(path, __HUDSON ? "msginfo" HUDS_EXT : "msginfo" GOLD_EXT)) == false) {
// User requested to exit
WideLog->ErrLock();
raw_close();
WideLog->printf("! A %s msgbase file could not be locked.", __HUDSON ? HUDS_NAME : GOLD_NAME);
WideLog->printf(": %smsginfo%s.", path, __HUDSON ? HUDS_EXT : GOLD_EXT);
WideLog->ErrOSInfo();
LockErrorExit();
}
// Request the other program to unlock
TouchFile(AddPath(path, "mbunlock.now"));
}
// Remove the popup window
if(_tries)
PopupLocked(0, 0, NULL);
// We got the lock
islocked = true;
}
// Refresh msgbase data
refresh();
GFTRK(NULL);
}
// ------------------------------------------------------------------
template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::unlock() {
GFTRK("HudsUnlock");
if(islocked and WideCanLock) {
::unlock(fhinf, sizeof(HudsInfo)+1, 1);
islocked = false;
}
GFTRK(NULL);
}
// ------------------------------------------------------------------
template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
void _HudsArea<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::lock() {
wide->lock();
}
// ------------------------------------------------------------------
template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
void _HudsArea<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::unlock() {
wide->unlock();
}
// ------------------------------------------------------------------
template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::scan() {
GFTRK("HudsWideScan");
iswidescanned = true;
// Alloc scan array
throw_free(scn);
scn = (HudsScan*)throw_calloc((__HUDSON ? HUDS_MAXBOARD : GOLD_MAXBOARD), sizeof(HudsScan));
// Board and scan array pointer
register int _board;
register HudsScan* _scan = scn;
// Init wide scan array
_board = 0;
while(_board < (__HUDSON ? HUDS_MAXBOARD : GOLD_MAXBOARD)) {
_scan->active = msginfo.active[_board];
_scan->lastread = lastrec[_board];
_board++;
_scan++;
}
// Setup MSGIDX pointer and counters
register HudsIdx* _msgidx_ptr = msgidxptr;
register uint _msgidx_count = 0;
register uint _msgidx_total = (uint)(msgidxsize/sizeof(HudsIdx));
int _invalidboards = 0;
// Scan the index
while(_msgidx_count < _msgidx_total) {
// Is the msg not deleted?
if(_msgidx_ptr->msgno != (__HUDSON ? HUDS_DELETEDMSGNO : GOLD_DELETEDMSGNO)) {
register int _idxboard = _msgidx_ptr->board;
if(_idxboard and (_idxboard <= (__HUDSON ? HUDS_MAXBOARD : GOLD_MAXBOARD))) {
_scan = scn + (_idxboard - 1);
// Get message number
_scan->lastmsgno = _msgidx_ptr->msgno;
_scan->count++;
// Set first message number
if(not _scan->firstmsgno)
_scan->firstmsgno = _scan->lastmsgno;
// Set lastread pointer
if((_scan->lastmsgno >= _scan->lastread) and (_scan->lastreadreln == 0)) {
_scan->lastreadfound = _scan->lastmsgno;
_scan->lastreadreln = _scan->count - (_scan->lastmsgno != _scan->lastread ? 1 : 0);
}
}
else {
_invalidboards++;
}
}
// Go to next record
_msgidx_count++;
_msgidx_ptr++;
}
if(_invalidboards) {
WideLog->printf("! Found %u msgs with an invalid board number (0 or >%u).", _invalidboards, (__HUDSON ? HUDS_MAXBOARD : GOLD_MAXBOARD));
WideLog->printf("! In the %s msgbase at %s.", __HUDSON ? HUDS_NAME : GOLD_NAME, path);
WideLog->printf(": Info: Your msgbase may be partially corrupted.");
WideLog->printf("+ Advice: Run a msgbase index rebuild/recover utility.");
}
// Check/fix boards
_board = 0;
_scan = scn;
while(_board < (__HUDSON ? HUDS_MAXBOARD : GOLD_MAXBOARD)) {
// Check/fix lastreads
if(_scan->count and (_scan->lastreadfound != _scan->lastread)) {
if(_scan->lastread > _scan->lastmsgno)
_scan->lastreadreln = _scan->count;
else if(_scan->lastread < _scan->firstmsgno)
_scan->lastreadreln = 0;
}
if(WideDebug) {
WideLog->printf("- b:%u: t:%u, l:%u, fm:%lu, hm:%lu, lr:%lu, u:%u",
_board,
_scan->count,
_scan->lastreadreln,
_scan->firstmsgno,
_scan->lastmsgno,
_scan->lastread,
userno
);
}
// Check active message count and log it if different
if(_scan->active != _scan->count) {
WideLog->printf("! Counted %u active msgs in %s board %u.", _scan->count, __HUDSON ? HUDS_NAME : GOLD_NAME, _board+1);
WideLog->printf("! According to msginfo%s there should be %u active msgs.", __HUDSON ? HUDS_EXT : GOLD_EXT, _scan->active);
WideLog->printf(": Info: A program did not update msginfo%s correctly.", __HUDSON ? HUDS_EXT : GOLD_EXT);
WideLog->printf("+ Advice: Run a msgbase index rebuild utility.");
}
_board++;
_scan++;
}
GFTRK(NULL);
}
// ------------------------------------------------------------------
template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
void _HudsArea<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::raw_scan(int __keep_index) {
GFTRK("HudsRawScan");
if(!wide)
wide = (HudsWide*) (__HUDSON ? (void *)hudsonwide : (void *)goldbasewide);
if(wide->iswideopen and not wide->iswidescanned)
wide->scan();
// Get wide scan data if any
if(wide->scn) {
// Update area data
register HudsScan* _scan = wide->scn + (board() - 1);
Msgn->SetCount(_scan->count);
lastread = _scan->lastreadreln;
lastreadentry = _scan->lastreadfound;
}
else {
// Open the msgbase if it wasn't already
int _was_open = wide->isopen;
if(not _was_open)
wide->open();
// Get the number of active msgs in the area
register board_t _board = (board_t)board();
register uint _active = wide->msginfo.active[_board-1];
register msgn_t _lastread = wide->lastrec[_board-1];
// Setup pointers and counts
register uint _msg_count = 0;
register HudsIdx* _msgidx_ptr = wide->msgidxptr;
register uint _msgidx_count = 0;
register uint _msgidx_total = (uint)(wide->msgidxsize/sizeof(HudsIdx));
register uint _lastread_reln = 0;
// (Re)Allocate index
if(__keep_index)
Msgn->Resize(_active);
// Index pointers
register ulong* _msgno_ptr = Msgn->tag;
// Fill index
register ulong _firstmsgno = 0;
register ulong _lastmsgno = 0;
register ulong _lastreadfound = 0;
while(_msgidx_count < _msgidx_total) {
// Is it our board and is the msg not deleted?
if((_msgidx_ptr->board == _board) and (_msgidx_ptr->msgno != (__HUDSON ? HUDS_DELETEDMSGNO : GOLD_DELETEDMSGNO))) {
// Get message number
_lastmsgno = _msgidx_ptr->msgno;
_msg_count++;
// Set first message number
if(not _firstmsgno)
_firstmsgno = _lastmsgno;
// Transfer data to the index
if(__keep_index)
*_msgno_ptr++ = _lastmsgno;
// Set lastread pointer
if((_lastmsgno >= _lastread) and (_lastread_reln == 0)) {
_lastreadfound = _lastmsgno;
_lastread_reln = _msg_count - (_lastmsgno != _lastread ? 1 : 0);
}
// Break loop as soon as we have all we need
if(_msg_count == _active)
break;
}
// Go to next record
_msgidx_count++;
_msgidx_ptr++;
}
// If the exact lastread was not found
if(_msg_count and (_lastreadfound != _lastread)) {
// Higher than highest or lower than lowest?
if(_lastread > _lastmsgno)
_lastread_reln = _msg_count;
else if(_lastread < _firstmsgno)
_lastread_reln = 0;
}
// Check active message count and log it if different
if(_active != _msg_count) {
WideLog->printf("! Counted %u active msgs in %s board %u (%s).", _msg_count, __HUDSON ? HUDS_NAME : GOLD_NAME, board(), echoid());
WideLog->printf("! According to msginfo%s there should be %u active msgs.", __HUDSON ? HUDS_EXT : GOLD_EXT, _active);
WideLog->printf(": Info: A program did not update msginfo%s correctly.", __HUDSON ? HUDS_EXT : GOLD_EXT);
WideLog->printf("+ Advice: Run a msgbase index rebuild utility.");
}
// Update area data
Msgn->SetCount(_msg_count);
lastread = _lastread_reln;
lastreadentry = _lastreadfound;
if(WideDebug) {
WideLog->printf("- b:%u: t:%u, l:%u, fm:%lu, hm:%lu, lr:%lu, u:%u",
board(),
Msgn->Count(),
lastread,
_firstmsgno,
_lastmsgno,
(ulong)_lastread,
wide->userno
);
}
// Close the msgbase again if we opened it in here
if(not _was_open)
wide->close();
}
GFTRK(NULL);
}
// ------------------------------------------------------------------
template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
void _HudsArea<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::scan() {
GFTRK("HudsScan");
raw_scan(true);
GFTRK(NULL);
}
// ------------------------------------------------------------------
template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
void _HudsArea<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::scan_area() {
GFTRK("HudsScanArea");
raw_scan(false);
GFTRK(NULL);
}
// ------------------------------------------------------------------
#define HudsIdxCmp(a,b) ((a.board-b.board != 0) ? a.board-b.board : ((int)(a.msgno-b.msgno)))
// ------------------------------------------------------------------
#define TOIDXBUFSZ 100u
#define PMSCANBUFSZ 50u
template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::realloc_pm_scan() {
pmscan = (HudsIdx*)throw_realloc(pmscan, (pmscantotal+PMSCANBUFSZ)*sizeof(HudsIdx));
}
// ------------------------------------------------------------------
template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::scan_pm() {
GFTRK("HudsWideScanPM");
if(not iswidescanned)
scan();
ispmscanned = true;
HudsToIdx* toidxbuf = (HudsToIdx*)throw_calloc(TOIDXBUFSZ, sizeof(HudsToIdx));
uint totrecs = (uint)(filelength(fhtoi) / sizeof(HudsToIdx));
HudsIdx* idxptr = msgidxptr;
throw_release(pmscan);
pmscantotal = 0;
int invalidboards = 0;
int gotpm, idxboard, umax, u;
uint getrecs, rec;
HudsToIdx* toidx;
do {
rec = 0;
gotpm = false;
getrecs = MinV(TOIDXBUFSZ, totrecs);
read(fhtoi, toidxbuf, getrecs*sizeof(HudsToIdx));
for(toidx=toidxbuf; rec<getrecs; idxptr++,toidx++,rec++) {
// Skip deleted msgs
if(idxptr->msgno == (__HUDSON ? HUDS_DELETEDMSGNO : GOLD_DELETEDMSGNO))
continue;
// Skip msgs in invalid boards
idxboard = idxptr->board;
if(not (idxboard and (idxboard <= (__HUDSON ? HUDS_MAXBOARD : GOLD_MAXBOARD)))) {
invalidboards++;
continue;
}
// If after lastread
if(idxptr->msgno <= scn[idxboard-1].lastreadfound)
continue;
// Convert name string
strnp2c(toidx->name, sizeof(HudsToIdx)-1);
// Is it a PM?
umax = (WidePersonalmail & PM_ALLNAMES) ? WideUsernames : 1;
for(u=0; u<umax; u++) {
if(strieql(toidx->name, WideUsername[u])) {
gotpm = true;
break;
}
}
if(gotpm) {
if((pmscantotal % PMSCANBUFSZ) == 0)
realloc_pm_scan();
pmscan[pmscantotal++] = *idxptr;
scn[idxboard-1].pmcount++;
gotpm = false;
}
}
totrecs -= getrecs;
} while(totrecs);
throw_free(toidxbuf);
pmscan = (HudsIdx*)throw_realloc(pmscan, (pmscantotal+1)*sizeof(HudsIdx));
// Sort all pm records in board/msgno order
for(uint k=pmscantotal >> 1; k; k >>= 1)
for(uint i=k; i < pmscantotal; i++)
for(uint j=i-k; (j >= 0) and HudsIdxCmp(pmscan[j], pmscan[j+k]) > 0; j-=k) {
HudsIdx e = pmscan[j];
pmscan[j] = pmscan[j+k];
pmscan[j+k] = e;
}
if(invalidboards) {
WideLog->printf("! Found %u msgs with an invalid board number (0 or >%u).", invalidboards, (__HUDSON ? HUDS_MAXBOARD : GOLD_MAXBOARD));
WideLog->printf("! In the %s msgbase at %s.", __HUDSON ? HUDS_NAME : GOLD_NAME, path);
WideLog->printf(": Info: Your msgbase may be partially corrupted.");
WideLog->printf("+ Advice: Run a msgbase index rebuild/recover utility.");
}
GFTRK(NULL);
}
// ------------------------------------------------------------------
template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
void _HudsArea<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::scan_area_pm() {
GFTRK("HudsScanAreaPM");
PMrk->ResetAll();
if(!wide)
wide = (HudsWide*) (__HUDSON ? (void *)hudsonwide : (void *)goldbasewide);
if(wide->iswideopen and not wide->ispmscanned)
wide->scan_pm();
// Get wide scan data if any
if(wide->scn) {
register board_t _board = (board_t)board();
register HudsScan* _scan = wide->scn + (_board - 1);
if(wide->pmscan) {
if(_scan->pmcount) {
register HudsIdx* pmscanptr = wide->pmscan;
while(pmscanptr->board != _board)
pmscanptr++;
register uint n = 0;
register uint cnt = _scan->pmcount;
while(n < cnt) {
PMrk->Append(pmscanptr->msgno);
pmscanptr++;
n++;
}
}
}
// Update area data
Msgn->SetCount(_scan->count);
lastread = _scan->lastreadreln;
lastreadentry = _scan->lastreadfound;
if(WideDebug) {
WideLog->printf("- b:%u: t:%u, l:%u, fm:%lu, hm:%lu, lr:%lu, u:%u, pm:%i",
_board,
_scan->count,
_scan->lastreadreln,
_scan->firstmsgno,
_scan->lastmsgno,
_scan->lastread,
wide->userno,
PMrk->Count()
);
}
}
else {
if(WideDebug)
WideLog->printf("- Oops! Fell into empty bracket.");
}
GFTRK(NULL);
}
// ------------------------------------------------------------------