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 //  Copyright (C) 1999-2000 Alex. S. Aganichev
7 //  ------------------------------------------------------------------
8 //  This library is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU Library General Public
10 //  License as published by the Free Software Foundation; either
11 //  version 2 of the License, or (at your option) any later version.
12 //
13 //  This library is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 //  Library General Public License for more details.
17 //
18 //  You should have received a copy of the GNU Library General Public
19 //  License along with this program; if not, write to the Free
20 //  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 //  MA 02111-1307, USA
22 //  ------------------------------------------------------------------
23 //  $Id: gmohuds2.cpp,v 1.6 2011/12/17 21:46:02 stas_degteff Exp $
24 //  ------------------------------------------------------------------
25 //  Hudson / Goldbase msgbase handling
26 //  ------------------------------------------------------------------
27 
28 
29 //  ------------------------------------------------------------------
30 
31 template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
raw_close()32 void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::raw_close()
33 {
34   GFTRK("HudsRawClose");
35 
36   fhtxt.Close();
37   fhhdr.Close();
38   fhidx.Close();
39   fhinf.Close();
40   fhlrd.Close();
41   fhtoi.Close();
42   fhusr.Close();
43 
44   GFTRK(0);
45 }
46 
47 
48 //  ------------------------------------------------------------------
49 
50 template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
test_open(gfile & __file,const char * __fname,int __oaccess)51 void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::test_open(gfile &__file, const char* __fname, int __oaccess)
52 {
53   GFTRK("HudsTestOpen");
54 
55   long _tries = 0;
56   __oaccess |= O_RDWR|O_BINARY;
57 
58   do
59   {
60     Path _testfn;
61     strcpy(_testfn, AddPath(path, __fname));
62     int _omode = (__oaccess & O_CREAT) ? S_STDRW : S_STDRD;
63 
64     __file.Open(_testfn, __oaccess, WideSharemode, _omode);
65     if (!__file.isopen())
66     {
67       if (errno == ENOENT)
68       {
69         if (_tries == 0)
70         {
71           __oaccess |= O_CREAT;
72           _tries++;
73           continue;
74         }
75       }
76 
77       // Request the other program to unlock
78       if (errno != ENOENT)
79         TouchFile(AddPath(path, "mbunlock.now"));
80 
81       // Tell the world
82       if (PopupLocked(++_tries, false, _testfn) == false)
83       {
84         // User requested to exit
85         WideLog->ErrOpen();
86         raw_close();
87         WideLog->printf("! A %s msgbase file could not be opened.", __HUDSON ? HUDS_NAME : GOLD_NAME);
88         WideLog->printf(": %s.", _testfn);
89         WideLog->ErrOSInfo();
90         OpenErrorExit();
91       }
92     }
93   }
94   while (!__file.isopen());
95 
96   // Remove the popup window
97   if (_tries)
98     PopupLocked(0, 0, NULL);
99 
100   GFTRK(0);
101 }
102 
103 
104 //  ------------------------------------------------------------------
105 
106 template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
raw_open(int __oaccess,int __all)107 void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::raw_open(int __oaccess, int __all) {
108 
109   GFTRK("HudsRawOpen");
110 
111   test_open(fhidx, __HUDSON ? "msgidx" HUDS_EXT : "msgidx" GOLD_EXT, __oaccess);
112   test_open(fhinf, __HUDSON ? "msginfo" HUDS_EXT : "msginfo" GOLD_EXT, __oaccess);
113   test_open(fhlrd, __HUDSON ? "lastread" HUDS_EXT : "lastread" GOLD_EXT, __oaccess);
114   test_open(fhtoi, __HUDSON ? "msgtoidx" HUDS_EXT : "msgtoidx" GOLD_EXT, __oaccess);
115   if (__all)
116   {
117     test_open(fhhdr, __HUDSON ? "msghdr" HUDS_EXT : "msghdr" GOLD_EXT, __oaccess);
118     test_open(fhtxt, __HUDSON ? "msgtxt" HUDS_EXT : "msgtxt" GOLD_EXT, __oaccess);
119     test_open(fhusr, __HUDSON ? "users" HUDS_EXT : "users" GOLD_EXT, __oaccess);
120   }
121 
122   GFTRK(0);
123 }
124 
125 
126 //  ------------------------------------------------------------------
127 
128 template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
raw_open_scan()129 void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::raw_open_scan() {
130 
131   GFTRK("HudsRawOpenScan");
132 
133   raw_open(0, false);
134 
135   GFTRK(0);
136 }
137 
138 
139 //  ------------------------------------------------------------------
140 
141 template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
refresh()142 void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::refresh() {
143 
144   GFTRK("HudsRefresh");
145 
146   // (Re)Allocate memory to hold the complete MSGIDX.BBS/DAT
147   msgidxsize = fhidx.FileLength();
148   msgidxptr = (HudsIdx*)throw_realloc(msgidxptr, (uint)(msgidxsize+sizeof(HudsIdx)));
149 
150   // Load MSGIDX.BBS/DAT
151   fhidx.LseekSet(0);
152   fhidx.Read(msgidxptr, (uint)msgidxsize);
153 
154   // Load MSGINFO.BBS/DAT
155   fhinf.LseekSet(0);
156   fhinf.Read(&msginfo, sizeof(HudsInfo));
157 
158   // Load LASTREAD.BBS/DAT
159   fhlrd.LseekSet(userno*sizeof(HudsLast));
160   fhlrd.Read(lastrec, sizeof(HudsLast));
161 
162   GFTRK(0);
163 }
164 
165 
166 //  ------------------------------------------------------------------
167 
168 template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
open()169 void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::open() {
170 
171   GFTRK("HudsWideOpen");
172 
173   isopen = 1;
174   iswideopen = true;
175   ispmscanned = false;
176   iswidescanned = false;
177   raw_open_scan();
178   lock();
179 
180   GFTRK(0);
181 }
182 
183 
184 //  ------------------------------------------------------------------
185 
186 template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
close()187 void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::close() {
188 
189   GFTRK("HudsWideClose");
190 
191   unlock();
192   raw_close();
193   throw_release(msgidxptr);
194   throw_release(pmscan);
195   throw_release(scn);
196   iswideopen = false;
197   isopen = 0;
198 
199   GFTRK(0);
200 }
201 
202 
203 //  ------------------------------------------------------------------
204 
205 template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
lock()206 void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::lock() {
207 
208   GFTRK("HudsLock");
209 
210   if(not islocked and WideCanLock) {
211 
212     long _tries = 0;
213 
214     // Try to get the lock
215     while (fhinf.Lock(sizeof(HudsInfo)+1, 1) == -1)
216     {
217       // Tell the world
218       if(PopupLocked(++_tries, true, AddPath(path, __HUDSON ? "msginfo" HUDS_EXT : "msginfo" GOLD_EXT)) == false) {
219 
220         // User requested to exit
221         WideLog->ErrLock();
222         raw_close();
223         WideLog->printf("! A %s msgbase file could not be locked.", __HUDSON ? HUDS_NAME : GOLD_NAME);
224         WideLog->printf(": %smsginfo%s.", path, __HUDSON ? HUDS_EXT : GOLD_EXT);
225         WideLog->ErrOSInfo();
226         LockErrorExit();
227       }
228 
229       // Request the other program to unlock
230       TouchFile(AddPath(path, "mbunlock.now"));
231     }
232 
233     // Remove the popup window
234     if(_tries)
235       PopupLocked(0, 0, NULL);
236 
237     // We got the lock
238     islocked = true;
239   }
240 
241   // Refresh msgbase data
242   refresh();
243 
244   GFTRK(0);
245 }
246 
247 
248 //  ------------------------------------------------------------------
249 
250 template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
unlock()251 void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::unlock() {
252 
253   GFTRK("HudsUnlock");
254 
255   if (islocked and WideCanLock)
256   {
257     fhinf.Unlock(sizeof(HudsInfo)+1, 1);
258     islocked = false;
259   }
260 
261   GFTRK(0);
262 }
263 
264 
265 //  ------------------------------------------------------------------
266 
267 template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
lock()268 void _HudsArea<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::lock() {
269 
270   wide->lock();
271 }
272 
273 
274 //  ------------------------------------------------------------------
275 
276 template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
unlock()277 void _HudsArea<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::unlock() {
278 
279   wide->unlock();
280 }
281 
282 
283 //  ------------------------------------------------------------------
284 
285 template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
scan()286 void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::scan() {
287 
288   GFTRK("HudsWideScan");
289 
290   iswidescanned = true;
291 
292   // Alloc scan array
293   throw_free(scn);
294   scn = (HudsScan*)throw_calloc((__HUDSON ? HUDS_MAXBOARD : GOLD_MAXBOARD), sizeof(HudsScan));
295 
296   // Board and scan array pointer
297   register int _board;
298   register HudsScan* _scan = scn;
299 
300   // Init wide scan array
301   _board = 0;
302   while(_board < (__HUDSON ? HUDS_MAXBOARD : GOLD_MAXBOARD)) {
303     _scan->active = msginfo.active[_board];
304     _scan->lastread = lastrec[_board];
305     _board++;
306     _scan++;
307   }
308 
309   // Setup MSGIDX pointer and counters
310   register HudsIdx* _msgidx_ptr = msgidxptr;
311   register uint    _msgidx_count = 0;
312   register uint    _msgidx_total = (uint)(msgidxsize/sizeof(HudsIdx));
313   int         _invalidboards = 0;
314 
315   // Scan the index
316   while(_msgidx_count < _msgidx_total) {
317 
318     // Is the msg not deleted?
319     if(_msgidx_ptr->msgno != (__HUDSON ? HUDS_DELETEDMSGNO : GOLD_DELETEDMSGNO)) {
320 
321       register int _idxboard = _msgidx_ptr->board;
322       if(_idxboard and (_idxboard <= (__HUDSON ? HUDS_MAXBOARD : GOLD_MAXBOARD))) {
323 
324         _scan = scn + (_idxboard - 1);
325 
326         // Get message number
327         _scan->lastmsgno = _msgidx_ptr->msgno;
328         _scan->count++;
329 
330         // Set first message number
331         if(not _scan->firstmsgno)
332           _scan->firstmsgno = _scan->lastmsgno;
333 
334         // Set lastread pointer
335         if((_scan->lastmsgno >= _scan->lastread) and (_scan->lastreadreln == 0)) {
336           _scan->lastreadfound = _scan->lastmsgno;
337           _scan->lastreadreln = _scan->count - (_scan->lastmsgno != _scan->lastread ? 1 : 0);
338         }
339       }
340       else {
341         _invalidboards++;
342       }
343     }
344 
345     // Go to next record
346     _msgidx_count++;
347     _msgidx_ptr++;
348   }
349 
350   if(_invalidboards) {
351     WideLog->printf("! Found %u msgs with an invalid board number (0 or >%u).", _invalidboards, (__HUDSON ? HUDS_MAXBOARD : GOLD_MAXBOARD));
352     WideLog->printf("! In the %s msgbase at %s.", __HUDSON ? HUDS_NAME : GOLD_NAME, path);
353     WideLog->printf(": Info: Your msgbase may be partially corrupted.");
354     WideLog->printf("+ Advice: Run a msgbase index rebuild/recover utility.");
355   }
356 
357   // Check/fix boards
358   _board = 0;
359   _scan = scn;
360   while(_board < (__HUDSON ? HUDS_MAXBOARD : GOLD_MAXBOARD)) {
361 
362     // Check/fix lastreads
363     if(_scan->count and (_scan->lastreadfound != _scan->lastread)) {
364       if(_scan->lastread > _scan->lastmsgno)
365         _scan->lastreadreln = _scan->count;
366       else if(_scan->lastread < _scan->firstmsgno)
367         _scan->lastreadreln = 0;
368     }
369 
370     if(WideDebug) {
371       WideLog->printf("- b:%u: t:%u, l:%u, fm:%u, hm:%u, lr:%u, u:%u",
372         _board,
373         _scan->count,
374         _scan->lastreadreln,
375         _scan->firstmsgno,
376         _scan->lastmsgno,
377         _scan->lastread,
378         userno
379       );
380     }
381 
382     // Check active message count and log it if different
383     if(_scan->active != _scan->count) {
384       WideLog->printf("! Counted %u active msgs in %s board %u.", _scan->count, __HUDSON ? HUDS_NAME : GOLD_NAME, _board+1);
385       WideLog->printf("! According to msginfo%s there should be %u active msgs.", __HUDSON ? HUDS_EXT : GOLD_EXT, _scan->active);
386       WideLog->printf(": Info: A program did not update msginfo%s correctly.", __HUDSON ? HUDS_EXT : GOLD_EXT);
387       WideLog->printf("+ Advice: Run a msgbase index rebuild utility.");
388     }
389 
390     _board++;
391     _scan++;
392   }
393 
394   GFTRK(0);
395 }
396 
397 
398 //  ------------------------------------------------------------------
399 
400 template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
raw_scan(int __keep_index)401 void _HudsArea<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::raw_scan(int __keep_index) {
402 
403   GFTRK("HudsRawScan");
404 
405   if(!wide)
406     wide = (HudsWide*) (__HUDSON ? (void *)hudsonwide : (void *)goldbasewide);
407 
408   if(wide->iswideopen and not wide->iswidescanned)
409     wide->scan();
410 
411   // Get wide scan data if any
412   if(wide->scn) {
413 
414     // Update area data
415     register HudsScan* _scan = wide->scn + (board() - 1);
416     Msgn->SetCount(_scan->count);
417     lastread = _scan->lastreadreln;
418     lastreadentry = _scan->lastreadfound;
419   }
420   else {
421 
422     // Open the msgbase if it wasn't already
423     int _was_open = wide->isopen;
424     if(not _was_open)
425       wide->open();
426 
427     // Get the number of active msgs in the area
428     register board_t _board = (board_t)board();
429     register uint _active = wide->msginfo.active[_board-1];
430     register msgn_t _lastread = wide->lastrec[_board-1];
431 
432     // Setup pointers and counts
433     register uint    _msg_count = 0;
434     register HudsIdx* _msgidx_ptr = wide->msgidxptr;
435     register uint    _msgidx_count = 0;
436     register uint    _msgidx_total = (uint)(wide->msgidxsize/sizeof(HudsIdx));
437     register uint    _lastread_reln = 0;
438 
439     // (Re)Allocate index
440     if(__keep_index)
441       Msgn->Resize(_active);
442 
443     // Index pointers
444     uint32_t* _msgno_ptr = Msgn->tag;
445 
446     // Fill index
447     uint _firstmsgno = 0;
448     uint _lastmsgno = 0;
449     uint _lastreadfound = 0;
450     while(_msgidx_count < _msgidx_total) {
451 
452       // Is it our board and is the msg not deleted?
453       if((_msgidx_ptr->board == _board) and (_msgidx_ptr->msgno != (__HUDSON ? HUDS_DELETEDMSGNO : GOLD_DELETEDMSGNO))) {
454 
455         // Get message number
456         _lastmsgno = _msgidx_ptr->msgno;
457         _msg_count++;
458 
459         // Set first message number
460         if(not _firstmsgno)
461           _firstmsgno = _lastmsgno;
462 
463         // Transfer data to the index
464         if(__keep_index)
465           *_msgno_ptr++ = _lastmsgno;
466 
467         // Set lastread pointer
468         if((_lastmsgno >= _lastread) and (_lastread_reln == 0)) {
469           _lastreadfound = _lastmsgno;
470           _lastread_reln = _msg_count - (_lastmsgno != _lastread ? 1 : 0);
471         }
472 
473         // Break loop as soon as we have all we need
474         if(_msg_count == _active)
475           break;
476       }
477 
478       // Go to next record
479       _msgidx_count++;
480       _msgidx_ptr++;
481     }
482 
483     // If the exact lastread was not found
484     if(_msg_count and (_lastreadfound != _lastread)) {
485 
486       // Higher than highest or lower than lowest?
487       if(_lastread > _lastmsgno)
488         _lastread_reln = _msg_count;
489       else if(_lastread < _firstmsgno)
490         _lastread_reln = 0;
491     }
492 
493     // Check active message count and log it if different
494     if(_active != _msg_count) {
495       WideLog->printf("! Counted %u active msgs in %s board %u (%s).", _msg_count, __HUDSON ? HUDS_NAME : GOLD_NAME, board(), echoid());
496       WideLog->printf("! According to msginfo%s there should be %u active msgs.", __HUDSON ? HUDS_EXT : GOLD_EXT, _active);
497       WideLog->printf(": Info: A program did not update msginfo%s correctly.", __HUDSON ? HUDS_EXT : GOLD_EXT);
498       WideLog->printf("+ Advice: Run a msgbase index rebuild utility.");
499     }
500 
501     // Update area data
502     Msgn->SetCount(_msg_count);
503     lastread = _lastread_reln;
504     lastreadentry = _lastreadfound;
505 
506     if(WideDebug) {
507       WideLog->printf("- b:%u: t:%u, l:%u, fm:%u, hm:%u, lr:%u, u:%u",
508         board(),
509         Msgn->Count(),
510         lastread,
511         _firstmsgno,
512         _lastmsgno,
513         _lastread,
514         wide->userno
515       );
516     }
517 
518     // Close the msgbase again if we opened it in here
519     if(not _was_open)
520       wide->close();
521   }
522 
523   GFTRK(0);
524 }
525 
526 
527 //  ------------------------------------------------------------------
528 
529 template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
scan()530 void _HudsArea<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::scan() {
531 
532   GFTRK("HudsScan");
533 
534   raw_scan(true);
535 
536   GFTRK(0);
537 }
538 
539 
540 //  ------------------------------------------------------------------
541 
542 template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
scan_area()543 void _HudsArea<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::scan_area() {
544 
545   GFTRK("HudsScanArea");
546 
547   raw_scan(false);
548 
549   GFTRK(0);
550 }
551 
552 
553 //  ------------------------------------------------------------------
554 
555 #define HudsIdxCmp(a,b) ((a.board-b.board != 0) ? a.board-b.board : ((int)(a.msgno-b.msgno)))
556 
557 
558 //  ------------------------------------------------------------------
559 
560 #define TOIDXBUFSZ 100u
561 #define PMSCANBUFSZ 50u
562 
563 template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
realloc_pm_scan()564 void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::realloc_pm_scan() {
565 
566   pmscan = (HudsIdx*)throw_realloc(pmscan, (pmscantotal+PMSCANBUFSZ)*sizeof(HudsIdx));
567 }
568 
569 
570 //  ------------------------------------------------------------------
571 
572 template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
scan_pm()573 void _HudsWide<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::scan_pm() {
574 
575   GFTRK("HudsWideScanPM");
576 
577   if(not iswidescanned)
578     scan();
579 
580   ispmscanned = true;
581 
582   HudsToIdx* toidxbuf = (HudsToIdx*)throw_calloc(TOIDXBUFSZ, sizeof(HudsToIdx));
583   uint totrecs = (uint)(fhtoi.FileLength() / sizeof(HudsToIdx));
584   HudsIdx* idxptr = msgidxptr;
585   throw_release(pmscan);
586   pmscantotal = 0;
587   int invalidboards = 0;
588   int gotpm, idxboard, umax, u;
589   uint getrecs, rec;
590   HudsToIdx* toidx;
591 
592   do {
593 
594     rec = 0;
595     gotpm = false;
596     getrecs = MinV(TOIDXBUFSZ, totrecs);
597     fhtoi.Read(toidxbuf, getrecs*sizeof(HudsToIdx));
598 
599     for(toidx=toidxbuf; rec<getrecs; idxptr++,toidx++,rec++) {
600 
601       // Skip deleted msgs
602       if(idxptr->msgno == (__HUDSON ? HUDS_DELETEDMSGNO : GOLD_DELETEDMSGNO))
603         continue;
604 
605       // Skip msgs in invalid boards
606       idxboard = idxptr->board;
607       if(not (idxboard and (idxboard <= (__HUDSON ? HUDS_MAXBOARD : GOLD_MAXBOARD)))) {
608         invalidboards++;
609         continue;
610       }
611 
612       // If after lastread
613       if(idxptr->msgno <= scn[idxboard-1].lastreadfound)
614         continue;
615 
616       // Convert name string
617       strnp2c(toidx->name, sizeof(HudsToIdx)-1);
618 
619       // Is it a PM?
620       umax = (WidePersonalmail & PM_ALLNAMES) ? WideUsernames : 1;
621       for(u=0; u<umax; u++) {
622         if(strieql(toidx->name, WideUsername[u])) {
623           gotpm = true;
624           break;
625         }
626       }
627 
628       if(gotpm) {
629         if((pmscantotal % PMSCANBUFSZ) == 0)
630           realloc_pm_scan();
631         pmscan[pmscantotal++] = *idxptr;
632         scn[idxboard-1].pmcount++;
633         gotpm = false;
634       }
635     }
636     totrecs -= getrecs;
637   } while(totrecs);
638 
639   throw_free(toidxbuf);
640   pmscan = (HudsIdx*)throw_realloc(pmscan, (pmscantotal+1)*sizeof(HudsIdx));
641 
642   // Sort all pm records in board/msgno order
643   for(uint k=pmscantotal >> 1; k; k >>= 1)
644     for(uint i=k; i < pmscantotal; i++)
645       for(uint j=i-k; (j >= 0) and HudsIdxCmp(pmscan[j], pmscan[j+k]) > 0; j-=k) {
646         HudsIdx e = pmscan[j];
647         pmscan[j] = pmscan[j+k];
648         pmscan[j+k] = e;
649       }
650 
651   if(invalidboards) {
652     WideLog->printf("! Found %u msgs with an invalid board number (0 or >%u).", invalidboards, (__HUDSON ? HUDS_MAXBOARD : GOLD_MAXBOARD));
653     WideLog->printf("! In the %s msgbase at %s.", __HUDSON ? HUDS_NAME : GOLD_NAME, path);
654     WideLog->printf(": Info: Your msgbase may be partially corrupted.");
655     WideLog->printf("+ Advice: Run a msgbase index rebuild/recover utility.");
656   }
657 
658   GFTRK(0);
659 }
660 
661 
662 //  ------------------------------------------------------------------
663 
664 template <class msgn_t, class rec_t, class attr_t, class board_t, class last_t, bool __HUDSON>
scan_area_pm()665 void _HudsArea<msgn_t, rec_t, attr_t, board_t, last_t, __HUDSON>::scan_area_pm() {
666 
667   GFTRK("HudsScanAreaPM");
668 
669   PMrk->ResetAll();
670 
671   if(!wide)
672     wide = (HudsWide*) (__HUDSON ? (void *)hudsonwide : (void *)goldbasewide);
673 
674   if(wide->iswideopen and not wide->ispmscanned)
675     wide->scan_pm();
676 
677   // Get wide scan data if any
678   if(wide->scn) {
679 
680     register board_t _board = (board_t)board();
681     register HudsScan* _scan = wide->scn + (_board - 1);
682 
683     if(wide->pmscan) {
684       if(_scan->pmcount) {
685 
686         register HudsIdx* pmscanptr = wide->pmscan;
687         while(pmscanptr->board != _board)
688           pmscanptr++;
689 
690         register uint n = 0;
691         register uint cnt = _scan->pmcount;
692         while(n < cnt) {
693           PMrk->Append(pmscanptr->msgno);
694           pmscanptr++;
695           n++;
696         }
697       }
698     }
699 
700     // Update area data
701     Msgn->SetCount(_scan->count);
702     lastread = _scan->lastreadreln;
703     lastreadentry = _scan->lastreadfound;
704 
705     if(WideDebug) {
706       WideLog->printf("- b:%u: t:%u, l:%u, fm:%u, hm:%u, lr:%u, u:%u, pm:%i",
707         _board,
708         _scan->count,
709         _scan->lastreadreln,
710         _scan->firstmsgno,
711         _scan->lastmsgno,
712         _scan->lastread,
713         wide->userno,
714         PMrk->Count()
715       );
716     }
717 
718   }
719   else {
720     if(WideDebug)
721       WideLog->printf("- Oops!  Fell into empty bracket.");
722   }
723 
724   GFTRK(0);
725 }
726 
727 
728 //  ------------------------------------------------------------------
729 
730