From 9f3482e40cfe2e0ee379aaeb130f931433ca7a3f Mon Sep 17 00:00:00 2001 From: rswindell <> Date: Sat, 11 Sep 2004 09:27:44 +0000 Subject: [PATCH] Split smblib.c into multiple smaller modules to make source maintenance easier and allow for selective linking of objects from library archives. --- src/smblib/smbadd.c | 302 ++++++++ src/smblib/smballoc.c | 476 +++++++++++++ src/smblib/smbfile.c | 201 ++++++ src/smblib/smbhash.c | 348 +++++++++ src/smblib/smblib.c | 1460 ++------------------------------------ src/smblib/smblib.dsp | 20 + src/smblib/smblib.h | 46 +- src/smblib/smblib_mt.dsp | 20 + src/smblib/smbstr.c | 245 +++++++ 9 files changed, 1681 insertions(+), 1437 deletions(-) create mode 100644 src/smblib/smbadd.c create mode 100644 src/smblib/smballoc.c create mode 100644 src/smblib/smbfile.c create mode 100644 src/smblib/smbhash.c create mode 100644 src/smblib/smbstr.c diff --git a/src/smblib/smbadd.c b/src/smblib/smbadd.c new file mode 100644 index 0000000000..6ed89fc07c --- /dev/null +++ b/src/smblib/smbadd.c @@ -0,0 +1,302 @@ +/* smbadd.c */ + +/* Synchronet message base (SMB) high-level "add message" function */ + +/* $Id$ */ + +/**************************************************************************** + * @format.tab-size 4 (Plain Text/Source Code File Header) * + * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * + * * + * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * See the GNU Lesser General Public License for more details: lgpl.txt or * + * http://www.fsf.org/copyleft/lesser.html * + * * + * Anonymous FTP access to the most recent released source is available at * + * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * + * * + * Anonymous CVS access to the development source and modification history * + * is available at cvs.synchro.net:/cvsroot/sbbs, example: * + * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login * + * (just hit return, no password is necessary) * + * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src * + * * + * For Synchronet coding style and modification guidelines, see * + * http://www.synchro.net/source.html * + * * + * You are encouraged to submit any modifications (preferably in Unix diff * + * format) via e-mail to mods@synchro.net * + * * + * Note: If this box doesn't appear square, then you need to fix your tabs. * + ****************************************************************************/ + +#include <time.h> +#include "smblib.h" +#include "genwrap.h" +#include "crc32.h" + +/****************************************************************************/ +/****************************************************************************/ +int SMBCALL smb_addmsg(smb_t* smb, smbmsg_t* msg, int storage, BOOL dupechk + ,ushort xlat, const uchar* body, const uchar* tail) +{ + uchar* lzhbuf=NULL; + long lzhlen; + int retval; + size_t n; + size_t l,length; + size_t taillen=0; + size_t bodylen=0; + long offset; + ulong crc=0xffffffff; + hash_t found; + hash_t** hashes=NULL; /* This is a NULL-terminated list of hashes */ + smbmsg_t remsg; + + if(!SMB_IS_OPEN(smb)) { + safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open"); + return(SMB_ERR_NOT_OPEN); + } + + if(filelength(fileno(smb->shd_fp))<1) { /* Create it if it doesn't exist */ + /* smb->status.max_crcs, max_msgs, max_age, and attr should be pre-initialized */ + if((retval=smb_create(smb))!=SMB_SUCCESS) + return(retval); + } + + if(!smb->locked && smb_locksmbhdr(smb)!=SMB_SUCCESS) + return(SMB_ERR_LOCK); + + msg->hdr.total_dfields = 0; + + /* try */ + do { + + if((retval=smb_getstatus(smb))!=SMB_SUCCESS) + break; + + msg->hdr.number=smb->status.last_msg+1; + + hashes=smb_msghashes(msg,body,dupechk); + + if(smb_findhash(smb, hashes, &found, /* update? */FALSE)==SMB_SUCCESS) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"duplicate %s hash found (message #%lu)" + ,smb_hashsource(found.source), found.number); + retval=SMB_DUPE_MSG; + break; + } + + if(tail!=NULL && (taillen=strlen(tail))>0) + taillen+=sizeof(xlat); /* xlat string terminator */ + + if(body!=NULL && (bodylen=strlen(body))>0) { + + /* Remove white-space from end of message text */ + while(bodylen && body[bodylen-1]<=' ') + bodylen--; + + /* Calculate CRC-32 of message text (before encoding, if any) */ + if(smb->status.max_crcs && dupechk) { + for(l=0;l<bodylen;l++) + crc=ucrc32(body[l],crc); + crc=~crc; + + /* Add CRC to CRC history (and check for duplicates) */ + if((retval=smb_addcrc(smb,crc))!=SMB_SUCCESS) + break; + } + + bodylen+=sizeof(xlat); /* xlat string terminator */ + + /* LZH compress? */ + if(xlat==XLAT_LZH && bodylen+taillen>=SDT_BLOCK_LEN + && (lzhbuf=(uchar *)malloc(bodylen*2))!=NULL) { + lzhlen=lzh_encode((uchar*)body,bodylen-sizeof(xlat),lzhbuf); + if(lzhlen>1 + && smb_datblocks(lzhlen+(sizeof(xlat)*2)+taillen) + < smb_datblocks(bodylen+taillen)) { + bodylen=lzhlen+(sizeof(xlat)*2); /* Compressible */ + body=lzhbuf; + } else + xlat=XLAT_NONE; + } else + xlat=XLAT_NONE; + } + + length=bodylen+taillen; + + if(length&0x80000000) { + sprintf(smb->last_error,"message length: 0x%lX",length); + retval=SMB_ERR_DAT_LEN; + break; + } + + /* Allocate Data Blocks */ + if(smb->status.attr&SMB_HYPERALLOC) { + offset=smb_hallocdat(smb); + storage=SMB_HYPERALLOC; + } else { + if((retval=smb_open_da(smb))!=SMB_SUCCESS) + break; + if(storage==SMB_FASTALLOC) + offset=smb_fallocdat(smb,length,1); + else { /* SMB_SELFPACK */ + offset=smb_allocdat(smb,length,1); + storage=SMB_SELFPACK; + } + smb_close_da(smb); + } + + if(offset<0) { + retval=offset; + break; + } + msg->hdr.offset=offset; + + smb_fseek(smb->sdt_fp,offset,SEEK_SET); + + if(bodylen) { + if((retval=smb_dfield(msg,TEXT_BODY,bodylen))!=SMB_SUCCESS) + break; + + if(xlat!=XLAT_NONE) { /* e.g. XLAT_LZH */ + if(smb_fwrite(smb,&xlat,sizeof(xlat),smb->sdt_fp)!=sizeof(xlat)) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"%d (%s) writing body xlat string" + ,ferror(smb->sdt_fp),STRERROR(ferror(smb->sdt_fp))); + retval=SMB_ERR_WRITE; + break; + } + bodylen-=sizeof(xlat); + } + xlat=XLAT_NONE; /* xlat string terminator */ + if(smb_fwrite(smb,&xlat,sizeof(xlat),smb->sdt_fp)!=sizeof(xlat)) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"%d (%s) writing body xlat terminator" + ,ferror(smb->sdt_fp),STRERROR(ferror(smb->sdt_fp))); + retval=SMB_ERR_WRITE; + break; + } + bodylen-=sizeof(xlat); + + if(smb_fwrite(smb,body,bodylen,smb->sdt_fp)!=bodylen) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"%d (%s) writing body (%ld bytes)" + ,ferror(smb->sdt_fp),STRERROR(ferror(smb->sdt_fp)) + ,bodylen); + retval=SMB_ERR_WRITE; + break; + } + } + + if(taillen) { + if((retval=smb_dfield(msg,TEXT_TAIL,taillen))!=SMB_SUCCESS) + break; + + xlat=XLAT_NONE; /* xlat string terminator */ + if(smb_fwrite(smb,&xlat,sizeof(xlat),smb->sdt_fp)!=sizeof(xlat)) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"%d (%s) writing tail xlat terminator" + ,ferror(smb->sdt_fp),STRERROR(ferror(smb->sdt_fp))); + retval=SMB_ERR_WRITE; + break; + } + + if(smb_fwrite(smb,tail,taillen-sizeof(xlat),smb->sdt_fp)!=taillen-sizeof(xlat)) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"%d (%s) writing tail (%ld bytes)" + ,ferror(smb->sdt_fp),STRERROR(ferror(smb->sdt_fp)) + ,taillen-sizeof(xlat)); + retval=SMB_ERR_WRITE; + break; + } + } + + for(l=length;l%SDT_BLOCK_LEN;l++) { + if(smb_fputc(0,smb->sdt_fp)!=0) + break; + } + if(l%SDT_BLOCK_LEN) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"%d (%s) writing data padding" + ,ferror(smb->sdt_fp),STRERROR(ferror(smb->sdt_fp))); + retval=SMB_ERR_WRITE; + break; + } + + fflush(smb->sdt_fp); + + if(msg->to==NULL) /* no recipient, don't add header (required for bulkmail) */ + break; + + msg->hdr.version=smb_ver(); + if(msg->hdr.when_imported.time==0) { + msg->hdr.when_imported.time=time(NULL); + msg->hdr.when_imported.zone=0; /* how do we detect system TZ? */ + } + if(msg->hdr.when_written.time==0) /* Uninitialized */ + msg->hdr.when_written = msg->hdr.when_imported; + msg->idx.time=msg->hdr.when_imported.time; + + /* Look-up thread_back if Reply-ID was specified */ + if(msg->hdr.thread_back==0 && msg->reply_id!=NULL) { + if(smb_getmsgidx_by_msgid(smb,&remsg,msg->reply_id)==SMB_SUCCESS) + msg->hdr.thread_back=remsg.idx.number; /* needed for threading backward */ + } + + /* Auto-thread linkage */ + if(msg->hdr.thread_back) { + memset(&remsg,0,sizeof(remsg)); + remsg.hdr.number=msg->hdr.thread_back; + if((retval=smb_getmsgidx(smb, &remsg))!=SMB_SUCCESS) /* invalid thread origin */ + break; + + if((retval=smb_lockmsghdr(smb,&remsg))!=SMB_SUCCESS) + break; + + if((retval=smb_getmsghdr(smb, &remsg))!=SMB_SUCCESS) { + smb_unlockmsghdr(smb, &remsg); + break; + } + + /* Add RFC-822 Reply-ID if original message has RFC Message-ID */ + if(msg->reply_id==NULL && remsg.id!=NULL + && (retval=smb_hfield_str(msg,RFC822REPLYID,remsg.id))!=SMB_SUCCESS) + break; + + /* Add FidoNet Reply if original message has FidoNet MSGID */ + if(msg->ftn_reply==NULL && remsg.ftn_msgid!=NULL + && (retval=smb_hfield_str(msg,FIDOREPLYID,remsg.ftn_msgid))!=SMB_SUCCESS) + break; + + retval=smb_updatethread(smb, &remsg, msg->hdr.number); + smb_unlockmsghdr(smb, &remsg); + smb_freemsgmem(&remsg); + + if(retval!=SMB_SUCCESS) + break; + } + + if(smb_addhashes(smb,hashes,/* skip_marked? */FALSE)==SMB_SUCCESS) + msg->flags|=MSG_FLAG_HASHED; + + retval=smb_addmsghdr(smb,msg,storage); // calls smb_unlocksmbhdr() + + } while(0); + /* finally */ + + if(retval!=SMB_SUCCESS) + smb_freemsg_dfields(smb,msg,1); + + smb_unlocksmbhdr(smb); + FREE_AND_NULL(lzhbuf); + FREE_LIST(hashes,n); + + return(retval); +} diff --git a/src/smblib/smballoc.c b/src/smblib/smballoc.c new file mode 100644 index 0000000000..8e14c9c498 --- /dev/null +++ b/src/smblib/smballoc.c @@ -0,0 +1,476 @@ +/* smballoc.c */ + +/* Synchronet message base (SMB) alloc/free routines */ + +/* $Id$ */ + +/**************************************************************************** + * @format.tab-size 4 (Plain Text/Source Code File Header) * + * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * + * * + * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * See the GNU Lesser General Public License for more details: lgpl.txt or * + * http://www.fsf.org/copyleft/lesser.html * + * * + * Anonymous FTP access to the most recent released source is available at * + * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * + * * + * Anonymous CVS access to the development source and modification history * + * is available at cvs.synchro.net:/cvsroot/sbbs, example: * + * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login * + * (just hit return, no password is necessary) * + * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src * + * * + * For Synchronet coding style and modification guidelines, see * + * http://www.synchro.net/source.html * + * * + * You are encouraged to submit any modifications (preferably in Unix diff * + * format) via e-mail to mods@synchro.net * + * * + * Note: If this box doesn't appear square, then you need to fix your tabs. * + ****************************************************************************/ + +#include "smblib.h" +#include "genwrap.h" + +/****************************************************************************/ +/* Finds unused space in data file based on block allocation table and */ +/* marks space as used in allocation table. */ +/* File must be opened read/write DENY ALL */ +/* Returns offset to beginning of data (in bytes, not blocks) */ +/* Assumes smb_open_da() has been called */ +/* smb_close_da() should be called after */ +/* Returns negative on error */ +/****************************************************************************/ +long SMBCALL smb_allocdat(smb_t* smb, ulong length, ushort refs) +{ + ushort i; + ulong j,l,blocks,offset=0L; + + if(smb->sda_fp==NULL) { + safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open"); + return(SMB_ERR_NOT_OPEN); + } + blocks=smb_datblocks(length); + j=0; /* j is consecutive unused block counter */ + fflush(smb->sda_fp); + rewind(smb->sda_fp); + while(!feof(smb->sda_fp) && (long)offset>=0) { + if(smb_fread(smb,&i,sizeof(i),smb->sda_fp)!=sizeof(i)) + break; + offset+=SDT_BLOCK_LEN; + if(!i) j++; + else j=0; + if(j==blocks) { + offset-=(blocks*SDT_BLOCK_LEN); + break; + } + } + if((long)offset<0) { + safe_snprintf(smb->last_error,sizeof(smb->last_error),"invalid data offset: %lu",offset); + return(SMB_ERR_DAT_OFFSET); + } + clearerr(smb->sda_fp); + if(fseek(smb->sda_fp,(offset/SDT_BLOCK_LEN)*sizeof(refs),SEEK_SET)) { + return(SMB_ERR_SEEK); + } + for(l=0;l<blocks;l++) + if(!fwrite(&refs,sizeof(refs),1,smb->sda_fp)) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"%d (%s) writing allocation bytes at offset %ld" + ,ferror(smb->sda_fp),STRERROR(ferror(smb->sda_fp)) + ,((offset/SDT_BLOCK_LEN)+l)*sizeof(refs)); + return(SMB_ERR_WRITE); + } + fflush(smb->sda_fp); + return(offset); +} + +/****************************************************************************/ +/* Allocates space for data, but doesn't search for unused blocks */ +/* Returns negative on error */ +/****************************************************************************/ +long SMBCALL smb_fallocdat(smb_t* smb, ulong length, ushort refs) +{ + ulong l,blocks,offset; + + if(smb->sda_fp==NULL) { + safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open"); + return(SMB_ERR_NOT_OPEN); + } + fflush(smb->sda_fp); + clearerr(smb->sda_fp); + blocks=smb_datblocks(length); + if(fseek(smb->sda_fp,0L,SEEK_END)) { + return(SMB_ERR_SEEK); + } + offset=(ftell(smb->sda_fp)/sizeof(refs))*SDT_BLOCK_LEN; + if((long)offset<0) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"invalid data offset: %lu",offset); + return(SMB_ERR_DAT_OFFSET); + } + for(l=0;l<blocks;l++) + if(!fwrite(&refs,sizeof(refs),1,smb->sda_fp)) + break; + fflush(smb->sda_fp); + if(l<blocks) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"%d (%s) writing allocation bytes" + ,ferror(smb->sda_fp),STRERROR(ferror(smb->sda_fp))); + return(SMB_ERR_WRITE); + } + return(offset); +} + +/****************************************************************************/ +/* De-allocates space for data */ +/* Returns non-zero on error */ +/****************************************************************************/ +int SMBCALL smb_freemsgdat(smb_t* smb, ulong offset, ulong length, ushort refs) +{ + BOOL da_opened=FALSE; + int retval=0; + ushort i; + ulong l,blocks; + ulong sda_offset; + + if(smb->status.attr&SMB_HYPERALLOC) /* do nothing */ + return(SMB_SUCCESS); + + blocks=smb_datblocks(length); + + if(smb->sda_fp==NULL) { + if((i=smb_open_da(smb))!=SMB_SUCCESS) + return(i); + da_opened=TRUE; + } + + clearerr(smb->sda_fp); + for(l=0;l<blocks;l++) { + sda_offset=((offset/SDT_BLOCK_LEN)+l)*sizeof(i); + if(fseek(smb->sda_fp,sda_offset,SEEK_SET)) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"%d (%s) seeking to %lu (0x%lX) of allocation file" + ,errno,STRERROR(errno) + ,sda_offset,sda_offset); + retval=SMB_ERR_SEEK; + break; + } + if(smb_fread(smb,&i,sizeof(i),smb->sda_fp)!=sizeof(i)) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"%d (%s) reading allocation bytes at offset %ld" + ,ferror(smb->sda_fp),STRERROR(ferror(smb->sda_fp)) + ,sda_offset); + retval=SMB_ERR_READ; + break; + } + if(refs==SMB_ALL_REFS || refs>i) + i=0; /* don't want to go negative */ + else + i-=refs; + if(fseek(smb->sda_fp,-(int)sizeof(i),SEEK_CUR)) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"%d (%s) seeking backwards 2 bytes in allocation file" + ,errno,STRERROR(errno)); + retval=SMB_ERR_SEEK; + break; + } + if(!fwrite(&i,sizeof(i),1,smb->sda_fp)) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"%d (%s) writing allocation bytes at offset %ld" + ,ferror(smb->sda_fp),STRERROR(ferror(smb->sda_fp)) + ,sda_offset); + retval=SMB_ERR_WRITE; + break; + } + } + fflush(smb->sda_fp); + if(da_opened) + smb_close_da(smb); + return(retval); +} + +/****************************************************************************/ +/* Adds to data allocation records for blocks starting at 'offset' */ +/* Returns non-zero on error */ +/****************************************************************************/ +int SMBCALL smb_incdat(smb_t* smb, ulong offset, ulong length, ushort refs) +{ + ushort i; + ulong l,blocks; + + if(smb->sda_fp==NULL) { + safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open"); + return(SMB_ERR_NOT_OPEN); + } + clearerr(smb->sda_fp); + blocks=smb_datblocks(length); + for(l=0;l<blocks;l++) { + if(fseek(smb->sda_fp,((offset/SDT_BLOCK_LEN)+l)*sizeof(i),SEEK_SET)) { + return(SMB_ERR_SEEK); + } + if(smb_fread(smb,&i,sizeof(i),smb->sda_fp)!=sizeof(i)) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"%d (%s) reading allocation record at offset %ld" + ,ferror(smb->sda_fp),STRERROR(ferror(smb->sda_fp)) + ,((offset/SDT_BLOCK_LEN)+l)*sizeof(i)); + return(SMB_ERR_READ); + } + i+=refs; + if(fseek(smb->sda_fp,-(int)sizeof(i),SEEK_CUR)) { + return(SMB_ERR_SEEK); + } + if(!fwrite(&i,sizeof(i),1,smb->sda_fp)) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"%d (%s) writing allocation record at offset %ld" + ,ferror(smb->sda_fp),STRERROR(ferror(smb->sda_fp)) + ,((offset/SDT_BLOCK_LEN)+l)*sizeof(i)); + return(SMB_ERR_WRITE); + } + } + fflush(smb->sda_fp); + return(SMB_SUCCESS); +} + +/****************************************************************************/ +/* Increments data allocation records (message references) by number of */ +/* header references specified (usually 1) */ +/* The opposite function of smb_freemsg() */ +/****************************************************************************/ +int SMBCALL smb_incmsg_dfields(smb_t* smb, smbmsg_t* msg, ushort refs) +{ + int i=0; + BOOL da_opened=FALSE; + ushort x; + + if(smb->status.attr&SMB_HYPERALLOC) /* Nothing to do */ + return(SMB_SUCCESS); + + if(smb->sda_fp==NULL) { + if((i=smb_open_da(smb))!=SMB_SUCCESS) + return(i); + da_opened=TRUE; + } + + for(x=0;x<msg->hdr.total_dfields;x++) { + if((i=smb_incdat(smb,msg->hdr.offset+msg->dfield[x].offset + ,msg->dfield[x].length,refs))!=SMB_SUCCESS) + break; + } + + if(da_opened) + smb_close_da(smb); + return(i); +} + +/****************************************************************************/ +/* De-allocates blocks for header record */ +/* Returns non-zero on error */ +/****************************************************************************/ +int SMBCALL smb_freemsghdr(smb_t* smb, ulong offset, ulong length) +{ + uchar c=0; + ulong l,blocks; + + if(smb->sha_fp==NULL) { + safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open"); + return(SMB_ERR_NOT_OPEN); + } + clearerr(smb->sha_fp); + blocks=smb_hdrblocks(length); + if(fseek(smb->sha_fp,offset/SHD_BLOCK_LEN,SEEK_SET)) + return(SMB_ERR_SEEK); + for(l=0;l<blocks;l++) + if(!fwrite(&c,1,1,smb->sha_fp)) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"%d (%s) writing allocation record" + ,ferror(smb->sha_fp),STRERROR(ferror(smb->sha_fp))); + return(SMB_ERR_WRITE); + } + fflush(smb->sha_fp); + return(SMB_SUCCESS); +} + +/****************************************************************************/ +/****************************************************************************/ +int SMBCALL smb_freemsg_dfields(smb_t* smb, smbmsg_t* msg, ushort refs) +{ + int i; + ushort x; + + for(x=0;x<msg->hdr.total_dfields;x++) { + if((i=smb_freemsgdat(smb,msg->hdr.offset+msg->dfield[x].offset + ,msg->dfield[x].length,refs))!=SMB_SUCCESS) + return(i); + } + return(SMB_SUCCESS); +} + +/****************************************************************************/ +/* Frees all allocated header and data blocks (1 reference) for 'msg' */ +/****************************************************************************/ +int SMBCALL smb_freemsg(smb_t* smb, smbmsg_t* msg) +{ + int i; + + if(smb->status.attr&SMB_HYPERALLOC) /* Nothing to do */ + return(SMB_SUCCESS); + + if(!smb_valid_hdr_offset(smb,msg->idx.offset)) + return(SMB_ERR_HDR_OFFSET); + + if((i=smb_freemsg_dfields(smb,msg,1))!=SMB_SUCCESS) + return(i); + + return(smb_freemsghdr(smb,msg->idx.offset-smb->status.header_offset + ,msg->hdr.length)); +} + +/****************************************************************************/ +/* Finds unused space in header file based on block allocation table and */ +/* marks space as used in allocation table. */ +/* File must be opened read/write DENY ALL */ +/* Returns offset to beginning of header (in bytes, not blocks) */ +/* Assumes smb_open_ha() has been called */ +/* smb_close_ha() should be called after */ +/* Returns negative value on error */ +/****************************************************************************/ +long SMBCALL smb_allochdr(smb_t* smb, ulong length) +{ + uchar c; + ulong i,l,blocks,offset=0; + + if(smb->sha_fp==NULL) { + safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open"); + return(SMB_ERR_NOT_OPEN); + } + blocks=smb_hdrblocks(length); + i=0; /* i is consecutive unused block counter */ + fflush(smb->sha_fp); + rewind(smb->sha_fp); + while(!feof(smb->sha_fp)) { + if(smb_fread(smb,&c,sizeof(c),smb->sha_fp)!=sizeof(c)) + break; + offset+=SHD_BLOCK_LEN; + if(!c) i++; + else i=0; + if(i==blocks) { + offset-=(blocks*SHD_BLOCK_LEN); + break; + } + } + clearerr(smb->sha_fp); + if(fseek(smb->sha_fp,offset/SHD_BLOCK_LEN,SEEK_SET)) + return(SMB_ERR_SEEK); + + for(l=0;l<blocks;l++) + if(fputc(1,smb->sha_fp)!=1) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"%d (%s) writing allocation record" + ,ferror(smb->sha_fp),STRERROR(ferror(smb->sha_fp))); + return(SMB_ERR_WRITE); + } + fflush(smb->sha_fp); + return(offset); +} + +/****************************************************************************/ +/* Allocates space for index, but doesn't search for unused blocks */ +/* Returns negative value on error */ +/****************************************************************************/ +long SMBCALL smb_fallochdr(smb_t* smb, ulong length) +{ + uchar c=1; + ulong l,blocks,offset; + + if(smb->sha_fp==NULL) { + safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open"); + return(SMB_ERR_NOT_OPEN); + } + blocks=smb_hdrblocks(length); + fflush(smb->sha_fp); + clearerr(smb->sha_fp); + if(fseek(smb->sha_fp,0L,SEEK_END)) + return(SMB_ERR_SEEK); + offset=ftell(smb->sha_fp)*SHD_BLOCK_LEN; + for(l=0;l<blocks;l++) + if(!fwrite(&c,1,1,smb->sha_fp)) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"%d (%s) writing allocation record" + ,ferror(smb->sha_fp),STRERROR(ferror(smb->sha_fp))); + return(SMB_ERR_WRITE); + } + fflush(smb->sha_fp); + return(offset); +} + +/************************************************************************/ +/* Allocate header blocks using Hyper Allocation */ +/* this function should be most likely not be called from anywhere but */ +/* smb_addmsghdr() */ +/************************************************************************/ +long SMBCALL smb_hallochdr(smb_t* smb) +{ + ulong offset; + + if(smb->shd_fp==NULL) { + safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open"); + return(SMB_ERR_NOT_OPEN); + } + fflush(smb->shd_fp); + if(fseek(smb->shd_fp,0L,SEEK_END)) + return(SMB_ERR_SEEK); + offset=ftell(smb->shd_fp); + if(offset<smb->status.header_offset) /* Header file truncated?!? */ + return(smb->status.header_offset); + + offset-=smb->status.header_offset; /* SMB headers not included */ + + /* Even block boundry */ + offset+=PAD_LENGTH_FOR_ALIGNMENT(offset,SHD_BLOCK_LEN); + + return(offset); +} + +/************************************************************************/ +/* Allocate data blocks using Hyper Allocation */ +/* smb_locksmbhdr() should be called before this function and not */ +/* unlocked until all data fields for this message have been written */ +/* to the SDT file */ +/************************************************************************/ +long SMBCALL smb_hallocdat(smb_t* smb) +{ + long offset; + + if(smb->sdt_fp==NULL) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"msgbase not open"); + return(SMB_ERR_NOT_OPEN); + } + fflush(smb->sdt_fp); + offset=filelength(fileno(smb->sdt_fp)); + if(offset<0) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"invalid file length: %lu",(ulong)offset); + return(SMB_ERR_FILE_LEN); + } + if(fseek(smb->sdt_fp,0L,SEEK_END)) + return(SMB_ERR_SEEK); + offset=ftell(smb->sdt_fp); + if(offset<0) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"invalid file offset: %ld",offset); + return(SMB_ERR_DAT_OFFSET); + } + + /* Make sure even block boundry */ + offset+=PAD_LENGTH_FOR_ALIGNMENT(offset,SDT_BLOCK_LEN); + + return(offset); +} diff --git a/src/smblib/smbfile.c b/src/smblib/smbfile.c new file mode 100644 index 0000000000..48678230b1 --- /dev/null +++ b/src/smblib/smbfile.c @@ -0,0 +1,201 @@ +/* smbfile.c */ + +/* Synchronet message base (SMB) FILE stream I/O routines */ + +/* $Id$ */ + +/**************************************************************************** + * @format.tab-size 4 (Plain Text/Source Code File Header) * + * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * + * * + * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * See the GNU Lesser General Public License for more details: lgpl.txt or * + * http://www.fsf.org/copyleft/lesser.html * + * * + * Anonymous FTP access to the most recent released source is available at * + * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * + * * + * Anonymous CVS access to the development source and modification history * + * is available at cvs.synchro.net:/cvsroot/sbbs, example: * + * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login * + * (just hit return, no password is necessary) * + * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src * + * * + * For Synchronet coding style and modification guidelines, see * + * http://www.synchro.net/source.html * + * * + * You are encouraged to submit any modifications (preferably in Unix diff * + * format) via e-mail to mods@synchro.net * + * * + * Note: If this box doesn't appear square, then you need to fix your tabs. * + ****************************************************************************/ + +#include <time.h> +#include "smblib.h" +#include "genwrap.h" + +int SMBCALL smb_feof(FILE* fp) +{ + return(feof(fp)); +} + +int SMBCALL smb_ferror(FILE* fp) +{ + return(ferror(fp)); +} + +int SMBCALL smb_fflush(FILE* fp) +{ + return(fflush(fp)); +} + +int SMBCALL smb_fgetc(FILE* fp) +{ + return(fgetc(fp)); +} + +int SMBCALL smb_fputc(int ch, FILE* fp) +{ + return(fputc(ch,fp)); +} + +int SMBCALL smb_fseek(FILE* fp, long offset, int whence) +{ + return(fseek(fp,offset,whence)); +} + +long SMBCALL smb_ftell(FILE* fp) +{ + return(ftell(fp)); +} + +long SMBCALL smb_fgetlength(FILE* fp) +{ + return(filelength(fileno(fp))); +} + +int SMBCALL smb_fsetlength(FILE* fp, long length) +{ + return(chsize(fileno(fp),length)); +} + +void SMBCALL smb_rewind(FILE* fp) +{ + rewind(fp); +} + +void SMBCALL smb_clearerr(FILE* fp) +{ + clearerr(fp); +} + +size_t SMBCALL smb_fread(smb_t* smb, void* buf, size_t bytes, FILE* fp) +{ + size_t ret; + time_t start=0; + + while(1) { + if((ret=fread(buf,sizeof(char),bytes,fp))==bytes) + return(ret); + if(ferror(fp)!=EDEADLOCK) + return(ret); + if(!start) + start=time(NULL); + else + if(time(NULL)-start>=(time_t)smb->retry_time) + break; + SLEEP(smb->retry_delay); + } + return(ret); +} + +#if defined(__BORLANDC__) + #pragma argsused +#endif + +size_t SMBCALL smb_fwrite(smb_t* smb, const void* buf, size_t bytes, FILE* fp) +{ + return(fwrite(buf,1,bytes,fp)); +} + +/****************************************************************************/ +/* Opens a non-shareable file (FILE*) associated with a message base */ +/* Retrys for retry_time number of seconds */ +/* Return 0 on success, non-zero otherwise */ +/****************************************************************************/ +int SMBCALL smb_open_fp(smb_t* smb, FILE** fp, int share) +{ + int file; + char path[MAX_PATH+1]; + char* ext; + time_t start=0; + + if(fp==&smb->shd_fp) + ext="shd"; + else if(fp==&smb->sid_fp) + ext="sid"; + else if(fp==&smb->sdt_fp) + ext="sdt"; + else if(fp==&smb->sda_fp) + ext="sda"; + else if(fp==&smb->sha_fp) + ext="sha"; + else if(fp==&smb->hash_fp) + ext="hash"; + else { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"opening %s: Illegal FILE* pointer argument: %p" + ,smb->file, fp); + return(SMB_ERR_OPEN); + } + SAFEPRINTF2(path,"%s.%s",smb->file,ext); + + if(*fp!=NULL) /* Already open! */ + return(SMB_SUCCESS); + + while(1) { + if((file=sopen(path,O_RDWR|O_CREAT|O_BINARY,share,S_IREAD|S_IWRITE))!=-1) + break; + if(errno!=EACCES && errno!=EAGAIN) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"%d (%s) opening %s" + ,errno,STRERROR(errno),path); + return(SMB_ERR_OPEN); + } + if(!start) + start=time(NULL); + else + if(time(NULL)-start>=(time_t)smb->retry_time) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"timeout opening %s (retry_time=%ld)" + ,path,smb->retry_time); + return(SMB_ERR_TIMEOUT); + } + SLEEP(smb->retry_delay); + } + if((*fp=fdopen(file,"r+b"))==NULL) { + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"%d (%s) fdopening %s (%d)" + ,errno,STRERROR(errno),path,file); + close(file); + return(SMB_ERR_OPEN); + } + setvbuf(*fp,NULL,_IOFBF,2*1024); + return(SMB_SUCCESS); +} + +/****************************************************************************/ +/****************************************************************************/ +void SMBCALL smb_close_fp(FILE** fp) +{ + if(fp!=NULL) { + if(*fp!=NULL) + fclose(*fp); + *fp=NULL; + } +} diff --git a/src/smblib/smbhash.c b/src/smblib/smbhash.c new file mode 100644 index 0000000000..980dee66d3 --- /dev/null +++ b/src/smblib/smbhash.c @@ -0,0 +1,348 @@ +/* smblib.c */ + +/* Synchronet message base (SMB) hash-related functions */ + +/* $Id$ */ + +/**************************************************************************** + * @format.tab-size 4 (Plain Text/Source Code File Header) * + * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * + * * + * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * See the GNU Lesser General Public License for more details: lgpl.txt or * + * http://www.fsf.org/copyleft/lesser.html * + * * + * Anonymous FTP access to the most recent released source is available at * + * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * + * * + * Anonymous CVS access to the development source and modification history * + * is available at cvs.synchro.net:/cvsroot/sbbs, example: * + * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login * + * (just hit return, no password is necessary) * + * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src * + * * + * For Synchronet coding style and modification guidelines, see * + * http://www.synchro.net/source.html * + * * + * You are encouraged to submit any modifications (preferably in Unix diff * + * format) via e-mail to mods@synchro.net * + * * + * Note: If this box doesn't appear square, then you need to fix your tabs. * + ****************************************************************************/ + +#include <time.h> +#include "smblib.h" +#include "md5.h" +#include "crc16.h" +#include "crc32.h" +#include "genwrap.h" + +/* If return value is SMB_ERROR_NOT_FOUND, hash file is left open */ +int SMBCALL smb_findhash(smb_t* smb, hash_t** compare, hash_t* found_hash, BOOL mark) +{ + int retval; + BOOL found=FALSE; + size_t c,count; + hash_t hash; + + if(found_hash!=NULL) + memset(found_hash,0,sizeof(hash_t)); + + if((retval=smb_open_hash(smb))!=SMB_SUCCESS) + return(retval); + + COUNT_LIST_ITEMS(compare, count); + + if(count) { + + rewind(smb->hash_fp); + while(!feof(smb->hash_fp)) { + memset(&hash,0,sizeof(hash)); + if(smb_fread(smb,&hash,sizeof(hash),smb->hash_fp)!=sizeof(hash)) + break; + + if(hash.flags==0) + continue; /* invalid hash record (!?) */ + + for(c=0;compare[c]!=NULL;c++) { + + if(compare[c]->source!=hash.source) + continue; /* wrong source */ + if(compare[c]->flags&SMB_HASH_MARKED) + continue; /* already marked */ + if((compare[c]->flags&SMB_HASH_PROC_MASK)!=(hash.flags&SMB_HASH_PROC_MASK)) + continue; /* wrong pre-process flags */ + if((compare[c]->flags&hash.flags&SMB_HASH_MASK)==0) + continue; /* no matching hashes */ + if(compare[c]->flags&hash.flags&SMB_HASH_CRC16 + && compare[c]->crc16!=hash.crc16) + continue; /* wrong crc-16 */ + if(compare[c]->flags&hash.flags&SMB_HASH_CRC32 + && compare[c]->crc32!=hash.crc32) + continue; /* wrong crc-32 */ + if(compare[c]->flags&hash.flags&SMB_HASH_MD5 + && memcmp(compare[c]->md5,hash.md5,sizeof(hash.md5))) + continue; /* wrong crc-16 */ + + /* successful match! */ + break; /* can't match more than one, so stop comparing */ + } + + if(compare[c]==NULL) + continue; /* no match */ + + found=TRUE; + + if(found_hash!=NULL) + memcpy(found_hash,&hash,sizeof(hash)); + + if(!mark) + break; + + compare[c]->flags|=SMB_HASH_MARKED; + } + if(found) { + smb_close_hash(smb); + return(SMB_SUCCESS); + } + } + + /* hash file left open */ + return(SMB_ERR_NOT_FOUND); +} + +int SMBCALL smb_addhashes(smb_t* smb, hash_t** hashes, BOOL skip_marked) +{ + int retval; + size_t h; + + COUNT_LIST_ITEMS(hashes, h); + if(!h) /* nothing to add */ + return(SMB_SUCCESS); + + if((retval=smb_open_hash(smb))!=SMB_SUCCESS) + return(retval); + + fseek(smb->hash_fp,0,SEEK_END); + + for(h=0;hashes[h]!=NULL;h++) { + + /* skip hashes marked by smb_findhash() */ + if(skip_marked && hashes[h]->flags&SMB_HASH_MARKED) + continue; + + /* can't think of any reason to strip SMB_HASH_MARKED flag right now */ + if(smb_fwrite(smb,hashes[h],sizeof(hash_t),smb->hash_fp)!=sizeof(hash_t)) + return(SMB_ERR_WRITE); + } + + smb_close_hash(smb); + + return(SMB_SUCCESS); +} + +static char* strip_chars(uchar* str, uchar* set) +{ + char* src; + char* dst; + char* tmp; + + if((tmp=strdup(str))==NULL) + return(NULL); + for(src=tmp,dst=str;*src;src++) { + if(strchr(set,*src)==NULL) + *(dst++)=*src; + } + *dst=0; + + return(str); +} + +/* Allocates and calculates hashes of data (based on flags) */ +/* Returns NULL on failure */ +hash_t* SMBCALL smb_hash(ulong msgnum, ulong t, unsigned source, unsigned flags + ,const void* data, size_t length) +{ + hash_t* hash; + + if((hash=(hash_t*)malloc(sizeof(hash_t)))==NULL) + return(NULL); + + hash->number=msgnum; + hash->time=t; + hash->source=source; + hash->flags=flags; + if(flags&SMB_HASH_CRC16) + hash->crc16=crc16((char*)data,length); + if(flags&SMB_HASH_CRC32) + hash->crc32=crc32((char*)data,length); + if(flags&SMB_HASH_MD5) + MD5_calc(hash->md5,data,length); + + return(hash); +} + +/* Allocates and calculates hashes of data (based on flags) */ +/* Supports string hash "pre-processing" (e.g. lowercase, strip whitespace) */ +/* Returns NULL on failure */ +hash_t* SMBCALL smb_hashstr(ulong msgnum, ulong t, unsigned source, unsigned flags + ,const char* str) +{ + char* p=(uchar*)str; + hash_t* hash; + + if(flags&SMB_HASH_PROC_MASK) { /* string pre-processing */ + if((p=strdup(str))==NULL) + return(NULL); + if(flags&SMB_HASH_LOWERCASE) + strlwr(p); + if(flags&SMB_HASH_STRIP_WSP) + strip_chars(p," \t\r\n"); + } + + hash=smb_hash(msgnum, t, source, flags, p, strlen(p)); + + if(p!=str) /* duped string */ + free(p); + + return(hash); +} + +/* Allocatese and calculates all hashes for a single message */ +/* Returns NULL on failure */ +hash_t** SMBCALL smb_msghashes(smbmsg_t* msg, const uchar* text, BOOL dupechk) +{ + size_t h=0; + uchar flags=SMB_HASH_CRC16|SMB_HASH_CRC32|SMB_HASH_MD5; + hash_t** hashes; /* This is a NULL-terminated list of hashes */ + hash_t* hash; + time_t t=time(NULL); + +#define SMB_MAX_HASH_COUNT 4 + + if((hashes=(hash_t**)malloc(sizeof(hash_t*)*SMB_MAX_HASH_COUNT))==NULL) + return(NULL); + + memset(hashes, 0, sizeof(hash_t*)*SMB_MAX_HASH_COUNT); + + if(msg->id!=NULL + && (hash=smb_hashstr(msg->hdr.number, t, RFC822MSGID, flags, msg->id))!=NULL) + hashes[h++]=hash; + + if(msg->ftn_msgid!=NULL + && (hash=smb_hashstr(msg->hdr.number, t, FIDOMSGID, flags, msg->ftn_msgid))!=NULL) + hashes[h++]=hash; + + flags|=SMB_HASH_STRIP_WSP; + if(!dupechk) + flags|=SMB_HASH_MARKED; /* ignore for dupe checks */ + if(text!=NULL + && (hash=smb_hashstr(msg->hdr.number, t, TEXT_BODY, flags, text))!=NULL) + hashes[h++]=hash; + + return(hashes); +} + +/* Calculates and stores the hashes for a single message */ +int SMBCALL smb_hashmsg(smb_t* smb, smbmsg_t* msg, const uchar* text, BOOL update) +{ + size_t n; + int retval=SMB_SUCCESS; + hash_t found; + hash_t** hashes; /* This is a NULL-terminated list of hashes */ + + hashes=smb_msghashes(msg,text,/* dupechk? */TRUE); + + if(smb_findhash(smb, hashes, &found, update)==SMB_SUCCESS && !update) { + retval=SMB_DUPE_MSG; + safe_snprintf(smb->last_error,sizeof(smb->last_error) + ,"duplicate %s hash found (message #%lu)" + ,smb_hashsource(found.source), found.number); + } else + if((retval=smb_addhashes(smb,hashes,/* skip_marked? */TRUE))==SMB_SUCCESS) + msg->flags|=MSG_FLAG_HASHED; + + FREE_LIST(hashes,n); + + return(retval); +} + +/* length=0 specifies ASCIIZ data */ +int SMBCALL smb_getmsgidx_by_hash(smb_t* smb, smbmsg_t* msg, unsigned source + ,unsigned flags, const void* data, size_t length) +{ + int retval; + size_t n; + hash_t** hashes; + hash_t found; + + if((hashes=(hash_t**)malloc(sizeof(hash_t*)*2))==NULL) + return(SMB_ERR_MEM); + + if(length==0) + hashes[0]=smb_hashstr(0,0,source,flags,data); + else + hashes[0]=smb_hash(0,0,source,flags,data,length); + if(hashes[0]==NULL) + return(SMB_ERR_MEM); + + hashes[1]=NULL; /* terminate list */ + + memset(&found,0,sizeof(found)); + if((retval=smb_findhash(smb, hashes, &found, FALSE))==SMB_SUCCESS) { + if(found.number==0) + retval=SMB_FAILURE; /* use better error value here? */ + else { + msg->hdr.number=found.number; + retval=smb_getmsgidx(smb, msg); + } + } + + FREE_LIST(hashes,n); + + return(retval); +} + +int SMBCALL smb_getmsghdr_by_hash(smb_t* smb, smbmsg_t* msg, unsigned source + ,unsigned flags, const void* data, size_t length) +{ + int retval; + + if((retval=smb_getmsgidx_by_hash(smb,msg,source,flags,data,length))!=SMB_SUCCESS) + return(retval); + + if((retval=smb_lockmsghdr(smb,msg))!=SMB_SUCCESS) + return(retval); + + retval=smb_getmsghdr(smb,msg); + + smb_unlockmsghdr(smb,msg); + + return(retval); +} + +ushort SMBCALL smb_subject_crc(const char *subj) +{ + char* str; + ushort crc; + + while(!strnicmp(subj,"RE:",3)) { + subj+=3; + while(*subj==' ') + subj++; + } + + if((str=strdup(subj))==NULL) + return(0xffff); + + strlwr(str); + crc=crc16(str,0 /* auto-length */); + free(str); + + return(crc); +} diff --git a/src/smblib/smblib.c b/src/smblib/smblib.c index 5ac3d4060a..0e3a1c5287 100644 --- a/src/smblib/smblib.c +++ b/src/smblib/smblib.c @@ -51,10 +51,6 @@ #include "smblib.h" #include "genwrap.h" #include "filewrap.h" -#include "md5.h" -#include "crc16.h" -#include "crc32.h" -#include "truncsp.c" /* Use smb_ver() and smb_lib_ver() to obtain these values */ #define SMBLIB_VERSION "2.40" /* SMB library version */ @@ -175,81 +171,6 @@ void SMBCALL smb_close(smb_t* smb) smb_close_fp(&smb->hash_fp); } -/****************************************************************************/ -/* Opens a non-shareable file (FILE*) associated with a message base */ -/* Retrys for retry_time number of seconds */ -/* Return 0 on success, non-zero otherwise */ -/****************************************************************************/ -int SMBCALL smb_open_fp(smb_t* smb, FILE** fp, int share) -{ - int file; - char path[MAX_PATH+1]; - char* ext; - time_t start=0; - - if(fp==&smb->shd_fp) - ext="shd"; - else if(fp==&smb->sid_fp) - ext="sid"; - else if(fp==&smb->sdt_fp) - ext="sdt"; - else if(fp==&smb->sda_fp) - ext="sda"; - else if(fp==&smb->sha_fp) - ext="sha"; - else if(fp==&smb->hash_fp) - ext="hash"; - else { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"opening %s: Illegal FILE* pointer argument: %p" - ,smb->file, fp); - return(SMB_ERR_OPEN); - } - SAFEPRINTF2(path,"%s.%s",smb->file,ext); - - if(*fp!=NULL) /* Already open! */ - return(SMB_SUCCESS); - - while(1) { - if((file=sopen(path,O_RDWR|O_CREAT|O_BINARY,share,S_IREAD|S_IWRITE))!=-1) - break; - if(errno!=EACCES && errno!=EAGAIN) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"%d (%s) opening %s" - ,errno,STRERROR(errno),path); - return(SMB_ERR_OPEN); - } - if(!start) - start=time(NULL); - else - if(time(NULL)-start>=(time_t)smb->retry_time) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"timeout opening %s (retry_time=%ld)" - ,path,smb->retry_time); - return(SMB_ERR_TIMEOUT); - } - SLEEP(smb->retry_delay); - } - if((*fp=fdopen(file,"r+b"))==NULL) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"%d (%s) fdopening %s (%d)" - ,errno,STRERROR(errno),path,file); - close(file); - return(SMB_ERR_OPEN); - } - setvbuf(*fp,NULL,_IOFBF,2*1024); - return(SMB_SUCCESS); -} - -void SMBCALL smb_close_fp(FILE** fp) -{ - if(fp!=NULL) { - if(*fp!=NULL) - fclose(*fp); - *fp=NULL; - } -} - /****************************************************************************/ /* This set of functions is used to exclusively-lock an entire message base */ /* against any other process opening any of the message base files. */ @@ -514,7 +435,7 @@ int SMBCALL smb_unlocksmbhdr(smb_t* smb) /****************************************************************************/ /* Is the offset a valid message header offset? */ /****************************************************************************/ -static BOOL smb_valid_hdr_offset(smb_t* smb, ulong offset) +BOOL SMBCALL smb_valid_hdr_offset(smb_t* smb, ulong offset) { if(offset<sizeof(smbhdr_t)+sizeof(smbstatus_t) || offset<smb->status.header_offset) { @@ -1484,266 +1405,6 @@ int SMBCALL smb_addmsghdr(smb_t* smb, smbmsg_t* msg, int storage) return(i); } -/****************************************************************************/ -/****************************************************************************/ -int SMBCALL smb_addmsg(smb_t* smb, smbmsg_t* msg, int storage, BOOL dupechk - ,ushort xlat, const uchar* body, const uchar* tail) -{ - uchar* lzhbuf=NULL; - long lzhlen; - int retval; - size_t n; - size_t l,length; - size_t taillen=0; - size_t bodylen=0; - long offset; - ulong crc=0xffffffff; - hash_t found; - hash_t** hashes=NULL; /* This is a NULL-terminated list of hashes */ - smbmsg_t remsg; - - if(!SMB_IS_OPEN(smb)) { - safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open"); - return(SMB_ERR_NOT_OPEN); - } - - if(filelength(fileno(smb->shd_fp))<1) { /* Create it if it doesn't exist */ - /* smb->status.max_crcs, max_msgs, max_age, and attr should be pre-initialized */ - if((retval=smb_create(smb))!=SMB_SUCCESS) - return(retval); - } - - if(!smb->locked && smb_locksmbhdr(smb)!=SMB_SUCCESS) - return(SMB_ERR_LOCK); - - msg->hdr.total_dfields = 0; - - /* try */ - do { - - if((retval=smb_getstatus(smb))!=SMB_SUCCESS) - break; - - msg->hdr.number=smb->status.last_msg+1; - - hashes=smb_msghashes(msg,body,dupechk); - - if(smb_findhash(smb, hashes, &found, /* update? */FALSE)==SMB_SUCCESS) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"duplicate %s hash found (message #%lu)" - ,smb_hashsource(found.source), found.number); - retval=SMB_DUPE_MSG; - break; - } - - if(tail!=NULL && (taillen=strlen(tail))>0) - taillen+=sizeof(xlat); /* xlat string terminator */ - - if(body!=NULL && (bodylen=strlen(body))>0) { - - /* Remove white-space from end of message text */ - while(bodylen && body[bodylen-1]<=' ') - bodylen--; - - /* Calculate CRC-32 of message text (before encoding, if any) */ - if(smb->status.max_crcs && dupechk) { - for(l=0;l<bodylen;l++) - crc=ucrc32(body[l],crc); - crc=~crc; - - /* Add CRC to CRC history (and check for duplicates) */ - if((retval=smb_addcrc(smb,crc))!=SMB_SUCCESS) - break; - } - - bodylen+=sizeof(xlat); /* xlat string terminator */ - - /* LZH compress? */ - if(xlat==XLAT_LZH && bodylen+taillen>=SDT_BLOCK_LEN - && (lzhbuf=(uchar *)malloc(bodylen*2))!=NULL) { - lzhlen=lzh_encode((uchar*)body,bodylen-sizeof(xlat),lzhbuf); - if(lzhlen>1 - && smb_datblocks(lzhlen+(sizeof(xlat)*2)+taillen) - < smb_datblocks(bodylen+taillen)) { - bodylen=lzhlen+(sizeof(xlat)*2); /* Compressible */ - body=lzhbuf; - } else - xlat=XLAT_NONE; - } else - xlat=XLAT_NONE; - } - - length=bodylen+taillen; - - if(length&0x80000000) { - sprintf(smb->last_error,"message length: 0x%lX",length); - retval=SMB_ERR_DAT_LEN; - break; - } - - /* Allocate Data Blocks */ - if(smb->status.attr&SMB_HYPERALLOC) { - offset=smb_hallocdat(smb); - storage=SMB_HYPERALLOC; - } else { - if((retval=smb_open_da(smb))!=SMB_SUCCESS) - break; - if(storage==SMB_FASTALLOC) - offset=smb_fallocdat(smb,length,1); - else { /* SMB_SELFPACK */ - offset=smb_allocdat(smb,length,1); - storage=SMB_SELFPACK; - } - smb_close_da(smb); - } - - if(offset<0) { - retval=offset; - break; - } - msg->hdr.offset=offset; - - smb_fseek(smb->sdt_fp,offset,SEEK_SET); - - if(bodylen) { - if((retval=smb_dfield(msg,TEXT_BODY,bodylen))!=SMB_SUCCESS) - break; - - if(xlat!=XLAT_NONE) { /* e.g. XLAT_LZH */ - if(smb_fwrite(smb,&xlat,sizeof(xlat),smb->sdt_fp)!=sizeof(xlat)) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"%d (%s) writing body xlat string" - ,ferror(smb->sdt_fp),STRERROR(ferror(smb->sdt_fp))); - retval=SMB_ERR_WRITE; - break; - } - bodylen-=sizeof(xlat); - } - xlat=XLAT_NONE; /* xlat string terminator */ - if(smb_fwrite(smb,&xlat,sizeof(xlat),smb->sdt_fp)!=sizeof(xlat)) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"%d (%s) writing body xlat terminator" - ,ferror(smb->sdt_fp),STRERROR(ferror(smb->sdt_fp))); - retval=SMB_ERR_WRITE; - break; - } - bodylen-=sizeof(xlat); - - if(smb_fwrite(smb,body,bodylen,smb->sdt_fp)!=bodylen) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"%d (%s) writing body (%ld bytes)" - ,ferror(smb->sdt_fp),STRERROR(ferror(smb->sdt_fp)) - ,bodylen); - retval=SMB_ERR_WRITE; - break; - } - } - - if(taillen) { - if((retval=smb_dfield(msg,TEXT_TAIL,taillen))!=SMB_SUCCESS) - break; - - xlat=XLAT_NONE; /* xlat string terminator */ - if(smb_fwrite(smb,&xlat,sizeof(xlat),smb->sdt_fp)!=sizeof(xlat)) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"%d (%s) writing tail xlat terminator" - ,ferror(smb->sdt_fp),STRERROR(ferror(smb->sdt_fp))); - retval=SMB_ERR_WRITE; - break; - } - - if(smb_fwrite(smb,tail,taillen-sizeof(xlat),smb->sdt_fp)!=taillen-sizeof(xlat)) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"%d (%s) writing tail (%ld bytes)" - ,ferror(smb->sdt_fp),STRERROR(ferror(smb->sdt_fp)) - ,taillen-sizeof(xlat)); - retval=SMB_ERR_WRITE; - break; - } - } - - for(l=length;l%SDT_BLOCK_LEN;l++) { - if(smb_fputc(0,smb->sdt_fp)!=0) - break; - } - if(l%SDT_BLOCK_LEN) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"%d (%s) writing data padding" - ,ferror(smb->sdt_fp),STRERROR(ferror(smb->sdt_fp))); - retval=SMB_ERR_WRITE; - break; - } - - fflush(smb->sdt_fp); - - if(msg->to==NULL) /* no recipient, don't add header (required for bulkmail) */ - break; - - msg->hdr.version=smb_ver(); - if(msg->hdr.when_imported.time==0) { - msg->hdr.when_imported.time=time(NULL); - msg->hdr.when_imported.zone=0; /* how do we detect system TZ? */ - } - if(msg->hdr.when_written.time==0) /* Uninitialized */ - msg->hdr.when_written = msg->hdr.when_imported; - msg->idx.time=msg->hdr.when_imported.time; - - /* Look-up thread_back if Reply-ID was specified */ - if(msg->hdr.thread_back==0 && msg->reply_id!=NULL) { - if(smb_getmsgidx_by_msgid(smb,&remsg,msg->reply_id)==SMB_SUCCESS) - msg->hdr.thread_back=remsg.idx.number; /* needed for threading backward */ - } - - /* Auto-thread linkage */ - if(msg->hdr.thread_back) { - memset(&remsg,0,sizeof(remsg)); - remsg.hdr.number=msg->hdr.thread_back; - if((retval=smb_getmsgidx(smb, &remsg))!=SMB_SUCCESS) /* invalid thread origin */ - break; - - if((retval=smb_lockmsghdr(smb,&remsg))!=SMB_SUCCESS) - break; - - if((retval=smb_getmsghdr(smb, &remsg))!=SMB_SUCCESS) { - smb_unlockmsghdr(smb, &remsg); - break; - } - - /* Add RFC-822 Reply-ID if original message has RFC Message-ID */ - if(msg->reply_id==NULL && remsg.id!=NULL - && (retval=smb_hfield_str(msg,RFC822REPLYID,remsg.id))!=SMB_SUCCESS) - break; - - /* Add FidoNet Reply if original message has FidoNet MSGID */ - if(msg->ftn_reply==NULL && remsg.ftn_msgid!=NULL - && (retval=smb_hfield_str(msg,FIDOREPLYID,remsg.ftn_msgid))!=SMB_SUCCESS) - break; - - retval=smb_updatethread(smb, &remsg, msg->hdr.number); - smb_unlockmsghdr(smb, &remsg); - smb_freemsgmem(&remsg); - - if(retval!=SMB_SUCCESS) - break; - } - - if(smb_addhashes(smb,hashes,/* skip_marked? */FALSE)==SMB_SUCCESS) - msg->flags|=MSG_FLAG_HASHED; - - retval=smb_addmsghdr(smb,msg,storage); // calls smb_unlocksmbhdr() - - } while(0); - /* finally */ - - if(retval!=SMB_SUCCESS) - smb_freemsg_dfields(smb,msg,1); - - smb_unlocksmbhdr(smb); - FREE_AND_NULL(lzhbuf); - FREE_LIST(hashes,n); - - return(retval); -} /****************************************************************************/ /* Writes both header and index information for msg 'msg' */ @@ -1965,1101 +1626,66 @@ ulong SMBCALL smb_hdrblocks(ulong length) } /****************************************************************************/ -/* Finds unused space in data file based on block allocation table and */ -/* marks space as used in allocation table. */ -/* File must be opened read/write DENY ALL */ -/* Returns offset to beginning of data (in bytes, not blocks) */ -/* Assumes smb_open_da() has been called */ -/* smb_close_da() should be called after */ -/* Returns negative on error */ +/* Returns difference from specified timezone and UTC/GMT */ /****************************************************************************/ -long SMBCALL smb_allocdat(smb_t* smb, ulong length, ushort refs) +int SMBCALL smb_tzutc(short zone) { - ushort i; - ulong j,l,blocks,offset=0L; - - if(smb->sda_fp==NULL) { - safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open"); - return(SMB_ERR_NOT_OPEN); - } - blocks=smb_datblocks(length); - j=0; /* j is consecutive unused block counter */ - fflush(smb->sda_fp); - rewind(smb->sda_fp); - while(!feof(smb->sda_fp) && (long)offset>=0) { - if(smb_fread(smb,&i,sizeof(i),smb->sda_fp)!=sizeof(i)) - break; - offset+=SDT_BLOCK_LEN; - if(!i) j++; - else j=0; - if(j==blocks) { - offset-=(blocks*SDT_BLOCK_LEN); - break; - } - } - if((long)offset<0) { - safe_snprintf(smb->last_error,sizeof(smb->last_error),"invalid data offset: %lu",offset); - return(SMB_ERR_DAT_OFFSET); - } - clearerr(smb->sda_fp); - if(fseek(smb->sda_fp,(offset/SDT_BLOCK_LEN)*sizeof(refs),SEEK_SET)) { - return(SMB_ERR_SEEK); - } - for(l=0;l<blocks;l++) - if(!fwrite(&refs,sizeof(refs),1,smb->sda_fp)) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"%d (%s) writing allocation bytes at offset %ld" - ,ferror(smb->sda_fp),STRERROR(ferror(smb->sda_fp)) - ,((offset/SDT_BLOCK_LEN)+l)*sizeof(refs)); - return(SMB_ERR_WRITE); - } - fflush(smb->sda_fp); - return(offset); -} + int tz; -/****************************************************************************/ -/* Allocates space for data, but doesn't search for unused blocks */ -/* Returns negative on error */ -/****************************************************************************/ -long SMBCALL smb_fallocdat(smb_t* smb, ulong length, ushort refs) -{ - ulong l,blocks,offset; + if(OTHER_ZONE(zone)) + return(zone); - if(smb->sda_fp==NULL) { - safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open"); - return(SMB_ERR_NOT_OPEN); - } - fflush(smb->sda_fp); - clearerr(smb->sda_fp); - blocks=smb_datblocks(length); - if(fseek(smb->sda_fp,0L,SEEK_END)) { - return(SMB_ERR_SEEK); - } - offset=(ftell(smb->sda_fp)/sizeof(refs))*SDT_BLOCK_LEN; - if((long)offset<0) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"invalid data offset: %lu",offset); - return(SMB_ERR_DAT_OFFSET); - } - for(l=0;l<blocks;l++) - if(!fwrite(&refs,sizeof(refs),1,smb->sda_fp)) - break; - fflush(smb->sda_fp); - if(l<blocks) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"%d (%s) writing allocation bytes" - ,ferror(smb->sda_fp),STRERROR(ferror(smb->sda_fp))); - return(SMB_ERR_WRITE); - } - return(offset); + tz=zone&0xfff; + if(zone&(WESTERN_ZONE|US_ZONE)) /* West of UTC? */ + return(-tz); + return(tz); } /****************************************************************************/ -/* De-allocates space for data */ -/* Returns non-zero on error */ /****************************************************************************/ -int SMBCALL smb_freemsgdat(smb_t* smb, ulong offset, ulong length, ushort refs) +int SMBCALL smb_updatethread(smb_t* smb, smbmsg_t* remsg, ulong newmsgnum) { - BOOL da_opened=FALSE; - int retval=0; - ushort i; - ulong l,blocks; - ulong sda_offset; - - if(smb->status.attr&SMB_HYPERALLOC) /* do nothing */ - return(SMB_SUCCESS); - - blocks=smb_datblocks(length); + int retval=SMB_ERR_NOT_FOUND; + ulong nextmsgnum; + smbmsg_t nextmsg; - if(smb->sda_fp==NULL) { - if((i=smb_open_da(smb))!=SMB_SUCCESS) - return(i); - da_opened=TRUE; + if(!remsg->hdr.thread_first) { /* New msg is first reply */ + remsg->hdr.thread_first=newmsgnum; + if((retval=smb_lockmsghdr(smb,remsg))!=SMB_SUCCESS) + return(retval); + retval=smb_putmsghdr(smb,remsg); + smb_unlockmsghdr(smb,remsg); + return(retval); } - - clearerr(smb->sda_fp); - for(l=0;l<blocks;l++) { - sda_offset=((offset/SDT_BLOCK_LEN)+l)*sizeof(i); - if(fseek(smb->sda_fp,sda_offset,SEEK_SET)) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"%d (%s) seeking to %lu (0x%lX) of allocation file" - ,errno,STRERROR(errno) - ,sda_offset,sda_offset); - retval=SMB_ERR_SEEK; + + /* Search for last reply and extend chain */ + memset(&nextmsg,0,sizeof(nextmsg)); + nextmsgnum=remsg->hdr.thread_first; /* start with first reply */ + while(1) { + nextmsg.idx.offset=0; + nextmsg.hdr.number=nextmsgnum; + if(smb_getmsgidx(smb, &nextmsg)!=SMB_SUCCESS) /* invalid thread origin */ break; - } - if(smb_fread(smb,&i,sizeof(i),smb->sda_fp)!=sizeof(i)) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"%d (%s) reading allocation bytes at offset %ld" - ,ferror(smb->sda_fp),STRERROR(ferror(smb->sda_fp)) - ,sda_offset); - retval=SMB_ERR_READ; + if(smb_lockmsghdr(smb,&nextmsg)!=SMB_SUCCESS) break; - } - if(refs==SMB_ALL_REFS || refs>i) - i=0; /* don't want to go negative */ - else - i-=refs; - if(fseek(smb->sda_fp,-(int)sizeof(i),SEEK_CUR)) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"%d (%s) seeking backwards 2 bytes in allocation file" - ,errno,STRERROR(errno)); - retval=SMB_ERR_SEEK; + if(smb_getmsghdr(smb, &nextmsg)!=SMB_SUCCESS) { + smb_unlockmsghdr(smb,&nextmsg); break; } - if(!fwrite(&i,sizeof(i),1,smb->sda_fp)) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"%d (%s) writing allocation bytes at offset %ld" - ,ferror(smb->sda_fp),STRERROR(ferror(smb->sda_fp)) - ,sda_offset); - retval=SMB_ERR_WRITE; - break; + if(nextmsg.hdr.thread_next && nextmsg.hdr.thread_next!=nextmsgnum) { + nextmsgnum=nextmsg.hdr.thread_next; + smb_unlockmsghdr(smb,&nextmsg); + smb_freemsgmem(&nextmsg); + continue; } + nextmsg.hdr.thread_next=newmsgnum; + retval=smb_putmsghdr(smb,&nextmsg); + smb_unlockmsghdr(smb,&nextmsg); + smb_freemsgmem(&nextmsg); + break; } - fflush(smb->sda_fp); - if(da_opened) - smb_close_da(smb); - return(retval); -} - -/****************************************************************************/ -/* Adds to data allocation records for blocks starting at 'offset' */ -/* Returns non-zero on error */ -/****************************************************************************/ -int SMBCALL smb_incdat(smb_t* smb, ulong offset, ulong length, ushort refs) -{ - ushort i; - ulong l,blocks; - if(smb->sda_fp==NULL) { - safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open"); - return(SMB_ERR_NOT_OPEN); - } - clearerr(smb->sda_fp); - blocks=smb_datblocks(length); - for(l=0;l<blocks;l++) { - if(fseek(smb->sda_fp,((offset/SDT_BLOCK_LEN)+l)*sizeof(i),SEEK_SET)) { - return(SMB_ERR_SEEK); - } - if(smb_fread(smb,&i,sizeof(i),smb->sda_fp)!=sizeof(i)) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"%d (%s) reading allocation record at offset %ld" - ,ferror(smb->sda_fp),STRERROR(ferror(smb->sda_fp)) - ,((offset/SDT_BLOCK_LEN)+l)*sizeof(i)); - return(SMB_ERR_READ); - } - i+=refs; - if(fseek(smb->sda_fp,-(int)sizeof(i),SEEK_CUR)) { - return(SMB_ERR_SEEK); - } - if(!fwrite(&i,sizeof(i),1,smb->sda_fp)) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"%d (%s) writing allocation record at offset %ld" - ,ferror(smb->sda_fp),STRERROR(ferror(smb->sda_fp)) - ,((offset/SDT_BLOCK_LEN)+l)*sizeof(i)); - return(SMB_ERR_WRITE); - } - } - fflush(smb->sda_fp); - return(SMB_SUCCESS); + return(retval); } -/****************************************************************************/ -/* Increments data allocation records (message references) by number of */ -/* header references specified (usually 1) */ -/* The opposite function of smb_freemsg() */ -/****************************************************************************/ -int SMBCALL smb_incmsg_dfields(smb_t* smb, smbmsg_t* msg, ushort refs) -{ - int i=0; - BOOL da_opened=FALSE; - ushort x; - - if(smb->status.attr&SMB_HYPERALLOC) /* Nothing to do */ - return(SMB_SUCCESS); - - if(smb->sda_fp==NULL) { - if((i=smb_open_da(smb))!=SMB_SUCCESS) - return(i); - da_opened=TRUE; - } - - for(x=0;x<msg->hdr.total_dfields;x++) { - if((i=smb_incdat(smb,msg->hdr.offset+msg->dfield[x].offset - ,msg->dfield[x].length,refs))!=SMB_SUCCESS) - break; - } - - if(da_opened) - smb_close_da(smb); - return(i); -} - -/****************************************************************************/ -/* De-allocates blocks for header record */ -/* Returns non-zero on error */ -/****************************************************************************/ -int SMBCALL smb_freemsghdr(smb_t* smb, ulong offset, ulong length) -{ - uchar c=0; - ulong l,blocks; - - if(smb->sha_fp==NULL) { - safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open"); - return(SMB_ERR_NOT_OPEN); - } - clearerr(smb->sha_fp); - blocks=smb_hdrblocks(length); - if(fseek(smb->sha_fp,offset/SHD_BLOCK_LEN,SEEK_SET)) - return(SMB_ERR_SEEK); - for(l=0;l<blocks;l++) - if(!fwrite(&c,1,1,smb->sha_fp)) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"%d (%s) writing allocation record" - ,ferror(smb->sha_fp),STRERROR(ferror(smb->sha_fp))); - return(SMB_ERR_WRITE); - } - fflush(smb->sha_fp); - return(SMB_SUCCESS); -} - -/****************************************************************************/ -/****************************************************************************/ -int SMBCALL smb_freemsg_dfields(smb_t* smb, smbmsg_t* msg, ushort refs) -{ - int i; - ushort x; - - for(x=0;x<msg->hdr.total_dfields;x++) { - if((i=smb_freemsgdat(smb,msg->hdr.offset+msg->dfield[x].offset - ,msg->dfield[x].length,refs))!=SMB_SUCCESS) - return(i); - } - return(SMB_SUCCESS); -} - -/****************************************************************************/ -/* Frees all allocated header and data blocks (1 reference) for 'msg' */ -/****************************************************************************/ -int SMBCALL smb_freemsg(smb_t* smb, smbmsg_t* msg) -{ - int i; - - if(smb->status.attr&SMB_HYPERALLOC) /* Nothing to do */ - return(SMB_SUCCESS); - - if(!smb_valid_hdr_offset(smb,msg->idx.offset)) - return(SMB_ERR_HDR_OFFSET); - - if((i=smb_freemsg_dfields(smb,msg,1))!=SMB_SUCCESS) - return(i); - - return(smb_freemsghdr(smb,msg->idx.offset-smb->status.header_offset - ,msg->hdr.length)); -} - -/****************************************************************************/ -/* Finds unused space in header file based on block allocation table and */ -/* marks space as used in allocation table. */ -/* File must be opened read/write DENY ALL */ -/* Returns offset to beginning of header (in bytes, not blocks) */ -/* Assumes smb_open_ha() has been called */ -/* smb_close_ha() should be called after */ -/* Returns negative value on error */ -/****************************************************************************/ -long SMBCALL smb_allochdr(smb_t* smb, ulong length) -{ - uchar c; - ulong i,l,blocks,offset=0; - - if(smb->sha_fp==NULL) { - safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open"); - return(SMB_ERR_NOT_OPEN); - } - blocks=smb_hdrblocks(length); - i=0; /* i is consecutive unused block counter */ - fflush(smb->sha_fp); - rewind(smb->sha_fp); - while(!feof(smb->sha_fp)) { - if(smb_fread(smb,&c,sizeof(c),smb->sha_fp)!=sizeof(c)) - break; - offset+=SHD_BLOCK_LEN; - if(!c) i++; - else i=0; - if(i==blocks) { - offset-=(blocks*SHD_BLOCK_LEN); - break; - } - } - clearerr(smb->sha_fp); - if(fseek(smb->sha_fp,offset/SHD_BLOCK_LEN,SEEK_SET)) - return(SMB_ERR_SEEK); - - for(l=0;l<blocks;l++) - if(fputc(1,smb->sha_fp)!=1) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"%d (%s) writing allocation record" - ,ferror(smb->sha_fp),STRERROR(ferror(smb->sha_fp))); - return(SMB_ERR_WRITE); - } - fflush(smb->sha_fp); - return(offset); -} - -/****************************************************************************/ -/* Allocates space for index, but doesn't search for unused blocks */ -/* Returns negative value on error */ -/****************************************************************************/ -long SMBCALL smb_fallochdr(smb_t* smb, ulong length) -{ - uchar c=1; - ulong l,blocks,offset; - - if(smb->sha_fp==NULL) { - safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open"); - return(SMB_ERR_NOT_OPEN); - } - blocks=smb_hdrblocks(length); - fflush(smb->sha_fp); - clearerr(smb->sha_fp); - if(fseek(smb->sha_fp,0L,SEEK_END)) - return(SMB_ERR_SEEK); - offset=ftell(smb->sha_fp)*SHD_BLOCK_LEN; - for(l=0;l<blocks;l++) - if(!fwrite(&c,1,1,smb->sha_fp)) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"%d (%s) writing allocation record" - ,ferror(smb->sha_fp),STRERROR(ferror(smb->sha_fp))); - return(SMB_ERR_WRITE); - } - fflush(smb->sha_fp); - return(offset); -} - -/************************************************************************/ -/* Allocate header blocks using Hyper Allocation */ -/* this function should be most likely not be called from anywhere but */ -/* smb_addmsghdr() */ -/************************************************************************/ -long SMBCALL smb_hallochdr(smb_t* smb) -{ - ulong offset; - - if(smb->shd_fp==NULL) { - safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open"); - return(SMB_ERR_NOT_OPEN); - } - fflush(smb->shd_fp); - if(fseek(smb->shd_fp,0L,SEEK_END)) - return(SMB_ERR_SEEK); - offset=ftell(smb->shd_fp); - if(offset<smb->status.header_offset) /* Header file truncated?!? */ - return(smb->status.header_offset); - - offset-=smb->status.header_offset; /* SMB headers not included */ - - /* Even block boundry */ - offset+=PAD_LENGTH_FOR_ALIGNMENT(offset,SHD_BLOCK_LEN); - - return(offset); -} - -/************************************************************************/ -/* Allocate data blocks using Hyper Allocation */ -/* smb_locksmbhdr() should be called before this function and not */ -/* unlocked until all data fields for this message have been written */ -/* to the SDT file */ -/************************************************************************/ -long SMBCALL smb_hallocdat(smb_t* smb) -{ - long offset; - - if(smb->sdt_fp==NULL) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"msgbase not open"); - return(SMB_ERR_NOT_OPEN); - } - fflush(smb->sdt_fp); - offset=filelength(fileno(smb->sdt_fp)); - if(offset<0) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"invalid file length: %lu",(ulong)offset); - return(SMB_ERR_FILE_LEN); - } - if(fseek(smb->sdt_fp,0L,SEEK_END)) - return(SMB_ERR_SEEK); - offset=ftell(smb->sdt_fp); - if(offset<0) { - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"invalid file offset: %ld",offset); - return(SMB_ERR_DAT_OFFSET); - } - - /* Make sure even block boundry */ - offset+=PAD_LENGTH_FOR_ALIGNMENT(offset,SDT_BLOCK_LEN); - - return(offset); -} - -int SMBCALL smb_feof(FILE* fp) -{ - return(feof(fp)); -} - -int SMBCALL smb_ferror(FILE* fp) -{ - return(ferror(fp)); -} - -int SMBCALL smb_fflush(FILE* fp) -{ - return(fflush(fp)); -} - -int SMBCALL smb_fgetc(FILE* fp) -{ - return(fgetc(fp)); -} - -int SMBCALL smb_fputc(int ch, FILE* fp) -{ - return(fputc(ch,fp)); -} - -int SMBCALL smb_fseek(FILE* fp, long offset, int whence) -{ - return(fseek(fp,offset,whence)); -} - -long SMBCALL smb_ftell(FILE* fp) -{ - return(ftell(fp)); -} - -long SMBCALL smb_fgetlength(FILE* fp) -{ - return(filelength(fileno(fp))); -} - -int SMBCALL smb_fsetlength(FILE* fp, long length) -{ - return(chsize(fileno(fp),length)); -} - -void SMBCALL smb_rewind(FILE* fp) -{ - rewind(fp); -} - -void SMBCALL smb_clearerr(FILE* fp) -{ - clearerr(fp); -} - -size_t SMBCALL smb_fread(smb_t* smb, void* buf, size_t bytes, FILE* fp) -{ - size_t ret; - time_t start=0; - - while(1) { - if((ret=fread(buf,sizeof(char),bytes,fp))==bytes) - return(ret); - if(ferror(fp)!=EDEADLOCK) - return(ret); - if(!start) - start=time(NULL); - else - if(time(NULL)-start>=(time_t)smb->retry_time) - break; - SLEEP(smb->retry_delay); - } - return(ret); -} - -#if defined(__BORLANDC__) - #pragma argsused -#endif - -size_t SMBCALL smb_fwrite(smb_t* smb, const void* buf, size_t bytes, FILE* fp) -{ - return(fwrite(buf,1,bytes,fp)); -} - -/************************************************************************/ -/* Returns difference from specified timezone and UTC/GMT */ -/************************************************************************/ -int SMBCALL smb_tzutc(short zone) -{ - int tz; - - if(OTHER_ZONE(zone)) - return(zone); - - tz=zone&0xfff; - if(zone&(WESTERN_ZONE|US_ZONE)) /* West of UTC? */ - return(-tz); - return(tz); -} - -char* SMBCALL smb_hfieldtype(ushort type) -{ - static char str[8]; - - switch(type) { - case SENDER: return("Sender"); - case SENDERAGENT: return("SenderAgent"); - case SENDERNETTYPE: return("SenderNetType"); - case SENDERNETADDR: return("SenderNetAddr"); - case SENDEREXT: return("SenderExt"); - case SENDERORG: return("SenderOrg"); - case SENDERIPADDR: return("SenderIpAddr"); - case SENDERHOSTNAME: return("SenderHostName"); - case SENDERPROTOCOL: return("SenderProtocol"); - case SENDERPORT: return("SenderPort"); - - case REPLYTO: return("ReplyTo"); - case REPLYTOAGENT: return("ReplyToAgent"); - case REPLYTONETTYPE: return("ReplyToNetType"); - case REPLYTONETADDR: return("ReplyToNetAddr"); - case REPLYTOEXT: return("ReplyToExt"); - - case RECIPIENT: return("Recipient"); - case RECIPIENTAGENT: return("RecipientAgent"); - case RECIPIENTNETTYPE: return("RecipientNetType"); - case RECIPIENTNETADDR: return("RecipientNetAddr"); - case RECIPIENTEXT: return("RecipientExt"); - - case SUBJECT: return("Subject"); - case SMB_SUMMARY: return("Summary"); - case SMB_COMMENT: return("Comment"); - case SMB_CARBONCOPY: return("CarbonCopy"); - case SMB_GROUP: return("Group"); - case SMB_EXPIRATION: return("Expiration"); - case SMB_PRIORITY: return("Priority"); - case SMB_COST: return("Cost"); - - case FIDOCTRL: return("FidoCtrl"); - case FIDOAREA: return("FidoArea"); - case FIDOSEENBY: return("FidoSeenBy"); - case FIDOPATH: return("FidoPath"); - case FIDOMSGID: return("FidoMsgID"); - case FIDOREPLYID: return("FidoReplyID"); - case FIDOPID: return("FidoPID"); - case FIDOFLAGS: return("FidoFlags"); - case FIDOTID: return("FidoTID"); - - case RFC822HEADER: return("RFC822Header"); - case RFC822MSGID: return("RFC822MsgID"); - case RFC822REPLYID: return("RFC822ReplyID"); - case RFC822TO: return("RFC822To"); - case RFC822FROM: return("RFC822From"); - case RFC822REPLYTO: return("RFC822ReplyTo"); - - case USENETPATH: return("UsenetPath"); - case USENETNEWSGROUPS: return("UsenetNewsgroups"); - - case SMTPCOMMAND: return("SMTPCommand"); - case SMTPREVERSEPATH: return("SMTPReversePath"); - - case SMTPSYSMSG: return("SMTPSysMsg"); - - case UNKNOWN: return("UNKNOWN"); - case UNKNOWNASCII: return("UNKNOWNASCII"); - case UNUSED: return("UNUSED"); - } - sprintf(str,"%02Xh",type); - return(str); -} - -ushort SMBCALL smb_hfieldtypelookup(const char* str) -{ - ushort type; - - if(isdigit(*str)) - return((ushort)strtol(str,NULL,0)); - - for(type=0;type<=UNUSED;type++) - if(stricmp(str,smb_hfieldtype(type))==0) - return(type); - - return(UNKNOWN); -} - -char* SMBCALL smb_dfieldtype(ushort type) -{ - static char str[8]; - - switch(type) { - case TEXT_BODY: return("TEXT_BODY"); - case TEXT_TAIL: return("TEXT_TAIL"); - case UNUSED: return("UNUSED"); - } - sprintf(str,"%02Xh",type); - return(str); -} - -char* SMBCALL smb_hashsource(uchar type) -{ - if(type==TEXT_BODY || type==TEXT_TAIL) - return(smb_dfieldtype(type)); - return(smb_hfieldtype(type)); -} - -int SMBCALL smb_updatethread(smb_t* smb, smbmsg_t* remsg, ulong newmsgnum) -{ - int retval=SMB_ERR_NOT_FOUND; - ulong nextmsgnum; - smbmsg_t nextmsg; - - if(!remsg->hdr.thread_first) { /* New msg is first reply */ - remsg->hdr.thread_first=newmsgnum; - if((retval=smb_lockmsghdr(smb,remsg))!=SMB_SUCCESS) - return(retval); - retval=smb_putmsghdr(smb,remsg); - smb_unlockmsghdr(smb,remsg); - return(retval); - } - - /* Search for last reply and extend chain */ - memset(&nextmsg,0,sizeof(nextmsg)); - nextmsgnum=remsg->hdr.thread_first; /* start with first reply */ - while(1) { - nextmsg.idx.offset=0; - nextmsg.hdr.number=nextmsgnum; - if(smb_getmsgidx(smb, &nextmsg)!=SMB_SUCCESS) /* invalid thread origin */ - break; - if(smb_lockmsghdr(smb,&nextmsg)!=SMB_SUCCESS) - break; - if(smb_getmsghdr(smb, &nextmsg)!=SMB_SUCCESS) { - smb_unlockmsghdr(smb,&nextmsg); - break; - } - if(nextmsg.hdr.thread_next && nextmsg.hdr.thread_next!=nextmsgnum) { - nextmsgnum=nextmsg.hdr.thread_next; - smb_unlockmsghdr(smb,&nextmsg); - smb_freemsgmem(&nextmsg); - continue; - } - nextmsg.hdr.thread_next=newmsgnum; - retval=smb_putmsghdr(smb,&nextmsg); - smb_unlockmsghdr(smb,&nextmsg); - smb_freemsgmem(&nextmsg); - break; - } - - return(retval); -} - -/**************************/ -/* Hash-related functions */ -/**************************/ - -/* If return value is SMB_ERROR_NOT_FOUND, hash file is left open */ -int SMBCALL smb_findhash(smb_t* smb, hash_t** compare, hash_t* found_hash, BOOL mark) -{ - int retval; - BOOL found=FALSE; - size_t c,count; - hash_t hash; - - if(found_hash!=NULL) - memset(found_hash,0,sizeof(hash_t)); - - if((retval=smb_open_hash(smb))!=SMB_SUCCESS) - return(retval); - - COUNT_LIST_ITEMS(compare, count); - - if(count) { - - rewind(smb->hash_fp); - while(!feof(smb->hash_fp)) { - memset(&hash,0,sizeof(hash)); - if(smb_fread(smb,&hash,sizeof(hash),smb->hash_fp)!=sizeof(hash)) - break; - - if(hash.flags==0) - continue; /* invalid hash record (!?) */ - - for(c=0;compare[c]!=NULL;c++) { - - if(compare[c]->source!=hash.source) - continue; /* wrong source */ - if(compare[c]->flags&SMB_HASH_MARKED) - continue; /* already marked */ - if((compare[c]->flags&SMB_HASH_PROC_MASK)!=(hash.flags&SMB_HASH_PROC_MASK)) - continue; /* wrong pre-process flags */ - if((compare[c]->flags&hash.flags&SMB_HASH_MASK)==0) - continue; /* no matching hashes */ - if(compare[c]->flags&hash.flags&SMB_HASH_CRC16 - && compare[c]->crc16!=hash.crc16) - continue; /* wrong crc-16 */ - if(compare[c]->flags&hash.flags&SMB_HASH_CRC32 - && compare[c]->crc32!=hash.crc32) - continue; /* wrong crc-32 */ - if(compare[c]->flags&hash.flags&SMB_HASH_MD5 - && memcmp(compare[c]->md5,hash.md5,sizeof(hash.md5))) - continue; /* wrong crc-16 */ - - /* successful match! */ - break; /* can't match more than one, so stop comparing */ - } - - if(compare[c]==NULL) - continue; /* no match */ - - found=TRUE; - - if(found_hash!=NULL) - memcpy(found_hash,&hash,sizeof(hash)); - - if(!mark) - break; - - compare[c]->flags|=SMB_HASH_MARKED; - } - if(found) { - smb_close_hash(smb); - return(SMB_SUCCESS); - } - } - - /* hash file left open */ - return(SMB_ERR_NOT_FOUND); -} - -int SMBCALL smb_addhashes(smb_t* smb, hash_t** hashes, BOOL skip_marked) -{ - int retval; - size_t h; - - COUNT_LIST_ITEMS(hashes, h); - if(!h) /* nothing to add */ - return(SMB_SUCCESS); - - if((retval=smb_open_hash(smb))!=SMB_SUCCESS) - return(retval); - - fseek(smb->hash_fp,0,SEEK_END); - - for(h=0;hashes[h]!=NULL;h++) { - - /* skip hashes marked by smb_findhash() */ - if(skip_marked && hashes[h]->flags&SMB_HASH_MARKED) - continue; - - /* can't think of any reason to strip SMB_HASH_MARKED flag right now */ - if(smb_fwrite(smb,hashes[h],sizeof(hash_t),smb->hash_fp)!=sizeof(hash_t)) - return(SMB_ERR_WRITE); - } - - smb_close_hash(smb); - - return(SMB_SUCCESS); -} - -static char* strip_chars(uchar* str, uchar* set) -{ - char* src; - char* dst; - char* tmp; - - if((tmp=strdup(str))==NULL) - return(NULL); - for(src=tmp,dst=str;*src;src++) { - if(strchr(set,*src)==NULL) - *(dst++)=*src; - } - *dst=0; - - return(str); -} - -/* Allocates and calculates hashes of data (based on flags) */ -/* Returns NULL on failure */ -hash_t* SMBCALL smb_hash(ulong msgnum, ulong t, unsigned source, unsigned flags - ,const void* data, size_t length) -{ - hash_t* hash; - - if((hash=(hash_t*)malloc(sizeof(hash_t)))==NULL) - return(NULL); - - hash->number=msgnum; - hash->time=t; - hash->source=source; - hash->flags=flags; - if(flags&SMB_HASH_CRC16) - hash->crc16=crc16((char*)data,length); - if(flags&SMB_HASH_CRC32) - hash->crc32=crc32((char*)data,length); - if(flags&SMB_HASH_MD5) - MD5_calc(hash->md5,data,length); - - return(hash); -} - -/* Allocates and calculates hashes of data (based on flags) */ -/* Supports string hash "pre-processing" (e.g. lowercase, strip whitespace) */ -/* Returns NULL on failure */ -hash_t* SMBCALL smb_hashstr(ulong msgnum, ulong t, unsigned source, unsigned flags - ,const char* str) -{ - char* p=(uchar*)str; - hash_t* hash; - - if(flags&SMB_HASH_PROC_MASK) { /* string pre-processing */ - if((p=strdup(str))==NULL) - return(NULL); - if(flags&SMB_HASH_LOWERCASE) - strlwr(p); - if(flags&SMB_HASH_STRIP_WSP) - strip_chars(p," \t\r\n"); - } - - hash=smb_hash(msgnum, t, source, flags, p, strlen(p)); - - if(p!=str) /* duped string */ - free(p); - - return(hash); -} - -/* Allocatese and calculates all hashes for a single message */ -/* Returns NULL on failure */ -hash_t** SMBCALL smb_msghashes(smbmsg_t* msg, const uchar* text, BOOL dupechk) -{ - size_t h=0; - uchar flags=SMB_HASH_CRC16|SMB_HASH_CRC32|SMB_HASH_MD5; - hash_t** hashes; /* This is a NULL-terminated list of hashes */ - hash_t* hash; - time_t t=time(NULL); - -#define SMB_MAX_HASH_COUNT 4 - - if((hashes=(hash_t**)malloc(sizeof(hash_t*)*SMB_MAX_HASH_COUNT))==NULL) - return(NULL); - - memset(hashes, 0, sizeof(hash_t*)*SMB_MAX_HASH_COUNT); - - if(msg->id!=NULL - && (hash=smb_hashstr(msg->hdr.number, t, RFC822MSGID, flags, msg->id))!=NULL) - hashes[h++]=hash; - - if(msg->ftn_msgid!=NULL - && (hash=smb_hashstr(msg->hdr.number, t, FIDOMSGID, flags, msg->ftn_msgid))!=NULL) - hashes[h++]=hash; - - flags|=SMB_HASH_STRIP_WSP; - if(!dupechk) - flags|=SMB_HASH_MARKED; /* ignore for dupe checks */ - if(text!=NULL - && (hash=smb_hashstr(msg->hdr.number, t, TEXT_BODY, flags, text))!=NULL) - hashes[h++]=hash; - - return(hashes); -} - -/* Calculates and stores the hashes for a single message */ -int SMBCALL smb_hashmsg(smb_t* smb, smbmsg_t* msg, const uchar* text, BOOL update) -{ - size_t n; - int retval=SMB_SUCCESS; - hash_t found; - hash_t** hashes; /* This is a NULL-terminated list of hashes */ - - hashes=smb_msghashes(msg,text,/* dupechk? */TRUE); - - if(smb_findhash(smb, hashes, &found, update)==SMB_SUCCESS && !update) { - retval=SMB_DUPE_MSG; - safe_snprintf(smb->last_error,sizeof(smb->last_error) - ,"duplicate %s hash found (message #%lu)" - ,smb_hashsource(found.source), found.number); - } else - if((retval=smb_addhashes(smb,hashes,/* skip_marked? */TRUE))==SMB_SUCCESS) - msg->flags|=MSG_FLAG_HASHED; - - FREE_LIST(hashes,n); - - return(retval); -} - -/* length=0 specifies ASCIIZ data */ -int SMBCALL smb_getmsgidx_by_hash(smb_t* smb, smbmsg_t* msg, unsigned source - ,unsigned flags, const void* data, size_t length) -{ - int retval; - size_t n; - hash_t** hashes; - hash_t found; - - if((hashes=(hash_t**)malloc(sizeof(hash_t*)*2))==NULL) - return(SMB_ERR_MEM); - - if(length==0) - hashes[0]=smb_hashstr(0,0,source,flags,data); - else - hashes[0]=smb_hash(0,0,source,flags,data,length); - if(hashes[0]==NULL) - return(SMB_ERR_MEM); - - hashes[1]=NULL; /* terminate list */ - - memset(&found,0,sizeof(found)); - if((retval=smb_findhash(smb, hashes, &found, FALSE))==SMB_SUCCESS) { - if(found.number==0) - retval=SMB_FAILURE; /* use better error value here? */ - else { - msg->hdr.number=found.number; - retval=smb_getmsgidx(smb, msg); - } - } - - FREE_LIST(hashes,n); - - return(retval); -} - -int SMBCALL smb_getmsghdr_by_hash(smb_t* smb, smbmsg_t* msg, unsigned source - ,unsigned flags, const void* data, size_t length) -{ - int retval; - - if((retval=smb_getmsgidx_by_hash(smb,msg,source,flags,data,length))!=SMB_SUCCESS) - return(retval); - - if((retval=smb_lockmsghdr(smb,msg))!=SMB_SUCCESS) - return(retval); - - retval=smb_getmsghdr(smb,msg); - - smb_unlockmsghdr(smb,msg); - - return(retval); -} - - -ushort SMBCALL smb_subject_crc(const char *subj) -{ - char* str; - ushort crc; - - while(!strnicmp(subj,"RE:",3)) { - subj+=3; - while(*subj==' ') - subj++; - } - - if((str=strdup(subj))==NULL) - return(0xffff); - - strlwr(str); - crc=crc16(str,0 /* auto-length */); - free(str); - - return(crc); -} - -/****************************************************************************/ -/* Returns an ASCII string for FidoNet address 'addr' */ -/****************************************************************************/ -char* SMBCALL smb_faddrtoa(fidoaddr_t* addr, char* outstr) -{ - static char str[64]; - char point[25]; - - if(addr==NULL) - return("0:0/0"); - sprintf(str,"%hu:%hu/%hu",addr->zone,addr->net,addr->node); - if(addr->point) { - sprintf(point,".%hu",addr->point); - strcat(str,point); - } - if(outstr==NULL) - return(str); - strcpy(outstr,str); - return(outstr); -} - -char* SMBCALL smb_netaddr(net_t* net) -{ - if(net->type==NET_FIDO) - return(smb_faddrtoa((fidoaddr_t*)net->addr,NULL)); - return(net->addr); -} - -/****************************************************************************/ -/* Converts when_t.zone into ASCII format */ -/****************************************************************************/ -char* SMBCALL smb_zonestr(short zone, char* outstr) -{ - char* plus; - static char str[32]; - - switch((ushort)zone) { - case 0: return("UTC"); - case AST: return("AST"); - case EST: return("EST"); - case CST: return("CST"); - case MST: return("MST"); - case PST: return("PST"); - case YST: return("YST"); - case HST: return("HST"); - case BST: return("BST"); - case ADT: return("ADT"); - case EDT: return("EDT"); - case CDT: return("CDT"); - case MDT: return("MDT"); - case PDT: return("PDT"); - case YDT: return("YDT"); - case HDT: return("HDT"); - case BDT: return("BDT"); - case MID: return("MID"); - case VAN: return("VAN"); - case EDM: return("EDM"); - case WIN: return("WIN"); - case BOG: return("BOG"); - case CAR: return("CAR"); - case RIO: return("RIO"); - case FER: return("FER"); - case AZO: return("AZO"); - case LON: return("LON"); - case BER: return("BER"); - case ATH: return("ATH"); - case MOS: return("MOS"); - case DUB: return("DUB"); - case KAB: return("KAB"); - case KAR: return("KAR"); - case BOM: return("BOM"); - case KAT: return("KAT"); - case DHA: return("DHA"); - case BAN: return("BAN"); - case HON: return("HON"); - case TOK: return("TOK"); - case SYD: return("SYD"); - case NOU: return("NOU"); - case WEL: return("WEL"); - } - - if(!OTHER_ZONE(zone)) { - if(zone&(WESTERN_ZONE|US_ZONE)) /* West of UTC? */ - zone=-(zone&0xfff); - else - zone&=0xfff; - } - - if(zone>0) - plus="+"; - else - plus=""; - sprintf(str,"UTC%s%d:%02u", plus, zone/60, zone<0 ? (-zone)%60 : zone%60); - - if(outstr==NULL) - return(str); - strcpy(outstr,str); - return(outstr); -} - - - /* End of SMBLIB.C */ diff --git a/src/smblib/smblib.dsp b/src/smblib/smblib.dsp index c579f7a171..3202515726 100644 --- a/src/smblib/smblib.dsp +++ b/src/smblib/smblib.dsp @@ -98,14 +98,34 @@ SOURCE=.\md5.c # End Source File # Begin Source File +SOURCE=.\smbadd.c +# End Source File +# Begin Source File + +SOURCE=.\smballoc.c +# End Source File +# Begin Source File + SOURCE=.\smbdump.c # End Source File # Begin Source File +SOURCE=.\smbfile.c +# End Source File +# Begin Source File + +SOURCE=.\smbhash.c +# End Source File +# Begin Source File + SOURCE=.\smblib.c # End Source File # Begin Source File +SOURCE=.\smbstr.c +# End Source File +# Begin Source File + SOURCE=.\smbtxt.c # End Source File # End Target diff --git a/src/smblib/smblib.h b/src/smblib/smblib.h index 4f550da6bc..685f117240 100644 --- a/src/smblib/smblib.h +++ b/src/smblib/smblib.h @@ -106,8 +106,6 @@ SMBEXPORT int SMBCALL smb_ver(void); SMBEXPORT char* SMBCALL smb_lib_ver(void); SMBEXPORT int SMBCALL smb_open(smb_t* smb); SMBEXPORT void SMBCALL smb_close(smb_t* smb); -SMBEXPORT int SMBCALL smb_open_fp(smb_t* smb, FILE**, int share); -SMBEXPORT void SMBCALL smb_close_fp(FILE**); SMBEXPORT int SMBCALL smb_create(smb_t* smb); SMBEXPORT int SMBCALL smb_stack(smb_t* smb, int op); SMBEXPORT int SMBCALL smb_trunchdr(smb_t* smb); @@ -135,12 +133,7 @@ SMBEXPORT int SMBCALL smb_hfield_append_str(smbmsg_t* msg, ushort type, const c SMBEXPORT int SMBCALL smb_hfield_addlist(smbmsg_t* msg, hfield_t** hfield_list, void** hfield_dat); SMBEXPORT int SMBCALL smb_dfield(smbmsg_t* msg, ushort type, ulong length); SMBEXPORT void* SMBCALL smb_get_hfield(smbmsg_t* msg, ushort type, hfield_t* hfield); -SMBEXPORT char* SMBCALL smb_hfieldtype(ushort type); -SMBEXPORT ushort SMBCALL smb_hfieldtypelookup(const char*); -SMBEXPORT char* SMBCALL smb_dfieldtype(ushort type); SMBEXPORT int SMBCALL smb_addmsghdr(smb_t* smb, smbmsg_t* msg, int storage); -SMBEXPORT int SMBCALL smb_addmsg(smb_t* smb, smbmsg_t* msg, int storage, BOOL dupechk - ,ushort xlat, const uchar* body, const uchar* tail); SMBEXPORT int SMBCALL smb_putmsg(smb_t* smb, smbmsg_t* msg); SMBEXPORT int SMBCALL smb_putmsgidx(smb_t* smb, smbmsg_t* msg); SMBEXPORT int SMBCALL smb_putmsghdr(smb_t* smb, smbmsg_t* msg); @@ -148,6 +141,16 @@ SMBEXPORT void SMBCALL smb_freemsgmem(smbmsg_t* msg); SMBEXPORT void SMBCALL smb_freemsghdrmem(smbmsg_t* msg); SMBEXPORT ulong SMBCALL smb_hdrblocks(ulong length); SMBEXPORT ulong SMBCALL smb_datblocks(ulong length); +SMBEXPORT int SMBCALL smb_copymsgmem(smb_t* smb, smbmsg_t* destmsg, smbmsg_t* srcmsg); +SMBEXPORT int SMBCALL smb_tzutc(short timezone); +SMBEXPORT int SMBCALL smb_updatethread(smb_t* smb, smbmsg_t* remsg, ulong newmsgnum); +SMBEXPORT BOOL SMBCALL smb_valid_hdr_offset(smb_t* smb, ulong offset); + +/* smbadd.c */ +SMBEXPORT int SMBCALL smb_addmsg(smb_t* smb, smbmsg_t* msg, int storage, BOOL dupechk + ,ushort xlat, const uchar* body, const uchar* tail); + +/* smballoc.c */ SMBEXPORT long SMBCALL smb_allochdr(smb_t* smb, ulong length); SMBEXPORT long SMBCALL smb_fallochdr(smb_t* smb, ulong length); SMBEXPORT long SMBCALL smb_hallochdr(smb_t* smb); @@ -161,25 +164,18 @@ SMBEXPORT int SMBCALL smb_freemsg_dfields(smb_t* smb, smbmsg_t* msg, ushort ref SMBEXPORT int SMBCALL smb_freemsgdat(smb_t* smb, ulong offset, ulong length, ushort refs); SMBEXPORT int SMBCALL smb_freemsghdr(smb_t* smb, ulong offset, ulong length); SMBEXPORT void SMBCALL smb_freemsgtxt(char* buf); -SMBEXPORT int SMBCALL smb_copymsgmem(smb_t* smb, smbmsg_t* destmsg, smbmsg_t* srcmsg); -SMBEXPORT int SMBCALL smb_tzutc(short timezone); -SMBEXPORT int SMBCALL smb_updatethread(smb_t* smb, smbmsg_t* remsg, ulong newmsgnum); -SMBEXPORT ushort SMBCALL smb_subject_crc(const char *subj); - -SMBEXPORT char* SMBCALL smb_faddrtoa(fidoaddr_t* addr, char* outstr); -SMBEXPORT char* SMBCALL smb_netaddr(net_t* net); -SMBEXPORT char* SMBCALL smb_zonestr(short zone, char* outstr); -/* hash-related functions */ +/* smbhash.c */ SMBEXPORT int SMBCALL smb_findhash(smb_t* smb, hash_t** compare_list, hash_t* found, BOOL mark); SMBEXPORT int SMBCALL smb_hashmsg(smb_t* smb, smbmsg_t* msg, const uchar* text, BOOL update); SMBEXPORT hash_t* SMBCALL smb_hash(ulong msgnum, ulong time, unsigned source ,unsigned flags, const void* data, size_t length); SMBEXPORT hash_t* SMBCALL smb_hashstr(ulong msgnum, ulong time, unsigned source ,unsigned flags, const char* str); -SMBEXPORT char* SMBCALL smb_hashsource(uchar type); + SMBEXPORT hash_t** SMBCALL smb_msghashes(smbmsg_t* msg, const uchar* text, BOOL dupechk); SMBEXPORT int SMBCALL smb_addhashes(smb_t* smb, hash_t** hash_list, BOOL skip_marked); +SMBEXPORT ushort SMBCALL smb_subject_crc(const char *subj); /* Fast look-up functions (using hashes) */ SMBEXPORT int SMBCALL smb_getmsgidx_by_hash(smb_t* smb, smbmsg_t* msg, unsigned source @@ -203,14 +199,22 @@ SMBEXPORT int SMBCALL smb_getmsghdr_by_hash(smb_t* smb, smbmsg_t* msg, unsigne #define smb_getmsghdr_by_ftnid(smb, msg, id) \ smb_getmsghdr_by_hashstr(smb, msg, FIDOMSGID, SMB_HASH_MASK, id) -/* smbtxt.c */ -SMBEXPORT char* SMBCALL smb_getmsgtxt(smb_t* smb, smbmsg_t* msg, ulong mode); +/* smbstr.c */ +SMBEXPORT char* SMBCALL smb_hfieldtype(ushort type); +SMBEXPORT ushort SMBCALL smb_hfieldtypelookup(const char*); +SMBEXPORT char* SMBCALL smb_dfieldtype(ushort type); +SMBEXPORT char* SMBCALL smb_faddrtoa(fidoaddr_t* addr, char* outstr); +SMBEXPORT char* SMBCALL smb_netaddr(net_t* net); +SMBEXPORT char* SMBCALL smb_zonestr(short zone, char* outstr); +SMBEXPORT char* SMBCALL smb_hashsource(uchar type); /* smbdump.c */ SMBEXPORT void SMBCALL smb_dump_msghdr(FILE* fp, smbmsg_t* msg); -/* FILE pointer I/O functions */ +/* smbtxt.c */ +SMBEXPORT char* SMBCALL smb_getmsgtxt(smb_t* smb, smbmsg_t* msg, ulong mode); +/* smbfile.c */ SMBEXPORT int SMBCALL smb_feof(FILE* fp); SMBEXPORT int SMBCALL smb_ferror(FILE* fp); SMBEXPORT int SMBCALL smb_fflush(FILE* fp); @@ -224,6 +228,8 @@ SMBEXPORT long SMBCALL smb_fgetlength(FILE* fp); SMBEXPORT int SMBCALL smb_fsetlength(FILE* fp, long length); SMBEXPORT void SMBCALL smb_rewind(FILE* fp); SMBEXPORT void SMBCALL smb_clearerr(FILE* fp); +SMBEXPORT int SMBCALL smb_open_fp(smb_t* smb, FILE**, int share); +SMBEXPORT void SMBCALL smb_close_fp(FILE**); #ifdef __cplusplus } diff --git a/src/smblib/smblib_mt.dsp b/src/smblib/smblib_mt.dsp index 40a32b15b0..6a664b9619 100644 --- a/src/smblib/smblib_mt.dsp +++ b/src/smblib/smblib_mt.dsp @@ -98,14 +98,34 @@ SOURCE=.\md5.c # End Source File # Begin Source File +SOURCE=.\smbadd.c +# End Source File +# Begin Source File + +SOURCE=.\smballoc.c +# End Source File +# Begin Source File + SOURCE=.\smbdump.c # End Source File # Begin Source File +SOURCE=.\smbfile.c +# End Source File +# Begin Source File + +SOURCE=.\smbhash.c +# End Source File +# Begin Source File + SOURCE=.\smblib.c # End Source File # Begin Source File +SOURCE=.\smbstr.c +# End Source File +# Begin Source File + SOURCE=.\smbtxt.c # End Source File # End Target diff --git a/src/smblib/smbstr.c b/src/smblib/smbstr.c new file mode 100644 index 0000000000..a74b146cc7 --- /dev/null +++ b/src/smblib/smbstr.c @@ -0,0 +1,245 @@ +/* smbstr.c */ + +/* Synchronet message base (SMB) library routines returning strings */ + +/* $Id$ */ + +/**************************************************************************** + * @format.tab-size 4 (Plain Text/Source Code File Header) * + * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * + * * + * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * See the GNU Lesser General Public License for more details: lgpl.txt or * + * http://www.fsf.org/copyleft/lesser.html * + * * + * Anonymous FTP access to the most recent released source is available at * + * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * + * * + * Anonymous CVS access to the development source and modification history * + * is available at cvs.synchro.net:/cvsroot/sbbs, example: * + * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login * + * (just hit return, no password is necessary) * + * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src * + * * + * For Synchronet coding style and modification guidelines, see * + * http://www.synchro.net/source.html * + * * + * You are encouraged to submit any modifications (preferably in Unix diff * + * format) via e-mail to mods@synchro.net * + * * + * Note: If this box doesn't appear square, then you need to fix your tabs. * + ****************************************************************************/ + +#include "smblib.h" + +char* SMBCALL smb_hfieldtype(ushort type) +{ + static char str[8]; + + switch(type) { + case SENDER: return("Sender"); + case SENDERAGENT: return("SenderAgent"); + case SENDERNETTYPE: return("SenderNetType"); + case SENDERNETADDR: return("SenderNetAddr"); + case SENDEREXT: return("SenderExt"); + case SENDERORG: return("SenderOrg"); + case SENDERIPADDR: return("SenderIpAddr"); + case SENDERHOSTNAME: return("SenderHostName"); + case SENDERPROTOCOL: return("SenderProtocol"); + case SENDERPORT: return("SenderPort"); + + case REPLYTO: return("ReplyTo"); + case REPLYTOAGENT: return("ReplyToAgent"); + case REPLYTONETTYPE: return("ReplyToNetType"); + case REPLYTONETADDR: return("ReplyToNetAddr"); + case REPLYTOEXT: return("ReplyToExt"); + + case RECIPIENT: return("Recipient"); + case RECIPIENTAGENT: return("RecipientAgent"); + case RECIPIENTNETTYPE: return("RecipientNetType"); + case RECIPIENTNETADDR: return("RecipientNetAddr"); + case RECIPIENTEXT: return("RecipientExt"); + + case SUBJECT: return("Subject"); + case SMB_SUMMARY: return("Summary"); + case SMB_COMMENT: return("Comment"); + case SMB_CARBONCOPY: return("CarbonCopy"); + case SMB_GROUP: return("Group"); + case SMB_EXPIRATION: return("Expiration"); + case SMB_PRIORITY: return("Priority"); + case SMB_COST: return("Cost"); + + case FIDOCTRL: return("FidoCtrl"); + case FIDOAREA: return("FidoArea"); + case FIDOSEENBY: return("FidoSeenBy"); + case FIDOPATH: return("FidoPath"); + case FIDOMSGID: return("FidoMsgID"); + case FIDOREPLYID: return("FidoReplyID"); + case FIDOPID: return("FidoPID"); + case FIDOFLAGS: return("FidoFlags"); + case FIDOTID: return("FidoTID"); + + case RFC822HEADER: return("RFC822Header"); + case RFC822MSGID: return("RFC822MsgID"); + case RFC822REPLYID: return("RFC822ReplyID"); + case RFC822TO: return("RFC822To"); + case RFC822FROM: return("RFC822From"); + case RFC822REPLYTO: return("RFC822ReplyTo"); + + case USENETPATH: return("UsenetPath"); + case USENETNEWSGROUPS: return("UsenetNewsgroups"); + + case SMTPCOMMAND: return("SMTPCommand"); + case SMTPREVERSEPATH: return("SMTPReversePath"); + + case SMTPSYSMSG: return("SMTPSysMsg"); + + case UNKNOWN: return("UNKNOWN"); + case UNKNOWNASCII: return("UNKNOWNASCII"); + case UNUSED: return("UNUSED"); + } + sprintf(str,"%02Xh",type); + return(str); +} + +ushort SMBCALL smb_hfieldtypelookup(const char* str) +{ + ushort type; + + if(isdigit(*str)) + return((ushort)strtol(str,NULL,0)); + + for(type=0;type<=UNUSED;type++) + if(stricmp(str,smb_hfieldtype(type))==0) + return(type); + + return(UNKNOWN); +} + +char* SMBCALL smb_dfieldtype(ushort type) +{ + static char str[8]; + + switch(type) { + case TEXT_BODY: return("TEXT_BODY"); + case TEXT_TAIL: return("TEXT_TAIL"); + case UNUSED: return("UNUSED"); + } + sprintf(str,"%02Xh",type); + return(str); +} + +char* SMBCALL smb_hashsource(uchar type) +{ + if(type==TEXT_BODY || type==TEXT_TAIL) + return(smb_dfieldtype(type)); + return(smb_hfieldtype(type)); +} + +/****************************************************************************/ +/* Converts when_t.zone into ASCII format */ +/****************************************************************************/ +char* SMBCALL smb_zonestr(short zone, char* outstr) +{ + char* plus; + static char str[32]; + + switch((ushort)zone) { + case 0: return("UTC"); + case AST: return("AST"); + case EST: return("EST"); + case CST: return("CST"); + case MST: return("MST"); + case PST: return("PST"); + case YST: return("YST"); + case HST: return("HST"); + case BST: return("BST"); + case ADT: return("ADT"); + case EDT: return("EDT"); + case CDT: return("CDT"); + case MDT: return("MDT"); + case PDT: return("PDT"); + case YDT: return("YDT"); + case HDT: return("HDT"); + case BDT: return("BDT"); + case MID: return("MID"); + case VAN: return("VAN"); + case EDM: return("EDM"); + case WIN: return("WIN"); + case BOG: return("BOG"); + case CAR: return("CAR"); + case RIO: return("RIO"); + case FER: return("FER"); + case AZO: return("AZO"); + case LON: return("LON"); + case BER: return("BER"); + case ATH: return("ATH"); + case MOS: return("MOS"); + case DUB: return("DUB"); + case KAB: return("KAB"); + case KAR: return("KAR"); + case BOM: return("BOM"); + case KAT: return("KAT"); + case DHA: return("DHA"); + case BAN: return("BAN"); + case HON: return("HON"); + case TOK: return("TOK"); + case SYD: return("SYD"); + case NOU: return("NOU"); + case WEL: return("WEL"); + } + + if(!OTHER_ZONE(zone)) { + if(zone&(WESTERN_ZONE|US_ZONE)) /* West of UTC? */ + zone=-(zone&0xfff); + else + zone&=0xfff; + } + + if(zone>0) + plus="+"; + else + plus=""; + sprintf(str,"UTC%s%d:%02u", plus, zone/60, zone<0 ? (-zone)%60 : zone%60); + + if(outstr==NULL) + return(str); + strcpy(outstr,str); + return(outstr); +} + +/****************************************************************************/ +/* Returns an ASCII string for FidoNet address 'addr' */ +/****************************************************************************/ +char* SMBCALL smb_faddrtoa(fidoaddr_t* addr, char* outstr) +{ + static char str[64]; + char point[25]; + + if(addr==NULL) + return("0:0/0"); + sprintf(str,"%hu:%hu/%hu",addr->zone,addr->net,addr->node); + if(addr->point) { + sprintf(point,".%hu",addr->point); + strcat(str,point); + } + if(outstr==NULL) + return(str); + strcpy(outstr,str); + return(outstr); +} + +/****************************************************************************/ +/* Returns ASCIIZ representation of network address (net_t) */ +/****************************************************************************/ +char* SMBCALL smb_netaddr(net_t* net) +{ + if(net->type==NET_FIDO) + return(smb_faddrtoa((fidoaddr_t*)net->addr,NULL)); + return(net->addr); +} -- GitLab