// This may look like C code, but it is really -*- C++ -*- // ------------------------------------------------------------------ // The Goldware Library // Copyright (C) 2000 Alexander S. Aganichev // ------------------------------------------------------------------ // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // ------------------------------------------------------------------ // $Id$ // ------------------------------------------------------------------ // Synchronet message base // ------------------------------------------------------------------ #include #include #include #include #include #include #include #include // ------------------------------------------------------------------ smb_t* smbdata = NULL; int smbdatano = 0; // ------------------------------------------------------------------ void SMBExit() { throw_release(smbdata); } // ------------------------------------------------------------------ void SMBInit() { smbdata = (smb_t *)throw_calloc(3, sizeof(smb_t)); } // ------------------------------------------------------------------ void SMBArea::data_open() { data = smbdata + (smbdatano++); strxcpy(data->file, real_path(), sizeof(data->file) - 3); data->sdt_fp = data->shd_fp = data->sid_fp = data->sda_fp = data->sha_fp = NULL; data->retry_time = 1; data->last_error[0] = NUL; } // ------------------------------------------------------------------ void SMBArea::data_close() { smbdatano--; data = NULL; } // ------------------------------------------------------------------ // Open the Synchronet message base void SMBArea::open() { GFTRK("SMBOpen"); isopen++; if(isopen > 2) { WideLog->ErrTest(); WideLog->printf("! Trying to open a Synchronet msgbase more than twice."); WideLog->printf(": %s, %s.", echoid(), path()); WideLog->printf("+ Info: This indicates a serious bug."); WideLog->printf("+ Advice: Report to the Author immediately."); TestErrorExit(); } if(isopen == 1) { if(ispacked()) { isopen--; const char* newpath = Unpack(path()); if(newpath == NULL) packed(false); set_real_path(newpath ? newpath : path()); isopen++; } data_open(); int _tries = 0; for(;;) { if(smb_open(data) != 0) { if((errno != EACCES) or (PopupLocked(++_tries, false, data->file) == false)) { // User requested to exit WideLog->ErrOpen(); WideLog->printf("! Synchronet message base could not be opened (%s).", data->last_error); WideLog->printf(": %s", real_path()); WideLog->ErrOSInfo(); OpenErrorExit(); } } else break; }; // Remove the popup window if(_tries) PopupLocked(0, 0, NULL); if(not fsize(data->shd_fp)) { data->status.max_crcs = 0; data->status.max_age = 0; data->status.max_msgs = 1000; data->status.attr = 0; if(smb_create(data) != 0) { smb_close(data); WideLog->ErrOpen(); WideLog->printf("! Synchronet message base could not be created (%s).", data->last_error); WideLog->printf(": %s", real_path()); WideLog->ErrOSInfo(); OpenErrorExit(); } } scan(); } GFTRK(0); } // ------------------------------------------------------------------ void SMBArea::close() { GFTRK("SMBClose"); if(isopen) { if(isopen == 1) { smb_close(data); data_close(); if(ispacked()) { CleanUnpacked(real_path()); } } isopen--; } else { WideLog->ErrTest(); WideLog->printf("! Trying to close an already closed Synchronet msgbase."); WideLog->printf(": %s, %s.", echoid(), path()); WideLog->printf("+ Info: This indicates a potentially serious bug."); WideLog->printf("+ Advice: Report to the Author immediately."); TestErrorExit(); } GFTRK(0); } // ------------------------------------------------------------------ void SMBArea::suspend() { smb_close(data); } // ------------------------------------------------------------------ void SMBArea::resume() { int _tries = 0; for(;;) { if(smb_open(data) != 0) { if((errno != EACCES) or (PopupLocked(++_tries, false, data->file) == false)) { // User requested to exit WideLog->ErrOpen(); WideLog->printf("! Synchronet message base could not be opened (%s).", data->last_error); WideLog->printf(": %s", real_path()); WideLog->ErrOSInfo(); OpenErrorExit(); } } else break; }; // Remove the popup window if(_tries) PopupLocked(0, 0, NULL); if(not fsize(data->shd_fp)) { data->status.max_crcs = 0; data->status.max_age = 0; data->status.max_msgs = 1000; data->status.attr = 0; if(smb_create(data) != 0) { smb_close(data); WideLog->ErrOpen(); WideLog->printf("! Synchronet message base could not be created (%s).", data->last_error); WideLog->printf(": %s", real_path()); WideLog->ErrOSInfo(); OpenErrorExit(); } } } // ------------------------------------------------------------------ void SMBArea::lock() { } // ------------------------------------------------------------------ void SMBArea::unlock() { } // ------------------------------------------------------------------ int SMBArea::load_hdr(gmsg* __msg, smbmsg_t *smsg) { GFTRK("SMBLoadHdr"); smbmsg_t local_smsg, *smsgp; smsgp = smsg ? smsg : &local_smsg; uint32_t reln = Msgn->ToReln(__msg->msgno); if(reln == 0) { GFTRK(0); return false; } fseek(data->sid_fp, (reln - 1L) * sizeof(idxrec_t), SEEK_SET); if(not fread(&smsgp->idx, 1, sizeof(idxrec_t), data->sid_fp) or (smb_lockmsghdr(data, smsgp) != 0)) { GFTRK(0); return false; } int rv = smb_getmsghdr(data, smsgp); smb_unlockmsghdr(data, smsgp); if(rv != 0) { GFTRK(0); return false; } __msg->link.to_set(smsgp->hdr.thread_orig); __msg->link.next_set(smsgp->hdr.thread_next); __msg->link.first_set(smsgp->hdr.thread_first); strxcpy(__msg->by, (char *)smsgp->from, 36); strxcpy(__msg->to, (char *)smsgp->to, 36); strxcpy(__msg->re, (char *)smsgp->subj, 72); if(smsgp->from_net.type == NET_FIDO) { __msg->orig.zone = __msg->oorig.zone = ((fidoaddr_t *)smsgp->from_net.addr)->zone; __msg->orig.net = __msg->oorig.net = ((fidoaddr_t *)smsgp->from_net.addr)->net; __msg->orig.node = __msg->oorig.node = ((fidoaddr_t *)smsgp->from_net.addr)->node; __msg->orig.point = __msg->oorig.point = ((fidoaddr_t *)smsgp->from_net.addr)->point; } else { __msg->orig.zone = __msg->oorig.zone = 0; __msg->orig.net = __msg->oorig.net = 0; __msg->orig.node = __msg->oorig.node = 0; __msg->orig.point = __msg->oorig.point = 0; } if(smsgp->to_net.type == NET_FIDO) { __msg->dest.zone = __msg->odest.zone = ((fidoaddr_t *)smsgp->to_net.addr)->zone; __msg->dest.net = __msg->odest.net = ((fidoaddr_t *)smsgp->to_net.addr)->net; __msg->dest.node = __msg->odest.node = ((fidoaddr_t *)smsgp->to_net.addr)->node; __msg->dest.point = __msg->odest.point = ((fidoaddr_t *)smsgp->to_net.addr)->point; } else { __msg->dest.zone = __msg->odest.zone = 0; __msg->dest.net = __msg->odest.net = 0; __msg->dest.node = __msg->odest.node = 0; __msg->dest.point = __msg->odest.point = 0; } // Transfer attributes __msg->attr.pvt(smsgp->hdr.attr & MSG_PRIVATE); __msg->attr.rcv(smsgp->hdr.attr & MSG_READ); __msg->attr.lok(smsgp->hdr.attr & MSG_LOCKED); __msg->attr.del(smsgp->hdr.attr & MSG_DELETE); __msg->attr.r_o(smsgp->hdr.attr & MSG_PERMANENT); __msg->attr.loc(smsgp->hdr.netattr & MSG_LOCAL); __msg->attr.cra(smsgp->hdr.netattr & MSG_CRASH); __msg->attr.imm(smsgp->hdr.netattr & MSG_IMMEDIATE); __msg->attr.dir(smsgp->hdr.netattr & MSG_DIRECT); __msg->attr.hld(smsgp->hdr.netattr & MSG_HOLD); __msg->attr.snt(smsgp->hdr.netattr & MSG_SENT); __msg->attr.trs(smsgp->hdr.netattr & MSG_INTRANSIT); __msg->attr.orp(smsgp->hdr.netattr & MSG_ORPHAN); __msg->attr.k_s(smsgp->hdr.netattr & MSG_KILLSENT); __msg->attr.a_s(smsgp->hdr.netattr & MSG_ARCHIVESENT); __msg->attr.zon(smsgp->hdr.netattr & MSG_GATE); __msg->attr.att(smsgp->hdr.auxattr & MSG_FILEATTACH); __msg->attr.frq(smsgp->hdr.auxattr & MSG_FILEREQUEST); __msg->attr.rrq(smsgp->hdr.auxattr & MSG_RECEIPTREQ); __msg->attr.cfm(smsgp->hdr.auxattr & MSG_CONFIRMREQ); __msg->attr.tfs(smsgp->hdr.auxattr & MSG_TRUNCFILE); time32_t a = smsgp->hdr.when_written.time; struct tm tp; ggmtime(&tp, &a); tp.tm_isdst = -1; time32_t b = gmktime(&tp); __msg->written = a + a - b; a = smsgp->hdr.when_imported.time; ggmtime(&tp, &a); b = gmktime(&tp); __msg->arrived = a + a - b; __msg->received = 0; if(not smsg) smb_freemsgmem(smsgp); GFTRK(0); return true; } // ------------------------------------------------------------------ int SMBArea::load_msg(gmsg* msg) { smbmsg_t smsg; uint16_t xlat; uint8_t *inbuf; int32_t outlen; char buf[512]; int i; bool lzh; bool tail = true; uint32_t l; uint32_t txt_len = 1; GFTRK("SMBLoadMsg"); if(not load_hdr(msg, &smsg)) { GFTRK(0); return false; } msg->txt = throw_strdup(""); if(smsg.from_net.type == NET_INTERNET) { sprintf(buf, "\001From: %s (%s)\r", (char *)smsg.from_net.addr, smsg.from); outlen = strlen(buf); msg->txt = (char *)throw_realloc(msg->txt, txt_len+outlen); strcpy(msg->txt+txt_len-1, buf); txt_len+=outlen; } if(smsg.to_net.type == NET_INTERNET) { sprintf(buf, "\001To: %s (%s)\r", (char *)smsg.to_net.addr, smsg.to); outlen = strlen(buf); msg->txt = (char *)throw_realloc(msg->txt, txt_len+outlen); strcpy(msg->txt+txt_len-1, buf); txt_len+=outlen; } for(i = 0; i < smsg.total_hfields; i++) switch(smsg.hfield[i].type) { case RFC822MSGID: sprintf(buf, "\001Message-ID: %s\r", (char *)smsg.hfield_dat[i]); goto add; case FIDOMSGID: sprintf(buf, "\001MSGID: %s\r", (char *)smsg.hfield_dat[i]); goto add; case RFC822REPLYID: sprintf(buf, "\001In-Reply-To: %s\r", (char *)smsg.hfield_dat[i]); goto add; case FIDOREPLYID: sprintf(buf, "\001REPLY: %s\r", (char *)smsg.hfield_dat[i]); goto add; case FIDOPID: sprintf(buf, "\001PID: %s\r", (char *)smsg.hfield_dat[i]); strcpy(msg->pid, (char *)smsg.hfield_dat[i]); goto add; case FIDOAREA: sprintf(buf, "\001AREA: %s\r", (char *)smsg.hfield_dat[i]); goto add; case FIDOFLAGS: sprintf(buf, "\001FLAGS: %s\r", (char *)smsg.hfield_dat[i]); goto add; case FIDOCTRL: if(not strncmp((char *)smsg.hfield_dat[i], "Via ", 4) or not strncmp((char *)smsg.hfield_dat[i], "Recd ", 5)) break; case RFC822HEADER: if(not strncmp((char *)smsg.hfield_dat[i], "Via:", 4)) break; sprintf(buf, "\001%s\r", (char *)smsg.hfield_dat[i]); add: outlen = strlen(buf); msg->txt = (char *)throw_realloc(msg->txt, txt_len+outlen); strcpy(msg->txt+txt_len-1, buf); txt_len+=outlen; break; default: break; } for(i = 0; i < smsg.hdr.total_dfields; i++) switch(smsg.dfield[i].type) { case TEXT_BODY: if(tail) tail = false; goto common; case TEXT_TAIL: if(not tail) { tail = true; msg->txt[txt_len-1] = '\r'; txt_len++; } common: fseek(data->sdt_fp, smsg.hdr.offset + smsg.dfield[i].offset, SEEK_SET); l = sizeof(xlat); fread(&xlat, sizeof(xlat), 1, data->sdt_fp); lzh = false; if(xlat == XLAT_LZH) { lzh = true; fread(&xlat, sizeof(xlat), 1, data->sdt_fp); l += sizeof(xlat); } if(xlat != XLAT_NONE) /* no other translations currently supported */ continue; if(lzh) { inbuf = (uint8_t *)throw_xmalloc(smsg.dfield[i].length); fread(inbuf, smsg.dfield[i].length - l, 1, data->sdt_fp); outlen = *(int32_t *)inbuf; msg->txt = (char *)throw_realloc(msg->txt, txt_len+outlen); lzh_decode(inbuf, smsg.dfield[i].length - l, (uint8_t *)(msg->txt+txt_len-1)); throw_xfree(inbuf); } else if(l < smsg.dfield[i].length) { outlen = smsg.dfield[i].length - l; msg->txt = (char *)throw_realloc(msg->txt, txt_len+outlen); fread(msg->txt+txt_len-1, smsg.dfield[i].length - l, 1, data->sdt_fp); } else outlen = 0; txt_len += outlen; msg->txt[txt_len-1] = NUL; break; } for(i = 0; i < smsg.total_hfields; i++) switch(smsg.hfield[i].type) { case FIDOPATH: sprintf(buf, "\r\001PATH: %s", (char *)smsg.hfield_dat[i]); goto add2; case FIDOSEENBY: sprintf(buf, "\rSEEN-BY: %s", (char *)smsg.hfield_dat[i]); goto add2; case FIDOCTRL: if(strncmp((char *)smsg.hfield_dat[i], "Via ", 4) and strncmp((char *)smsg.hfield_dat[i], "Recd ", 5)) break; sprintf(buf, "\r\001%s", (char *)smsg.hfield_dat[i]); add2: outlen = strlen(buf); msg->txt = (char *)throw_realloc(msg->txt, txt_len+outlen); strcpy(msg->txt+txt_len-1, buf); txt_len+=outlen; break; default: break; } smb_freemsgmem(&smsg); GFTRK(0); return true; } // ------------------------------------------------------------------ // Returns current timezone offset based on TZ environment variable. int tzoffset_in_minutes() { time32_t t1 = gtime(NULL); struct tm tp; ggmtime(&tp, &t1); tp.tm_isdst = -1; time32_t t2 = gmktime(&tp); int dt = (int)(t1 - t2); return dt / 60; } // ------------------------------------------------------------------ void SMBArea::save_hdr(int mode, gmsg* msg) { int rv; char ch; bool done, cr; uint32_t l, m, bodylen, taillen, crc; char *fbuf, *sbody, *stail; char buf[256]; smbmsg_t smsg; fidoaddr_t destaddr; GFTRK("SMBSaveHdr"); smb_getstatus(data); memset(&smsg, 0, sizeof(smbmsg_t)); if(not (mode & GMSG_NEW)) { uint32_t reln = Msgn->ToReln(msg->msgno); if(reln == 0) { GFTRK(0); return; } fseek(data->sid_fp, (reln - 1L) * sizeof(idxrec_t), SEEK_SET); if(not fread(&smsg.idx, 1, sizeof(idxrec_t), data->sid_fp) or (smb_lockmsghdr(data, &smsg) != 0)) { GFTRK(0); return; } int rv = smb_getmsghdr(data, &smsg); smb_unlockmsghdr(data, &smsg); if(rv != 0) { GFTRK(0); return; } smsg.hdr.attr = 0; smsg.hdr.netattr = 0; smsg.hdr.auxattr = 0; } else { memcpy(smsg.hdr.id, "SHD\x1a", 4); smsg.hdr.version = smb_ver(); struct tm tp; ggmtime(&tp, &msg->written); tp.tm_isdst = -1; smsg.hdr.when_written.time = gmktime(&tp); smsg.hdr.when_written.zone = tzoffset_in_minutes(); } smsg.hdr.when_imported.time = gtime(NULL); smsg.hdr.when_imported.zone = tzoffset_in_minutes(); // Transfer attributes if(msg->attr.pvt()) smsg.hdr.attr |= MSG_PRIVATE; if(msg->attr.rcv()) smsg.hdr.attr |= MSG_READ; if(msg->attr.lok()) smsg.hdr.attr |= MSG_LOCKED; if(msg->attr.del()) smsg.hdr.attr |= MSG_DELETE; if(msg->attr.r_o()) smsg.hdr.attr |= MSG_PERMANENT; if(msg->attr.loc()) smsg.hdr.netattr |= MSG_LOCAL; if(msg->attr.cra()) smsg.hdr.netattr |= MSG_CRASH; if(msg->attr.imm()) smsg.hdr.netattr |= MSG_IMMEDIATE; if(msg->attr.dir()) smsg.hdr.netattr |= MSG_DIRECT; if(msg->attr.hld()) smsg.hdr.netattr |= MSG_HOLD; if(msg->attr.snt()) smsg.hdr.netattr |= MSG_SENT; if(msg->attr.trs()) smsg.hdr.netattr |= MSG_INTRANSIT; if(msg->attr.orp()) smsg.hdr.netattr |= MSG_ORPHAN; if(msg->attr.k_s()) smsg.hdr.netattr |= MSG_KILLSENT; if(msg->attr.a_s()) smsg.hdr.netattr |= MSG_ARCHIVESENT; if(msg->attr.zon()) smsg.hdr.netattr |= MSG_GATE; if(msg->attr.att()) smsg.hdr.auxattr |= MSG_FILEATTACH; if(msg->attr.frq()) smsg.hdr.auxattr |= MSG_FILEREQUEST; if(msg->attr.rrq()) smsg.hdr.auxattr |= MSG_RECEIPTREQ; if(msg->attr.cfm()) smsg.hdr.auxattr |= MSG_CONFIRMREQ; if(msg->attr.tfs()) smsg.hdr.auxattr |= MSG_TRUNCFILE; smsg.hdr.thread_orig = msg->link.to(); smsg.hdr.thread_next = msg->link.next(); smsg.hdr.thread_first = msg->link.first(); if((mode & GMSG_UPDATE) and not (mode & GMSG_TXT)) { if(mode & GMSG_NEW) smb_addmsghdr(data, &smsg, data->status.attr & SMB_HYPERALLOC); else { smsg.idx.time = smsg.hdr.when_imported.time; smsg.idx.attr = smsg.hdr.attr; smsg.offset = Msgn->ToReln(msg->msgno) - 1; smb_putmsg(data, &smsg); } smb_freemsgmem(&smsg); GFTRK(0); return; } if(not (mode & GMSG_NEW)) { if(not (data->status.attr & SMB_HYPERALLOC)) { if(smb_open_da(data) == 0) { if(smb_open_ha(data) == 0) { smb_freemsg(data, &smsg); smb_close_ha(data); } smb_close_da(data); } } else { smb_freemsg(data, &smsg); } smb_freemsgmem(&smsg); smsg.dfield = NULL; smsg.hdr.total_dfields = 0; smsg.total_hfields = 0; smsg.hfield = NULL; smsg.hfield_dat = NULL; } uint16_t net = NET_FIDO; destaddr.zone = msg->dest.zone; destaddr.net = msg->dest.net; destaddr.node = msg->dest.node; destaddr.point = msg->dest.point; smb_hfield(&smsg, RECIPIENTNETTYPE, sizeof(uint16_t), &net); smb_hfield(&smsg, RECIPIENTNETADDR, sizeof(fidoaddr_t), &destaddr); smb_hfield(&smsg, SENDER, strlen(msg->by), msg->by); strcpy(buf, msg->by); strlwr(buf); smsg.idx.from = strCrc16c(buf); smb_hfield(&smsg, RECIPIENT, strlen(msg->to), msg->to); strcpy(buf, msg->to); strlwr(buf); smsg.idx.to = strCrc16c(buf); smb_hfield(&smsg, SUBJECT, strlen(msg->re), msg->re); strcpy(buf, msg->re); strlwr(buf); smsg.idx.subj = strCrc16c(buf); // calculate maximum possible size of sbody/stail for(l = 0, fbuf = msg->txt; *fbuf != NUL; l++, fbuf++) if(*fbuf == CR) ++l; l += 2; // reserve 2 bytes for the encoding type fbuf = msg->txt; sbody = (char *)throw_malloc(SDT_BLOCK_LEN*smb_datblocks(l))+2; stail = (char *)throw_malloc(SDT_BLOCK_LEN*smb_datblocks(l))+2; for(l = bodylen = taillen = done = 0, cr = true; (ch = fbuf[l]) != NUL; l++) { if(ch == CTRL_A and cr) { ++l; if(not strncmp(fbuf+l, "MSGID:", 6)) { l += 6; while(fbuf[l] and fbuf[l] == ' ') l++; m = l; while(fbuf[m] and not iscntrl(fbuf[m])) m++; if(m != l) smb_hfield(&smsg, FIDOMSGID, m-l, fbuf+l); } else if(not strncmp(fbuf+l, "REPLY:", 6)) { l += 6; while(fbuf[l] and fbuf[l] == ' ') l++; m = l; while(fbuf[m] and not iscntrl(fbuf[m])) m++; if(m != l) smb_hfield(&smsg, FIDOREPLYID, m-l, fbuf+l); } else if(not strncmp(fbuf+l, "FLAGS:", 6)) { l += 6; while(fbuf[l] and fbuf[l] == ' ') l++; m = l; while(fbuf[m] and not iscntrl(fbuf[m])) m++; if(m != l) smb_hfield(&smsg, FIDOFLAGS, m-l, fbuf+l); } else if(not strncmp(fbuf+l, "PATH:", 5)) { l += 5; while(fbuf[l] and fbuf[l] == ' ') l++; m = l; while(fbuf[m] and not iscntrl(fbuf[m])) m++; if(m != l) smb_hfield(&smsg, FIDOPATH, m-l, fbuf+l); } else if(not strncmp(fbuf+l, "PID:", 4)) { l += 4; while(fbuf[l] and fbuf[l] == ' ') l++; m = l; while(fbuf[m] and not iscntrl(fbuf[m])) m++; if(m != l) smb_hfield(&smsg, FIDOPID, m-l, fbuf+l); } else { if(strncmp(fbuf+l, "TOPT ", 5) and strncmp(fbuf+l, "FMPT ", 5) and strncmp(fbuf+l, "INTL ", 5)) { while(fbuf[l] and fbuf[l] == ' ') l++; m = l; while(fbuf[m] and not iscntrl(fbuf[m])) m++; if(m != l) smb_hfield(&smsg, FIDOCTRL, m-l, fbuf+l); } } while(fbuf[l] and fbuf[l]!=CR) l++; continue; } if(ch != LF and ch != SOFTCR) { if(cr) { if(not done and not strncmp(fbuf+l, "--- ", 4) or not strncmp(fbuf+l, "---\r", 4)) done = true; // tear line and down go into tail else if(done and not strncmp(fbuf+l, "SEEN-BY:", 8)) { l += 8; while(fbuf[l] and fbuf[l] == ' ') l++; m = l; while(fbuf[m] and not iscntrl(fbuf[m])) m++; if(m != l) smb_hfield(&smsg, FIDOSEENBY, m-l, fbuf+l); while(fbuf[l] and fbuf[l]!=CR) l++; continue; } else if(not done and not strncmp(fbuf+l, " * Origin: ", 11)) done = true; } if(done) stail[taillen++] = ch; else sbody[bodylen++] = ch; if(ch == CR) { cr = true; if(done) stail[taillen++] = LF; else sbody[bodylen++] = LF; } else cr = false; } } if(bodylen>=2 && sbody[bodylen-2]==CR && sbody[bodylen-1]==LF) bodylen-=2; // remove last CRLF if present crc = ~memCrc32(sbody, bodylen, false, CRC32_MASK_CCITT); rv = smb_addcrc(data, crc); while(taillen and (iscntrl(stail[taillen-1]) or isspace(stail[taillen-1]))) taillen--; l = bodylen+2; if(taillen) l += (taillen+2); if(not (data->status.attr & SMB_HYPERALLOC)) { if(smb_open_da(data) == 0) { smsg.hdr.offset = smb_allocdat(data, l, 1); smb_close_da(data); } else smsg.hdr.offset = (uint32_t)-1L; } else { smsg.hdr.offset = smb_hallocdat(data); } if(smsg.hdr.offset != (uint32_t)-1L) { fseek(data->sdt_fp, smsg.hdr.offset, SEEK_SET); *(uint16_t *)(sbody-2) = XLAT_NONE; l = ftell(data->sdt_fp); fwrite(sbody-2, SDT_BLOCK_LEN, smb_datblocks(bodylen), data->sdt_fp); if(taillen) { fseek(data->sdt_fp, l+bodylen+2, SEEK_SET); *(uint16_t *)(stail-2) = XLAT_NONE; fwrite(stail-2, SDT_BLOCK_LEN, smb_datblocks(taillen), data->sdt_fp); } fflush(data->sdt_fp); smb_dfield(&smsg, TEXT_BODY, bodylen+2); if(taillen) smb_dfield(&smsg, TEXT_TAIL, taillen+2); int storage = data->status.attr & SMB_HYPERALLOC; if(mode & GMSG_NEW) { smb_addmsghdr(data, &smsg, storage); Msgn->Append(smsg.hdr.number); } else { // Changing message... It is always bad idea since it is usually // undescribed and not supported by the API int32_t l; if(data->locked or (smb_locksmbhdr(data) == 0)) { if(smb_getstatus(data) == 0) { if((storage == SMB_HYPERALLOC) or (smb_open_ha(data) == 0)) { smsg.hdr.length = smb_getmsghdrlen(&smsg); if(storage == SMB_HYPERALLOC) l = smb_hallochdr(data); else if(storage == SMB_FASTALLOC) l = smb_fallochdr(data, smsg.hdr.length); else l = smb_allochdr(data, smsg.hdr.length); if(storage != SMB_HYPERALLOC) smb_close_ha(data); if(l!=-1L) { smsg.idx.offset = data->status.header_offset+l; smsg.idx.time = smsg.hdr.when_imported.time; smsg.idx.attr = smsg.hdr.attr; smsg.offset = Msgn->ToReln(msg->msgno) - 1; smb_putmsg(data, &smsg); } } } } smb_unlocksmbhdr(data); } } throw_xfree(sbody-2); throw_xfree(stail-2); smb_freemsgmem(&smsg); GFTRK(0); } // ------------------------------------------------------------------ void SMBArea::save_msg(int mode, gmsg* msg) { GFTRK("SMBSaveMsg"); save_hdr(mode | GMSG_HDRTXT, msg); GFTRK(0); } // ------------------------------------------------------------------ void SMBArea::del_msg(gmsg* msg) { GFTRK("SMBDelMsg"); smbmsg_t smsg; uint32_t reln = Msgn->ToReln(msg->msgno); if(reln == 0) { GFTRK(0); return; } fseek(data->sid_fp, (reln - 1L) * sizeof(idxrec_t), SEEK_SET); if(not fread(&smsg.idx, 1, sizeof(idxrec_t), data->sid_fp) or (smb_lockmsghdr(data, &smsg) != 0)) { GFTRK(0); return; } if(smb_getmsghdr(data, &smsg) == 0) { smsg.hdr.attr |= MSG_DELETE; smsg.idx.time = smsg.hdr.when_imported.time; smsg.idx.attr = smsg.hdr.attr; smsg.offset = reln - 1L; int rv = smb_putmsg(data, &smsg); smb_unlockmsghdr(data, &smsg); if(rv == 0) msg->attr.del1(); } else smb_unlockmsghdr(data, &smsg); smb_freemsgmem(&smsg); GFTRK(0); } // ------------------------------------------------------------------ void SMBArea::new_msgno(gmsg* msg) { int res = smb_getstatus(data); smb_unlocksmbhdr(data); msg->msgno = (res == 0) ? data->status.last_msg+1 : 0; } // ------------------------------------------------------------------ char* SMBArea::user_lookup(char* lookfor) { NW(lookfor); return NULL; } // ------------------------------------------------------------------ int SMBArea::renumber() { return false; } // ------------------------------------------------------------------ void SMBArea::update_timesread(gmsg* msg) { NW(msg); return; } // ------------------------------------------------------------------ static char *binstr(char *buf, uint16_t length) { static char str[128]; char tmp[128]; int i; str[0] = 0; for(i = 0; i < length; i++) if(buf[i] and not isprint(buf[i])) break; if(i == length) /* not binary */ return buf; if(length > 42) length = 42; for(i = 0; i < length; i++) { sprintf(tmp, "%02X ", buf[i]); strcat(str, tmp); } return str; } // ------------------------------------------------------------------ static char *faddrtoa(fidoaddr_t addr) { static char str[25]; char point[25]; sprintf(str, "%u:%u/%u", addr.zone, addr.net, addr.node); if (addr.point) { sprintf(point, ".%u", addr.point); strcat(str, point); } return str; } // ------------------------------------------------------------------ Line* SMBArea::make_dump_msg(Line*& lin, gmsg* msg, char* lng_head) { GFTRK("SMBMakeDump"); Line* line = lin = AddLine (NULL, "Hexdump of Synchronet-style message header and text"); AddLineF(line, "------------------------------------------------------------------------------"); line = AddLine(line, ""); smbmsg_t smsg; char buf[512]; int i; GFTRK("SMBLoadMsg"); if(not load_hdr(msg, &smsg)) { line = AddLine(line, "Error loading header"); GFTRK(0); return line; } line = AddLineF(line, "Subject : %s", smsg.subj); line = AddLineF(line, "From : %s", smsg.from); line = AddLineF(line, "To : %s", smsg.to); line = AddLineF(line, "Type : %04Xh", smsg.hdr.type); line = AddLineF(line, "Version : %04Xh", smsg.hdr.version); line = AddLineF(line, "Length : %u", smsg.hdr.length); line = AddLineF(line, "Attr : %04Xh", smsg.hdr.attr); line = AddLineF(line, "AUXAttr : %04Xh", smsg.hdr.auxattr); line = AddLineF(line, "NetAttr : %04Xh", smsg.hdr.netattr); gctime(buf, ARRAYSIZE(buf), &smsg.hdr.when_written.time); line = AddLineF(line, "Written : %s", buf); gctime(buf, ARRAYSIZE(buf), &smsg.hdr.when_imported.time); line = AddLineF(line, "Imported : %s", buf); line = AddLineF(line, "Number : %d (%d)", smsg.hdr.number, (int32_t)(ftell(data->sid_fp)/sizeof(idxrec_t))); line = AddLineF(line, "Thread orig : %d", smsg.hdr.thread_orig); line = AddLineF(line, "Thread next : %d", smsg.hdr.thread_next); line = AddLineF(line, "Thread first : %d", smsg.hdr.thread_first); 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")); line = AddLineF(line, "Offset : %06Xh", smsg.hdr.offset); line = AddLineF(line, "Total dfields : %u", smsg.hdr.total_dfields); if(smsg.from_net.type) { line = AddLineF(line, "From net type : %02Xh", smsg.from_net.type); 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)); } if(smsg.to_net.type) { line = AddLineF(line, "To net type : %02Xh", smsg.to_net.type); 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)); } if(smsg.replyto_net.type) { line = AddLineF(line, "Replyto net type : %02Xh", smsg.replyto_net.type); 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)); } line = AddLineF(line, "From agent : %02Xh", smsg.from_agent); line = AddLineF(line, "To agent : %02Xh", smsg.to_agent); line = AddLineF(line, "Replyto agent : %02Xh", smsg.replyto_agent); line = AddLine(line, ""); AddLineF(line, "dfields:"); line = AddLine(line, ""); for (i = 0; i < smsg.hdr.total_dfields; i++) { line = AddLineF(line, "dfield[%02u].type : %02X", i, smsg.dfield[i].type); line = AddLineF(line, "dfield[%02u].offset : %u", i, smsg.dfield[i].offset); line = AddLineF(line, "dfield[%02u].length : %u", i, smsg.dfield[i].length); } line = AddLine(line, ""); AddLineF(line, "hfields:"); line = AddLine(line, ""); for (i = 0; i < smsg.total_hfields; i++) { line = AddLineF(line, "hfield[%02u].type : %02X", i, smsg.hfield[i].type); line = AddLineF(line, "hfield[%02u].length : %d", i, smsg.hfield[i].length); line = AddLineF(line, "hfield_dat[%02u] : %s", i, binstr((char *)smsg.hfield_dat[i], smsg.hfield[i].length)); } line = AddLine(line, ""); AddLineF(line, lng_head); line = AddLine(line, ""); int _count = 0; char* _ptr = (char*)&smsg.hdr; while(_count < sizeof(msghdr_t)) { sprintf(buf, "%04X ", _count); HexDump16(buf+7, _ptr, 16, HEX_DUMP2); line = AddLine(line, buf); _count += 16; _ptr += 16; } sprintf(buf, "%04X ", _count); HexDump16(buf+7, _ptr, sizeof(msghdr_t)%16, HEX_DUMP2); line = AddLine(line, buf); uint16_t xlat; uint8_t *inbuf; int32_t outlen; bool lzh; bool tail = true; uint32_t l; uint32_t txt_len = 1; msg->txt = throw_strdup(""); for(i = 0; i < smsg.hdr.total_dfields; i++) switch(smsg.dfield[i].type) { case TEXT_BODY: if(tail) tail = false; goto common; case TEXT_TAIL: if(not tail) { tail = true; msg->txt[txt_len-1] = '\r'; txt_len++; } common: fseek(data->sdt_fp, smsg.hdr.offset + smsg.dfield[i].offset, SEEK_SET); l = sizeof(xlat); fread(&xlat, sizeof(xlat), 1, data->sdt_fp); lzh = false; if(xlat == XLAT_LZH) { lzh = true; fread(&xlat, sizeof(xlat), 1, data->sdt_fp); l += sizeof(xlat); } if(xlat != XLAT_NONE) /* no other translations currently supported */ continue; if(lzh) { inbuf = (uint8_t *)throw_xmalloc(smsg.dfield[i].length); fread(inbuf, smsg.dfield[i].length - l, 1, data->sdt_fp); outlen = *(int32_t *)inbuf; msg->txt = (char *)throw_realloc(msg->txt, txt_len+outlen); lzh_decode(inbuf, smsg.dfield[i].length - l, (uint8_t *)(msg->txt+txt_len-1)); throw_xfree(inbuf); } else if(l < smsg.dfield[i].length) { outlen = smsg.dfield[i].length - l; msg->txt = (char *)throw_realloc(msg->txt, txt_len+outlen); fread(msg->txt+txt_len-1, smsg.dfield[i].length - l, 1, data->sdt_fp); } else outlen = 0; txt_len+=outlen; msg->txt[txt_len-1] = NUL; break; } smb_freemsgmem(&smsg); GFTRK(0); return line; } // ------------------------------------------------------------------