1 //  This may look like C code, but it is really -*- C++ -*-
2 
3 //  ------------------------------------------------------------------
4 //  The Goldware Library
5 //  Copyright (C) 1990-1999 Odinn Sorensen
6 //  ------------------------------------------------------------------
7 //  This library is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU Library General Public
9 //  License as published by the Free Software Foundation; either
10 //  version 2 of the License, or (at your option) any later version.
11 //
12 //  This library is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 //  Library General Public License for more details.
16 //
17 //  You should have received a copy of the GNU Library General Public
18 //  License along with this program; if not, write to the Free
19 //  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 //  MA 02111-1307, USA
21 //  ------------------------------------------------------------------
22 //  $Id: gmosqsh4.cpp,v 1.8 2008/01/20 14:46:15 stas_degteff Exp $
23 //  ------------------------------------------------------------------
24 //  Squish msgbase handling and Maximus user functions.
25 //  ------------------------------------------------------------------
26 
27 
28 //  ------------------------------------------------------------------
29 
30 #include <gdbgerr.h>
31 #include <gmemdbg.h>
32 #include <gdbgtrk.h>
33 #include <gstrall.h>
34 #include <gcrcall.h>
35 
36 #include <gmosqsh.h>
37 
38 
39 //  ------------------------------------------------------------------
40 
lock()41 void SquishArea::lock() {
42 
43   GFTRK("SquishLock");
44 
45   if(not data->islocked) {
46     if(WideCanLock) {
47       long _tries = 0;
48       while(::lock(data->fhsqd, 0, 1) == -1) {
49         if(PopupLocked(++_tries, true, real_path()) == false) {
50           WideLog->ErrLock();
51           raw_close();
52           WideLog->printf("! A Squish msgbase file could not be locked.");
53           WideLog->printf(": %s.sqd.", real_path());
54           WideLog->ErrOSInfo();
55           LockErrorExit();
56         }
57       }
58       if(_tries)
59         PopupLocked(0, 0, NULL);
60     }
61     refresh();
62     data->islocked = true;
63   }
64 
65   GFTRK(0);
66 }
67 
68 
69 //  ------------------------------------------------------------------
70 
unlock()71 void SquishArea::unlock() {
72 
73   GFTRK("SquishUnlock");
74 
75   if(WideCanLock and data->islocked)
76     ::unlock(data->fhsqd, 0, 1);
77   lseekset(data->fhsqd, 0);
78   write(data->fhsqd, &data->base, sizeof(SqshBase));
79   lseekset(data->fhsqi, 0);
80   write(data->fhsqi, data->idx, (uint)(data->base.totalmsgs*sizeof(SqshIdx)));
81   chsize(data->fhsqi, data->base.totalmsgs*sizeof(SqshIdx));
82   data->islocked = false;
83 
84   GFTRK(0);
85 }
86 
87 
88 //  ------------------------------------------------------------------
89 
read_frm(dword __offset,SqshFrm * __frm)90 void SquishArea::read_frm(dword __offset, SqshFrm* __frm) {
91 
92   lseekset(data->fhsqd, __offset);
93   read(data->fhsqd, __frm, sizeof(SqshFrm));
94 }
95 
96 
97 //  ------------------------------------------------------------------
98 
write_frm(dword __offset,SqshFrm * __frm)99 void SquishArea::write_frm(dword __offset, SqshFrm* __frm) {
100 
101   lseekset(data->fhsqd, __offset);
102   write(data->fhsqd, __frm, sizeof(SqshFrm));
103 }
104 
105 
106 //  ------------------------------------------------------------------
107 
upd_frm_next(dword __offset,SqshFrm * __frm,dword __next)108 void SquishArea::upd_frm_next(dword __offset, SqshFrm* __frm, dword __next) {
109 
110   if(__offset != SQFRAME_NULL) {
111     read_frm(__offset, __frm);
112     __frm->next = __next;
113     write_frm(__offset, __frm);
114   }
115 }
116 
117 
118 //  ------------------------------------------------------------------
119 
upd_frm_prev(dword __offset,SqshFrm * __frm,dword __prev)120 void SquishArea::upd_frm_prev(dword __offset, SqshFrm* __frm, dword __prev) {
121 
122   if(__offset != SQFRAME_NULL) {
123     read_frm(__offset, __frm);
124     __frm->prev = __prev;
125     write_frm(__offset, __frm);
126   }
127 }
128 
129 
130 //  ------------------------------------------------------------------
131 
add_to_free_chain(dword __delframe,SqshFrm * __delfrm)132 void SquishArea::add_to_free_chain(dword __delframe, SqshFrm* __delfrm) {
133 
134   SqshBase& _base = data->base;
135 
136   // Update free frame chain
137   if((_base.firstfreeframe == SQFRAME_NULL) or (_base.lastfreeframe == SQFRAME_NULL)) {
138 
139     // No other free frames, so create new chain
140     _base.firstfreeframe = _base.lastfreeframe = __delframe;
141     __delfrm->prev = __delfrm->next = SQFRAME_NULL;
142   }
143   else {
144 
145     // Insert this frame into the chain
146     __delfrm->next = SQFRAME_NULL;
147     __delfrm->prev = _base.lastfreeframe;
148     SqshFrm _lastfrm;
149     upd_frm_next(_base.lastfreeframe, &_lastfrm, __delframe);
150     _base.lastfreeframe = __delframe;
151   }
152 
153   // Write the deleted frame
154   __delfrm->type = SQFRAME_FREE;
155   //WideLog->printf("- Deleted frame 0x%08X of length %u.", __delframe, __delfrm->length);
156   write_frm(__delframe, __delfrm);
157 }
158 
159 
160 //  ------------------------------------------------------------------
161 
delete_msg(uint __reln)162 void SquishArea::delete_msg(uint __reln) {
163 
164   GFTRK("SquishDeleteMsg");
165 
166   int _was_locked = data->islocked;
167   if(not _was_locked)
168     lock();
169 
170   // Setup some local variables for speed
171   SqshIdx* _idx = data->idx;
172   SqshBase& _base = data->base;
173 
174   // Load the frame to be deleted
175   SqshFrm _delfrm;
176   dword _delframe = _idx[__reln].offset;
177   read_frm(_delframe, &_delfrm);
178 
179   // Chain the previous and next frames together
180   SqshFrm _tmpfrm;
181   upd_frm_next(_delfrm.prev, &_tmpfrm, _delfrm.next);
182   upd_frm_prev(_delfrm.next, &_tmpfrm, _delfrm.prev);
183 
184   // Update base data if the first or last frame was deleted
185   if(_delframe == _base.firstframe)
186     _base.firstframe = _delfrm.next;
187   if(_delframe == _base.lastframe)
188     _base.lastframe = _delfrm.prev;
189 
190   // Add the deleted msg to the free frame chain
191   add_to_free_chain(_delframe, &_delfrm);
192 
193   // Remove deleted message number from the indexes
194   Msgn->DelReln(__reln+1);
195   dword _tomove = _base.totalmsgs - __reln - 1;
196   memmove(_idx+__reln, _idx+__reln+1, (uint)(_tomove*sizeof(SqshIdx)));
197 
198   // Update base data
199   _base.highestmsg--;
200   _base.totalmsgs--;
201 
202   // Update area data
203   if(lastread)
204     lastread--;
205 
206   if(not _was_locked)
207     unlock();
208 
209   GFTRK(0);
210 }
211 
212 
213 //  ------------------------------------------------------------------
214 
init_frm(SqshFrm * __frm)215 void SquishArea::init_frm(SqshFrm* __frm) {
216 
217   memset(__frm, 0, sizeof(SqshFrm));
218   __frm->type = SQFRAME_NORMAL;
219   __frm->id = SQFRAMEID;
220 }
221 
222 
223 //  ------------------------------------------------------------------
224 //  Copy the text itself to a buffer, or count its length if out==NULL
225 
CopyToBuf(char * p,char * out,char ** end)226 uint CopyToBuf(char* p, char* out, char** end) {
227 
228   if(out)
229     *out++ = CTRL_A;
230 
231   uint len = 1;
232 
233   while((*p==CR) or (*p==LF) or issoftcr(*p))
234     p++;
235 
236   while((*p==CTRL_A) or (strncmp(p, "AREA:", 5)==0)) {
237 
238     // Skip over the first ^A
239     if(*p == CTRL_A)
240       p++;
241 
242     while(*p and (*p != CR) and (*p != LF) and !issoftcr(*p)) {
243       if(out)
244         *out++ = *p;
245       len++;
246       p++;
247     }
248 
249     if(out)
250       *out++ = CTRL_A;
251 
252     len++;
253 
254     while((*p==LF) or issoftcr(*p))
255       p++;
256     if(*p == CR)
257       p++;
258     while((*p==LF) or issoftcr(*p))
259       p++;
260   }
261 
262   // Nul-term the string
263   if(out)
264     *out = NUL;
265 
266   len++;
267 
268   // Make sure to leave no trailing CTRL_A's.
269   if(out and (out[-1]==CTRL_A))
270     out[-1] = NUL;
271 
272 
273   // Now store the new end location of the kludge lines
274   if(end)
275     *end = p;
276 
277   return len;
278 }
279 
280 
281 //  ------------------------------------------------------------------
282 
CopyToControlBuf(char * txt,char ** newtext,uint * length)283 char* CopyToControlBuf(char* txt, char** newtext, uint* length) {
284 
285   // Figure out how int32_t the control info is
286   uint ctlsize = CopyToBuf(txt, NULL, NULL);
287 
288   // Allocate memory for it
289   char* cbuf = (char*)throw_calloc(1, ctlsize+20);
290 
291   // Now copy the text itself
292   char* end;
293   CopyToBuf(txt, cbuf, &end);
294 
295   if(length)
296     *length -= (uint)(end-txt);
297   if(newtext)
298     *newtext = end;
299 
300   return cbuf;
301 }
302 
303 
304 //  ------------------------------------------------------------------
305 
excess_frm(dword __lastframe,dword __newframe,SqshFrm * __newfrm,dword __totsize)306 void SquishArea::excess_frm(dword __lastframe, dword __newframe, SqshFrm* __newfrm, dword __totsize) {
307 
308   // Is the excess length large enough for a frame and message header?
309   dword _excesslength = __newfrm->length - __totsize;
310   if(_excesslength >= sizeof(SqshFrm)) {
311 
312     // Calculate frame offset of the excess frame
313     dword _exframe = __newframe + __totsize + sizeof(SqshFrm);
314 
315     // Adjust base data if this becomes the last free frame
316     if(__lastframe == data->base.lastfreeframe)
317       data->base.lastfreeframe = _exframe;
318 
319     // Setup the excess frame and write it
320     SqshFrm _exfrm;
321     init_frm(&_exfrm);
322     _exfrm.type = SQFRAME_FREE;
323     _exfrm.next = __newfrm->next;
324     _exfrm.prev = __newframe;
325     __newfrm->next = _exframe;
326     __newfrm->length = __totsize;
327     _exfrm.length = _excesslength - sizeof(SqshFrm);
328     write_frm(_exframe, &_exfrm);
329     SqshFrm _tmpfrm;
330     upd_frm_prev(_exfrm.next, &_tmpfrm, _exframe);
331     //WideLog->printf("- Created excess free frame 0x%08X of length %u.", _exframe, _exfrm.length);
332   }
333 }
334 
335 
336 //  ------------------------------------------------------------------
337 
find_msgn(uint32_t __tagn)338 uint SquishArea::find_msgn(uint32_t __tagn) {
339 
340   if(data->idx) {
341 
342     register SqshIdx* tag = data->idx;
343     register uint tags = (uint)data->base.totalmsgs;
344 
345     if(__tagn and tags and (__tagn > tag[tags-1].msgno))
346       return 0;
347 
348     if(tags and __tagn) {
349 
350       register int32_t _mid;
351       register int32_t _left = 0;
352       register int32_t _right = tags;
353 
354       do {
355         _mid = (_left+_right)/2;
356         if(__tagn < tag[(uint)_mid].msgno)
357           _right = _mid - 1;
358         else if(__tagn > tag[(uint)_mid].msgno)
359           _left = _mid + 1;
360         else
361           return (uint)(_mid + 1);
362       } while(_left < _right);
363 
364       if(__tagn == tag[(uint)_left].msgno)
365         return (uint)(_left + 1);
366     }
367   }
368 
369   return 0;
370 }
371 
372 
373 //  ------------------------------------------------------------------
374 
save_message(int __mode,gmsg * __msg)375 void SquishArea::save_message(int __mode, gmsg* __msg) {
376 
377   SqshHdr __hdr;
378   int _was_locked = data->islocked;
379   if(not _was_locked)
380     lock();
381 
382   // If not new, does the message still exist?
383   if((__mode & GMSG_NEW) or find_msgn(__msg->msgno)) {
384 
385     uint _reln = (__mode & GMSG_NEW) ? 0 : (Msgn->ToReln(__msg->msgno) - 1);
386 
387     // Reset header
388     memset(&__hdr, 0, sizeof(SqshHdr));
389 
390     // Convert attributes
391     __hdr.attr |= MSGUID;
392     __hdr.attr |= __msg->attr.pvt() ? MSGPRIVATE : 0;
393     __hdr.attr |= __msg->attr.cra() ? MSGCRASH   : 0;
394     __hdr.attr |= __msg->attr.rcv() ? MSGREAD    : 0;
395     __hdr.attr |= __msg->attr.snt() ? MSGSENT    : 0;
396     __hdr.attr |= __msg->attr.att() ? MSGFILE    : 0;
397     __hdr.attr |= __msg->attr.trs() ? MSGFWD     : 0;
398     __hdr.attr |= __msg->attr.orp() ? MSGORPHAN  : 0;
399     __hdr.attr |= __msg->attr.k_s() ? MSGKILL    : 0;
400     __hdr.attr |= __msg->attr.loc() ? MSGLOCAL   : 0;
401     __hdr.attr |= __msg->attr.hld() ? MSGHOLD    : 0;
402     __hdr.attr |= __msg->attr.rsv() ? MSGXX2     : 0;
403     __hdr.attr |= __msg->attr.frq() ? MSGFRQ     : 0;
404     __hdr.attr |= __msg->attr.rrq() ? MSGRRQ     : 0;
405     __hdr.attr |= __msg->attr.rrc() ? MSGCPT     : 0;
406     __hdr.attr |= __msg->attr.arq() ? MSGARQ     : 0;
407     __hdr.attr |= __msg->attr.urq() ? MSGURQ     : 0;
408     __hdr.attr |= __msg->attr.prn() ? MSGPRINTED : 0;
409     __hdr.attr |= __msg->attr.lok() ? MSGLOK     : 0;
410     __hdr.attr |= __msg->timesread  ? MSGSEEN    : 0;
411 
412     if(__msg->attr.scn() and not __msg->attr.uns())
413       __hdr.attr |= MSGSCANNED;
414 
415     if(__msg->attr.dir() and wide->direct)
416       __hdr.attr |= MSGCRASH | MSGHOLD;
417 
418     memcpy(__hdr.from, __msg->by, 36);
419     memcpy(__hdr.to,   __msg->to, 36);
420     memcpy(__hdr.subj, __msg->re, 72);
421 
422     __hdr.orig.zone  = __msg->oorig.zone;
423     __hdr.orig.net   = __msg->oorig.net;
424     __hdr.orig.node  = __msg->oorig.node;
425     __hdr.orig.point = __msg->oorig.point;
426 
427     __hdr.dest.zone  = __msg->odest.zone;
428     __hdr.dest.net   = __msg->odest.net;
429     __hdr.dest.node  = __msg->odest.node;
430     __hdr.dest.point = __msg->odest.point;
431 
432     __hdr.replyto    = __msg->link.to();
433     __hdr.replies[0] = __msg->link.first();
434     for(int r=1; r<=8; r++)
435       __hdr.replies[r] = __msg->link.list(r-1);
436     __hdr.umsgid = (__mode & GMSG_NEW) ? data->base.nextmsgno : __msg->msgno;
437 
438     __hdr.date_written = TimeToFTime(__msg->written);
439     __hdr.date_arrived = TimeToFTime(__msg->arrived);
440 
441     struct tm _tm; ggmtime(&_tm, &__msg->written);
442     sprintf(__hdr.ftsc_date, "%02d %3s %02d  %02d:%02d:%02d",
443         _tm.tm_mday, gmonths[_tm.tm_mon + 1], _tm.tm_year % 100,
444         _tm.tm_hour, _tm.tm_min, _tm.tm_sec
445       );
446 
447     // Setup some local variables for speed
448     int _fhsqd = data->fhsqd;
449     SqshIdx* _idx = data->idx;
450     SqshBase& _base = data->base;
451     dword _hash = strHash32(__hdr.to) | ((__hdr.attr & MSGREAD) ? 0x80000000LU : 0);
452 
453     // Writing msg text?
454     if(__mode & GMSG_TXT) {
455 
456       char* _txt = __msg->txt;
457       uint _usize = strlen(_txt) + 1;
458       char* _ctl = CopyToControlBuf(_txt, &_txt, &_usize);
459       dword _txtsize = strlen(_txt) + 1;
460       dword _ctlsize = strlen(_ctl) + 1;
461       dword _totsize = sizeof(SqshHdr) + _ctlsize + _txtsize;
462 
463       SqshFrm _oldfrm, _newfrm;
464       dword _newframe = SQFRAME_NULL;
465       dword _oldframe = _idx ? _idx[_reln].offset : _base.endframe;
466       if(not (__mode & GMSG_NEW)) {
467 
468         // Get the original frame and see if there is still room for the msg
469         read_frm(_oldframe, &_oldfrm);
470         if(_oldfrm.length >= _totsize) {
471           _newframe = _oldframe;
472           _newfrm = _oldfrm;
473         }
474       }
475 
476       // It's a new message or the changed message doesn't fit
477       if(_newframe == SQFRAME_NULL) {
478 
479         // If there is a max msgs limit and are we writing a new
480         // msg, delete msgs to (hopefully) make room for this msg
481         if(_base.maxmsgs and (__mode & GMSG_NEW))
482           while(_base.maxmsgs <= _base.totalmsgs)
483             delete_msg((uint)_base.protmsgs);
484 
485         // Locate a free frame, if possible
486         _newframe = _base.firstfreeframe;
487         //WideLog->printf("- Looking for a frame of at least length %u.", _totsize);
488         while(1) {
489 
490           // At end of free frames?
491           if(_newframe == SQFRAME_NULL) {
492             _newframe = _base.endframe;
493             init_frm(&_newfrm);
494             //WideLog->printf("- Allocated new frame 0x%08X of length %u.", _newframe, _totsize);
495             break;
496           }
497 
498           // Is this frame large enough in itself?
499           read_frm(_newframe, &_newfrm);
500           //WideLog->printf("- Found free frame 0x%08X of length %u.", _newframe, _newfrm.length);
501           if(_newfrm.length >= _totsize) {
502 
503             // Create excess frame if possible
504             if(wide->recycle == SQUISHRECYCLE_YES) {
505               excess_frm(_newframe, _newframe, &_newfrm, _totsize);
506               //WideLog->printf("- Frame was large enough (%u bytes wasted).", _newfrm.length - _totsize);
507             }
508             break;
509           }
510 
511           // If two frames are adjacent, try to merge them to make more room
512           if(wide->recycle and (wide->recycle != SQUISHRECYCLE_MSGAPI2)) {
513             dword _lastframe = SQFRAME_NULL;
514             while((_newfrm.next == (_newframe+_newfrm.length+sizeof(SqshFrm))) and (_newfrm.length < _totsize)) {
515               SqshFrm _lastfrm;
516               read_frm(_newfrm.next, &_lastfrm);
517               _newfrm.length += _lastfrm.length + sizeof(SqshFrm);
518               //WideLog->printf("- Merged frames 0x%08X and 0x%08X. New length: %u.", _newframe, _newfrm.next, _newfrm.length);
519               _lastframe = _newfrm.next;
520               _newfrm.next = _lastfrm.next;
521             }
522 
523             // Did we get a large enough frame?
524             if(_newfrm.length >= _totsize) {
525 
526               // Create excess frame if possible
527               if(wide->recycle == SQUISHRECYCLE_YES) {
528                 excess_frm(_lastframe, _newframe, &_newfrm, _totsize);
529                 //WideLog->printf("- Merged frame was large enough (%u bytes wasted).", _newfrm.length - _totsize);
530               }
531 
532               // If one of the frames in our chain was the last free frame,
533               // set the last free frame to the one we've merged it into,
534               // for later a clean up effort.
535               if(_lastframe == _base.lastfreeframe)
536                 _base.lastfreeframe = _newframe;
537 
538               // Got a free frame
539               break;
540             }
541           }
542 
543           // Go to next free frame and try again
544           _newframe = _newfrm.next;
545         }
546 
547         // If this was the first frame (ie. the first one pointed to by
548         // firstfreeframe, which means that the first frame found was int32_t
549         // enough to hold the message), then set the free pointer to the
550         // start of the new free chain.
551         if(_newframe == _base.firstfreeframe)
552           _base.firstfreeframe = _newfrm.next;
553         if(_newframe == _base.lastfreeframe)
554           _base.lastfreeframe = _newfrm.prev;
555 
556         // Now update the linked list of free frames, to remove the current
557         // frame from the free-frame list, if necessary.  We only need to do
558         // this if the current frame wasn't just being appended to the .SQD
559         // file, since there would be no links to update in that case.
560         if(_newframe != _base.endframe) {
561           SqshFrm _tmpfrm;
562           upd_frm_next(_newfrm.prev, &_tmpfrm, _newfrm.next);
563           upd_frm_prev(_newfrm.next, &_tmpfrm, _newfrm.prev);
564         }
565 
566         if(__mode & GMSG_NEW) {
567 
568           // Link the frame to the last frame
569           _newfrm.prev = _base.lastframe;
570           _newfrm.next = SQFRAME_NULL;
571           SqshFrm _tmpfrm;
572           upd_frm_next(_newfrm.prev, &_tmpfrm, _newframe);
573           if(_base.firstframe == SQFRAME_NULL)
574             _base.firstframe = _newframe;
575           _base.lastframe = _newframe;
576         }
577         else {
578 
579           // Rewriting old message
580           _newfrm.next = _oldfrm.next;
581           _newfrm.prev = _oldfrm.prev;
582           add_to_free_chain(_oldframe, &_oldfrm);
583           SqshFrm _tmpfrm;
584           upd_frm_next(_newfrm.prev, &_tmpfrm, _newframe);
585           upd_frm_prev(_newfrm.next, &_tmpfrm, _newframe);
586           if(_base.firstframe == _oldframe)
587             _base.firstframe = _newframe;
588           if(_base.lastframe == _oldframe)
589             _base.lastframe = _newframe;
590         }
591 
592         // Set the frame length only if this is a brand new frame
593         if(_newframe == _base.endframe) {
594           _newfrm.length = _totsize;
595           _base.endframe += sizeof(SqshFrm) + _totsize;
596         }
597       }
598 
599       // Set sizes in the frame
600       _newfrm.totsize = _totsize;
601       _newfrm.ctlsize = _ctlsize;
602       _newfrm.type = SQFRAME_NORMAL;
603 
604       // Write frame, header, control info and message text
605       write_frm(_newframe, &_newfrm);
606       write(_fhsqd, &__hdr, sizeof(SqshHdr));
607       write(_fhsqd, _ctl, (uint)_ctlsize);
608       write(_fhsqd, _txt, (uint)_txtsize);
609       throw_free(_ctl);
610 
611       // Update internal arrays if new
612       if(__mode & GMSG_NEW) {
613         _base.highestmsg++;
614         _reln = (uint)(_base.totalmsgs++);
615         __msg->msgno = _base.nextmsgno++;
616         Msgn->Append(__msg->msgno);
617         data->idx = _idx = (SqshIdx*)throw_realloc(data->idx, (uint)(_base.totalmsgs*sizeof(SqshIdx)));
618       }
619 
620       // Update index
621       SqshIdx* _idxp = _idx + _reln;
622       _idxp->offset = _newframe;
623       _idxp->msgno = __msg->msgno;
624       _idxp->hash = _hash;
625     }
626     else {
627 
628       // Just update the header
629       _idx[_reln].hash = _hash;
630       lseekset(_fhsqd, _idx[_reln].offset+sizeof(SqshFrm));
631       write(_fhsqd, &__hdr, sizeof(SqshHdr));
632     }
633 
634     // Adjust the highwatermark if required
635     if(__msg->attr.uns())
636       if(_base.highwatermark >= __msg->msgno)
637         _base.highwatermark = __msg->msgno - 1;
638   }
639   else {
640     scan();
641   }
642 
643   if(not _was_locked)
644     unlock();
645 
646   GFTRK(0);
647 }
648 
649 
650 //  ------------------------------------------------------------------
651 
save_hdr(int __mode,gmsg * __msg)652 void SquishArea::save_hdr(int __mode, gmsg* __msg) {
653 
654   GFTRK("SquishSaveHdr");
655 
656   save_message(__mode|GMSG_HDR, __msg);
657 }
658 
659 
660 //  ------------------------------------------------------------------
661 
save_msg(int __mode,gmsg * __msg)662 void SquishArea::save_msg(int __mode, gmsg* __msg) {
663 
664   GFTRK("SquishSaveMsg");
665 
666   save_message(__mode|GMSG_HDRTXT, __msg);
667 }
668 
669 
670 //  ------------------------------------------------------------------
671 
del_msg(gmsg * __msg)672 void SquishArea::del_msg(gmsg* __msg) {
673 
674   GFTRK("SquishDelMsg");
675 
676   delete_msg(Msgn->ToReln(__msg->msgno)-1);
677 
678   GFTRK(0);
679 }
680 
681 
682 //  ------------------------------------------------------------------
683 
new_msgno(gmsg * __msg)684 void SquishArea::new_msgno(gmsg* __msg) {
685 
686   __msg->msgno = data->base.nextmsgno;
687 }
688 
689 
690 //  ------------------------------------------------------------------
691 
update_timesread(gmsg * msg)692 void SquishArea::update_timesread(gmsg* msg) {
693 
694   GFTRK("SquishArea::update_timesread");
695 
696   lock();
697 
698   uint reln = Msgn->ToReln(msg->msgno) - 1;
699 
700   dword frame = data->idx[reln].offset;
701 
702   SqshHdr hdr;
703   ::lseekset(data->fhsqd, frame+sizeof(SqshFrm));
704   ::read(data->fhsqd, &hdr, sizeof(SqshHdr));
705 
706   hdr.attr |= msg->timesread ? MSGSEEN : 0;
707 
708   ::lseekset(data->fhsqd, frame+sizeof(SqshFrm));
709   ::write(data->fhsqd, &hdr, sizeof(SqshHdr));
710 
711   unlock();
712 
713   GFTRK(0);
714 }
715 
716 
717 //  ------------------------------------------------------------------
718 
719