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: gmopcbd4.cpp,v 1.7 2006/05/14 11:45:05 ssianky Exp $
23 //  ------------------------------------------------------------------
24 //  PCBoard msgbase handling.
25 //  ------------------------------------------------------------------
26 
27 
28 //  ------------------------------------------------------------------
29 
30 #include <gdbgerr.h>
31 #include <gdbgtrk.h>
32 #include <gstrall.h>
33 #include <gutlmisc.h>
34 
35 #include <gmopcbd.h>
36 
37 
38 // ------------------------------------------------------------------
39 
lock()40 void PcbArea::lock() {
41 
42   GFTRK("PcbLock");
43 
44   if(not data->islocked) {
45     if(WideCanLock) {
46       long _tries = 0;
47       while(::lock(data->fhmsg, 16, 6) == -1) {
48         if(PopupLocked(++_tries, true, real_path()) == false) {
49           WideLog->ErrLock();
50           raw_close();
51           WideLog->printf("! A PCBoard msgbase file could not be locked.");
52           WideLog->printf(": %s.", real_path());
53           WideLog->ErrOSInfo();
54           LockErrorExit();
55         }
56       }
57       if(_tries)
58         PopupLocked(0, 0, NULL);
59     }
60     lseekset(data->fhmsg, 0);
61     read(data->fhmsg, &data->base, sizeof(PcbBase));
62     lseekset(data->fhmsg, 0);
63     memcpy(data->base.locked, "LOCKED", 6);
64     write(data->fhmsg, &data->base, sizeof(PcbBase));
65     data->base.highmsgno = B2L(data->base.highmsgno);
66     data->base.lowmsgno  = B2L(data->base.lowmsgno);
67     data->base.active    = B2L(data->base.active);
68     data->islocked = true;
69   }
70 
71   GFTRK(0);
72 }
73 
74 
75 // ------------------------------------------------------------------
76 
unlock()77 void PcbArea::unlock() {
78 
79   GFTRK("PcbUnlock");
80 
81   if(WideCanLock and data->islocked)
82     ::unlock(data->fhmsg, 16, 6);
83   lseekset(data->fhmsg, 0);
84   memset(data->base.locked, ' ', 6);
85   data->base.highmsgno = L2B(data->base.highmsgno);
86   data->base.lowmsgno  = L2B(data->base.lowmsgno);
87   data->base.active    = L2B(data->base.active);
88   write(data->fhmsg, &data->base, sizeof(PcbBase));
89   data->base.highmsgno = B2L(data->base.highmsgno);
90   data->base.lowmsgno  = B2L(data->base.lowmsgno);
91   data->base.active    = B2L(data->base.active);
92   data->islocked = false;
93 
94   GFTRK(0);
95 }
96 
97 
98 // ------------------------------------------------------------------
99 
save_message(int __mode,gmsg * __msg,PcbHdr & __hdr)100 void PcbArea::save_message(int __mode, gmsg* __msg, PcbHdr& __hdr) {
101 
102   // Lock and refresh base
103   int _was_locked = data->islocked;
104   if(not _was_locked)
105     lock();
106 
107   // Reset header
108   memset(&__hdr, 0, sizeof(PcbHdr));
109 
110   // Find msgno and index offset
111   PcbIdx _idx;
112   uint32_t oldmsgno = __msg->msgno;
113   int32_t oldtxtstart = __msg->txtstart;
114   int32_t oldtxtlength = __msg->txtlength;
115   if(__mode & GMSG_TXT) {
116     if(data->base.lowmsgno == 0)
117       data->base.lowmsgno = 1;
118     data->base.highmsgno++;
119     data->base.active++;
120     __msg->msgno = data->base.highmsgno;
121     Msgn->Append(__msg->msgno);
122   }
123   int32_t _idxoffset = (__msg->msgno-data->base.lowmsgno)*sizeof(PcbIdx);
124   __hdr.blocks = (byte)__msg->txtblocks;
125   _idx.num = __msg->msgno;
126   _idx.reserved[0] = _idx.reserved[1] = _idx.reserved[2] = 0;
127 
128   // Convert msgno and replylinks
129   __hdr.msgno = L2B(__msg->msgno);
130   __hdr.refno = L2B(__msg->link.to());
131 
132   // Convert attributes
133   char _status = __msg->pcboard.status;
134   int _pvt = __msg->attr.pvt();
135   int _rcv = __msg->attr.rcv();
136   if(_rcv) {
137     switch(_status) {
138       case '$':   __hdr.status = '#';   break;
139       case '!':   __hdr.status = '#';   break;
140       case '%':   __hdr.status = '^';   break;
141       case '~':   __hdr.status = '`';   break;
142       case '*':   __hdr.status = '+';   break;
143       case ' ':   __hdr.status = '-';   break;
144       default:    __hdr.status = _pvt ? '+' : '-';
145     }
146   }
147   else {
148     if(_status and not _pvt)
149       __hdr.status = _status;
150     else if(_pvt)
151       __hdr.status = '*';
152     else
153       __hdr.status = ' ';
154   }
155   _idx.status = __hdr.status;
156   __hdr.activestatus = (__mode & GMSG_DELETE) ? '\xE2' : '\xE1';
157   __hdr.echoed = ((isnet() or isecho()) and not isinternet()) ? 'E' : ' ';
158 
159   // Convert dates and times
160   char _dtbuf[9];
161   struct tm _tm; ggmtime(&_tm, &__msg->written);
162   memcpy(__hdr.date, strftimei(_dtbuf, 9, __msg->attr.uns() ? "%d-%m-%y" : "%d-%m\xC4%y", &_tm), 8);
163   memcpy(__hdr.time, strftimei(_dtbuf, 6, "%H:%M", &_tm), 5);
164 
165   _idx.date = (word)YMD2JDN(1900+_tm.tm_year, _tm.tm_mon+1, _tm.tm_mday);
166 
167   if (__msg->link.first())
168   {
169     __hdr.hasreply = 'R';
170     ggmtime(&_tm, &__msg->pcboard.reply_written);
171     int _year = _tm.tm_year % 100;
172     __hdr.replydate = L2B((10000L*_year) + (100L*(_tm.tm_mon+1)) + _tm.tm_mday);
173     memcpy(__hdr.replytime, strftimei(_dtbuf, 6, "%H:%M", &_tm), 5);
174   }
175   else
176   {
177     __hdr.hasreply = ' ';
178     __hdr.replydate = L2B(0);
179     memcpy(__hdr.replytime, "     ", 5);
180   }
181 
182   // Convert names, subject and password
183   char tobuf[150];
184   char bybuf[150];
185   strcpy(tobuf, __msg->to);
186   strcpy(bybuf, __msg->by);
187   int _tolen = strlen(tobuf);
188   int _bylen = strlen(bybuf);
189   int _relen = strlen(__msg->re);
190   int _pwlen = strlen(__msg->pcboard.password);
191   memset(__hdr.destname, ' ', 25);
192   memset(__hdr.origname, ' ', 25);
193   memset(__hdr.subject,  ' ', 25);
194   memset(__hdr.password, ' ', 12);
195   strncpy(__hdr.destname, tobuf, MinV(_tolen, 25));
196   strncpy(__hdr.origname, bybuf, MinV(_bylen, 25));
197   strncpy(__hdr.subject,  __msg->re, MinV(_relen, 25));
198   strncpy(__hdr.password, __msg->pcboard.password, MinV(_pwlen, 12));
199   memcpy(_idx.to, __hdr.destname, 25);
200   memcpy(_idx.from, __hdr.origname, 25);
201   if(isnet()) {
202     char toaddr[40];
203     char byaddr[40];
204     __msg->dest.make_string(toaddr);
205     strcpy(byaddr, " [");
206     __msg->orig.make_string(byaddr+2);
207     strcat(byaddr, "]");
208     sprintf(tobuf+strlen(tobuf), "@%s%s%s%s",
209       toaddr,
210       __msg->attr.cra() ? " +C" : "",
211       __msg->attr.dir() ? " +D" : "",
212       byaddr
213     );
214     _tolen = strlen(tobuf);
215     _bylen = strlen(bybuf);
216   }
217 
218   // Determine size of the msg text including extended headers
219   uint _txtlen = 0;
220   if(__mode & GMSG_TXT) {
221     __msg->txtlength = _txtlen = strlen(__msg->txt);
222     if((_tolen > 25) or isnet()) {
223       __msg->txtlength += sizeof(PcbExtHdr);
224       __hdr.exthdrflags |= 0x01;
225     }
226     if((_bylen > 25) or isnet()) {
227       __msg->txtlength += sizeof(PcbExtHdr);
228       __hdr.exthdrflags |= 0x02;
229     }
230     if(_relen > 25) {
231       __msg->txtlength += sizeof(PcbExtHdr);
232       __hdr.exthdrflags |= 0x04;
233     }
234 
235     // Translate msg text to PCB linefeeds if running non-foreign system
236     if(not wide->foreign)
237       strchg(__msg->txt, 0x0D, 0xE3);
238 
239     // Calculate new number of blocks
240     __hdr.blocks = (byte)(1 + (__msg->txtlength/128) + ((__msg->txtlength%128)?1:0));
241 
242     // Determine where to write the message text
243     __msg->txtstart = filelength(data->fhmsg);
244     __msg->txtblocks = __hdr.blocks;
245   }
246 
247   // Write index
248   _idx.offset = (__mode & GMSG_DELETE) ? -__msg->txtstart : __msg->txtstart;
249   lseekset(data->fhidx, _idxoffset);
250   write(data->fhidx, &_idx, sizeof(PcbIdx));
251 
252   // Write header
253   lseekset(data->fhmsg, AbsV(_idx.offset));
254   write(data->fhmsg, &__hdr, sizeof(PcbHdr));
255 
256   // Writing msg text?
257   if(__mode & GMSG_TXT) {
258 
259     uint _txtlenwritten = 0;
260 
261     // Write extended headers
262     if((_tolen > 25) or isnet()) {
263       PcbExtHdr _ehdr;
264       _ehdr.id = 0x40FF;
265       _ehdr.colon = ':';
266       _ehdr.status = 'N';
267       _ehdr.separator = wide->foreign ? '\x0D' : '\xE3';
268       memcpy(_ehdr.function, "TO     ", 7);
269       memset(_ehdr.desc, ' ', 60);
270       memcpy(_ehdr.desc, tobuf, MinV(60,_tolen));
271       write(data->fhmsg, &_ehdr, sizeof(PcbExtHdr));
272       _txtlenwritten += sizeof(PcbExtHdr);
273       if(_tolen > 60) {
274         memcpy(_ehdr.function, "TO2    ", 7);
275         memset(_ehdr.desc, ' ', 60);
276         memcpy(_ehdr.desc, tobuf+60, MinV(60,(_tolen-60)));
277         write(data->fhmsg, &_ehdr, sizeof(PcbExtHdr));
278         _txtlenwritten += sizeof(PcbExtHdr);
279       }
280     }
281     if((_bylen > 25) or isnet()) {
282       PcbExtHdr _ehdr;
283       _ehdr.id = 0x40FF;
284       _ehdr.colon = ':';
285       _ehdr.status = 'N';
286       _ehdr.separator = wide->foreign ? '\x0D' : '\xE3';
287       memcpy(_ehdr.function, "FROM   ", 7);
288       memset(_ehdr.desc, ' ', 60);
289       memcpy(_ehdr.desc, bybuf, MinV(60,_bylen));
290       write(data->fhmsg, &_ehdr, sizeof(PcbExtHdr));
291       _txtlenwritten += sizeof(PcbExtHdr);
292       if(_bylen > 60) {
293         memcpy(_ehdr.function, "FROM2  ", 7);
294         memset(_ehdr.desc, ' ', 60);
295         memcpy(_ehdr.desc, bybuf+60, MinV(60,(_bylen-60)));
296         write(data->fhmsg, &_ehdr, sizeof(PcbExtHdr));
297         _txtlenwritten += sizeof(PcbExtHdr);
298       }
299     }
300     if(_relen > 25) {
301       PcbExtHdr _ehdr;
302       _ehdr.id = 0x40FF;
303       memcpy(_ehdr.function, "SUBJECT", 7);
304       _ehdr.colon = ':';
305       memset(_ehdr.desc, ' ', 60);
306       memcpy(_ehdr.desc, __msg->re, MinV(60,_relen));
307       _ehdr.status = 'N';
308       _ehdr.separator = wide->foreign ? '\x0D' : '\xE3';
309       write(data->fhmsg, &_ehdr, sizeof(PcbExtHdr));
310       _txtlenwritten += sizeof(PcbExtHdr);
311     }
312 
313     // Special handling of netmails
314     #if 0
315     if(isnet()) {
316 
317       // Write destination address in netmail for FidoPCB
318       char _abuf[40], _sbuf[45];
319       sprintf(_sbuf, "(%s)%c",
320         __msg->dest.make_string(_abuf),
321         wide->foreign ? '\x0D' : '\xE3'
322       );
323       uint _sbuflen = strlen(_sbuf);
324       write(data->fhmsg, _sbuf, _sbuflen);
325       _txtlenwritten += _sbuflen;
326 
327       // Write flags
328       int _hld = __msg->attr.hld();
329       int _imm = __msg->attr.imm();
330       int _cra = __msg->attr.cra();
331       int _zon = __msg->attr.zon();
332       if(_hld or _imm or _cra or _zon) {
333         strcpy(_sbuf, "(" /*)*/);
334         if(_hld)
335           strcat(_sbuf, "HOLD,");
336         if(_imm)
337           strcat(_sbuf, "IMM,");
338         if(_cra)
339           strcat(_sbuf, "CRASH,");
340         if(_zon)
341           strcat(_sbuf, "INTL,");
342         _sbuf[strlen(_sbuf)] = /*(*/ ')';
343         _sbuflen = strlen(_sbuf);
344         write(data->fhmsg, _sbuf, _sbuflen);
345         _txtlenwritten += _sbuflen;
346       }
347     }
348     #endif
349 
350     // Write message text
351     write(data->fhmsg, __msg->txt, _txtlen);
352     _txtlenwritten += _txtlen;
353 
354     // Write remainder of the last message block (if any)
355     uint _remainlen = ((__hdr.blocks-1)*128) - _txtlenwritten;
356     if(_remainlen) {
357       byte _remainrecord[128];
358       memset(_remainrecord, ' ', 128);
359       write(data->fhmsg, _remainrecord, _remainlen);
360     }
361 
362     // Translate back
363     if(not wide->foreign)
364       strchg(__msg->txt, 0xE3, 0x0D);
365   }
366 
367   if(not (__mode & GMSG_DELETE)) {
368     // Set the mail waiting flag
369     int _status = true;
370     // Reset it if the msg is being received
371     if((__mode & GMSG_UPDATE) and __msg->attr.rcv())
372       _status = false;
373     // Don't touch the flag if the msg was already received
374     if(not (_status and __msg->attr.rcv()))
375       pcbwide->user->update_mail_waiting(__msg->to, board(), _status);
376   }
377 
378   if((__mode & GMSG_TXT) and (__mode & GMSG_UPDATE)) {
379     __msg->msgno = oldmsgno;
380     __msg->txtstart = oldtxtstart;
381     __msg->txtlength = oldtxtlength;
382     del_msg(__msg);
383   }
384 
385   // Unlock and update base
386   if(not _was_locked)
387     unlock();
388 
389   GFTRK(0);
390 }
391 
392 
393 // ------------------------------------------------------------------
394 
save_hdr(int __mode,gmsg * __msg)395 void PcbArea::save_hdr(int __mode, gmsg* __msg) {
396 
397   GFTRK("PcbSaveHdr");
398 
399   PcbHdr _hdr;
400   save_message(__mode|GMSG_HDR, __msg, _hdr);
401 }
402 
403 
404 // ------------------------------------------------------------------
405 
save_msg(int __mode,gmsg * __msg)406 void PcbArea::save_msg(int __mode, gmsg* __msg) {
407 
408   GFTRK("PcbSaveMsg");
409 
410   PcbHdr _hdr;
411   save_message(__mode|GMSG_HDRTXT, __msg, _hdr);
412 }
413 
414 
415 //  ------------------------------------------------------------------
416 
del_msg(gmsg * __msg)417 void PcbArea::del_msg(gmsg* __msg) {
418 
419   GFTRK("PcbDelMsg");
420 
421   PcbHdr _hdr;
422   save_message(GMSG_HDR | GMSG_DELETE, __msg, _hdr);
423 }
424 
425 
426 // ------------------------------------------------------------------
427 
new_msgno(gmsg * msg)428 void PcbArea::new_msgno(gmsg* msg) {
429 
430   GFTRK("PcbNewMsgno");
431 
432   msg->msgno = data->base.highmsgno + 1;
433 
434   GFTRK(0);
435 }
436 
437 
438 //  ------------------------------------------------------------------
439 
update_timesread(gmsg *)440 void PcbArea::update_timesread(gmsg*) {
441 
442 }
443 
444 
445 // ------------------------------------------------------------------
446 
447