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