chksmb.c 20.51 KiB
/* chksmb.c */
/* Synchronet message base (SMB) validity checker */
/* $Id$ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.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 <dos.h>
#include <conio.h> /* getch */
#include "smblib.h"
#ifdef _MSC_VER
/****************************************************************************/
/* Checks the disk drive for the existence of a file. Returns 1 if it */
/* exists, 0 if it doesn't. */
/****************************************************************************/
int fexist(char *filespec)
{
long handle;
struct _finddata_t f;
if((handle=_findfirst(filespec,&f))==-1)
return(0);
_findclose(handle);
if(f.attrib&_A_SUBDIR)
return(0);
return(1);
}
#else
/****************************************************************************/
/* Checks the disk drive for the existence of a file. Returns 1 if it */
/* exists, 0 if it doesn't. */
/****************************************************************************/
char fexist(char *filespec)
{
struct find_t f;
if(!_dos_findfirst(filespec,0,&f))
return(1);
return(0);
}
#endif
/****************************************************************************/
/* Returns in 'string' a character representation of the number in l with */
/* commas. */
/****************************************************************************/
char *ultoac(ulong l, char *string)
{
char str[256];
signed char i,j,k;
ultoa(l,str,10);
i=strlen(str)-1;
j=i/3+1+i;
string[j--]=0;
for(k=1;i>-1;k++) {
string[j--]=str[i--];
if(j>0 && !(k%3))
string[j--]=','; }
return(string);
}
/****************************************************************************/
/* Returns an ASCII string for FidoNet address 'addr' */
/****************************************************************************/
char *faddrtoa(fidoaddr_t addr)
{
static char str[25];
char point[25];
sprintf(str,"%u:%u/%u",addr.zone,addr.net,addr.node);
if(addr.point) {
sprintf(point,".%u",addr.point);
strcat(str,point); }
return(str);
}
char *usage="\nusage: chksmb [/opts] <filespec.SHD>\n"
"\n"
" opts:\n"
" s - stop after errored message base\n"
" p - pause after errored messsage base\n"
" q - quiet mode (no beeps while checking)\n"
" a - don't check allocation files\n"
" t - don't check translation strings\n"
" e - display extended info on corrupted msgs\n";
int main(int argc, char **argv)
{
char str[128],*p,*s,*beep="\7";
int i,j,x,y,lzh,errors,errlast,stop_on_error=0,pause_on_error=0
,chkxlat=1,chkalloc=1,lzhmsg,extinfo=0,msgerr;
ushort xlat;
ulong l,m,n,length,size,total=0,orphan=0,deleted=0,headers=0
,*offset,*number,xlaterr
,delidx
,delhdrblocks,deldatblocks,hdrerr=0,lockerr=0,hdrnumerr=0
,acthdrblocks,actdatblocks
,dfieldlength=0,dfieldoffset=0
,dupenum=0,dupenumhdr=0,dupeoff=0,attr=0,actalloc=0
,datactalloc=0,misnumbered=0,timeerr=0,idxofferr=0,idxerr
,zeronum,idxzeronum,idxnumerr,packable=0L,totallzhsaved=0L
,totalmsgs=0,totallzhmsgs=0,totaldelmsgs=0,totalmsgbytes=0L
,lzhblocks,lzhsaved;
smb_t smb;
idxrec_t idx;
smbmsg_t msg;
fprintf(stderr,"\nCHKSMB v2.10 - Check Synchronet Message Base - "
"Copyright 2000 Rob Swindell\n");
if(argc<2) {
printf("%s",usage);
exit(1); }
errlast=errors=0;
for(x=1;x<argc;x++) {
if(stop_on_error && errors)
break;
if(pause_on_error && errlast!=errors) {
fprintf(stderr,"\7\nHit any key to continue...");
if(!getch())
getch();
printf("\n"); }
errlast=errors;
if(argv[x][0]=='/') {
for(y=1;argv[x][y];y++)
switch(toupper(argv[x][y])) {
case 'Q':
beep="";
break;
case 'P':
pause_on_error=1;
break;
case 'S':
stop_on_error=1;
break;
case 'T':
chkxlat=0;
break;
case 'A':
chkalloc=0;
break;
case 'E':
extinfo=1;
break;
default:
printf("%s",usage);
exit(1); }
continue; }
strcpy(smb.file,argv[x]);
p=strrchr(smb.file,'.');
s=strrchr(smb.file,'\\');
if(p>s) *p=0;
strupr(smb.file);
sprintf(str,"%s.SHD",smb.file);
if(!fexist(str)) {
printf("\n%s doesn't exist.\n",smb.file);
continue; }
fprintf(stderr,"\nChecking %s Headers\n\n",smb.file);
smb.retry_time=30;
if((i=smb_open(&smb))!=0) {
printf("smb_open returned %d\n",i);
errors++;
continue; }
length=filelength(fileno(smb.shd_fp));
if(length<sizeof(smbhdr_t)) {
printf("Empty\n");
smb_close(&smb);
continue; }
if((i=smb_locksmbhdr(&smb))!=0) {
smb_close(&smb);
printf("smb_locksmbhdr returned %d\n",i);
errors++;
continue; }
if((length/SHD_BLOCK_LEN)*sizeof(ulong)) {
if((number=(ulong *)MALLOC(((length/SHD_BLOCK_LEN)+2)*sizeof(ulong)))
==NULL) {
printf("Error allocating %lu bytes of memory\n"
,(length/SHD_BLOCK_LEN)*sizeof(ulong));
return(++errors); } }
else
number=NULL;
if(chkalloc && !(smb.status.attr&SMB_HYPERALLOC)) {
if((i=smb_open_ha(&smb))!=0) {
printf("smb_open_ha returned %d\n",i);
return(++errors); }
if((i=smb_open_da(&smb))!=0) {
printf("smb_open_da returned %d\n",i);
return(++errors); } }
headers=deleted=orphan=dupenumhdr=attr=zeronum=timeerr=lockerr=hdrerr=0;
actalloc=datactalloc=deldatblocks=delhdrblocks=xlaterr=0;
lzhblocks=lzhsaved=acthdrblocks=actdatblocks=0;
for(l=smb.status.header_offset;l<length;l+=size) {
fprintf(stderr,"\r%2u%% ",(long)(100.0/((float)length/l)));
msg.idx.offset=l;
msgerr=0;
if((i=smb_lockmsghdr(&smb,&msg))!=0) {
printf("\n(%06lX) smb_lockmsghdr returned %d\n",l,i);
lockerr++;
headers++;
size=SHD_BLOCK_LEN;
continue; }
if((i=smb_getmsghdr(&smb,&msg))!=0) {
smb_unlockmsghdr(&smb,&msg);
if(chkalloc && !(smb.status.attr&SMB_HYPERALLOC)) {
fseek(smb.sha_fp
,(l-smb.status.header_offset)/SHD_BLOCK_LEN,SEEK_SET);
j=fgetc(smb.sha_fp);
if(j) { /* Allocated block or at EOF */
printf("%s\n(%06lX) smb_getmsghdr returned %d\n",beep,l,i);
hdrerr++; }
else
delhdrblocks++; }
else {
/* printf("%s\n(%06lX) smb_getmsghdr returned %d\n",beep,l,i); */
delhdrblocks++; }
size=SHD_BLOCK_LEN;
continue; }
smb_unlockmsghdr(&smb,&msg);
fprintf(stderr,"#%-5lu (%06lX) %-25.25s ",msg.hdr.number,l,msg.from);
lzhmsg=0;
if(msg.hdr.attr&MSG_DELETE) {
deleted++;
if(number)
number[headers]=0;
if(smb.status.attr&SMB_HYPERALLOC)
deldatblocks+=smb_datblocks(smb_getmsgdatlen(&msg)); }
else {
actdatblocks+=smb_datblocks(smb_getmsgdatlen(&msg));
if(msg.hdr.number>smb.status.last_msg) {
fprintf(stderr,"%sOut-Of-Range message number\n",beep);
msgerr=1;
if(extinfo)
printf("MSGERR: Header number (%lu) greater than last (%lu)\n"
,msg.hdr.number,smb.status.last_msg);
hdrnumerr++; }
if(smb_getmsgidx(&smb,&msg)) {
fprintf(stderr,"%sNot found in index\n",beep);
msgerr=1;
if(extinfo)
printf("MSGERR: Header number (%lu) not found in index\n"
,msg.hdr.number);
orphan++; }
else if(msg.hdr.attr!=msg.idx.attr) {
fprintf(stderr,"%sAttributes mismatch index\n",beep);
msgerr=1;
if(extinfo)
printf("MSGERR: Header attributes (%04X) do not match index "
"attributes (%04X)\n"
,msg.hdr.attr,msg.idx.attr);
attr++; }
else if(msg.hdr.when_imported.time!=msg.idx.time) {
fprintf(stderr,"%sImport date/time mismatch index\n",beep);
msgerr=1;
if(extinfo)
printf("MSGERR: Header import date/time does not match "
"index import date/time\n");
timeerr++; }
if(msg.hdr.number==0) {
fprintf(stderr,"%sZero message number\n",beep);
msgerr=1;
if(extinfo)
printf("MSGERR: Header number is zero (invalid)\n");
zeronum++; }
if(number) {
for(m=0;m<headers;m++)
if(number[m] && msg.hdr.number==number[m]) {
fprintf(stderr,"%sDuplicate message number\n",beep);
msgerr=1;
if(extinfo)
printf("MSGERR: Header number (%lu) duplicated\n"
,msg.hdr.number);
dupenumhdr++;
break; }
number[headers]=msg.hdr.number; }
if(chkxlat) { /* Check translation strings */
for(i=0;i<msg.hdr.total_dfields;i++) {
fseek(smb.sdt_fp,msg.hdr.offset+msg.dfield[i].offset,SEEK_SET);
if(!fread(&xlat,2,1,smb.sdt_fp))
xlat=0xffff;
lzh=0;
if(xlat==XLAT_LZH) {
lzh=1;
if(!fread(&xlat,2,1,smb.sdt_fp))
xlat=0xffff; }
if(xlat!=XLAT_NONE) {
fprintf(stderr,"%sUnsupported Xlat %04X dfield[%u]\n"
,beep,xlat,i);
msgerr=1;
if(extinfo)
printf("MSGERR: Unsupported translation type (%04X) "
"in dfield[%u]\n"
,xlat,i);
xlaterr++; }
else {
if(lzh) {
lzhmsg=1;
if(fread(&m,4,1,smb.sdt_fp)) { /* Get uncompressed len */
lzhsaved+=(smb_datblocks(m+2)
-smb_datblocks(msg.dfield[i].length))
*SDT_BLOCK_LEN;
lzhblocks+=smb_datblocks(msg.dfield[i].length);
} } } } } }
size=smb_getmsghdrlen(&msg);
while(size%SHD_BLOCK_LEN) size++;
if(chkalloc && !(smb.status.attr&SMB_HYPERALLOC)) {
fseek(smb.sha_fp,(l-smb.status.header_offset)/SHD_BLOCK_LEN,SEEK_SET);
for(m=0;m<size;m+=SHD_BLOCK_LEN) {
/***
if(msg.hdr.attr&MSG_DELETE && (i=fgetc(smb.sha_fp))!=0) {
fprintf(stderr,"%sDeleted Header Block %lu marked %02X\n"
,beep,m/SHD_BLOCK_LEN,i);
msgerr=1;
delalloc++; }
***/
if(!(msg.hdr.attr&MSG_DELETE) && (i=fgetc(smb.sha_fp))!=1) {
fprintf(stderr,"%sActive Header Block %lu marked %02X\n"
,beep,m/SHD_BLOCK_LEN,i);
msgerr=1;
if(extinfo)
printf("MSGERR: Active header block %lu marked %02X "
"instead of 01\n"
,m/SHD_BLOCK_LEN,i);
actalloc++; } }
if(!(msg.hdr.attr&MSG_DELETE)) {
acthdrblocks+=(size/SHD_BLOCK_LEN);
for(n=0;n<msg.hdr.total_dfields;n++) {
if(msg.dfield[n].offset&0x80000000UL) {
msgerr=1;
if(extinfo)
printf("MSGERR: Invalid Data Field [%u] Offset: %lu\n"
,n,msg.dfield[n].offset);
dfieldoffset++; }
if(msg.dfield[n].length&0x80000000UL) {
msgerr=1;
if(extinfo)
printf("MSGERR: Invalid Data Field [%u] Length: %lu\n"
,n,msg.dfield[n].length);
dfieldlength++; }
fseek(smb.sda_fp
,((msg.hdr.offset+msg.dfield[n].offset)/SDT_BLOCK_LEN)*2
,SEEK_SET);
for(m=0;m<msg.dfield[n].length;m+=SDT_BLOCK_LEN) {
if(!fread(&i,2,1,smb.sda_fp) || !i) {
fprintf(stderr
,"%sActive Data Block %lu.%lu marked free\n"
,beep,n,m/SHD_BLOCK_LEN);
msgerr=1;
if(extinfo)
printf("MSGERR: Active Data Block %lu.%lu "
"marked free\n"
,n,m/SHD_BLOCK_LEN);
datactalloc++; } } } }
else
delhdrblocks+=(size/SHD_BLOCK_LEN); }
else { /* Hyper Alloc */
if(msg.hdr.attr&MSG_DELETE)
delhdrblocks+=(size/SHD_BLOCK_LEN);
else
acthdrblocks+=(size/SHD_BLOCK_LEN); }
totallzhmsgs+=lzhmsg;
headers++;
if(msgerr && extinfo) {
printf("\n");
printf("%-20s: %s\n","Message Base",smb.file);
printf("%-20s: %lu (%lu)\n","Message Number"
,msg.hdr.number,msg.offset+1);
printf("%-20s: %s\n","Subject",msg.subj);
printf("%-20s: %s","To",msg.to);
if(msg.to_net.type)
printf(" (%s)",msg.to_net.type==NET_FIDO
? faddrtoa(*(fidoaddr_t *)msg.to_net.addr) : msg.to_net.addr);
printf("\n%-20s: %s","From",msg.from);
if(msg.from_net.type)
printf(" (%s)",msg.from_net.type==NET_FIDO
? faddrtoa(*(fidoaddr_t *)msg.from_net.addr)
: msg.from_net.addr);
printf("\n");
printf("%-20s: %.24s\n","When Written"
,ctime((time_t *)&msg.hdr.when_written.time));
printf("%-20s: %.24s\n","When Imported"
,ctime((time_t *)&msg.hdr.when_imported.time));
printf("%-20s: %04hXh\n","Type"
,msg.hdr.type);
printf("%-20s: %04hXh\n","Version"
,msg.hdr.version);
printf("%-20s: %u\n","Length"
,msg.hdr.length);
printf("%-20s: %04hXh\n","Attributes"
,msg.hdr.attr);
printf("%-20s: %08lXh\n","Auxilary Attributes"
,msg.hdr.auxattr);
printf("%-20s: %08lXh\n","Network Attributes"
,msg.hdr.netattr);
printf("%-20s: %06lXh\n","Header Offset"
,msg.idx.offset);
printf("%-20s: %06lXh\n","Data Offset"
,msg.hdr.offset);
printf("%-20s: %u\n","Total Data Fields"
,msg.hdr.total_dfields);
printf("\n"); }
smb_freemsgmem(&msg); }
if(number)
FREE(number);
fprintf(stderr,"\r%79s\r100%%\n","");
if(chkalloc && !(smb.status.attr&SMB_HYPERALLOC)) {
fprintf(stderr,"\nChecking %s Data Blocks\n\n",smb.file);
length=filelength(fileno(smb.sda_fp));
fseek(smb.sda_fp,0L,SEEK_SET);
for(l=0;l<length;l+=2) {
fprintf(stderr,"\r%2u%% ",l ? (long)(100.0/((float)length/l)) : 0);
i=0;
if(!fread(&i,2,1,smb.sda_fp))
break;
if(!i)
deldatblocks++; }
fclose(smb.sha_fp);
fclose(smb.sda_fp);
fprintf(stderr,"\r%79s\r100%%\n",""); }
total=filelength(fileno(smb.sid_fp))/sizeof(idxrec_t);
dupenum=dupeoff=misnumbered=idxzeronum=idxnumerr=idxofferr=idxerr=delidx=0;
if(total) {
fprintf(stderr,"\nChecking %s Index\n\n",smb.file);
if((offset=(ulong *)MALLOC(total*sizeof(ulong)))==NULL) {
printf("Error allocating %lu bytes of memory\n",total*sizeof(ulong));
return(++errors); }
if((number=(ulong *)MALLOC(total*sizeof(ulong)))==NULL) {
printf("Error allocating %lu bytes of memory\n",total*sizeof(ulong));
return(++errors); }
fseek(smb.sid_fp,0L,SEEK_SET);
for(l=0;l<total;l++) {
fprintf(stderr,"\r%2lu%% %5lu ",l ? (long)(100.0/((float)total/l)) : 0,l);
if(!fread(&idx,sizeof(idxrec_t),1,smb.sid_fp))
break;
fprintf(stderr,"#%-5lu (%06lX) 1st Pass ",idx.number,idx.offset);
if(idx.attr&MSG_DELETE) {
// fprintf(stderr,"%sMarked for deletion\n",beep);
delidx++; }
for(m=0;m<l;m++)
if(number[m]==idx.number) {
fprintf(stderr,"%sDuplicate message number\n",beep);
dupenum++;
break; }
for(m=0;m<l;m++)
if(offset[m]==idx.offset) {
fprintf(stderr,"%sDuplicate offset\n",beep,idx.offset);
dupeoff++;
break; }
if(idx.offset<smb.status.header_offset) {
fprintf(stderr,"%sInvalid offset\n",beep);
idxofferr++;
break; }
if(idx.number==0) {
fprintf(stderr,"%sZero message number\n",beep);
idxzeronum++;
break; }
if(idx.number>smb.status.last_msg) {
fprintf(stderr,"%sOut-Of-Range message number\n",beep);
idxnumerr++;
break; }
number[l]=idx.number;
offset[l]=idx.offset; }
if(l<total) {
fprintf(stderr,"%sError reading index record\n",beep);
idxerr=1; }
else {
fprintf(stderr,"\r%79s\r","");
for(m=0;m<total;m++) {
fprintf(stderr,"\r%2lu%% %5lu ",m ? (long)(100.0/((float)total/m)) : 0,m);
fprintf(stderr,"#%-5lu (%06lX) 2nd Pass ",number[m],offset[m]);
for(n=0;n<m;n++)
if(number[m] && number[n] && number[m]<number[n]) {
fprintf(stderr,"%sMisordered message number\n",beep);
misnumbered++;
number[n]=0;
break; } }
fprintf(stderr,"\r%79s\r100%%\n",""); }
FREE(number);
FREE(offset);
} /* if(total) */
totalmsgs+=smb.status.total_msgs;
totalmsgbytes+=(acthdrblocks*SHD_BLOCK_LEN)+(actdatblocks*SDT_BLOCK_LEN);
totaldelmsgs+=deleted;
totallzhsaved+=lzhsaved;
printf("\n");
printf("%-35.35s (=): %lu\n"
,"Status Total"
,smb.status.total_msgs);
printf("%-35.35s (=): %lu\n"
,"Total Indexes"
,total);
printf("%-35.35s (=): %lu\n"
,"Active Indexes"
,total-delidx);
printf("%-35.35s (=): %lu\n"
,"Active Headers"
,headers-deleted);
printf("%-35.35s ( ): %-8lu %13s bytes used\n"
,"Active Header Blocks"
,acthdrblocks,ultoac(acthdrblocks*SHD_BLOCK_LEN,str));
printf("%-35.35s ( ): %-8lu %13s bytes used\n"
,"Active Data Blocks"
,actdatblocks,ultoac(actdatblocks*SDT_BLOCK_LEN,str));
if(lzhblocks)
printf("%-35.35s ( ): %-8lu %13s bytes saved\n"
,"Active LZH Compressed Data Blocks"
,lzhblocks,ultoac(lzhsaved,str));
printf("%-35.35s ( ): %lu\n"
,"Header Records"
,headers);
printf("%-35.35s ( ): %lu\n"
,"Deleted Indexes"
,delidx);
printf("%-35.35s ( ): %lu\n"
,"Deleted Headers"
,deleted);
printf("%-35.35s ( ): %-8lu %13s bytes used\n"
,"Deleted Header Blocks"
,delhdrblocks,ultoac(delhdrblocks*SHD_BLOCK_LEN,str));
packable+=(delhdrblocks*SHD_BLOCK_LEN);
printf("%-35.35s ( ): %-8lu %13s bytes used\n"
,"Deleted Data Blocks"
,deldatblocks,ultoac(deldatblocks*SDT_BLOCK_LEN,str));
packable+=(deldatblocks*SDT_BLOCK_LEN);
if(orphan)
printf("%-35.35s (!): %lu\n"
,"Orphaned Headers"
,orphan);
if(idxzeronum)
printf("%-35.35s (!): %lu\n"
,"Zeroed Index Numbers"
,idxzeronum);
if(zeronum)
printf("%-35.35s (!): %lu\n"
,"Zeroed Header Numbers"
,zeronum);
if(idxofferr)
printf("%-35.35s (!): %lu\n"
,"Invalid Index Offsets"
,idxofferr);
if(dupenum)
printf("%-35.35s (!): %lu\n"
,"Duplicate Index Numbers"
,dupenum);
if(dupeoff)
printf("%-35.35s (!): %lu\n"
,"Duplicate Index Offsets"
,dupeoff);
if(dupenumhdr)
printf("%-35.35s (!): %lu\n"
,"Duplicate Header Numbers"
,dupenumhdr);
if(misnumbered)
printf("%-35.35s (!): %lu\n"
,"Misordered Index Numbers"
,misnumbered);
if(lockerr)
printf("%-35.35s (!): %lu\n"
,"Unlockable Header Records"
,lockerr);
if(hdrerr)
printf("%-35.35s (!): %lu\n"
,"Unreadable Header Records"
,hdrerr);
if(idxnumerr)
printf("%-35.35s (!): %lu\n"
,"Out-Of-Range Index Numbers"
,idxnumerr);
if(hdrnumerr)
printf("%-35.35s (!): %lu\n"
,"Out-Of-Range Header Numbers"
,hdrnumerr);
if(attr)
printf("%-35.35s (!): %lu\n"
,"Mismatched Header Attributes"
,attr);
if(timeerr)
printf("%-35.35s (!): %lu\n"
,"Mismatched Header Import Time"
,timeerr);
if(xlaterr)
printf("%-35.35s (!): %lu\n"
,"Unsupported Translation Types"
,xlaterr);
if(datactalloc)
printf("%-35.35s (!): %lu\n"
,"Misallocated Active Data Blocks"
,datactalloc);
if(actalloc)
printf("%-35.35s (!): %lu\n"
,"Misallocated Active Header Blocks"
,actalloc);
/***
if(delalloc)
printf("%-35.35s (!): %lu\n"
,"Misallocated Deleted Header Blocks"
,delalloc);
***/
if(dfieldoffset)
printf("%-35.35s (!): %lu\n"
,"Invalid Data Field Offsets"
,dfieldoffset);
if(dfieldlength)
printf("%-35.35s (!): %lu\n"
,"Invalid Data Field Lengths"
,dfieldlength);
printf("\n%s Message Base ",smb.file);
if(/* (headers-deleted)!=smb.status.total_msgs || */
total!=smb.status.total_msgs
|| (headers-deleted)!=total-delidx
|| idxzeronum || zeronum
|| orphan || dupenumhdr || dupenum || dupeoff || attr
|| lockerr || hdrerr || hdrnumerr || idxnumerr || idxofferr
|| actalloc || datactalloc || misnumbered || timeerr
|| dfieldoffset || dfieldlength || xlaterr || idxerr) {
printf("%shas Errors!\n",beep);
errors++; }
else
printf("is OK\n");
smb_unlocksmbhdr(&smb);
smb_close(&smb);
}
if((totalmsgs && (totalmsgs!=smb.status.total_msgs || totallzhmsgs))
|| packable)
printf("\n");
if(totalmsgs && totalmsgs!=smb.status.total_msgs)
printf("%-39.39s: %-8lu %13s bytes used\n"
,"Total Active Messages"
,totalmsgs,ultoac(totalmsgbytes,str));
if(totallzhmsgs && totalmsgs!=smb.status.total_msgs)
printf("%-39.39s: %-8lu %13s bytes saved\n"
,"Total LZH Compressed Messages"
,totallzhmsgs,ultoac(totallzhsaved,str));
if(packable)
printf("%-39.39s: %-8lu %13s bytes used\n"
,"Total Deleted Messages"
,totaldelmsgs,ultoac(packable,str));
if(pause_on_error && errlast!=errors) {
fprintf(stderr,"\7\nHit any key to continue...");
if(!getch())
getch();
fprintf(stderr,"\n"); }
return(errors);
}