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: gmojamm2.cpp,v 1.12 2006/05/14 11:45:05 ssianky Exp $
23 //  ------------------------------------------------------------------
24 //  JAM msgbase implementation, scanning.
25 //  ------------------------------------------------------------------
26 
27 #include <cerrno>
28 #include <gdbgerr.h>
29 #include <gmemdbg.h>
30 #include <gdbgtrk.h>
31 #include <gstrall.h>
32 #include <gcrcall.h>
33 #include <gmojamm.h>
34 
35 
36 //  ------------------------------------------------------------------
37 
data_open()38 void JamArea::data_open() {
39 
40   wide = jamwide;
41   data = jamdata + (jamdatano++);
42   data->fhjhr = data->fhjdt = data->fhjdx = data->fhjlr = data->fhjhw = -1;
43   data->islocked = false;
44   data->timesposted = 0;
45   data->lastpos = 0;
46 }
47 
48 
49 //  ------------------------------------------------------------------
50 
data_close()51 void JamArea::data_close() {
52 
53   jamdatano--;
54 }
55 
56 
57 //  ------------------------------------------------------------------
58 
test_open(const char * file)59 int JamArea::test_open(const char* file) {
60 
61   GFTRK("JamArea::test_open");
62 
63   int fh;
64   long tries = 0;
65 
66   do {
67 
68     fh = ::sopen(file, O_RDWR|O_CREAT|O_BINARY, WideSharemode, S_STDRW);
69     if(fh == -1) {
70 
71       // Tell the world
72       if((errno != EACCES) or (PopupLocked(++tries, false, file) == false)) {
73         WideLog->ErrOpen();
74         raw_close();
75         WideLog->printf("! A JAM msgbase file could not be opened.");
76         WideLog->printf(": %s.", file);
77         WideLog->ErrOSInfo();
78         OpenErrorExit();
79       }
80     }
81   } while(fh == -1);
82 
83   // Remove the popup window
84   if(tries)
85     PopupLocked(0, 0, NULL);
86 
87   GFTRK(0);
88 
89   return fh;
90 }
91 
92 
93 //  ------------------------------------------------------------------
94 
raw_open()95 void JamArea::raw_open() {
96 
97   GFTRK("JamArea::raw_open");
98 
99   Path file;
100   sprintf(file, "%s.jhr", real_path());  data->fhjhr = test_open(file);
101   sprintf(file, "%s.jdx", real_path());  data->fhjdx = test_open(file);
102   sprintf(file, "%s.jlr", real_path());  data->fhjlr = test_open(file);
103   if(not just_scanning) {
104     sprintf(file, "%s.jdt", real_path());  data->fhjdt = test_open(file);
105     if(not jamwide->smapihw) {
106       sprintf(file, "%s.cmhw", real_path()); data->fhjhw = ::sopen(file, O_RDWR|O_BINARY, WideSharemode, S_STDRW);
107     }
108   }
109 
110   GFTRK(0);
111 }
112 
113 
114 //  ------------------------------------------------------------------
115 
raw_close()116 void JamArea::raw_close() {
117 
118   GFTRK("JamArea::raw_close");
119 
120   if(data->fhjlr != -1) { ::close(data->fhjlr);  data->fhjlr = -1; }
121   if(data->fhjdx != -1) { ::close(data->fhjdx);  data->fhjdx = -1; }
122   if(data->fhjdt != -1) { ::close(data->fhjdt);  data->fhjdt = -1; }
123   if(data->fhjhr != -1) { ::close(data->fhjhr);  data->fhjhr = -1; }
124   if(data->fhjhw != -1) { ::close(data->fhjhw);  data->fhjhw = -1; }
125 
126   GFTRK(0);
127 }
128 
129 
130 //  ------------------------------------------------------------------
131 
open_area()132 void JamArea::open_area() {
133 
134   GFTRK("JamArea::open_area");
135 
136   // Open the msgbase files
137   raw_open();
138 
139   // Read the header info
140   memset(&data->hdrinfo, 0, sizeof(JamHdrInfo));
141   read(data->fhjhr, &data->hdrinfo, sizeof(JamHdrInfo));
142 
143   if(not jamwide->smapihw and (data->fhjhw != -1)) {
144     lseek(data->fhjhw, 0, SEEK_SET);
145     read(data->fhjhw, &data->highwater, sizeof(int32_t));
146   }
147   else
148     data->highwater = -1;
149 
150   // Is the signature invalid?
151   if (memcmp(data->hdrinfo.signature, JAM_SIGNATURE, 4))
152   {
153     // Initialize header info
154     memcpy(data->hdrinfo.signature, JAM_SIGNATURE, 4);
155     time32_t a  = gtime(NULL);
156     struct tm tp; ggmtime(&tp, &a);
157     tp.tm_isdst = -1;
158     time32_t b  = gmktime(&tp);
159     data->hdrinfo.datecreated = a + a - b;
160     data->hdrinfo.passwordcrc = 0xFFFFFFFFL;
161     data->hdrinfo.basemsgnum  = 1;
162 
163     // Write header info
164     lseekset(data->fhjhr, 0);
165     write(data->fhjhr, &data->hdrinfo, sizeof(JamHdrInfo));
166   }
167 
168   // Adjust base msg number if necessary
169   if(data->hdrinfo.basemsgnum == 0)
170     data->hdrinfo.basemsgnum = 1;
171 
172   // Seek to beginning of the .JLR
173   lseekset(data->fhjlr, 0);
174 
175   // Search for the userid (not the usercrc?!)
176   data->lastpos = 0;
177   int founduser = false;
178   while(read(data->fhjlr, &data->lastrec, sizeof(JamLast)) == sizeof(JamLast)) {
179     if(data->lastrec.usercrc == wide->usercrc) {
180       founduser = true;
181       break;
182     }
183     data->lastpos++;
184   }
185 
186   // If user was not found, init the lastread with our values
187   if(not founduser) {
188     data->lastrec.usercrc = wide->usercrc;
189     data->lastrec.userid  = wide->userid;
190     data->lastrec.lastread = 0;
191     data->lastrec.highread = 0;
192   }
193 
194   data->timesposted = 0;
195 
196   GFTRK(0);
197 }
198 
199 
200 //  ------------------------------------------------------------------
201 
raw_scan(int __keep_index,int __scanpm)202 void JamArea::raw_scan(int __keep_index, int __scanpm) {
203 
204   GFTRK("JamRawScan");
205 
206   // Open the msgbase if it wasn't already
207   int _was_open = isopen;
208   if(not _was_open) {
209     if(not __keep_index or __scanpm)
210       just_scanning = true;
211     if(ispacked()) {
212       const char* newpath = Unpack(path());
213       if(newpath == NULL)
214         packed(false);
215       set_real_path(newpath ? newpath : path());
216     }
217     isopen++;
218     data_open();
219     open_area();
220     just_scanning = false;
221   }
222 
223   // Get some sizes
224   int32_t _jdxlen = filelength(data->fhjdx);
225   uint _jdxsize  = (uint)_jdxlen;
226   uint _jdxtotal = _jdxsize / sizeof(JamIndex);
227 
228   // (Re)Allocate message index
229   if(__keep_index)
230     Msgn->Resize(_jdxtotal);
231 
232   // Allocate buffer to hold .JDX data
233   JamIndex* _jdxbuf = (JamIndex*)throw_malloc(_jdxsize+1);
234 
235   // Read the entire .JDX file into memory
236   lseekset(data->fhjdx, 0);
237   read(data->fhjdx, _jdxbuf, _jdxsize);
238 
239   // Variables for the loop
240   uint _active = 0;
241   uint _firstmsgno = 0;
242   uint _lastmsgno = 0;
243   uint _lastreadfound = 0;
244   uint _msgno = data->hdrinfo.basemsgnum;
245   uint _total = data->hdrinfo.basemsgnum + _jdxtotal;
246   uint _lastread = data->lastrec.lastread;
247   uint _lastread_reln = 0;
248   uint32_t* _msgndxptr = Msgn->tag;
249   JamIndex* _jdxptr = _jdxbuf;
250 
251   // Fill message index
252   while(_msgno < _total) {
253     if(_jdxptr->hdroffset != 0xFFFFFFFFL) {
254       _active++;
255       if(not _firstmsgno)
256         _firstmsgno = _msgno;
257       if(__keep_index)
258         *_msgndxptr++ = _msgno;
259       if((_msgno >= _lastread) and (_lastread_reln == 0)) {
260         _lastreadfound = _msgno;
261         _lastread_reln = (uint)(_active - (_msgno != _lastread ? 1 : 0));
262       }
263       _lastmsgno = _msgno;
264     }
265     _jdxptr++;
266     _msgno++;
267   }
268 
269   // If the exact lastread was not found
270   if(_active and (_lastreadfound != _lastread)) {
271 
272     // Higher than highest or lower than lowest?
273     if(_lastread > _lastmsgno)
274       _lastread_reln = _active;
275     else if(_lastread < _firstmsgno)
276       _lastread_reln = 0;
277   }
278 
279   // Update area data
280   Msgn->SetCount(_active);
281   lastread = _lastread_reln;
282   lastreadentry = _lastreadfound;
283 
284   // Scan for personal mail
285   if(__scanpm) {
286     INam uname;
287     int umax = (WidePersonalmail & PM_ALLNAMES) ? WideUsernames : 1;
288     dword* ucrc = (dword*)throw_calloc(umax, sizeof(dword));
289     for(int uc=0; uc<umax; uc++) {
290       jamstrlwr(strcpy(uname, WideUsername[uc]));
291       ucrc[uc] = strCrc32(uname, NO, CRC32_MASK_CCITT);
292     }
293     PMrk->ResetAll();
294     uint n = lastread + 1;
295     uint cnt = Msgn->Count();
296     int gotpm = false;
297     while(n <= cnt) {
298       JamIndex* idx = _jdxbuf + (uint)(Msgn->at(n-1) - data->hdrinfo.basemsgnum);
299       for(int u=0; u<umax; u++) {
300         if(idx->usercrc == ucrc[u]) {
301           gotpm = true;
302           break;
303         }
304       }
305       if(gotpm) {
306         JamHdr hdr;
307         lseekset(data->fhjhr, idx->hdroffset);
308         read(data->fhjhr, &hdr, sizeof(JamHdr));
309         if(not (hdr.attribute & JAMATTR_READ)) {
310           if(not (hdr.attribute & JAMATTR_DELETED)) {
311             PMrk->Append(hdr.messagenumber);
312           }
313         }
314         gotpm = false;
315       }
316       n++;
317     }
318     throw_free(ucrc);
319   }
320 
321   if(WideDebug) {
322     WideLog->printf("- %s: t:%u, l:%u, fm:%u, hm:%u, lr:%u, u:%u, pm:%i",
323       echoid(),
324       Msgn->Count(),
325       lastread,
326       _firstmsgno,
327       _lastmsgno,
328       _lastread,
329       data->lastpos,
330       __scanpm ? (int)PMrk->Count() : -1
331     );
332   }
333 
334   // Free the .JDX buffer
335   throw_free(_jdxbuf);
336 
337   // Close the msgbase again if we opened it in here
338   if(not _was_open) {
339     raw_close();
340     data_close();
341     if(ispacked()) {
342       CleanUnpacked(real_path());
343     }
344     isopen--;
345   }
346 
347   GFTRK(0);
348 }
349 
350 
351 //  ------------------------------------------------------------------
352 
scan()353 void JamArea::scan() {
354 
355   GFTRK("JamArea::scan");
356 
357   raw_scan(true);
358 
359   GFTRK(0);
360 }
361 
362 
363 //  ------------------------------------------------------------------
364 
scan_area()365 void JamArea::scan_area() {
366 
367   GFTRK("JamArea::scan_area");
368 
369   raw_scan(false);
370 
371   GFTRK(0);
372 }
373 
374 
375 //  ------------------------------------------------------------------
376 
scan_area_pm()377 void JamArea::scan_area_pm() {
378 
379   GFTRK("JamArea::scan_area_pm");
380 
381   raw_scan(true, true);
382   Msgn->Reset();
383 
384   GFTRK(0);
385 }
386 
387 
388 //  ------------------------------------------------------------------
389