1 // This may look like C code, but it is really -*- C++ -*-
2
3 // ------------------------------------------------------------------
4 // The Goldware Library
5 // Copyright (C) 2000 Alexander S. Aganichev
6 // ------------------------------------------------------------------
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program 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 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 // ------------------------------------------------------------------
21 // $Id: gmosmb1.cpp,v 1.22 2016/02/01 14:29:17 vasilyevmax Exp $
22 // ------------------------------------------------------------------
23 // Synchronet message base
24 // ------------------------------------------------------------------
25
26 #include <cerrno>
27 #include <gcrcall.h>
28 #include <gstrall.h>
29 #include <gmemall.h>
30 #include <gmemdbg.h>
31 #include <gdbgerr.h>
32 #include <gdbgtrk.h>
33 #include <gmosmb.h>
34
35
36 // ------------------------------------------------------------------
37
38 smb_t* smbdata = NULL;
39 int smbdatano = 0;
40
41
42 // ------------------------------------------------------------------
43
SMBExit()44 void SMBExit() {
45
46 throw_release(smbdata);
47 }
48
49
50 // ------------------------------------------------------------------
51
SMBInit()52 void SMBInit() {
53
54 smbdata = (smb_t *)throw_calloc(3, sizeof(smb_t));
55 }
56
57
58 // ------------------------------------------------------------------
59
data_open()60 void SMBArea::data_open() {
61
62 data = smbdata + (smbdatano++);
63 strxcpy(data->file, real_path(), sizeof(data->file) - 3);
64 data->sdt_fp = data->shd_fp = data->sid_fp = data->sda_fp = data->sha_fp = NULL;
65 data->retry_time = 1;
66 data->last_error[0] = NUL;
67 }
68
69
70 // ------------------------------------------------------------------
71
data_close()72 void SMBArea::data_close() {
73
74 smbdatano--;
75 data = NULL;
76 }
77
78
79 // ------------------------------------------------------------------
80 // Open the Synchronet message base
81
open()82 void SMBArea::open() {
83
84 GFTRK("SMBOpen");
85
86 isopen++;
87 if(isopen > 2) {
88 WideLog->ErrTest();
89 WideLog->printf("! Trying to open a Synchronet msgbase more than twice.");
90 WideLog->printf(": %s, %s.", echoid(), path());
91 WideLog->printf("+ Info: This indicates a serious bug.");
92 WideLog->printf("+ Advice: Report to the Author immediately.");
93 TestErrorExit();
94 }
95 if(isopen == 1) {
96 if(ispacked()) {
97 isopen--;
98 const char* newpath = Unpack(path());
99 if(newpath == NULL)
100 packed(false);
101 set_real_path(newpath ? newpath : path());
102 isopen++;
103 }
104 data_open();
105
106 int _tries = 0;
107
108 for(;;) {
109 if(smb_open(data) != 0) {
110
111 if((errno != EACCES) or (PopupLocked(++_tries, false, data->file) == false)) {
112
113 // User requested to exit
114 WideLog->ErrOpen();
115 WideLog->printf("! Synchronet message base could not be opened (%s).", data->last_error);
116 WideLog->printf(": %s", real_path());
117 WideLog->ErrOSInfo();
118 OpenErrorExit();
119 }
120 }
121 else
122 break;
123 };
124
125 // Remove the popup window
126 if(_tries)
127 PopupLocked(0, 0, NULL);
128
129 if(not fsize(data->shd_fp)) {
130 data->status.max_crcs = 0;
131 data->status.max_age = 0;
132 data->status.max_msgs = 1000;
133 data->status.attr = 0;
134 if(smb_create(data) != 0) {
135 smb_close(data);
136
137 WideLog->ErrOpen();
138 WideLog->printf("! Synchronet message base could not be created (%s).", data->last_error);
139 WideLog->printf(": %s", real_path());
140 WideLog->ErrOSInfo();
141 OpenErrorExit();
142 }
143 }
144 scan();
145 }
146
147 GFTRK(0);
148 }
149
150
151 // ------------------------------------------------------------------
152
close()153 void SMBArea::close()
154 {
155 GFTRK("SMBClose");
156
157 if(isopen) {
158 if(isopen == 1) {
159 smb_close(data);
160 data_close();
161 if(ispacked()) {
162 CleanUnpacked(real_path());
163 }
164 }
165 isopen--;
166 }
167 else {
168 WideLog->ErrTest();
169 WideLog->printf("! Trying to close an already closed Synchronet msgbase.");
170 WideLog->printf(": %s, %s.", echoid(), path());
171 WideLog->printf("+ Info: This indicates a potentially serious bug.");
172 WideLog->printf("+ Advice: Report to the Author immediately.");
173 TestErrorExit();
174 }
175
176 GFTRK(0);
177 }
178
179
180 // ------------------------------------------------------------------
181
suspend()182 void SMBArea::suspend()
183 {
184 smb_close(data);
185 }
186
187
188 // ------------------------------------------------------------------
189
resume()190 void SMBArea::resume()
191 {
192 int _tries = 0;
193
194 for(;;) {
195 if(smb_open(data) != 0) {
196
197 if((errno != EACCES) or (PopupLocked(++_tries, false, data->file) == false)) {
198
199 // User requested to exit
200 WideLog->ErrOpen();
201 WideLog->printf("! Synchronet message base could not be opened (%s).", data->last_error);
202 WideLog->printf(": %s", real_path());
203 WideLog->ErrOSInfo();
204 OpenErrorExit();
205 }
206 }
207 else
208 break;
209 };
210
211 // Remove the popup window
212 if(_tries)
213 PopupLocked(0, 0, NULL);
214
215 if(not fsize(data->shd_fp)) {
216 data->status.max_crcs = 0;
217 data->status.max_age = 0;
218 data->status.max_msgs = 1000;
219 data->status.attr = 0;
220 if(smb_create(data) != 0) {
221 smb_close(data);
222
223 WideLog->ErrOpen();
224 WideLog->printf("! Synchronet message base could not be created (%s).", data->last_error);
225 WideLog->printf(": %s", real_path());
226 WideLog->ErrOSInfo();
227 OpenErrorExit();
228 }
229 }
230 }
231
232
233 // ------------------------------------------------------------------
234
lock()235 void SMBArea::lock()
236 {
237 }
238
239
240 // ------------------------------------------------------------------
241
unlock()242 void SMBArea::unlock()
243 {
244 }
245
246
247 // ------------------------------------------------------------------
248
load_hdr(gmsg * __msg,smbmsg_t * smsg)249 int SMBArea::load_hdr(gmsg* __msg, smbmsg_t *smsg)
250 {
251 GFTRK("SMBLoadHdr");
252
253 smbmsg_t local_smsg, *smsgp;
254 smsgp = smsg ? smsg : &local_smsg;
255 uint32_t reln = Msgn->ToReln(__msg->msgno);
256 if(reln == 0) {
257 GFTRK(0);
258 return false;
259 }
260 fseek(data->sid_fp, (reln - 1L) * sizeof(idxrec_t), SEEK_SET);
261 if(not fread(&smsgp->idx, 1, sizeof(idxrec_t), data->sid_fp) or (smb_lockmsghdr(data, smsgp) != 0)) {
262 GFTRK(0);
263 return false;
264 }
265 int rv = smb_getmsghdr(data, smsgp);
266 smb_unlockmsghdr(data, smsgp);
267 if(rv != 0) {
268 GFTRK(0);
269 return false;
270 }
271 __msg->link.to_set(smsgp->hdr.thread_orig);
272 __msg->link.next_set(smsgp->hdr.thread_next);
273 __msg->link.first_set(smsgp->hdr.thread_first);
274
275 strxcpy(__msg->by, (char *)smsgp->from, 36);
276 strxcpy(__msg->to, (char *)smsgp->to, 36);
277 strxcpy(__msg->re, (char *)smsgp->subj, 72);
278
279 if(smsgp->from_net.type == NET_FIDO) {
280 __msg->orig.zone = __msg->oorig.zone = ((fidoaddr_t *)smsgp->from_net.addr)->zone;
281 __msg->orig.net = __msg->oorig.net = ((fidoaddr_t *)smsgp->from_net.addr)->net;
282 __msg->orig.node = __msg->oorig.node = ((fidoaddr_t *)smsgp->from_net.addr)->node;
283 __msg->orig.point = __msg->oorig.point = ((fidoaddr_t *)smsgp->from_net.addr)->point;
284 }
285 else {
286 __msg->orig.zone = __msg->oorig.zone = 0;
287 __msg->orig.net = __msg->oorig.net = 0;
288 __msg->orig.node = __msg->oorig.node = 0;
289 __msg->orig.point = __msg->oorig.point = 0;
290 }
291 if(smsgp->to_net.type == NET_FIDO) {
292 __msg->dest.zone = __msg->odest.zone = ((fidoaddr_t *)smsgp->to_net.addr)->zone;
293 __msg->dest.net = __msg->odest.net = ((fidoaddr_t *)smsgp->to_net.addr)->net;
294 __msg->dest.node = __msg->odest.node = ((fidoaddr_t *)smsgp->to_net.addr)->node;
295 __msg->dest.point = __msg->odest.point = ((fidoaddr_t *)smsgp->to_net.addr)->point;
296 }
297 else {
298 __msg->dest.zone = __msg->odest.zone = 0;
299 __msg->dest.net = __msg->odest.net = 0;
300 __msg->dest.node = __msg->odest.node = 0;
301 __msg->dest.point = __msg->odest.point = 0;
302 }
303
304 // Transfer attributes
305 __msg->attr.pvt(smsgp->hdr.attr & MSG_PRIVATE);
306 __msg->attr.rcv(smsgp->hdr.attr & MSG_READ);
307 __msg->attr.lok(smsgp->hdr.attr & MSG_LOCKED);
308 __msg->attr.del(smsgp->hdr.attr & MSG_DELETE);
309 __msg->attr.r_o(smsgp->hdr.attr & MSG_PERMANENT);
310 __msg->attr.loc(smsgp->hdr.netattr & MSG_LOCAL);
311 __msg->attr.cra(smsgp->hdr.netattr & MSG_CRASH);
312 __msg->attr.imm(smsgp->hdr.netattr & MSG_IMMEDIATE);
313 __msg->attr.dir(smsgp->hdr.netattr & MSG_DIRECT);
314 __msg->attr.hld(smsgp->hdr.netattr & MSG_HOLD);
315 __msg->attr.snt(smsgp->hdr.netattr & MSG_SENT);
316 __msg->attr.trs(smsgp->hdr.netattr & MSG_INTRANSIT);
317 __msg->attr.orp(smsgp->hdr.netattr & MSG_ORPHAN);
318 __msg->attr.k_s(smsgp->hdr.netattr & MSG_KILLSENT);
319 __msg->attr.a_s(smsgp->hdr.netattr & MSG_ARCHIVESENT);
320 __msg->attr.zon(smsgp->hdr.netattr & MSG_GATE);
321 __msg->attr.att(smsgp->hdr.auxattr & MSG_FILEATTACH);
322 __msg->attr.frq(smsgp->hdr.auxattr & MSG_FILEREQUEST);
323 __msg->attr.rrq(smsgp->hdr.auxattr & MSG_RECEIPTREQ);
324 __msg->attr.cfm(smsgp->hdr.auxattr & MSG_CONFIRMREQ);
325 __msg->attr.tfs(smsgp->hdr.auxattr & MSG_TRUNCFILE);
326
327 time32_t a = smsgp->hdr.when_written.time;
328 struct tm tp; ggmtime(&tp, &a);
329 tp.tm_isdst = -1;
330 time32_t b = gmktime(&tp);
331 __msg->written = a + a - b;
332 a = smsgp->hdr.when_imported.time;
333 ggmtime(&tp, &a);
334 b = gmktime(&tp);
335 __msg->arrived = a + a - b;
336 __msg->received = 0;
337
338 if(not smsg)
339 smb_freemsgmem(smsgp);
340 GFTRK(0);
341 return true;
342 }
343
344
345 // ------------------------------------------------------------------
346
load_msg(gmsg * msg)347 int SMBArea::load_msg(gmsg* msg)
348 {
349 smbmsg_t smsg;
350 uint16_t xlat;
351 uint8_t *inbuf;
352 int32_t outlen;
353 char buf[512];
354 int i;
355 bool lzh;
356 bool tail = true;
357 uint32_t l;
358 uint32_t txt_len = 1;
359
360 GFTRK("SMBLoadMsg");
361
362 if(not load_hdr(msg, &smsg)) {
363 GFTRK(0);
364 return false;
365 }
366
367 msg->txt = throw_strdup("");
368
369 if(smsg.from_net.type == NET_INTERNET) {
370 sprintf(buf, "\001From: %s (%s)\r", (char *)smsg.from_net.addr, smsg.from);
371 outlen = strlen(buf);
372 msg->txt = (char *)throw_realloc(msg->txt, txt_len+outlen);
373 strcpy(msg->txt+txt_len-1, buf);
374 txt_len+=outlen;
375 }
376 if(smsg.to_net.type == NET_INTERNET) {
377 sprintf(buf, "\001To: %s (%s)\r", (char *)smsg.to_net.addr, smsg.to);
378 outlen = strlen(buf);
379 msg->txt = (char *)throw_realloc(msg->txt, txt_len+outlen);
380 strcpy(msg->txt+txt_len-1, buf);
381 txt_len+=outlen;
382 }
383
384 for(i = 0; i < smsg.total_hfields; i++)
385 switch(smsg.hfield[i].type) {
386 case RFC822MSGID:
387 sprintf(buf, "\001Message-ID: %s\r", (char *)smsg.hfield_dat[i]);
388 goto add;
389 case FIDOMSGID:
390 sprintf(buf, "\001MSGID: %s\r", (char *)smsg.hfield_dat[i]);
391 goto add;
392 case RFC822REPLYID:
393 sprintf(buf, "\001In-Reply-To: %s\r", (char *)smsg.hfield_dat[i]);
394 goto add;
395 case FIDOREPLYID:
396 sprintf(buf, "\001REPLY: %s\r", (char *)smsg.hfield_dat[i]);
397 goto add;
398 case FIDOPID:
399 sprintf(buf, "\001PID: %s\r", (char *)smsg.hfield_dat[i]);
400 strcpy(msg->pid, (char *)smsg.hfield_dat[i]);
401 goto add;
402 case FIDOAREA:
403 sprintf(buf, "\001AREA: %s\r", (char *)smsg.hfield_dat[i]);
404 goto add;
405 case FIDOFLAGS:
406 sprintf(buf, "\001FLAGS: %s\r", (char *)smsg.hfield_dat[i]);
407 goto add;
408 case FIDOCTRL:
409 if(not strncmp((char *)smsg.hfield_dat[i], "Via ", 4) or not strncmp((char *)smsg.hfield_dat[i], "Recd ", 5))
410 break;
411 case RFC822HEADER:
412 if(not strncmp((char *)smsg.hfield_dat[i], "Via:", 4))
413 break;
414 sprintf(buf, "\001%s\r", (char *)smsg.hfield_dat[i]);
415 add:
416 outlen = strlen(buf);
417 msg->txt = (char *)throw_realloc(msg->txt, txt_len+outlen);
418 strcpy(msg->txt+txt_len-1, buf);
419 txt_len+=outlen;
420 break;
421 default:
422 break;
423 }
424
425 for(i = 0; i < smsg.hdr.total_dfields; i++)
426 switch(smsg.dfield[i].type) {
427 case TEXT_BODY:
428 if(tail)
429 tail = false;
430 goto common;
431 case TEXT_TAIL:
432 if(not tail) {
433 tail = true;
434 msg->txt[txt_len-1] = '\r';
435 txt_len++;
436 }
437 common:
438 fseek(data->sdt_fp, smsg.hdr.offset + smsg.dfield[i].offset, SEEK_SET);
439 l = sizeof(xlat);
440 fread(&xlat, sizeof(xlat), 1, data->sdt_fp);
441 lzh = false;
442 if(xlat == XLAT_LZH) {
443 lzh = true;
444 fread(&xlat, sizeof(xlat), 1, data->sdt_fp);
445 l += sizeof(xlat);
446 }
447 if(xlat != XLAT_NONE) /* no other translations currently supported */
448 continue;
449 if(lzh) {
450 inbuf = (uint8_t *)throw_xmalloc(smsg.dfield[i].length);
451 fread(inbuf, smsg.dfield[i].length - l, 1, data->sdt_fp);
452 outlen = *(int32_t *)inbuf;
453 msg->txt = (char *)throw_realloc(msg->txt, txt_len+outlen);
454 lzh_decode(inbuf, smsg.dfield[i].length - l, (uint8_t *)(msg->txt+txt_len-1));
455 throw_xfree(inbuf);
456 }
457 else if(l < smsg.dfield[i].length) {
458 outlen = smsg.dfield[i].length - l;
459 msg->txt = (char *)throw_realloc(msg->txt, txt_len+outlen);
460 fread(msg->txt+txt_len-1, smsg.dfield[i].length - l, 1, data->sdt_fp);
461 }
462 else
463 outlen = 0;
464 txt_len += outlen;
465 msg->txt[txt_len-1] = NUL;
466 break;
467 }
468
469 for(i = 0; i < smsg.total_hfields; i++)
470 switch(smsg.hfield[i].type) {
471 case FIDOPATH:
472 sprintf(buf, "\r\001PATH: %s", (char *)smsg.hfield_dat[i]);
473 goto add2;
474 case FIDOSEENBY:
475 sprintf(buf, "\rSEEN-BY: %s", (char *)smsg.hfield_dat[i]);
476 goto add2;
477 case FIDOCTRL:
478 if(strncmp((char *)smsg.hfield_dat[i], "Via ", 4) and strncmp((char *)smsg.hfield_dat[i], "Recd ", 5))
479 break;
480 sprintf(buf, "\r\001%s", (char *)smsg.hfield_dat[i]);
481 add2:
482 outlen = strlen(buf);
483 msg->txt = (char *)throw_realloc(msg->txt, txt_len+outlen);
484 strcpy(msg->txt+txt_len-1, buf);
485 txt_len+=outlen;
486 break;
487 default:
488 break;
489 }
490
491
492 smb_freemsgmem(&smsg);
493
494 GFTRK(0);
495 return true;
496 }
497
498 // ------------------------------------------------------------------
499 // Returns current timezone offset based on TZ environment variable.
500
tzoffset_in_minutes()501 int tzoffset_in_minutes()
502 {
503 time32_t t1 = gtime(NULL);
504 struct tm tp; ggmtime(&tp, &t1);
505 tp.tm_isdst = -1;
506 time32_t t2 = gmktime(&tp);
507 int dt = (int)(t1 - t2);
508 return dt / 60;
509 }
510
511 // ------------------------------------------------------------------
512
save_hdr(int mode,gmsg * msg)513 void SMBArea::save_hdr(int mode, gmsg* msg)
514 {
515 int rv;
516 char ch;
517 bool done, cr;
518 uint32_t l, m, bodylen, taillen, crc;
519 char *fbuf, *sbody, *stail;
520 char buf[256];
521 smbmsg_t smsg;
522 fidoaddr_t destaddr;
523
524 GFTRK("SMBSaveHdr");
525
526 smb_getstatus(data);
527 memset(&smsg, 0, sizeof(smbmsg_t));
528 if(not (mode & GMSG_NEW)) {
529 uint32_t reln = Msgn->ToReln(msg->msgno);
530 if(reln == 0) {
531 GFTRK(0);
532 return;
533 }
534 fseek(data->sid_fp, (reln - 1L) * sizeof(idxrec_t), SEEK_SET);
535 if(not fread(&smsg.idx, 1, sizeof(idxrec_t), data->sid_fp) or (smb_lockmsghdr(data, &smsg) != 0)) {
536 GFTRK(0);
537 return;
538 }
539 int rv = smb_getmsghdr(data, &smsg);
540 smb_unlockmsghdr(data, &smsg);
541 if(rv != 0) {
542 GFTRK(0);
543 return;
544 }
545 smsg.hdr.attr = 0;
546 smsg.hdr.netattr = 0;
547 smsg.hdr.auxattr = 0;
548 }
549 else
550 {
551 memcpy(smsg.hdr.id, "SHD\x1a", 4);
552 smsg.hdr.version = smb_ver();
553 struct tm tp; ggmtime(&tp, &msg->written);
554 tp.tm_isdst = -1;
555 smsg.hdr.when_written.time = gmktime(&tp);
556 smsg.hdr.when_written.zone = tzoffset_in_minutes();
557 }
558 smsg.hdr.when_imported.time = gtime(NULL);
559 smsg.hdr.when_imported.zone = tzoffset_in_minutes();
560
561 // Transfer attributes
562 if(msg->attr.pvt()) smsg.hdr.attr |= MSG_PRIVATE;
563 if(msg->attr.rcv()) smsg.hdr.attr |= MSG_READ;
564 if(msg->attr.lok()) smsg.hdr.attr |= MSG_LOCKED;
565 if(msg->attr.del()) smsg.hdr.attr |= MSG_DELETE;
566 if(msg->attr.r_o()) smsg.hdr.attr |= MSG_PERMANENT;
567 if(msg->attr.loc()) smsg.hdr.netattr |= MSG_LOCAL;
568 if(msg->attr.cra()) smsg.hdr.netattr |= MSG_CRASH;
569 if(msg->attr.imm()) smsg.hdr.netattr |= MSG_IMMEDIATE;
570 if(msg->attr.dir()) smsg.hdr.netattr |= MSG_DIRECT;
571 if(msg->attr.hld()) smsg.hdr.netattr |= MSG_HOLD;
572 if(msg->attr.snt()) smsg.hdr.netattr |= MSG_SENT;
573 if(msg->attr.trs()) smsg.hdr.netattr |= MSG_INTRANSIT;
574 if(msg->attr.orp()) smsg.hdr.netattr |= MSG_ORPHAN;
575 if(msg->attr.k_s()) smsg.hdr.netattr |= MSG_KILLSENT;
576 if(msg->attr.a_s()) smsg.hdr.netattr |= MSG_ARCHIVESENT;
577 if(msg->attr.zon()) smsg.hdr.netattr |= MSG_GATE;
578 if(msg->attr.att()) smsg.hdr.auxattr |= MSG_FILEATTACH;
579 if(msg->attr.frq()) smsg.hdr.auxattr |= MSG_FILEREQUEST;
580 if(msg->attr.rrq()) smsg.hdr.auxattr |= MSG_RECEIPTREQ;
581 if(msg->attr.cfm()) smsg.hdr.auxattr |= MSG_CONFIRMREQ;
582 if(msg->attr.tfs()) smsg.hdr.auxattr |= MSG_TRUNCFILE;
583
584 smsg.hdr.thread_orig = msg->link.to();
585 smsg.hdr.thread_next = msg->link.next();
586 smsg.hdr.thread_first = msg->link.first();
587
588 if((mode & GMSG_UPDATE) and not (mode & GMSG_TXT)) {
589 if(mode & GMSG_NEW)
590 smb_addmsghdr(data, &smsg, data->status.attr & SMB_HYPERALLOC);
591 else {
592 smsg.idx.time = smsg.hdr.when_imported.time;
593 smsg.idx.attr = smsg.hdr.attr;
594 smsg.offset = Msgn->ToReln(msg->msgno) - 1;
595 smb_putmsg(data, &smsg);
596 }
597 smb_freemsgmem(&smsg);
598 GFTRK(0);
599 return;
600 }
601
602 if(not (mode & GMSG_NEW)) {
603 if(not (data->status.attr & SMB_HYPERALLOC)) {
604 if(smb_open_da(data) == 0) {
605 if(smb_open_ha(data) == 0) {
606 smb_freemsg(data, &smsg);
607 smb_close_ha(data);
608 }
609 smb_close_da(data);
610 }
611 }
612 else {
613 smb_freemsg(data, &smsg);
614 }
615 smb_freemsgmem(&smsg);
616 smsg.dfield = NULL;
617 smsg.hdr.total_dfields = 0;
618 smsg.total_hfields = 0;
619 smsg.hfield = NULL;
620 smsg.hfield_dat = NULL;
621 }
622
623 uint16_t net = NET_FIDO;
624 destaddr.zone = msg->dest.zone;
625 destaddr.net = msg->dest.net;
626 destaddr.node = msg->dest.node;
627 destaddr.point = msg->dest.point;
628 smb_hfield(&smsg, RECIPIENTNETTYPE, sizeof(uint16_t), &net);
629 smb_hfield(&smsg, RECIPIENTNETADDR, sizeof(fidoaddr_t), &destaddr);
630
631 smb_hfield(&smsg, SENDER, strlen(msg->by), msg->by);
632 strcpy(buf, msg->by);
633 strlwr(buf);
634 smsg.idx.from = strCrc16c(buf);
635
636 smb_hfield(&smsg, RECIPIENT, strlen(msg->to), msg->to);
637 strcpy(buf, msg->to);
638 strlwr(buf);
639 smsg.idx.to = strCrc16c(buf);
640
641 smb_hfield(&smsg, SUBJECT, strlen(msg->re), msg->re);
642 strcpy(buf, msg->re);
643 strlwr(buf);
644 smsg.idx.subj = strCrc16c(buf);
645
646 // calculate maximum possible size of sbody/stail
647 for(l = 0, fbuf = msg->txt; *fbuf != NUL; l++, fbuf++)
648 if(*fbuf == CR)
649 ++l;
650
651 l += 2; // reserve 2 bytes for the encoding type
652
653 fbuf = msg->txt;
654 sbody = (char *)throw_malloc(SDT_BLOCK_LEN*smb_datblocks(l))+2;
655 stail = (char *)throw_malloc(SDT_BLOCK_LEN*smb_datblocks(l))+2;
656
657 for(l = bodylen = taillen = done = 0, cr = true; (ch = fbuf[l]) != NUL; l++) {
658 if(ch == CTRL_A and cr) {
659 ++l;
660 if(not strncmp(fbuf+l, "MSGID:", 6)) {
661 l += 6;
662 while(fbuf[l] and fbuf[l] == ' ') l++;
663 m = l;
664 while(fbuf[m] and not iscntrl(fbuf[m])) m++;
665 if(m != l)
666 smb_hfield(&smsg, FIDOMSGID, m-l, fbuf+l);
667 }
668 else if(not strncmp(fbuf+l, "REPLY:", 6)) {
669 l += 6;
670 while(fbuf[l] and fbuf[l] == ' ') l++;
671 m = l;
672 while(fbuf[m] and not iscntrl(fbuf[m])) m++;
673 if(m != l)
674 smb_hfield(&smsg, FIDOREPLYID, m-l, fbuf+l);
675 }
676 else if(not strncmp(fbuf+l, "FLAGS:", 6)) {
677 l += 6;
678 while(fbuf[l] and fbuf[l] == ' ') l++;
679 m = l;
680 while(fbuf[m] and not iscntrl(fbuf[m])) m++;
681 if(m != l)
682 smb_hfield(&smsg, FIDOFLAGS, m-l, fbuf+l);
683 }
684 else if(not strncmp(fbuf+l, "PATH:", 5)) {
685 l += 5;
686 while(fbuf[l] and fbuf[l] == ' ') l++;
687 m = l;
688 while(fbuf[m] and not iscntrl(fbuf[m])) m++;
689 if(m != l)
690 smb_hfield(&smsg, FIDOPATH, m-l, fbuf+l);
691 }
692 else if(not strncmp(fbuf+l, "PID:", 4)) {
693 l += 4;
694 while(fbuf[l] and fbuf[l] == ' ') l++;
695 m = l;
696 while(fbuf[m] and not iscntrl(fbuf[m])) m++;
697 if(m != l)
698 smb_hfield(&smsg, FIDOPID, m-l, fbuf+l);
699 }
700 else {
701 if(strncmp(fbuf+l, "TOPT ", 5) and strncmp(fbuf+l, "FMPT ", 5) and
702 strncmp(fbuf+l, "INTL ", 5)) {
703 while(fbuf[l] and fbuf[l] == ' ') l++;
704 m = l;
705 while(fbuf[m] and not iscntrl(fbuf[m])) m++;
706 if(m != l)
707 smb_hfield(&smsg, FIDOCTRL, m-l, fbuf+l);
708 }
709 }
710 while(fbuf[l] and fbuf[l]!=CR) l++;
711 continue;
712 }
713 if(ch != LF and ch != SOFTCR) {
714 if(cr) {
715 if(not done and not strncmp(fbuf+l, "--- ", 4) or not strncmp(fbuf+l, "---\r", 4))
716 done = true; // tear line and down go into tail
717 else if(done and not strncmp(fbuf+l, "SEEN-BY:", 8)) {
718 l += 8;
719 while(fbuf[l] and fbuf[l] == ' ') l++;
720 m = l;
721 while(fbuf[m] and not iscntrl(fbuf[m])) m++;
722 if(m != l)
723 smb_hfield(&smsg, FIDOSEENBY, m-l, fbuf+l);
724 while(fbuf[l] and fbuf[l]!=CR) l++;
725 continue;
726 }
727 else if(not done and not strncmp(fbuf+l, " * Origin: ", 11))
728 done = true;
729 }
730 if(done)
731 stail[taillen++] = ch;
732 else
733 sbody[bodylen++] = ch;
734 if(ch == CR) {
735 cr = true;
736 if(done)
737 stail[taillen++] = LF;
738 else
739 sbody[bodylen++] = LF;
740 }
741 else
742 cr = false;
743 }
744 }
745 if(bodylen>=2 && sbody[bodylen-2]==CR && sbody[bodylen-1]==LF)
746 bodylen-=2; // remove last CRLF if present
747
748 crc = ~memCrc32(sbody, bodylen, false, CRC32_MASK_CCITT);
749 rv = smb_addcrc(data, crc);
750
751 while(taillen and (iscntrl(stail[taillen-1]) or isspace(stail[taillen-1])))
752 taillen--;
753
754 l = bodylen+2;
755 if(taillen)
756 l += (taillen+2);
757
758 if(not (data->status.attr & SMB_HYPERALLOC)) {
759 if(smb_open_da(data) == 0) {
760 smsg.hdr.offset = smb_allocdat(data, l, 1);
761 smb_close_da(data);
762 }
763 else
764 smsg.hdr.offset = (uint32_t)-1L;
765 }
766 else {
767 smsg.hdr.offset = smb_hallocdat(data);
768 }
769
770 if(smsg.hdr.offset != (uint32_t)-1L) {
771 fseek(data->sdt_fp, smsg.hdr.offset, SEEK_SET);
772 *(uint16_t *)(sbody-2) = XLAT_NONE;
773 l = ftell(data->sdt_fp);
774 fwrite(sbody-2, SDT_BLOCK_LEN, smb_datblocks(bodylen), data->sdt_fp);
775 if(taillen) {
776 fseek(data->sdt_fp, l+bodylen+2, SEEK_SET);
777 *(uint16_t *)(stail-2) = XLAT_NONE;
778 fwrite(stail-2, SDT_BLOCK_LEN, smb_datblocks(taillen), data->sdt_fp);
779 }
780 fflush(data->sdt_fp);
781 smb_dfield(&smsg, TEXT_BODY, bodylen+2);
782 if(taillen)
783 smb_dfield(&smsg, TEXT_TAIL, taillen+2);
784
785 int storage = data->status.attr & SMB_HYPERALLOC;
786
787 if(mode & GMSG_NEW) {
788 smb_addmsghdr(data, &smsg, storage);
789 Msgn->Append(smsg.hdr.number);
790 }
791 else {
792 // Changing message... It is always bad idea since it is usually
793 // undescribed and not supported by the API
794 int32_t l;
795
796 if(data->locked or (smb_locksmbhdr(data) == 0)) {
797 if(smb_getstatus(data) == 0) {
798 if((storage == SMB_HYPERALLOC) or (smb_open_ha(data) == 0)) {
799 smsg.hdr.length = smb_getmsghdrlen(&smsg);
800 if(storage == SMB_HYPERALLOC)
801 l = smb_hallochdr(data);
802 else if(storage == SMB_FASTALLOC)
803 l = smb_fallochdr(data, smsg.hdr.length);
804 else
805 l = smb_allochdr(data, smsg.hdr.length);
806 if(storage != SMB_HYPERALLOC)
807 smb_close_ha(data);
808 if(l!=-1L) {
809 smsg.idx.offset = data->status.header_offset+l;
810 smsg.idx.time = smsg.hdr.when_imported.time;
811 smsg.idx.attr = smsg.hdr.attr;
812 smsg.offset = Msgn->ToReln(msg->msgno) - 1;
813 smb_putmsg(data, &smsg);
814 }
815 }
816 }
817 }
818 smb_unlocksmbhdr(data);
819 }
820 }
821 throw_xfree(sbody-2);
822 throw_xfree(stail-2);
823 smb_freemsgmem(&smsg);
824
825 GFTRK(0);
826 }
827
828
829 // ------------------------------------------------------------------
830
save_msg(int mode,gmsg * msg)831 void SMBArea::save_msg(int mode, gmsg* msg)
832 {
833 GFTRK("SMBSaveMsg");
834
835 save_hdr(mode | GMSG_HDRTXT, msg);
836
837 GFTRK(0);
838 }
839
840
841 // ------------------------------------------------------------------
842
del_msg(gmsg * msg)843 void SMBArea::del_msg(gmsg* msg)
844 {
845 GFTRK("SMBDelMsg");
846
847 smbmsg_t smsg;
848 uint32_t reln = Msgn->ToReln(msg->msgno);
849 if(reln == 0) {
850 GFTRK(0);
851 return;
852 }
853 fseek(data->sid_fp, (reln - 1L) * sizeof(idxrec_t), SEEK_SET);
854 if(not fread(&smsg.idx, 1, sizeof(idxrec_t), data->sid_fp) or (smb_lockmsghdr(data, &smsg) != 0)) {
855 GFTRK(0);
856 return;
857 }
858 if(smb_getmsghdr(data, &smsg) == 0) {
859 smsg.hdr.attr |= MSG_DELETE;
860 smsg.idx.time = smsg.hdr.when_imported.time;
861 smsg.idx.attr = smsg.hdr.attr;
862 smsg.offset = reln - 1L;
863 int rv = smb_putmsg(data, &smsg);
864 smb_unlockmsghdr(data, &smsg);
865 if(rv == 0)
866 msg->attr.del1();
867 }
868 else
869 smb_unlockmsghdr(data, &smsg);
870 smb_freemsgmem(&smsg);
871
872 GFTRK(0);
873 }
874
875
876 // ------------------------------------------------------------------
877
new_msgno(gmsg * msg)878 void SMBArea::new_msgno(gmsg* msg)
879 {
880 int res = smb_getstatus(data);
881 smb_unlocksmbhdr(data);
882 msg->msgno = (res == 0) ? data->status.last_msg+1 : 0;
883 }
884
885
886 // ------------------------------------------------------------------
887
user_lookup(char * lookfor)888 char* SMBArea::user_lookup(char* lookfor)
889 {
890 NW(lookfor);
891 return NULL;
892 }
893
894
895 // ------------------------------------------------------------------
896
renumber()897 int SMBArea::renumber()
898 {
899 return false;
900 }
901
902
903 // ------------------------------------------------------------------
904
update_timesread(gmsg * msg)905 void SMBArea::update_timesread(gmsg* msg)
906 {
907 NW(msg);
908 return;
909 }
910
911
912 // ------------------------------------------------------------------
913
binstr(char * buf,uint16_t length)914 static char *binstr(char *buf, uint16_t length)
915 {
916 static char str[128];
917 char tmp[128];
918 int i;
919
920 str[0] = 0;
921 for(i = 0; i < length; i++)
922 if(buf[i] and not isprint(buf[i]))
923 break;
924 if(i == length) /* not binary */
925 return buf;
926
927 if(length > 42)
928 length = 42;
929
930 for(i = 0; i < length; i++) {
931 sprintf(tmp, "%02X ", buf[i]);
932 strcat(str, tmp);
933 }
934 return str;
935 }
936
937
938 // ------------------------------------------------------------------
939
faddrtoa(fidoaddr_t addr)940 static char *faddrtoa(fidoaddr_t addr)
941 {
942 static char str[25];
943 char point[25];
944
945 sprintf(str, "%u:%u/%u", addr.zone, addr.net, addr.node);
946 if (addr.point) {
947 sprintf(point, ".%u", addr.point);
948 strcat(str, point);
949 }
950 return str;
951 }
952
953
954 // ------------------------------------------------------------------
955
make_dump_msg(Line * & lin,gmsg * msg,char * lng_head)956 Line* SMBArea::make_dump_msg(Line*& lin, gmsg* msg, char* lng_head)
957 {
958
959 GFTRK("SMBMakeDump");
960
961 Line* line = lin =
962 AddLine (NULL, "Hexdump of Synchronet-style message header and text");
963 AddLineF(line, "------------------------------------------------------------------------------");
964 line = AddLine(line, "");
965
966 smbmsg_t smsg;
967 char buf[512];
968 int i;
969
970 GFTRK("SMBLoadMsg");
971
972 if(not load_hdr(msg, &smsg)) {
973 line = AddLine(line, "Error loading header");
974 GFTRK(0);
975 return line;
976 }
977
978 line = AddLineF(line, "Subject : %s", smsg.subj);
979 line = AddLineF(line, "From : %s", smsg.from);
980 line = AddLineF(line, "To : %s", smsg.to);
981 line = AddLineF(line, "Type : %04Xh", smsg.hdr.type);
982 line = AddLineF(line, "Version : %04Xh", smsg.hdr.version);
983 line = AddLineF(line, "Length : %u", smsg.hdr.length);
984 line = AddLineF(line, "Attr : %04Xh", smsg.hdr.attr);
985 line = AddLineF(line, "AUXAttr : %04Xh", smsg.hdr.auxattr);
986 line = AddLineF(line, "NetAttr : %04Xh", smsg.hdr.netattr);
987 gctime(buf, ARRAYSIZE(buf), &smsg.hdr.when_written.time);
988 line = AddLineF(line, "Written : %s", buf);
989 gctime(buf, ARRAYSIZE(buf), &smsg.hdr.when_imported.time);
990 line = AddLineF(line, "Imported : %s", buf);
991 line = AddLineF(line, "Number : %d (%d)", smsg.hdr.number, (int32_t)(ftell(data->sid_fp)/sizeof(idxrec_t)));
992 line = AddLineF(line, "Thread orig : %d", smsg.hdr.thread_orig);
993 line = AddLineF(line, "Thread next : %d", smsg.hdr.thread_next);
994 line = AddLineF(line, "Thread first : %d", smsg.hdr.thread_first);
995 line = AddLineF(line, "Reserved : %s", HexDump16(buf, (const char*)smsg.hdr.reserved, 16, "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X"));
996 line = AddLineF(line, "Offset : %06Xh", smsg.hdr.offset);
997 line = AddLineF(line, "Total dfields : %u", smsg.hdr.total_dfields);
998
999 if(smsg.from_net.type) {
1000 line = AddLineF(line, "From net type : %02Xh", smsg.from_net.type);
1001 line = AddLineF(line, "From net addr : %s", (char *)(smsg.from_net.type == NET_FIDO ? faddrtoa(*(fidoaddr_t *)smsg.from_net.addr) : smsg.from_net.addr));
1002 }
1003
1004 if(smsg.to_net.type) {
1005 line = AddLineF(line, "To net type : %02Xh", smsg.to_net.type);
1006 line = AddLineF(line, "To net addr : %s", (char *)(smsg.to_net.type == NET_FIDO ? faddrtoa(*(fidoaddr_t *)smsg.to_net.addr) : smsg.to_net.addr));
1007 }
1008
1009 if(smsg.replyto_net.type) {
1010 line = AddLineF(line, "Replyto net type : %02Xh", smsg.replyto_net.type);
1011 line = AddLineF(line, "Replyto net addr : %s", (char *)(smsg.replyto_net.type == NET_FIDO ? faddrtoa(*(fidoaddr_t *)smsg.replyto_net.addr) : smsg.replyto_net.addr));
1012 }
1013
1014 line = AddLineF(line, "From agent : %02Xh", smsg.from_agent);
1015 line = AddLineF(line, "To agent : %02Xh", smsg.to_agent);
1016 line = AddLineF(line, "Replyto agent : %02Xh", smsg.replyto_agent);
1017
1018 line = AddLine(line, "");
1019 AddLineF(line, "dfields:");
1020 line = AddLine(line, "");
1021
1022 for (i = 0; i < smsg.hdr.total_dfields; i++) {
1023 line = AddLineF(line, "dfield[%02u].type : %02X", i, smsg.dfield[i].type);
1024 line = AddLineF(line, "dfield[%02u].offset : %u", i, smsg.dfield[i].offset);
1025 line = AddLineF(line, "dfield[%02u].length : %u", i, smsg.dfield[i].length);
1026 }
1027
1028 line = AddLine(line, "");
1029 AddLineF(line, "hfields:");
1030 line = AddLine(line, "");
1031
1032 for (i = 0; i < smsg.total_hfields; i++) {
1033 line = AddLineF(line, "hfield[%02u].type : %02X", i, smsg.hfield[i].type);
1034 line = AddLineF(line, "hfield[%02u].length : %d", i, smsg.hfield[i].length);
1035 line = AddLineF(line, "hfield_dat[%02u] : %s", i, binstr((char *)smsg.hfield_dat[i], smsg.hfield[i].length));
1036 }
1037
1038 line = AddLine(line, "");
1039 AddLineF(line, lng_head);
1040 line = AddLine(line, "");
1041
1042 int _count = 0;
1043 char* _ptr = (char*)&smsg.hdr;
1044 while(_count < sizeof(msghdr_t)) {
1045 sprintf(buf, "%04X ", _count);
1046 HexDump16(buf+7, _ptr, 16, HEX_DUMP2);
1047 line = AddLine(line, buf);
1048 _count += 16;
1049 _ptr += 16;
1050 }
1051 sprintf(buf, "%04X ", _count);
1052 HexDump16(buf+7, _ptr, sizeof(msghdr_t)%16, HEX_DUMP2);
1053 line = AddLine(line, buf);
1054
1055 uint16_t xlat;
1056 uint8_t *inbuf;
1057 int32_t outlen;
1058 bool lzh;
1059 bool tail = true;
1060 uint32_t l;
1061 uint32_t txt_len = 1;
1062
1063 msg->txt = throw_strdup("");
1064
1065 for(i = 0; i < smsg.hdr.total_dfields; i++)
1066 switch(smsg.dfield[i].type) {
1067 case TEXT_BODY:
1068 if(tail)
1069 tail = false;
1070 goto common;
1071 case TEXT_TAIL:
1072 if(not tail) {
1073 tail = true;
1074 msg->txt[txt_len-1] = '\r';
1075 txt_len++;
1076 }
1077 common:
1078 fseek(data->sdt_fp, smsg.hdr.offset + smsg.dfield[i].offset, SEEK_SET);
1079 l = sizeof(xlat);
1080 fread(&xlat, sizeof(xlat), 1, data->sdt_fp);
1081 lzh = false;
1082 if(xlat == XLAT_LZH) {
1083 lzh = true;
1084 fread(&xlat, sizeof(xlat), 1, data->sdt_fp);
1085 l += sizeof(xlat);
1086 }
1087 if(xlat != XLAT_NONE) /* no other translations currently supported */
1088 continue;
1089 if(lzh) {
1090 inbuf = (uint8_t *)throw_xmalloc(smsg.dfield[i].length);
1091 fread(inbuf, smsg.dfield[i].length - l, 1, data->sdt_fp);
1092 outlen = *(int32_t *)inbuf;
1093 msg->txt = (char *)throw_realloc(msg->txt, txt_len+outlen);
1094 lzh_decode(inbuf, smsg.dfield[i].length - l, (uint8_t *)(msg->txt+txt_len-1));
1095 throw_xfree(inbuf);
1096 }
1097 else if(l < smsg.dfield[i].length) {
1098 outlen = smsg.dfield[i].length - l;
1099 msg->txt = (char *)throw_realloc(msg->txt, txt_len+outlen);
1100 fread(msg->txt+txt_len-1, smsg.dfield[i].length - l, 1, data->sdt_fp);
1101 }
1102 else
1103 outlen = 0;
1104 txt_len+=outlen;
1105 msg->txt[txt_len-1] = NUL;
1106 break;
1107 }
1108
1109 smb_freemsgmem(&smsg);
1110
1111 GFTRK(0);
1112
1113 return line;
1114 }
1115
1116
1117 // ------------------------------------------------------------------
1118