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: gmojamm4.cpp,v 1.12 2006/05/14 11:45:05 ssianky Exp $
23 //  ------------------------------------------------------------------
24 //  JAM msgbase implementation, save/delete.
25 //  ------------------------------------------------------------------
26 
27 #include <gmemdbg.h>
28 #include <gdbgtrk.h>
29 #include <gdbgerr.h>
30 #include <gcrcall.h>
31 #include <gstrall.h>
32 #include <gtxtpara.h>
33 #include <gutlmisc.h>
34 #include <gmojamm.h>
35 
36 
37 //  ------------------------------------------------------------------
38 
lock()39 void JamArea::lock() {
40 
41   GFTRK("JamArea::lock");
42 
43   if(not data->islocked and WideCanLock) {
44 
45     long _tries = 0;
46 
47     // Try to get the lock
48     while(::lock(data->fhjhr, 0, 1) == -1) {
49 
50       // Tell the world
51       if(PopupLocked(++_tries, true, real_path()) == false) {
52         WideLog->ErrLock();
53         raw_close();
54         WideLog->printf("! A JAM msgbase file could not be locked.");
55         WideLog->printf(": %s.jhr.", real_path());
56         WideLog->ErrOSInfo();
57         LockErrorExit();
58       }
59     }
60 
61     // Remove the popup window
62     if(_tries)
63       PopupLocked(0, 0, NULL);
64 
65     data->islocked = true;
66   }
67 
68   // Load fresh copy of the header info
69   lseekset(data->fhjhr, 0);
70   read(data->fhjhr, &data->hdrinfo, sizeof(JamHdrInfo));
71 
72   if(not jamwide->smapihw) {
73     if(data->fhjhw == -1) {
74       Path file;
75       sprintf(file, "%s.cmhw", real_path()); data->fhjhw = ::sopen(file, O_RDWR|O_BINARY, WideSharemode, S_STDRW);
76     }
77     if(data->fhjhw != -1) {
78       lseek(data->fhjhw, 0, SEEK_SET);
79       read(data->fhjhw, &data->highwater, sizeof(int32_t));
80     }
81     else
82       data->highwater = -1;
83   }
84   else
85     data->highwater = -1;
86 
87   GFTRK(0);
88 }
89 
90 
91 //  ------------------------------------------------------------------
92 
unlock()93 void JamArea::unlock() {
94 
95   GFTRK("JamArea::unlock");
96 
97   if(data->islocked) {
98     ::unlock(data->fhjhr, 0, 1);
99     data->islocked = false;
100   }
101 
102   GFTRK(0);
103 }
104 
105 
106 //  ------------------------------------------------------------------
107 
add_subfield(JamHdr & __hdr,byte * & __subfield,word __loid,word __hiid,char * __data,uint32_t __maxlen)108 void JamArea::add_subfield(JamHdr& __hdr, byte*& __subfield, word __loid, word __hiid, char* __data, uint32_t __maxlen) {
109 
110   uint32_t _datlen = strlen(__data);
111   __subfield = (byte*)throw_realloc(__subfield, (uint)__hdr.subfieldlen+sizeof(JamSubFieldHdr)+_datlen);
112   JamSubField* _subfieldptr = (JamSubField*)(__subfield + (uint)__hdr.subfieldlen);
113   _subfieldptr->loid = __loid;
114   _subfieldptr->hiid = __hiid;
115   _subfieldptr->datlen = MinV(_datlen, __maxlen);
116   memcpy(_subfieldptr->buffer, __data, _subfieldptr->datlen);
117   __hdr.subfieldlen += sizeof(JamSubFieldHdr) + _subfieldptr->datlen;
118 }
119 
120 
121 //  ------------------------------------------------------------------
122 
save_message(int __mode,gmsg * __msg,JamHdr & __hdr)123 void JamArea::save_message(int __mode, gmsg* __msg, JamHdr& __hdr) {
124 
125   int _was_locked = data->islocked;
126   if(not _was_locked)
127     lock();
128 
129   // Reset header
130   memset(&__hdr, 0, sizeof(JamHdr));
131 
132   // Init paragraph class
133   GParagraph _para;
134   if(WideDispsoftcr)
135     _para.softcr = SOFTCR;
136 
137   // Set default msg text offset and length
138   __hdr.offset = __msg->txtstart;
139   __hdr.txtlen = __msg->txtlength;
140 
141   // Get message text size
142   char* _txtcpy = NULL;
143   if(__msg->txt and (__mode & GMSG_TXT)) {
144 
145     // Work on a copy of the original msg text
146     _txtcpy = throw_strdup(__msg->txt);
147 
148     // Convert message text to a paragraph list
149     _para.ConvertText(_txtcpy, strlen(_txtcpy));
150 
151     // Mark control lines and calculate pure message text size
152     __hdr.txtlen = _para.CheckCtrlLines();
153   }
154 
155   // Determine where to write the message text
156   if((__mode & GMSG_NEW) or (__hdr.txtlen > __msg->txtlength))
157     __hdr.offset = filelength(data->fhjdt);
158 
159   byte* _subfield = NULL;
160   char _buf[1024];
161   __hdr.subfieldlen = __msg->jam.subfieldlen;
162 
163   if(__mode & GMSG_TXT) {
164 
165     // Build the subfields
166     __hdr.subfieldlen = 0;
167 
168     // Process addressing kludges
169     int _line = 0;
170     GParaData* _pdptr = _para.paraidx;
171     while(_line < _para.lines) {
172       if(_pdptr->control > CTRL_KLUDGE) {
173         word fmpt, topt;
174         char buf1[201], buf2[201];
175         switch(_pdptr->control) {
176           case CTRL_INTL:
177             fmpt = __msg->orig.point;
178             topt = __msg->dest.point;
179             sscanf(_pdptr->text+6, "%s %s", buf1, buf2);
180             __msg->dest.set(buf1);
181             __msg->orig.set(buf2);
182             __msg->orig.point = fmpt;
183             __msg->dest.point = topt;
184             break;
185           case CTRL_FMPT:
186             __msg->orig.point = atow(_pdptr->text+6);
187             break;
188           case CTRL_TOPT:
189             __msg->dest.point = atow(_pdptr->text+6);
190             break;
191           case CTRL_MSGID:
192             __msg->msgid.reset(_pdptr->text+8, __msg->odom);
193             break;
194         }
195       }
196       _pdptr++;
197       _line++;
198     }
199 
200     if(*__msg->by)
201       add_subfield(__hdr, _subfield, JAMSUB_SENDERNAME, 0, __msg->by, JAMSUB_SENDERNAME_LEN);
202 
203     if(__msg->orig.net) {
204       __msg->orig.make_string(_buf, __msg->odom);
205       add_subfield(__hdr, _subfield, JAMSUB_OADDRESS, 0, _buf, JAMSUB_OADDRESS_LEN);
206     }
207 
208     if(*__msg->to)
209       add_subfield(__hdr, _subfield, JAMSUB_RECEIVERNAME, 0, __msg->to, JAMSUB_RECEIVERNAME_LEN);
210 
211     if(__msg->dest.net) {
212       __msg->dest.make_string(_buf, __msg->ddom);
213       add_subfield(__hdr, _subfield, JAMSUB_DADDRESS, 0, _buf, JAMSUB_DADDRESS_LEN);
214     }
215 
216     if(*__msg->re)
217       add_subfield(__hdr, _subfield, JAMSUB_SUBJECT, 0, __msg->re, JAMSUB_SUBJECT_LEN);
218 
219     // Convert kludges
220     _line = 0;
221     _pdptr = _para.paraidx;
222     while(_line < _para.lines) {
223       if(_pdptr->control > CTRL_KLUDGE) {
224         uint _offset = 0;
225         word _loid = 0;
226         uint32_t _maxlen = 0;
227         switch(_pdptr->control) {
228           case CTRL_INTL:
229           case CTRL_FMPT:
230           case CTRL_TOPT:
231             // Strip these. Data is stored in the address subfields
232             break;
233           case CTRL_MSGID:
234             _loid = JAMSUB_MSGID;
235             _maxlen = JAMSUB_MSGID_LEN;
236             _offset = 8;
237             strxcpy(__msg->msgids, _pdptr->text+_offset, sizeof(__msg->msgids));
238             break;
239           case CTRL_REPLY:
240             _loid = JAMSUB_REPLYID;
241             _maxlen = JAMSUB_REPLYID_LEN;
242             _offset = 8;
243             strxcpy(__msg->replys, _pdptr->text+_offset, sizeof(__msg->replys));
244             break;
245           case CTRL_PID:
246             _loid = JAMSUB_PID;
247             _maxlen = JAMSUB_PID_LEN;
248             _offset = 6;
249             break;
250           case CTRL_VIA:
251             _loid = JAMSUB_TRACE;
252             _maxlen = JAMSUB_TRACE_LEN;
253             _offset = 5;
254             break;
255           case CTRL_SEENBY:
256             _loid = JAMSUB_SEENBY2D;
257             _maxlen = JAMSUB_SEENBY2D_LEN;
258             _offset = 9;
259             break;
260           case CTRL_SEENBY1:
261             _loid = JAMSUB_SEENBY2D;
262             _maxlen = JAMSUB_SEENBY2D_LEN;
263             _offset = 10;
264             break;
265           case CTRL_PATH:
266             _loid = JAMSUB_PATH2D;
267             _maxlen = JAMSUB_PATH2D_LEN;
268             _offset = 7;
269             break;
270           case CTRL_FLAGS:
271             _loid = JAMSUB_FLAGS;
272             _maxlen = JAMSUB_FLAGS_LEN;
273             _offset = 7;
274             break;
275           default:
276             _loid = JAMSUB_FTSKLUDGE;
277             _maxlen = JAMSUB_FTSKLUDGE_LEN;
278             _offset = 1;
279         }
280         if(_offset)
281           add_subfield(__hdr, _subfield, _loid, 0, _pdptr->text+_offset, _maxlen);
282       }
283       _pdptr++;
284       _line++;
285     }
286   }
287 
288   JamIndex _idx;
289   bool was_deleted = false;
290   if(__mode & GMSG_NEW) {
291     __msg->msgno = data->hdrinfo.basemsgnum + (filelength(data->fhjdx)/sizeof(JamIndex));
292     __hdr.messagenumber = __msg->msgno;
293     _idx.hdroffset = filelength(data->fhjhr);
294   }
295   else {
296     __hdr.messagenumber = __msg->msgno;
297     lseekset(data->fhjdx, __hdr.messagenumber-data->hdrinfo.basemsgnum, sizeof(JamIndex));
298     read(data->fhjdx, &_idx, sizeof(JamIndex));
299     if(_idx.hdroffset != 0xFFFFFFFFL) {
300       lseekset(data->fhjhr, _idx.hdroffset);
301       JamHdr oldhdr;
302       read(data->fhjhr, &oldhdr, sizeof(JamHdr));
303       was_deleted = make_bool(oldhdr.attribute & JAMATTR_DELETED);
304       if(oldhdr.subfieldlen != __hdr.subfieldlen) {
305         oldhdr.attribute |= JAMATTR_DELETED;
306         oldhdr.txtlen = 0;
307         lseekset(data->fhjhr, _idx.hdroffset);
308         write(data->fhjhr, &oldhdr, sizeof(JamHdr));
309         _idx.hdroffset = filelength(data->fhjhr);
310       }
311     }
312   }
313 
314   if(_idx.hdroffset != 0xFFFFFFFFL) {
315 
316     memcpy(__hdr.signature, JAM_SIGNATURE, 4);
317     __hdr.revision = JAM_REVISION;
318 
319     __hdr.replyto   = __msg->link.to();
320     __hdr.reply1st  = __msg->link.first();
321     __hdr.replynext = __msg->link.next();
322 
323     __hdr.cost      = __msg->cost;
324     __hdr.timesread = __msg->timesread;
325     __hdr.passwordcrc = 0xFFFFFFFFL;
326 
327     __hdr.msgidcrc = strCrc32(jamstrlwr(strcpy(_buf, __msg->msgids)), NO, CRC32_MASK_CCITT);
328     __hdr.replycrc = strCrc32(jamstrlwr(strcpy(_buf, __msg->replys)), NO, CRC32_MASK_CCITT);
329     _idx.usercrc   = strCrc32(jamstrlwr(strcpy(_buf, __msg->to)),     NO, CRC32_MASK_CCITT);
330 
331     __hdr.datewritten   = __msg->written;
332     __hdr.datereceived  = __msg->received;
333     __hdr.dateprocessed = __msg->arrived;
334 
335     __hdr.attribute |= __msg->attr.loc() ? JAMATTR_LOCAL       : 0;
336     __hdr.attribute |= __msg->attr.trs() ? JAMATTR_INTRANSIT   : 0;
337     __hdr.attribute |= __msg->attr.pvt() ? JAMATTR_PRIVATE     : 0;
338     __hdr.attribute |= __msg->attr.rcv() ? JAMATTR_READ        : 0;
339     __hdr.attribute |= __msg->attr.snt() ? JAMATTR_SENT        : 0;
340     __hdr.attribute |= __msg->attr.k_s() ? JAMATTR_KILLSENT    : 0;
341     __hdr.attribute |= __msg->attr.a_s() ? JAMATTR_ARCHIVESENT : 0;
342     __hdr.attribute |= __msg->attr.hld() ? JAMATTR_HOLD        : 0;
343     __hdr.attribute |= __msg->attr.cra() ? JAMATTR_CRASH       : 0;
344     __hdr.attribute |= __msg->attr.imm() ? JAMATTR_IMMEDIATE   : 0;
345     __hdr.attribute |= __msg->attr.dir() ? JAMATTR_DIRECT      : 0;
346     __hdr.attribute |= __msg->attr.zon() ? JAMATTR_GATE        : 0;
347     __hdr.attribute |= __msg->attr.frq() ? JAMATTR_FILEREQUEST : 0;
348     __hdr.attribute |= __msg->attr.att() ? JAMATTR_FILEATTACH  : 0;
349     __hdr.attribute |= __msg->attr.tfs() ? JAMATTR_TRUNCFILE   : 0;
350     __hdr.attribute |= __msg->attr.kfs() ? JAMATTR_KILLFILE    : 0;
351     __hdr.attribute |= __msg->attr.rrq() ? JAMATTR_RECEIPTREQ  : 0;
352     __hdr.attribute |= __msg->attr.cfm() ? JAMATTR_CONFIRMREQ  : 0;
353     __hdr.attribute |= __msg->attr.orp() ? JAMATTR_ORPHAN      : 0;
354     __hdr.attribute |= __msg->attr.lok() ? JAMATTR_LOCKED      : 0;
355     __hdr.attribute |= __msg->attr.del() ? JAMATTR_DELETED     : 0;
356 
357     if(isnet())
358       __hdr.attribute |= JAMATTR_TYPENET;
359     else if(isecho())
360       __hdr.attribute |= JAMATTR_TYPEECHO;
361     else
362       __hdr.attribute |= JAMATTR_TYPELOCAL;
363 
364     lseekset(data->fhjhr, _idx.hdroffset);
365     write(data->fhjhr, &__hdr, sizeof(JamHdr));
366 
367     // Only write subfields if the msg body is written
368     if(__mode & GMSG_TXT)
369       write(data->fhjhr, _subfield, (uint)__hdr.subfieldlen);
370 
371     // Delete msg if requested
372     if(__mode & GMSG_DELETE) {
373       if(not was_deleted)
374         data->hdrinfo.activemsgs--;
375       __hdr.attribute |= JAMATTR_DELETED;
376       _idx.usercrc = 0xFFFFFFFFL;
377       if(wide->harddelete)
378         _idx.hdroffset = 0xFFFFFFFFL;
379     }
380 
381     // Write msg index
382     lseekset(data->fhjdx, __hdr.messagenumber-data->hdrinfo.basemsgnum, sizeof(JamIndex));
383     write(data->fhjdx, &_idx, sizeof(JamIndex));
384 
385     // Free subfield buffer
386     throw_release(_subfield);
387 
388     // Update the header info
389     if((__mode & GMSG_NEW) or (was_deleted and not __msg->attr.del()))
390       data->hdrinfo.activemsgs++;
391     data->hdrinfo.modcounter++;
392     lseekset(data->fhjhr, 0);
393     write(data->fhjhr, &data->hdrinfo, sizeof(JamHdrInfo));
394 
395     // If message text is used
396     if(__mode & GMSG_TXT) {
397 
398       char* _txt = (char*)throw_malloc((uint)(__hdr.txtlen+256));
399 
400       // Copy text paragraphs, excluding kludges
401       int _line = 0;
402       char* _tptr = _txt;
403       GParaData* _pdptr = _para.paraidx;
404       while(_line < _para.lines) {
405         if(_pdptr->control < CTRL_KLUDGE) {
406           memcpy(_tptr, _pdptr->text, _pdptr->length);
407           _tptr += _pdptr->length;
408           *_tptr++ = CR;
409         }
410         _pdptr++;
411         _line++;
412       }
413       *_tptr = NUL;
414 
415       // Seek to start position of the message text
416       lseekset(data->fhjdt, __hdr.offset);
417 
418       // Write the message text
419       write(data->fhjdt, _txt, (uint)__hdr.txtlen);
420 
421       // Release the memory we have used
422       throw_free(_txtcpy);
423       throw_free(_txt);
424     }
425 
426     // Update internals if new
427     if(__mode & GMSG_NEW) {
428 
429       // Count our msgs
430       data->timesposted++;
431 
432       // Update internal array
433       Msgn->Append(__msg->msgno);
434     }
435 
436     // Adjust the highwatermark if required
437     if(jamwide->smapihw and __msg->attr.uns()) {
438       if(data->hdrinfo.highwatermark >= __msg->msgno)
439         data->hdrinfo.highwatermark = __msg->msgno - 1;
440     }
441     else if((data->highwater != -1) and (data->fhjhw != -1)) {
442       if(data->highwater >= __msg->msgno) {
443         data->highwater = __msg->msgno - 1;
444         lseek(data->fhjhw, 0, SEEK_SET);
445         write(data->fhjhw, &data->highwater, sizeof(int32_t));
446       }
447     }
448   }
449   else {
450     scan();
451   }
452 
453   if(not _was_locked) {
454     lseekset(data->fhjhr, 0);
455     write(data->fhjhr, &data->hdrinfo, sizeof(JamHdrInfo));
456     unlock();
457   }
458 
459   GFTRK(0);
460 }
461 
462 
463 //  ------------------------------------------------------------------
464 
save_hdr(int __mode,gmsg * __msg)465 void JamArea::save_hdr(int __mode, gmsg* __msg) {
466 
467   GFTRK("JamArea::save_hdr");
468 
469   JamHdr _hdr;
470   save_message(__mode | GMSG_HDR, __msg, _hdr);
471 }
472 
473 
474 //  ------------------------------------------------------------------
475 
save_msg(int __mode,gmsg * __msg)476 void JamArea::save_msg(int __mode, gmsg* __msg) {
477 
478   GFTRK("JamArea::save_msg");
479 
480   JamHdr _hdr;
481   save_message(__mode | GMSG_HDRTXT, __msg, _hdr);
482 }
483 
484 
485 //  ------------------------------------------------------------------
486 
del_msg(gmsg * __msg)487 void JamArea::del_msg(gmsg* __msg) {
488 
489   GFTRK("JamArea::del_msg");
490 
491   JamHdr _hdr;
492   save_message(GMSG_HDR | GMSG_DELETE, __msg, _hdr);
493 }
494 
495 
496 //  ------------------------------------------------------------------
497 
new_msgno(gmsg * __msg)498 void JamArea::new_msgno(gmsg* __msg) {
499 
500   GFTRK("JamArea::new_msgno");
501 
502   __msg->msgno = data->hdrinfo.basemsgnum + (filelength(data->fhjdx)/sizeof(JamIndex));
503 
504   GFTRK(0);
505 }
506 
507 
508 //  ------------------------------------------------------------------
509 
update_timesread(gmsg * msg)510 void JamArea::update_timesread(gmsg* msg) {
511 
512   GFTRK("JamArea::update_timesread");
513 
514   lock();
515 
516   lseekset(data->fhjdx, msg->msgno-data->hdrinfo.basemsgnum, sizeof(JamIndex));
517 
518   JamIndex idx;
519   read(data->fhjdx, &idx, sizeof(JamIndex));
520 
521   JamHdr hdr;
522   lseekset(data->fhjhr, idx.hdroffset);
523   read(data->fhjhr, &hdr, sizeof(JamHdr));
524 
525   hdr.timesread = msg->timesread;
526 
527   lseekset(data->fhjhr, idx.hdroffset);
528   write(data->fhjhr, &hdr, sizeof(JamHdr));
529 
530   data->hdrinfo.modcounter++;
531   lseekset(data->fhjhr, 0);
532   write(data->fhjhr, &data->hdrinfo, sizeof(JamHdrInfo));
533 
534   unlock();
535 
536   GFTRK(0);
537 }
538 
539 
540 //  ------------------------------------------------------------------
541 
542