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