718 lines
20 KiB
C++
718 lines
20 KiB
C++
|
// This may look like C code, but it is really -*- C++ -*-
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
// The Goldware Library
|
||
|
// Copyright (C) 1990-1999 Odinn Sorensen
|
||
|
// ------------------------------------------------------------------
|
||
|
// 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$
|
||
|
// ------------------------------------------------------------------
|
||
|
// Squish msgbase handling and Maximus user functions.
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
#include <gdbgerr.h>
|
||
|
#include <gmemdbg.h>
|
||
|
#include <gdbgtrk.h>
|
||
|
#include <gstrall.h>
|
||
|
#include <gcrcall.h>
|
||
|
|
||
|
#include <gmosqsh.h>
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
void SquishArea::lock() {
|
||
|
|
||
|
GFTRK("SquishLock");
|
||
|
|
||
|
if(NOT data->islocked) {
|
||
|
if(WideCanLock) {
|
||
|
long _tries = 0;
|
||
|
while(::lock(data->fhsqd, 0, 1) == -1) {
|
||
|
if(PopupLocked(++_tries, true, path()) == false) {
|
||
|
WideLog->ErrLock();
|
||
|
raw_close();
|
||
|
WideLog->printf("! A Squish msgbase file could not be locked.");
|
||
|
WideLog->printf(": %s.SQD.", path());
|
||
|
WideLog->ErrOSInfo();
|
||
|
LockErrorExit();
|
||
|
}
|
||
|
}
|
||
|
if(_tries)
|
||
|
PopupLocked(0, 0, NULL);
|
||
|
}
|
||
|
refresh();
|
||
|
data->islocked = true;
|
||
|
}
|
||
|
|
||
|
GFTRK(NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
void SquishArea::unlock() {
|
||
|
|
||
|
GFTRK("SquishUnlock");
|
||
|
|
||
|
if(WideCanLock AND data->islocked)
|
||
|
::unlock(data->fhsqd, 0, 1);
|
||
|
lseekset(data->fhsqd, 0);
|
||
|
write(data->fhsqd, &data->base, sizeof(SqshBase));
|
||
|
lseekset(data->fhsqi, 0);
|
||
|
write(data->fhsqi, data->idx, (uint)(data->base.totalmsgs*sizeof(SqshIdx)));
|
||
|
chsize(data->fhsqi, data->base.totalmsgs*sizeof(SqshIdx));
|
||
|
data->islocked = false;
|
||
|
|
||
|
GFTRK(NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
void SquishArea::read_frm(dword __offset, SqshFrm* __frm) {
|
||
|
|
||
|
lseekset(data->fhsqd, __offset);
|
||
|
read(data->fhsqd, __frm, sizeof(SqshFrm));
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
void SquishArea::write_frm(dword __offset, SqshFrm* __frm) {
|
||
|
|
||
|
lseekset(data->fhsqd, __offset);
|
||
|
write(data->fhsqd, __frm, sizeof(SqshFrm));
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
void SquishArea::upd_frm_next(dword __offset, SqshFrm* __frm, dword __next) {
|
||
|
|
||
|
if(__offset != SQFRAME_NULL) {
|
||
|
read_frm(__offset, __frm);
|
||
|
__frm->next = __next;
|
||
|
write_frm(__offset, __frm);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
void SquishArea::upd_frm_prev(dword __offset, SqshFrm* __frm, dword __prev) {
|
||
|
|
||
|
if(__offset != SQFRAME_NULL) {
|
||
|
read_frm(__offset, __frm);
|
||
|
__frm->prev = __prev;
|
||
|
write_frm(__offset, __frm);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
void SquishArea::add_to_free_chain(dword __delframe, SqshFrm* __delfrm) {
|
||
|
|
||
|
SqshBase& _base = data->base;
|
||
|
|
||
|
// Update free frame chain
|
||
|
if((_base.firstfreeframe == SQFRAME_NULL) or (_base.lastfreeframe == SQFRAME_NULL)) {
|
||
|
|
||
|
// No other free frames, so create new chain
|
||
|
_base.firstfreeframe = _base.lastfreeframe = __delframe;
|
||
|
__delfrm->prev = __delfrm->next = SQFRAME_NULL;
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
// Insert this frame into the chain
|
||
|
__delfrm->next = SQFRAME_NULL;
|
||
|
__delfrm->prev = _base.lastfreeframe;
|
||
|
SqshFrm _lastfrm;
|
||
|
upd_frm_next(_base.lastfreeframe, &_lastfrm, __delframe);
|
||
|
_base.lastfreeframe = __delframe;
|
||
|
}
|
||
|
|
||
|
// Write the deleted frame
|
||
|
__delfrm->type = SQFRAME_FREE;
|
||
|
//WideLog->printf("- Deleted frame 0x%08lX of length %lu.", __delframe, __delfrm->length);
|
||
|
write_frm(__delframe, __delfrm);
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
void SquishArea::delete_msg(uint __reln) {
|
||
|
|
||
|
GFTRK("SquishDeleteMsg");
|
||
|
|
||
|
int _was_locked = data->islocked;
|
||
|
if(NOT _was_locked)
|
||
|
lock();
|
||
|
|
||
|
// Setup some local variables for speed
|
||
|
SqshIdx* _idx = data->idx;
|
||
|
SqshBase& _base = data->base;
|
||
|
|
||
|
// Load the frame to be deleted
|
||
|
SqshFrm _delfrm;
|
||
|
dword _delframe = _idx[__reln].offset;
|
||
|
read_frm(_delframe, &_delfrm);
|
||
|
|
||
|
// Chain the previous and next frames together
|
||
|
SqshFrm _tmpfrm;
|
||
|
upd_frm_next(_delfrm.prev, &_tmpfrm, _delfrm.next);
|
||
|
upd_frm_prev(_delfrm.next, &_tmpfrm, _delfrm.prev);
|
||
|
|
||
|
// Update base data if the first or last frame was deleted
|
||
|
if(_delframe == _base.firstframe)
|
||
|
_base.firstframe = _delfrm.next;
|
||
|
if(_delframe == _base.lastframe)
|
||
|
_base.lastframe = _delfrm.prev;
|
||
|
|
||
|
// Add the deleted msg to the free frame chain
|
||
|
add_to_free_chain(_delframe, &_delfrm);
|
||
|
|
||
|
// Remove deleted message number from the indexes
|
||
|
Msgn->DelReln(__reln+1);
|
||
|
dword _tomove = _base.totalmsgs - __reln - 1;
|
||
|
memmove(_idx+__reln, _idx+__reln+1, (uint)(_tomove*sizeof(SqshIdx)));
|
||
|
|
||
|
// Update base data
|
||
|
_base.highestmsg--;
|
||
|
_base.totalmsgs--;
|
||
|
|
||
|
// Update area data
|
||
|
if(lastread)
|
||
|
lastread--;
|
||
|
|
||
|
if(NOT _was_locked)
|
||
|
unlock();
|
||
|
|
||
|
GFTRK(NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
void SquishArea::init_frm(SqshFrm* __frm) {
|
||
|
|
||
|
memset(__frm, 0, sizeof(SqshFrm));
|
||
|
__frm->type = SQFRAME_NORMAL;
|
||
|
__frm->id = SQFRAMEID;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
// Copy the text itself to a buffer, or count its length if out==NULL
|
||
|
|
||
|
uint CopyToBuf(char* p, char* out, char** end) {
|
||
|
|
||
|
if(out)
|
||
|
*out++ = CTRL_A;
|
||
|
|
||
|
uint len = 1;
|
||
|
|
||
|
while((*p==CR) or (*p==LF) or (not WideDispsoftcr and *p==SOFTCR))
|
||
|
p++;
|
||
|
|
||
|
while((*p==CTRL_A) or (strncmp(p, "AREA:", 5)==0)) {
|
||
|
|
||
|
// Skip over the first ^A
|
||
|
if(*p == CTRL_A)
|
||
|
p++;
|
||
|
|
||
|
while(*p and (*p != CR) and (*p != LF) and (WideDispsoftcr or *p!=SOFTCR)) {
|
||
|
if(out)
|
||
|
*out++ = *p;
|
||
|
len++;
|
||
|
p++;
|
||
|
}
|
||
|
|
||
|
if(out)
|
||
|
*out++ = CTRL_A;
|
||
|
|
||
|
len++;
|
||
|
|
||
|
while((*p==LF) or (not WideDispsoftcr and *p==SOFTCR))
|
||
|
p++;
|
||
|
if(*p == CR)
|
||
|
p++;
|
||
|
while((*p==LF) or (not WideDispsoftcr and *p==SOFTCR))
|
||
|
p++;
|
||
|
}
|
||
|
|
||
|
// Nul-term the string
|
||
|
if(out)
|
||
|
*out = NUL;
|
||
|
|
||
|
len++;
|
||
|
|
||
|
// Make sure to leave no trailing CTRL_A's.
|
||
|
if(out and (out[-1]==CTRL_A))
|
||
|
out[-1] = NUL;
|
||
|
|
||
|
|
||
|
// Now store the new end location of the kludge lines
|
||
|
if(end)
|
||
|
*end = p;
|
||
|
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
char* CopyToControlBuf(char* txt, char** newtext, uint* length) {
|
||
|
|
||
|
// Figure out how long the control info is
|
||
|
uint ctlsize = CopyToBuf(txt, NULL, NULL);
|
||
|
|
||
|
// Allocate memory for it
|
||
|
char* cbuf = (char*)throw_calloc(1, ctlsize+20);
|
||
|
|
||
|
// Now copy the text itself
|
||
|
char* end;
|
||
|
CopyToBuf(txt, cbuf, &end);
|
||
|
|
||
|
if(length)
|
||
|
*length -= (uint)(end-txt);
|
||
|
if(newtext)
|
||
|
*newtext = end;
|
||
|
|
||
|
return cbuf;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
void SquishArea::excess_frm(dword __lastframe, dword __newframe, SqshFrm* __newfrm, dword __totsize) {
|
||
|
|
||
|
// Is the excess length large enough for a frame and message header?
|
||
|
dword _excesslength = __newfrm->length - __totsize;
|
||
|
if(_excesslength >= sizeof(SqshFrm)) {
|
||
|
|
||
|
// Calculate frame offset of the excess frame
|
||
|
dword _exframe = __newframe + __totsize + sizeof(SqshFrm);
|
||
|
|
||
|
// Adjust base data if this becomes the last free frame
|
||
|
if(__lastframe == data->base.lastfreeframe)
|
||
|
data->base.lastfreeframe = _exframe;
|
||
|
|
||
|
// Setup the excess frame and write it
|
||
|
SqshFrm _exfrm;
|
||
|
init_frm(&_exfrm);
|
||
|
_exfrm.type = SQFRAME_FREE;
|
||
|
_exfrm.next = __newfrm->next;
|
||
|
_exfrm.prev = __newframe;
|
||
|
__newfrm->next = _exframe;
|
||
|
__newfrm->length = __totsize;
|
||
|
_exfrm.length = _excesslength - sizeof(SqshFrm);
|
||
|
write_frm(_exframe, &_exfrm);
|
||
|
SqshFrm _tmpfrm;
|
||
|
upd_frm_prev(_exfrm.next, &_tmpfrm, _exframe);
|
||
|
//WideLog->printf("- Created excess free frame 0x%08lX of length %lu.", _exframe, _exfrm.length);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
uint SquishArea::find_msgn(ulong __tagn) {
|
||
|
|
||
|
if(data->idx) {
|
||
|
|
||
|
register SqshIdx* tag = data->idx;
|
||
|
register uint tags = (uint)data->base.totalmsgs;
|
||
|
|
||
|
if(__tagn AND tags AND (__tagn > tag[tags-1].msgno))
|
||
|
return 0;
|
||
|
|
||
|
if(tags AND __tagn) {
|
||
|
|
||
|
register long _mid;
|
||
|
register long _left = 0;
|
||
|
register long _right = tags;
|
||
|
|
||
|
do {
|
||
|
_mid = (_left+_right)/2;
|
||
|
if(__tagn < tag[(uint)_mid].msgno)
|
||
|
_right = _mid - 1;
|
||
|
else if(__tagn > tag[(uint)_mid].msgno)
|
||
|
_left = _mid + 1;
|
||
|
else
|
||
|
return (uint)(_mid + 1);
|
||
|
} while(_left < _right);
|
||
|
|
||
|
if(__tagn == tag[(uint)_left].msgno)
|
||
|
return (uint)(_left + 1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
void SquishArea::save_message(int __mode, gmsg* __msg) {
|
||
|
|
||
|
SqshHdr __hdr;
|
||
|
int _was_locked = data->islocked;
|
||
|
if(not _was_locked)
|
||
|
lock();
|
||
|
|
||
|
// If not new, does the message still exist?
|
||
|
if((__mode & GMSG_NEW) or find_msgn(__msg->msgno)) {
|
||
|
|
||
|
uint _reln = (__mode & GMSG_NEW) ? 0 : (Msgn->ToReln(__msg->msgno) - 1);
|
||
|
|
||
|
// Reset header
|
||
|
memset(&__hdr, 0, sizeof(SqshHdr));
|
||
|
|
||
|
// Convert attributes
|
||
|
__hdr.attr |= MSGUID;
|
||
|
__hdr.attr |= __msg->attr.pvt() ? MSGPRIVATE : 0;
|
||
|
__hdr.attr |= __msg->attr.cra() ? MSGCRASH : 0;
|
||
|
__hdr.attr |= __msg->attr.rcv() ? MSGREAD : 0;
|
||
|
__hdr.attr |= __msg->attr.snt() ? MSGSENT : 0;
|
||
|
__hdr.attr |= __msg->attr.att() ? MSGFILE : 0;
|
||
|
__hdr.attr |= __msg->attr.trs() ? MSGFWD : 0;
|
||
|
__hdr.attr |= __msg->attr.orp() ? MSGORPHAN : 0;
|
||
|
__hdr.attr |= __msg->attr.k_s() ? MSGKILL : 0;
|
||
|
__hdr.attr |= __msg->attr.loc() ? MSGLOCAL : 0;
|
||
|
__hdr.attr |= __msg->attr.hld() ? MSGHOLD : 0;
|
||
|
__hdr.attr |= __msg->attr.rsv() ? MSGXX2 : 0;
|
||
|
__hdr.attr |= __msg->attr.frq() ? MSGFRQ : 0;
|
||
|
__hdr.attr |= __msg->attr.rrq() ? MSGRRQ : 0;
|
||
|
__hdr.attr |= __msg->attr.rrc() ? MSGCPT : 0;
|
||
|
__hdr.attr |= __msg->attr.arq() ? MSGARQ : 0;
|
||
|
__hdr.attr |= __msg->attr.urq() ? MSGURQ : 0;
|
||
|
__hdr.attr |= __msg->attr.prn() ? MSGPRINTED : 0;
|
||
|
__hdr.attr |= __msg->attr.lok() ? MSGLOK : 0;
|
||
|
__hdr.attr |= __msg->timesread ? MSGSEEN : 0;
|
||
|
|
||
|
if(__msg->attr.scn() and not __msg->attr.uns())
|
||
|
__hdr.attr |= MSGSCANNED;
|
||
|
|
||
|
if(__msg->attr.dir() and wide->direct)
|
||
|
__hdr.attr |= MSGCRASH | MSGHOLD;
|
||
|
|
||
|
memcpy(__hdr.from, __msg->by, 36);
|
||
|
memcpy(__hdr.to, __msg->to, 36);
|
||
|
memcpy(__hdr.subj, __msg->re, 72);
|
||
|
|
||
|
__hdr.orig.zone = __msg->oorig.zone;
|
||
|
__hdr.orig.net = __msg->oorig.net;
|
||
|
__hdr.orig.node = __msg->oorig.node;
|
||
|
__hdr.orig.point = __msg->oorig.point;
|
||
|
|
||
|
__hdr.dest.zone = __msg->odest.zone;
|
||
|
__hdr.dest.net = __msg->odest.net;
|
||
|
__hdr.dest.node = __msg->odest.node;
|
||
|
__hdr.dest.point = __msg->odest.point;
|
||
|
|
||
|
__hdr.replyto = __msg->link.to();
|
||
|
__hdr.replies[0] = __msg->link.first();
|
||
|
for(int r=1; r<=8; r++)
|
||
|
__hdr.replies[r] = __msg->link.list(r-1);
|
||
|
__hdr.umsgid = (__mode & GMSG_NEW) ? data->base.nextmsgno : __msg->msgno;
|
||
|
|
||
|
__hdr.date_written = TimeToFTime(__msg->written);
|
||
|
__hdr.date_arrived = TimeToFTime(__msg->arrived);
|
||
|
struct tm* _tm = gmtime(&__msg->written);
|
||
|
sprintf(__hdr.ftsc_date, "%02d %3s %02d %02d:%02d:%02d",
|
||
|
_tm->tm_mday, gmonths[_tm->tm_mon+1], _tm->tm_year % 100,
|
||
|
_tm->tm_hour, _tm->tm_min, _tm->tm_sec
|
||
|
);
|
||
|
|
||
|
// Setup some local variables for speed
|
||
|
int _fhsqd = data->fhsqd;
|
||
|
SqshIdx* _idx = data->idx;
|
||
|
SqshBase& _base = data->base;
|
||
|
dword _hash = strHash32(__hdr.to) | ((__hdr.attr & MSGREAD) ? 0x80000000LU : 0);
|
||
|
|
||
|
// Writing msg text?
|
||
|
if(__mode & GMSG_TXT) {
|
||
|
|
||
|
char* _txt = __msg->txt;
|
||
|
uint _usize = strlen(_txt) + 1;
|
||
|
char* _ctl = CopyToControlBuf(_txt, &_txt, &_usize);
|
||
|
dword _txtsize = strlen(_txt) + 1;
|
||
|
dword _ctlsize = strlen(_ctl) + 1;
|
||
|
dword _totsize = sizeof(SqshHdr) + _ctlsize + _txtsize;
|
||
|
|
||
|
SqshFrm _oldfrm, _newfrm;
|
||
|
dword _newframe = SQFRAME_NULL;
|
||
|
dword _oldframe = _idx ? _idx[_reln].offset : _base.endframe;
|
||
|
if(NOT(__mode & GMSG_NEW)) {
|
||
|
|
||
|
// Get the original frame and see if there is still room for the msg
|
||
|
read_frm(_oldframe, &_oldfrm);
|
||
|
if(_oldfrm.length >= _totsize) {
|
||
|
_newframe = _oldframe;
|
||
|
_newfrm = _oldfrm;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// It's a new message or the changed message doesn't fit
|
||
|
if(_newframe == SQFRAME_NULL) {
|
||
|
|
||
|
// If there is a max msgs limit and are we writing a new
|
||
|
// msg, delete msgs to (hopefully) make room for this msg
|
||
|
if(_base.maxmsgs AND (__mode & GMSG_NEW))
|
||
|
while(_base.maxmsgs <= _base.totalmsgs)
|
||
|
delete_msg((uint)_base.protmsgs);
|
||
|
|
||
|
// Locate a free frame, if possible
|
||
|
_newframe = _base.firstfreeframe;
|
||
|
//WideLog->printf("- Looking for a frame of at least length %lu.", _totsize);
|
||
|
while(1) {
|
||
|
|
||
|
// At end of free frames?
|
||
|
if(_newframe == SQFRAME_NULL) {
|
||
|
_newframe = _base.endframe;
|
||
|
init_frm(&_newfrm);
|
||
|
//WideLog->printf("- Allocated new frame 0x%08lX of length %lu.", _newframe, _totsize);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Is this frame large enough in itself?
|
||
|
read_frm(_newframe, &_newfrm);
|
||
|
//WideLog->printf("- Found free frame 0x%08lX of length %lu.", _newframe, _newfrm.length);
|
||
|
if(_newfrm.length >= _totsize) {
|
||
|
|
||
|
// Create excess frame if possible
|
||
|
if(wide->recycle == SQUISHRECYCLE_YES) {
|
||
|
excess_frm(_newframe, _newframe, &_newfrm, _totsize);
|
||
|
//WideLog->printf("- Frame was large enough (%lu bytes wasted).", _newfrm.length - _totsize);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// If two frames are adjacent, try to merge them to make more room
|
||
|
if(wide->recycle and (wide->recycle != SQUISHRECYCLE_MSGAPI2)) {
|
||
|
dword _lastframe = SQFRAME_NULL;
|
||
|
while((_newfrm.next == (_newframe+_newfrm.length+sizeof(SqshFrm))) and (_newfrm.length < _totsize)) {
|
||
|
SqshFrm _lastfrm;
|
||
|
read_frm(_newfrm.next, &_lastfrm);
|
||
|
_newfrm.length += _lastfrm.length + sizeof(SqshFrm);
|
||
|
//WideLog->printf("- Merged frames 0x%08lX and 0x%08lX. New length: %lu.", _newframe, _newfrm.next, _newfrm.length);
|
||
|
_lastframe = _newfrm.next;
|
||
|
_newfrm.next = _lastfrm.next;
|
||
|
}
|
||
|
|
||
|
// Did we get a large enough frame?
|
||
|
if(_newfrm.length >= _totsize) {
|
||
|
|
||
|
// Create excess frame if possible
|
||
|
if(wide->recycle == SQUISHRECYCLE_YES) {
|
||
|
excess_frm(_lastframe, _newframe, &_newfrm, _totsize);
|
||
|
//WideLog->printf("- Merged frame was large enough (%lu bytes wasted).", _newfrm.length - _totsize);
|
||
|
}
|
||
|
|
||
|
// If one of the frames in our chain was the last free frame,
|
||
|
// set the last free frame to the one we've merged it into,
|
||
|
// for later a clean up effort.
|
||
|
if(_lastframe == _base.lastfreeframe)
|
||
|
_base.lastfreeframe = _newframe;
|
||
|
|
||
|
// Got a free frame
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Go to next free frame and try again
|
||
|
_newframe = _newfrm.next;
|
||
|
}
|
||
|
|
||
|
// If this was the first frame (ie. the first one pointed to by
|
||
|
// firstfreeframe, which means that the first frame found was long
|
||
|
// enough to hold the message), then set the free pointer to the
|
||
|
// start of the new free chain.
|
||
|
if(_newframe == _base.firstfreeframe)
|
||
|
_base.firstfreeframe = _newfrm.next;
|
||
|
if(_newframe == _base.lastfreeframe)
|
||
|
_base.lastfreeframe = _newfrm.prev;
|
||
|
|
||
|
// Now update the linked list of free frames, to remove the current
|
||
|
// frame from the free-frame list, if necessary. We only need to do
|
||
|
// this if the current frame wasn't just being appended to the .SQD
|
||
|
// file, since there would be no links to update in that case.
|
||
|
if(_newframe != _base.endframe) {
|
||
|
SqshFrm _tmpfrm;
|
||
|
upd_frm_next(_newfrm.prev, &_tmpfrm, _newfrm.next);
|
||
|
upd_frm_prev(_newfrm.next, &_tmpfrm, _newfrm.prev);
|
||
|
}
|
||
|
|
||
|
if(__mode & GMSG_NEW) {
|
||
|
|
||
|
// Link the frame to the last frame
|
||
|
_newfrm.prev = _base.lastframe;
|
||
|
_newfrm.next = SQFRAME_NULL;
|
||
|
SqshFrm _tmpfrm;
|
||
|
upd_frm_next(_newfrm.prev, &_tmpfrm, _newframe);
|
||
|
if(_base.firstframe == SQFRAME_NULL)
|
||
|
_base.firstframe = _newframe;
|
||
|
_base.lastframe = _newframe;
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
// Rewriting old message
|
||
|
_newfrm.next = _oldfrm.next;
|
||
|
_newfrm.prev = _oldfrm.prev;
|
||
|
add_to_free_chain(_oldframe, &_oldfrm);
|
||
|
SqshFrm _tmpfrm;
|
||
|
upd_frm_next(_newfrm.prev, &_tmpfrm, _newframe);
|
||
|
upd_frm_prev(_newfrm.next, &_tmpfrm, _newframe);
|
||
|
if(_base.firstframe == _oldframe)
|
||
|
_base.firstframe = _newframe;
|
||
|
if(_base.lastframe == _oldframe)
|
||
|
_base.lastframe = _newframe;
|
||
|
}
|
||
|
|
||
|
// Set the frame length only if this is a brand new frame
|
||
|
if(_newframe == _base.endframe) {
|
||
|
_newfrm.length = _totsize;
|
||
|
_base.endframe += sizeof(SqshFrm) + _totsize;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set sizes in the frame
|
||
|
_newfrm.totsize = _totsize;
|
||
|
_newfrm.ctlsize = _ctlsize;
|
||
|
_newfrm.type = SQFRAME_NORMAL;
|
||
|
|
||
|
// Write frame, header, control info and message text
|
||
|
write_frm(_newframe, &_newfrm);
|
||
|
write(_fhsqd, &__hdr, sizeof(SqshHdr));
|
||
|
write(_fhsqd, _ctl, (uint)_ctlsize);
|
||
|
write(_fhsqd, _txt, (uint)_txtsize);
|
||
|
throw_free(_ctl);
|
||
|
|
||
|
// Update internal arrays if new
|
||
|
if(__mode & GMSG_NEW) {
|
||
|
_base.highestmsg++;
|
||
|
_reln = (uint)(_base.totalmsgs++);
|
||
|
__msg->msgno = _base.nextmsgno++;
|
||
|
Msgn->Append(__msg->msgno);
|
||
|
data->idx = _idx = (SqshIdx*)throw_realloc(data->idx, (uint)(_base.totalmsgs*sizeof(SqshIdx)));
|
||
|
}
|
||
|
|
||
|
// Update index
|
||
|
SqshIdx* _idxp = _idx + _reln;
|
||
|
_idxp->offset = _newframe;
|
||
|
_idxp->msgno = __msg->msgno;
|
||
|
_idxp->hash = _hash;
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
// Just update the header
|
||
|
_idx[_reln].hash = _hash;
|
||
|
lseekset(_fhsqd, _idx[_reln].offset+sizeof(SqshFrm));
|
||
|
write(_fhsqd, &__hdr, sizeof(SqshHdr));
|
||
|
}
|
||
|
|
||
|
// Adjust the highwatermark if required
|
||
|
if(__msg->attr.uns())
|
||
|
if(_base.highwatermark >= __msg->msgno)
|
||
|
_base.highwatermark = __msg->msgno - 1;
|
||
|
}
|
||
|
else {
|
||
|
scan();
|
||
|
}
|
||
|
|
||
|
if(not _was_locked)
|
||
|
unlock();
|
||
|
|
||
|
GFTRK(NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
void SquishArea::save_hdr(int __mode, gmsg* __msg) {
|
||
|
|
||
|
GFTRK("SquishSaveHdr");
|
||
|
|
||
|
save_message(__mode|GMSG_HDR, __msg);
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
void SquishArea::save_msg(int __mode, gmsg* __msg) {
|
||
|
|
||
|
GFTRK("SquishSaveMsg");
|
||
|
|
||
|
save_message(__mode|GMSG_HDRTXT, __msg);
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
void SquishArea::del_msg(gmsg* __msg) {
|
||
|
|
||
|
GFTRK("SquishDelMsg");
|
||
|
|
||
|
delete_msg(Msgn->ToReln(__msg->msgno)-1);
|
||
|
|
||
|
GFTRK(NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
void SquishArea::new_msgno(gmsg* __msg) {
|
||
|
|
||
|
__msg->msgno = data->base.nextmsgno;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
void SquishArea::update_timesread(gmsg* msg) {
|
||
|
|
||
|
GFTRK("SquishArea::update_timesread");
|
||
|
|
||
|
lock();
|
||
|
|
||
|
uint reln = Msgn->ToReln(msg->msgno) - 1;
|
||
|
|
||
|
dword frame = data->idx[reln].offset;
|
||
|
|
||
|
SqshHdr hdr;
|
||
|
::lseekset(data->fhsqd, frame+sizeof(SqshFrm));
|
||
|
::read(data->fhsqd, &hdr, sizeof(SqshHdr));
|
||
|
|
||
|
hdr.attr |= msg->timesread ? MSGSEEN : 0;
|
||
|
|
||
|
::lseekset(data->fhsqd, frame+sizeof(SqshFrm));
|
||
|
::write(data->fhsqd, &hdr, sizeof(SqshHdr));
|
||
|
|
||
|
unlock();
|
||
|
|
||
|
GFTRK(NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|