home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1998 September / PCO_0998.ISO / filesbbs / dos / sbbs_src.exe / SBBS / SMB / SMBUTIL / SMBUTIL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-13  |  36.8 KB  |  1,429 lines

  1. /* SMBUTIL.C */
  2.  
  3. /* Developed 1990-1997 by Rob Swindell; PO Box 501, Yorba Linda, CA 92885 */
  4.  
  5. /* Synchronet Message Base Utility */
  6.  
  7. #define SMBUTIL_VER "2.01"
  8.  
  9. #include "smblib.h"
  10. #include "smbutil.h"
  11. #include "crc32.h"
  12. #include "crc16.c"
  13.  
  14. #ifdef __WATCOMC__
  15.     #include <dos.h>
  16. #endif
  17.  
  18. /********************/
  19. /* Global variables */
  20. /********************/
  21.  
  22. smb_t smb;
  23. ulong mode=0L;
  24. ushort tzone=PST;
  25. char filein[128];
  26. char attach[128];
  27.  
  28. /************************/
  29. /* Program usage/syntax */
  30. /************************/
  31.  
  32. char *usage=
  33. "usage: smbutil [/opts] cmd <filespec.SHD>\n"
  34. "\n"
  35. "cmd:\n"
  36. "       l[n] = list msgs starting at number n\n"
  37. "       r[n] = read msgs starting at number n\n"
  38. "       v[n] = view msg headers starting at number n\n"
  39. "       i<f> = import msg from text file f\n"
  40. "       e<f> = import e-mail from text file f\n"
  41. "       n<f> = import netmail from text file f\n"
  42. "       s    = display msg base status\n"
  43. "       c    = change msg base status\n"
  44. "       m    = maintain msg base - delete old msgs and msgs over max\n"
  45. "       p[k] = pack msg base (k specifies minimum packable Kbytes)\n"
  46. "opts:\n"
  47. "       a    = always pack msg base (disable compression analysis)\n"
  48. "       z[n] = set time zone (n=min +/- from UT or 'EST','EDT','CST',etc)\n"
  49. ;
  50.  
  51. char *wday[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
  52. char *mon[]={"Jan","Feb","Mar","Apr","May","Jun"
  53.             ,"Jul","Aug","Sep","Oct","Nov","Dec"};
  54.  
  55.  
  56. /****************************************************************************/
  57. /* Checks the disk drive for the existence of a file. Returns 1 if it       */
  58. /* exists, 0 if it doesn't.                                                 */
  59. /****************************************************************************/
  60. char fexist(char *filespec)
  61. {
  62.     struct ffblk f;
  63.  
  64. if(findfirst(filespec,&f,0)==0)
  65.     return(1);
  66. return(0);
  67. }
  68.  
  69. /****************************************************************************/
  70. /* Returns the length of the file in 'filespec'                             */
  71. /****************************************************************************/
  72. long flength(char *filespec)
  73. {
  74.     struct ffblk f;
  75.  
  76. if(findfirst(filespec,&f,0)==0)
  77. #ifdef __WATCOMC__
  78.     return(f.size);
  79. #else
  80.     return(f.ff_fsize);
  81. #endif
  82. return(-1L);
  83. }
  84.  
  85. void remove_re(char *str)
  86. {
  87. while(!strnicmp(str,"RE:",3)) {
  88.     strcpy(str,str+3);
  89.     while(str[0]==SP)
  90.         strcpy(str,str+1); }
  91. }
  92.  
  93. /****************************************************************************/
  94. /* Adds a new message to the message base                                    */
  95. /****************************************************************************/
  96. void postmsg(char type)
  97. {
  98.     char    str[128],buf[SDT_BLOCK_LEN];
  99.     ushort    xlat,net;
  100.     int     i,j,k,file;
  101.     long    length;
  102.     ulong    offset,crc=0xffffffffUL;
  103.     FILE    *instream;
  104.     smbmsg_t    msg;
  105.  
  106. length=flength(filein);
  107. if(length<1L) {
  108.     printf("Invalid file size for '%s'\n",filein);
  109.     exit(1); }
  110. length+=2;    /* for translation string */
  111. if(!(smb.status.attr&SMB_HYPERALLOC)) {
  112.     i=smb_open_da(&smb);
  113.     if(i) {
  114.         printf("smb_open_da returned %d\n",i);
  115.         exit(1); }
  116.     offset=smb_allocdat(&smb,length,1);
  117.     smb_close_da(&smb); }
  118. else
  119.     offset=smb_hallocdat(&smb);
  120.  
  121. if((file=open(filein,O_RDONLY|O_BINARY))==-1
  122.     || (instream=fdopen(file,"rb"))==NULL) {
  123.     printf("Error opening %s for read\n",filein);
  124.     smb_freemsgdat(&smb,offset,length,1);
  125.     exit(1); }
  126. setvbuf(instream,NULL,_IOFBF,32*1024);
  127. fseek(smb.sdt_fp,offset,SEEK_SET);
  128. xlat=XLAT_NONE;
  129. fwrite(&xlat,2,1,smb.sdt_fp);
  130. k=SDT_BLOCK_LEN-2;
  131. while(!feof(instream)) {
  132.     memset(buf,0,k);
  133.     j=fread(buf,1,k,instream);
  134.     if(smb.status.max_crcs)
  135.         for(i=0;i<j;i++)
  136.             crc=ucrc32(buf[i],crc);
  137.     fwrite(buf,k,1,smb.sdt_fp);
  138.     k=SDT_BLOCK_LEN; }
  139. fflush(smb.sdt_fp);
  140. fclose(instream);
  141. crc=~crc;
  142.  
  143. memset(&msg,0,sizeof(smbmsg_t));
  144. memcpy(msg.hdr.id,"SHD\x1a",4);
  145. msg.hdr.version=SMB_VERSION;
  146. msg.hdr.when_written.time=time(NULL);
  147. msg.hdr.when_written.zone=tzone;
  148. msg.hdr.when_imported=msg.hdr.when_written;
  149.  
  150. if(smb.status.max_crcs) {
  151.     i=smb_addcrc(&smb,crc);
  152.     if(i) {
  153.         printf("smb_addcrc returned %d\n",i);
  154.         smb_freemsgdat(&smb,offset,length,1);
  155.         exit(1); } }
  156.  
  157. msg.hdr.offset=offset;
  158.  
  159. printf("To User Name: ");
  160. gets(str);
  161. i=smb_hfield(&msg,RECIPIENT,strlen(str),str);
  162. if(i) {
  163.     printf("smb_hfield returned %d\n",i);
  164.     smb_freemsgdat(&smb,offset,length,1);
  165.     exit(1); }
  166. if(type=='E' || type=='N')
  167.     smb.status.attr|=SMB_EMAIL;
  168. if(smb.status.attr&SMB_EMAIL) {
  169.     printf("To User Number (0=QWKnet or Internet): ");
  170.     gets(str);
  171.     i=smb_hfield(&msg,RECIPIENTEXT,strlen(str),str);
  172.     if(i) {
  173.         printf("smb_hfield returned %d\n",i);
  174.         smb_freemsgdat(&smb,offset,length,1);
  175.         exit(1); }
  176.     msg.idx.to=atoi(str); }
  177. else {
  178.     strlwr(str);
  179.     msg.idx.to=crc16(str); }
  180.  
  181. if(type=='N') {
  182.     printf("To Address: ");
  183.     gets(str);
  184.     if(*str) {
  185.         if(strchr(str,'.'))
  186.             net=NET_INTERNET;
  187.         else
  188.             net=NET_QWK;
  189.         i=smb_hfield(&msg,RECIPIENTNETTYPE,sizeof(net),&net);
  190.         if(i) {
  191.             printf("smb_hfield returned %d\n",i);
  192.             smb_freemsgdat(&smb,offset,length,1);
  193.             exit(1); }
  194.         i=smb_hfield(&msg,RECIPIENTNETADDR,strlen(str),str);
  195.         if(i) {
  196.             printf("smb_hfield returned %d\n",i);
  197.             smb_freemsgdat(&smb,offset,length,1);
  198.             exit(1); } } }
  199.  
  200. printf("From User Name: ");
  201. gets(str);
  202. i=smb_hfield(&msg,SENDER,strlen(str),str);
  203. if(i) {
  204.     printf("smb_hfield returned %d\n",i);
  205.     smb_freemsgdat(&smb,offset,length,1);
  206.     exit(1); }
  207. if(smb.status.attr&SMB_EMAIL) {
  208.     printf("From User Number: ");
  209.     gets(str);
  210.     i=smb_hfield(&msg,SENDEREXT,strlen(str),str);
  211.     if(i) {
  212.         printf("smb_hfield returned %d\n",i);
  213.         smb_freemsgdat(&smb,offset,length,1);
  214.         exit(1); }
  215.     msg.idx.from=atoi(str); }
  216. else {
  217.     strlwr(str);
  218.     msg.idx.from=crc16(str); }
  219.  
  220. printf("Subject: ");
  221. gets(str);
  222. i=smb_hfield(&msg,SUBJECT,strlen(str),str);
  223. if(i) {
  224.     printf("smb_hfield returned %d\n",i);
  225.     smb_freemsgdat(&smb,offset,length,1);
  226.     exit(1); }
  227. remove_re(str);
  228. strlwr(str);
  229. msg.idx.subj=crc16(str);
  230.  
  231. i=smb_dfield(&msg,TEXT_BODY,length);
  232. if(i) {
  233.     printf("smb_dfield returned %d\n",i);
  234.     smb_freemsgdat(&smb,offset,length,1);
  235.     exit(1); }
  236.  
  237. i=smb_addmsghdr(&smb,&msg,smb.status.attr&SMB_HYPERALLOC);
  238.  
  239. if(i) {
  240.     printf("smb_addmsghdr returned %d\n",i);
  241.     smb_freemsgdat(&smb,offset,length,1);
  242.     exit(1); }
  243. smb_freemsgmem(&msg);
  244.  
  245. }
  246.  
  247. /****************************************************************************/
  248. /* Shows the message base header                                            */
  249. /****************************************************************************/
  250. void showstatus()
  251. {
  252.     int i;
  253.  
  254. i=smb_locksmbhdr(&smb);
  255. if(i) {
  256.     printf("smb_locksmbhdr returned %d\n",i);
  257.     return; }
  258. i=smb_getstatus(&smb);
  259. smb_unlocksmbhdr(&smb);
  260. if(i) {
  261.     printf("smb_getstatus returned %d\n",i);
  262.     return; }
  263. printf("last_msg        =%lu\n"
  264.        "total_msgs      =%lu\n"
  265.        "header_offset   =%lu\n"
  266.        "max_crcs        =%lu\n"
  267.        "max_msgs        =%lu\n"
  268.        "max_age         =%u\n"
  269.        "attr            =%04Xh\n"
  270.        ,smb.status.last_msg
  271.        ,smb.status.total_msgs
  272.        ,smb.status.header_offset
  273.        ,smb.status.max_crcs
  274.        ,smb.status.max_msgs
  275.        ,smb.status.max_age
  276.        ,smb.status.attr
  277.        );
  278. }
  279.  
  280. /****************************************************************************/
  281. /* Configure message base header                                            */
  282. /****************************************************************************/
  283. void config()
  284. {
  285.     char max_msgs[128],max_crcs[128],max_age[128],header_offset[128],attr[128];
  286.     int i;
  287.  
  288. i=smb_locksmbhdr(&smb);
  289. if(i) {
  290.     printf("smb_locksmbhdr returned %d\n",i);
  291.     return; }
  292. i=smb_getstatus(&smb);
  293. smb_unlocksmbhdr(&smb);
  294. if(i) {
  295.     printf("smb_getstatus returned %d\n",i);
  296.     return; }
  297. printf("Header offset =%-5lu  New value (CR=No Change): "
  298.     ,smb.status.header_offset);
  299. gets(header_offset);
  300. printf("Max msgs      =%-5lu  New value (CR=No Change): "
  301.     ,smb.status.max_msgs);
  302. gets(max_msgs);
  303. printf("Max crcs      =%-5lu  New value (CR=No Change): "
  304.     ,smb.status.max_crcs);
  305. gets(max_crcs);
  306. printf("Max age       =%-5u  New value (CR=No Change): "
  307.     ,smb.status.max_age);
  308. gets(max_age);
  309. printf("Attributes    =%-5u  New value (CR=No Change): "
  310.     ,smb.status.attr);
  311. gets(attr);
  312. i=smb_locksmbhdr(&smb);
  313. if(i) {
  314.     printf("smb_locksmbhdr returned %d\n",i);
  315.     return; }
  316. i=smb_getstatus(&smb);
  317. if(i) {
  318.     printf("smb_getstatus returned %d\n",i);
  319.     smb_unlocksmbhdr(&smb);
  320.     return; }
  321. if(isdigit(max_msgs[0]))
  322.     smb.status.max_msgs=atol(max_msgs);
  323. if(isdigit(max_crcs[0]))
  324.     smb.status.max_crcs=atol(max_crcs);
  325. if(isdigit(max_age[0]))
  326.     smb.status.max_age=atoi(max_age);
  327. if(isdigit(header_offset[0]))
  328.     smb.status.header_offset=atol(header_offset);
  329. if(isdigit(attr[0]))
  330.     smb.status.attr=atoi(attr);
  331. i=smb_putstatus(&smb);
  332. smb_unlocksmbhdr(&smb);
  333. if(i)
  334.     printf("smb_putstatus returned %d\n",i);
  335. }
  336.  
  337. /****************************************************************************/
  338. /* Lists messages' to, from, and subject                                    */
  339. /****************************************************************************/
  340. void listmsgs(ulong start, ulong count)
  341. {
  342.     int i;
  343.     ulong l=0;
  344.     smbmsg_t msg;
  345.     idxrec_t idxrec;
  346.  
  347. if(!start)
  348.     start=1;
  349. fseek(smb.sid_fp,(start-1L)*sizeof(idxrec_t),SEEK_SET);
  350. while(l<count) {
  351.     if(!fread(&msg.idx,1,sizeof(idxrec_t),smb.sid_fp))
  352.         break;
  353.     i=smb_lockmsghdr(&smb,&msg);
  354.     if(i) {
  355.         printf("smb_lockmsghdr returned %d\n",i);
  356.         break; }
  357.     i=smb_getmsghdr(&smb,&msg);
  358.     smb_unlockmsghdr(&smb,&msg);
  359.     if(i) {
  360.         printf("smb_getmsghdr returned %d\n",i);
  361.         break; }
  362.     printf("%4lu %-25.25s %-25.25s %.20s\n"
  363.         ,msg.hdr.number,msg.from,msg.to,msg.subj);
  364.     smb_freemsgmem(&msg);
  365.     l++; }
  366. }
  367.  
  368. /****************************************************************************/
  369. /* Returns an ASCII string for FidoNet address 'addr'                       */
  370. /****************************************************************************/
  371. char *faddrtoa(fidoaddr_t addr)
  372. {
  373.     static char str[25];
  374.     char point[25];
  375.  
  376. sprintf(str,"%u:%u/%u",addr.zone,addr.net,addr.node);
  377. if(addr.point) {
  378.     sprintf(point,".%u",addr.point);
  379.     strcat(str,point); }
  380. return(str);
  381. }
  382.  
  383. char *binstr(uchar *buf, ushort length)
  384. {
  385.     static char str[128];
  386.     char tmp[128];
  387.     int i;
  388.  
  389. str[0]=0;
  390. for(i=0;i<length;i++)
  391.     if(buf[i] && (buf[i]<SP || buf[i]>=0x7f))
  392.         break;
  393. if(i==length)        /* not binary */
  394.     return(buf);
  395. for(i=0;i<length;i++) {
  396.     sprintf(tmp,"%02X ",buf[i]);
  397.     strcat(str,tmp); }
  398. return(str);
  399. }
  400.  
  401. /****************************************************************************/
  402. /* Generates a 24 character ASCII string that represents the time_t pointer */
  403. /* Used as a replacement for ctime()                                        */
  404. /****************************************************************************/
  405. char *timestr(time_t *intime)
  406. {
  407.     static char str[256];
  408.     char mer[3],hour;
  409.     struct tm *gm;
  410.  
  411. printf("before localtime\n");
  412. gm=localtime(intime);
  413. printf("after\n");
  414. if(gm==NULL) {
  415.     strcpy(str,"Invalid Time");
  416.     return(str); }
  417. if(gm->tm_hour>=12) {
  418.     if(gm->tm_hour==12)
  419.         hour=12;
  420.     else
  421.         hour=gm->tm_hour-12;
  422.     strcpy(mer,"pm"); }
  423. else {
  424.     if(gm->tm_hour==0)
  425.         hour=12;
  426.     else
  427.         hour=gm->tm_hour;
  428.     strcpy(mer,"am"); }
  429. sprintf(str,"%s %s %02d %4d %02d:%02d %s"
  430.     ,wday[gm->tm_wday],mon[gm->tm_mon],gm->tm_mday,1900+gm->tm_year
  431.     ,hour,gm->tm_min,mer);
  432. return(str);
  433. }
  434.  
  435.  
  436. /****************************************************************************/
  437. /* Converts when_t.zone into ASCII format                                    */
  438. /****************************************************************************/
  439. char *zonestr(short zone)
  440. {
  441.     static char str[32];
  442.  
  443. switch((ushort)zone) {
  444.     case 0:     return("UT");
  445.     case AST:    return("AST");
  446.     case EST:    return("EST");
  447.     case CST:    return("CST");
  448.     case MST:    return("MST");
  449.     case PST:    return("PST");
  450.     case YST:    return("YST");
  451.     case HST:    return("HST");
  452.     case BST:    return("BST");
  453.     case ADT:    return("ADT");
  454.     case EDT:    return("EDT");
  455.     case CDT:    return("CDT");
  456.     case MDT:    return("MDT");
  457.     case PDT:    return("PDT");
  458.     case YDT:    return("YDT");
  459.     case HDT:    return("HDT");
  460.     case BDT:    return("BDT");
  461.     case MID:    return("MID");
  462.     case VAN:    return("VAN");
  463.     case EDM:    return("EDM");
  464.     case WIN:    return("WIN");
  465.     case BOG:    return("BOG");
  466.     case CAR:    return("CAR");
  467.     case RIO:    return("RIO");
  468.     case FER:    return("FER");
  469.     case AZO:    return("AZO");
  470.     case LON:    return("LON");
  471.     case BER:    return("BER");
  472.     case ATH:    return("ATH");
  473.     case MOS:    return("MOS");
  474.     case DUB:    return("DUB");
  475.     case KAB:    return("KAB");
  476.     case KAR:    return("KAR");
  477.     case BOM:    return("BOM");
  478.     case KAT:    return("KAT");
  479.     case DHA:    return("DHA");
  480.     case BAN:    return("BAN");
  481.     case HON:    return("HON");
  482.     case TOK:    return("TOK");
  483.     case SYD:    return("SYD");
  484.     case NOU:    return("NOU");
  485.     case WEL:    return("WEL");
  486.     }
  487.  
  488. sprintf(str,"%02d:%02u",zone/60,zone<0 ? (-zone)%60 : zone%60);
  489. return(str);
  490. }
  491.              
  492.  
  493. /****************************************************************************/
  494. /* Displays message header information                                        */
  495. /****************************************************************************/
  496. void viewmsgs(ulong start, ulong count)
  497. {
  498.     char when_written[128]
  499.         ,when_imported[128];
  500.     int i;
  501.     ulong l=0;
  502.     smbmsg_t msg;
  503.     idxrec_t idxrec;
  504.  
  505. if(!start)
  506.     start=1;
  507. fseek(smb.sid_fp,(start-1L)*sizeof(idxrec_t),SEEK_SET);
  508. while(l<count) {
  509.     if(!fread(&msg.idx,1,sizeof(idxrec_t),smb.sid_fp))
  510.         break;
  511.     i=smb_lockmsghdr(&smb,&msg);
  512.     if(i) {
  513.         printf("smb_lockmsghdr returned %d\n",i);
  514.         break; }
  515.     i=smb_getmsghdr(&smb,&msg);
  516.     smb_unlockmsghdr(&smb,&msg);
  517.     if(i) {
  518.         printf("smb_getmsghdr returned %d\n",i);
  519.         break; }
  520.  
  521.     sprintf(when_written,"%.24s %s"
  522.         ,timestr((time_t *)msg.hdr.when_written.time)
  523.         ,zonestr(msg.hdr.when_written.zone));
  524.     sprintf(when_imported,"%.24s %s"
  525.         ,timestr((time_t *)msg.hdr.when_imported.time)
  526.         ,zonestr(msg.hdr.when_imported.zone));
  527.  
  528.     printf( "%-20.20s %s\n"
  529.             "%-20.20s %s\n"
  530.             "%-20.20s %s\n"
  531.             "%-20.20s %04Xh\n"
  532.             "%-20.20s %04Xh\n"
  533.             "%-20.20s %u\n"
  534.             "%-20.20s %04Xh\n"
  535.             "%-20.20s %08lXh\n"
  536.             "%-20.20s %08lXh\n"
  537.             "%-20.20s %s\n"
  538.             "%-20.20s %s\n"
  539.             "%-20.20s %ld (%ld)\n"
  540.             "%-20.20s %ld\n"
  541.             "%-20.20s %ld\n"
  542.             "%-20.20s %ld\n"
  543.             "%-20.20s %s\n"
  544.             "%-20.20s %06lXh\n"
  545.             "%-20.20s %u\n",
  546.  
  547.         "subj",
  548.         msg.subj,
  549.  
  550.         "from",
  551.         msg.from,
  552.  
  553.         "to",
  554.         msg.to,
  555.  
  556.         "type",
  557.         msg.hdr.type,
  558.  
  559.         "version",
  560.         msg.hdr.version,
  561.  
  562.         "length",
  563.         msg.hdr.length,
  564.  
  565.         "attr",
  566.         msg.hdr.attr,
  567.  
  568.         "auxattr",
  569.         msg.hdr.auxattr,
  570.  
  571.         "netattr",
  572.         msg.hdr.netattr,
  573.  
  574.         "when_written",
  575.         when_written,
  576.  
  577.         "when_imported",
  578.         when_imported,
  579.  
  580.         "number",
  581.         msg.hdr.number,
  582.         ftell(smb.sid_fp)/sizeof(idxrec_t),
  583.  
  584.         "thread_orig",
  585.         msg.hdr.thread_orig,
  586.  
  587.         "thread_next",
  588.         msg.hdr.thread_next,
  589.  
  590.         "thread_first",
  591.         msg.hdr.thread_first,
  592.  
  593.         "reserved[16]",
  594.         binstr(msg.hdr.reserved,16),
  595.  
  596.         "offset",
  597.         msg.hdr.offset,
  598.  
  599.         "total_dfields",
  600.         msg.hdr.total_dfields
  601.         );
  602.     for(i=0;i<msg.hdr.total_dfields;i++)
  603.         printf("dfield[%02u].type      %02Xh\n"
  604.                "dfield[%02u].offset    %lu\n"
  605.                "dfield[%02u].length    %lu\n"
  606.                ,i,msg.dfield[i].type
  607.                ,i,msg.dfield[i].offset
  608.                ,i,msg.dfield[i].length);
  609.  
  610.     for(i=0;i<msg.total_hfields;i++)
  611.         printf("hfield[%02u].type      %02Xh\n"
  612.                "hfield[%02u].length    %d\n"
  613.                "hfield[%02u]_dat       %s\n"
  614.                ,i,msg.hfield[i].type
  615.                ,i,msg.hfield[i].length
  616.                ,i,binstr(msg.hfield_dat[i],msg.hfield[i].length));
  617.  
  618.     if(msg.from_net.type)
  619.         printf("from_net.type        %02Xh\n"
  620.                "from_net.addr        %s\n"
  621.             ,msg.from_net.type
  622.             ,msg.from_net.type==NET_FIDO
  623.             ? faddrtoa(*(fidoaddr_t *)msg.from_net.addr) : msg.from_net.addr);
  624.  
  625.     if(msg.to_net.type)
  626.         printf("to_net.type          %02Xh\n"
  627.                "to_net.addr          %s\n"
  628.             ,msg.to_net.type
  629.             ,msg.to_net.type==NET_FIDO
  630.             ? faddrtoa(*(fidoaddr_t *)msg.to_net.addr) : msg.to_net.addr);
  631.  
  632.     if(msg.replyto_net.type)
  633.         printf("replyto_net.type     %02Xh\n"
  634.                "replyto_net.addr     %s\n"
  635.             ,msg.replyto_net.type
  636.             ,msg.replyto_net.type==NET_FIDO
  637.             ? faddrtoa(*(fidoaddr_t *)msg.replyto_net.addr)
  638.                 : msg.replyto_net.addr);
  639.  
  640.     printf("from_agent           %02Xh\n"
  641.            "to_agent             %02Xh\n"
  642.            "replyto_agent        %02Xh\n"
  643.            ,msg.from_agent
  644.            ,msg.to_agent
  645.            ,msg.replyto_agent);
  646.  
  647.     printf("\n");
  648.     smb_freemsgmem(&msg);
  649.     l++; }
  650. }
  651.  
  652. /****************************************************************************/
  653. /* Maintain message base - deletes messages older than max age (in days)    */
  654. /* or messages that exceed maximum                                            */
  655. /****************************************************************************/
  656. void maint(void)
  657. {
  658.     int i;
  659.     ulong l,m,n,f,flagged=0;
  660.     time_t now;
  661.     smbmsg_t msg;
  662.     idxrec_t HUGE16 *idx;
  663.  
  664. printf("Maintaining %s\r\n",smb.file);
  665. now=time(NULL);
  666. i=smb_locksmbhdr(&smb);
  667. if(i) {
  668.     printf("smb_locksmbhdr returned %d\n",i);
  669.     return; }
  670. i=smb_getstatus(&smb);
  671. if(i) {
  672.     smb_unlocksmbhdr(&smb);
  673.     printf("smb_getstatus returned %d\n",i);
  674.     return; }
  675. if(!smb.status.total_msgs) {
  676.     smb_unlocksmbhdr(&smb);
  677.     printf("Empty\n");
  678.     return; }
  679. printf("Loading index...\n");
  680. if((idx=(idxrec_t *)LMALLOC(sizeof(idxrec_t)*smb.status.total_msgs))
  681.     ==NULL) {
  682.     smb_unlocksmbhdr(&smb);
  683.     printf("can't allocate %lu bytes of memory\n"
  684.         ,sizeof(idxrec_t)*smb.status.total_msgs);
  685.     return; }
  686. fseek(smb.sid_fp,0L,SEEK_SET);
  687. for(l=0;l<smb.status.total_msgs;l++) {
  688.     printf("%lu of %lu\r"
  689.         ,l+1,smb.status.total_msgs);
  690.     if(!fread(&idx[l],1,sizeof(idxrec_t),smb.sid_fp))
  691.         break; }
  692. printf("\nDone.\n\n");
  693.  
  694. printf("Scanning for pre-flagged messages...\n");
  695. for(m=0;m<l;m++) {
  696.     printf("\r%2u%%",m ? (long)(100.0/((float)l/m)) : 0);
  697.     if(idx[m].attr&MSG_DELETE)
  698.         flagged++; }
  699. printf("\r100%% (%lu pre-flagged for deletion)\n",flagged);
  700.  
  701. if(smb.status.max_age) {
  702.     printf("Scanning for messages more than %u days old...\n"
  703.         ,smb.status.max_age);
  704.     for(m=f=0;m<l;m++) {
  705.         printf("\r%2u%%",m ? (long)(100.0/((float)l/m)) : 0);
  706.         if(idx[m].attr&(MSG_PERMANENT|MSG_DELETE))
  707.             continue;
  708.         if(now>idx[m].time && (now-idx[m].time)/(24L*60L*60L)
  709.             >smb.status.max_age) {
  710.             f++;
  711.             flagged++;
  712.             idx[m].attr|=MSG_DELETE; } }  /* mark for deletion */
  713.     printf("\r100%% (%lu flagged for deletion)\n",f); }
  714.  
  715. printf("Scanning for read messages to be killed...\n");
  716. for(m=f=0;m<l;m++) {
  717.     printf("\r%2u%%",m ? (long)(100.0/((float)l/m)) : 0);
  718.     if(idx[m].attr&(MSG_PERMANENT|MSG_DELETE))
  719.         continue;
  720.     if((idx[m].attr&(MSG_READ|MSG_KILLREAD))==(MSG_READ|MSG_KILLREAD)) {
  721.         f++;
  722.         flagged++;
  723.         idx[m].attr|=MSG_DELETE; } }
  724. printf("\r100%% (%lu flagged for deletion)\n",f);
  725.  
  726. if(l-flagged>smb.status.max_msgs) {
  727.     printf("Flagging excess messages for deletion...\n");
  728.     for(m=n=0,f=flagged;l-flagged>smb.status.max_msgs && m<l;m++) {
  729.         if(idx[m].attr&(MSG_PERMANENT|MSG_DELETE))
  730.             continue;
  731.         printf("%lu of %lu\r",++n,(l-f)-smb.status.max_msgs);
  732.         flagged++;
  733.         idx[m].attr|=MSG_DELETE; }            /* mark for deletion */
  734.     printf("\nDone.\n\n"); }
  735.  
  736. if(!flagged) {                /* No messages to delete */
  737.     LFREE(idx);
  738.     smb_unlocksmbhdr(&smb);
  739.     return; }
  740.  
  741. if(!(mode&NOANALYSIS)) {
  742.  
  743.     printf("Freeing allocated header and data blocks for deleted messages...\n");
  744.     if(!(smb.status.attr&SMB_HYPERALLOC)) {
  745.         i=smb_open_da(&smb);
  746.         if(i) {
  747.             smb_unlocksmbhdr(&smb);
  748.             printf("smb_open_da returned %d\n",i);
  749.             exit(1); }
  750.         i=smb_open_ha(&smb);
  751.         if(i) {
  752.             smb_unlocksmbhdr(&smb);
  753.             printf("smb_open_ha returned %d\n",i);
  754.             exit(1); } }
  755.  
  756.     for(m=n=0;m<l;m++) {
  757.         if(idx[m].attr&MSG_DELETE) {
  758.             printf("%lu of %lu\r",++n,flagged);
  759.             msg.idx=idx[m];
  760.             msg.hdr.number=msg.idx.number;
  761.             if((i=smb_getmsgidx(&smb,&msg))!=0) {
  762.                 printf("\nsmb_getmsgidx returned %d\n",i);
  763.                 continue; }
  764.             i=smb_lockmsghdr(&smb,&msg);
  765.             if(i) {
  766.                 printf("\nsmb_lockmsghdr returned %d\n",i);
  767.                 break; }
  768.             if((i=smb_getmsghdr(&smb,&msg))!=0) {
  769.                 smb_unlockmsghdr(&smb,&msg);
  770.                 printf("\nsmb_getmsghdr returned %d\n",i);
  771.                 break; }
  772.             msg.hdr.attr|=MSG_DELETE;            /* mark header as deleted */
  773.             if((i=smb_putmsg(&smb,&msg))!=0) {
  774.                 smb_freemsgmem(&msg);
  775.                 smb_unlockmsghdr(&smb,&msg);
  776.                 printf("\nsmb_putmsg returned %d\n",i);
  777.                 break; }
  778.             smb_unlockmsghdr(&smb,&msg);
  779.             if((i=smb_freemsg(&smb,&msg))!=0) {
  780.                 smb_freemsgmem(&msg);
  781.                 printf("\nsmb_freemsg returned %d\n",i);
  782.                 break; }
  783.             smb_freemsgmem(&msg); } }
  784.     if(!(smb.status.attr&SMB_HYPERALLOC)) {
  785.         smb_close_ha(&smb);
  786.         smb_close_da(&smb); }
  787.     printf("\nDone.\n\n"); }
  788.  
  789. printf("Re-writing index...\n");
  790. rewind(smb.sid_fp);
  791. if(chsize(fileno(smb.sid_fp),0L))
  792.     printf("chsize failed!\n");
  793. for(m=n=0;m<l;m++) {
  794.     if(idx[m].attr&MSG_DELETE)
  795.         continue;
  796.     printf("%lu of %lu\r",++n,l-flagged);
  797.     fwrite(&idx[m],sizeof(idxrec_t),1,smb.sid_fp); }
  798. printf("\nDone.\n\n");
  799. fflush(smb.sid_fp);
  800.  
  801. LFREE(idx);
  802. smb.status.total_msgs-=flagged;
  803. smb_putstatus(&smb);
  804. smb_unlocksmbhdr(&smb);
  805. }
  806.  
  807.  
  808. typedef struct {
  809.     ulong old,new;
  810.     } datoffset_t;
  811.  
  812. /****************************************************************************/
  813. /* Removes all unused blocks from SDT and SHD files                         */
  814. /****************************************************************************/
  815. void packmsgs(ulong packable)
  816. {
  817.     uchar str[128],buf[SDT_BLOCK_LEN],ch,fname[128],tmpfname[128];
  818.     int i,file,size;
  819.     ulong l,m,n,datoffsets=0,length,total,now;
  820.     FILE *tmp_sdt,*tmp_shd,*tmp_sid;
  821.     smbhdr_t    hdr;
  822.     smbmsg_t    msg;
  823.     datoffset_t *datoffset=NULL;
  824.  
  825. now=time(NULL);
  826. printf("Packing %s\n",smb.file);
  827. i=smb_locksmbhdr(&smb);
  828. if(i) {
  829.     printf("smb_locksmbhdr returned %d\n",i);
  830.     return; }
  831. i=smb_getstatus(&smb);
  832. if(i) {
  833.     smb_unlocksmbhdr(&smb);
  834.     printf("smb_getstatus returned %d\n",i);
  835.     return; }
  836.  
  837. if(!(smb.status.attr&SMB_HYPERALLOC)) {
  838.     i=smb_open_ha(&smb);
  839.     if(i) {
  840.         smb_unlocksmbhdr(&smb);
  841.         printf("smb_open_ha returned %d\n",i);
  842.         return; }
  843.     i=smb_open_da(&smb);
  844.     if(i) {
  845.         smb_unlocksmbhdr(&smb);
  846.         smb_close_ha(&smb);
  847.         printf("smb_open_da returned %d\n",i);
  848.         return; } }
  849.  
  850. if(!smb.status.total_msgs) {
  851.     printf("Empty\n");
  852.     rewind(smb.shd_fp);
  853.     chsize(fileno(smb.shd_fp),smb.status.header_offset);
  854.     rewind(smb.sdt_fp);
  855.     chsize(fileno(smb.sdt_fp),0L);
  856.     rewind(smb.sid_fp);
  857.     chsize(fileno(smb.sid_fp),0L);
  858.     if(!(smb.status.attr&SMB_HYPERALLOC)) {
  859.         rewind(smb.sha_fp);
  860.         chsize(fileno(smb.sha_fp),0L);
  861.         rewind(smb.sda_fp);
  862.         chsize(fileno(smb.sda_fp),0L);
  863.         smb_close_ha(&smb);
  864.         smb_close_da(&smb); }
  865.     smb_unlocksmbhdr(&smb);
  866.     return; }
  867.  
  868.  
  869. if(!(smb.status.attr&SMB_HYPERALLOC) && !(mode&NOANALYSIS)) {
  870.     printf("Analyzing data blocks...\n");
  871.  
  872.     length=filelength(fileno(smb.sda_fp));
  873.  
  874.     fseek(smb.sda_fp,0L,SEEK_SET);
  875.     for(l=m=0;l<length;l+=2) {
  876.         printf("\r%2u%%  ",l ? (long)(100.0/((float)length/l)) : 0);
  877.         i=0;
  878.         if(!fread(&i,2,1,smb.sda_fp))
  879.             break;
  880.         if(!i)
  881.             m++; }
  882.  
  883.     printf("\rAnalyzing header blocks...\n");
  884.  
  885.     length=filelength(fileno(smb.sha_fp));
  886.  
  887.     fseek(smb.sha_fp,0L,SEEK_SET);
  888.     for(l=n=0;l<length;l++) {
  889.         printf("\r%2u%%  ",l ? (long)(100.0/((float)length/l)) : 0);
  890.         ch=0;
  891.         if(!fread(&ch,1,1,smb.sha_fp))
  892.             break;
  893.         if(!ch)
  894.             n++; }
  895.  
  896.     if(!m && !n) {
  897.         printf("\rAlready compressed.\n\n");
  898.         smb_close_ha(&smb);
  899.         smb_close_da(&smb);
  900.         smb_unlocksmbhdr(&smb);
  901.         return; }
  902.  
  903.     if(packable && (m*SDT_BLOCK_LEN)+(n*SHD_BLOCK_LEN)<packable*1024L) {
  904.         printf("\rLess than %luk compressable bytes.\n\n",packable);
  905.         smb_close_ha(&smb);
  906.         smb_close_da(&smb);
  907.         smb_unlocksmbhdr(&smb);
  908.         return; }
  909.  
  910.     printf("\rCompressing %lu data blocks (%lu bytes)\n"
  911.              "        and %lu header blocks (%lu bytes)\n"
  912.               ,m,m*SDT_BLOCK_LEN,n,n*SHD_BLOCK_LEN); }
  913.  
  914. if(!(smb.status.attr&SMB_HYPERALLOC)) {
  915.     rewind(smb.sha_fp);
  916.     chsize(fileno(smb.sha_fp),0L);        /* Reset both allocation tables */
  917.     rewind(smb.sda_fp);
  918.     chsize(fileno(smb.sda_fp),0L); }
  919.  
  920. if(smb.status.attr&SMB_HYPERALLOC && !(mode&NOANALYSIS)) {
  921.     printf("Analyzing %s\n",smb.file);
  922.  
  923.     length=filelength(fileno(smb.shd_fp));
  924.     m=n=0;
  925.     for(l=smb.status.header_offset;l<length;l+=size) {
  926.         printf("\r%2u%%  ",(long)(100.0/((float)length/l)));
  927.         msg.idx.offset=l;
  928.         if((i=smb_lockmsghdr(&smb,&msg))!=0) {
  929.             printf("\n(%06lX) smb_lockmsghdr returned %d\n",l,i);
  930.             size=SHD_BLOCK_LEN;
  931.             continue; }
  932.         if((i=smb_getmsghdr(&smb,&msg))!=0) {
  933.             smb_unlockmsghdr(&smb,&msg);
  934.             m++;
  935.             size=SHD_BLOCK_LEN;
  936.             continue; }
  937.         smb_unlockmsghdr(&smb,&msg);
  938.         if(msg.hdr.attr&MSG_DELETE) {
  939.             m+=smb_hdrblocks(msg.hdr.length);
  940.             total=0;
  941.             for(i=0;i<msg.hdr.total_dfields;i++)
  942.                 total+=msg.dfield[i].length;
  943.             n+=smb_datblocks(total); }
  944.         size=smb_getmsghdrlen(&msg);
  945.         if(size<1) size=SHD_BLOCK_LEN;
  946.         while(size%SHD_BLOCK_LEN)
  947.             size++;
  948.         smb_freemsgmem(&msg); }
  949.  
  950.  
  951.     if(!m && !n) {
  952.         printf("\rAlready compressed.\n\n");
  953.         smb_unlocksmbhdr(&smb);
  954.         return; }
  955.  
  956.     if(packable && (n*SDT_BLOCK_LEN)+(m*SHD_BLOCK_LEN)<packable*1024L) {
  957.         printf("\rLess than %luk compressable bytes.\n\n",packable);
  958.         smb_unlocksmbhdr(&smb);
  959.         return; }
  960.  
  961.     printf("\rCompressing %lu data blocks (%lu bytes)\n"
  962.              "        and %lu header blocks (%lu bytes)\n"
  963.               ,n,n*SDT_BLOCK_LEN,m,m*SHD_BLOCK_LEN); }
  964.  
  965. sprintf(fname,"%s.SD$",smb.file);
  966. tmp_sdt=fopen(fname,"wb");
  967. sprintf(fname,"%s.SH$",smb.file);
  968. tmp_shd=fopen(fname,"wb");
  969. sprintf(fname,"%s.SI$",smb.file);
  970. tmp_sid=fopen(fname,"wb");
  971. if(!tmp_sdt || !tmp_shd || !tmp_sid) {
  972.     smb_unlocksmbhdr(&smb);
  973.     if(!(smb.status.attr&SMB_HYPERALLOC)) {
  974.         smb_close_ha(&smb);
  975.         smb_close_da(&smb); }
  976.     printf("error opening temp file\n");
  977.     return; }
  978. setvbuf(tmp_sdt,NULL,_IOFBF,2*1024);
  979. setvbuf(tmp_shd,NULL,_IOFBF,2*1024);
  980. setvbuf(tmp_sid,NULL,_IOFBF,2*1024);
  981. if(!(smb.status.attr&SMB_HYPERALLOC)
  982.     && (datoffset=(datoffset_t *)LMALLOC(sizeof(datoffset_t)*smb.status.total_msgs))
  983.     ==NULL) {
  984.     smb_unlocksmbhdr(&smb);
  985.     smb_close_ha(&smb);
  986.     smb_close_da(&smb);
  987.     fclose(tmp_sdt);
  988.     fclose(tmp_shd);
  989.     fclose(tmp_sid);
  990.     printf("error allocating mem\n");
  991.     return; }
  992. fseek(smb.shd_fp,0L,SEEK_SET);
  993. fread(&hdr,1,sizeof(smbhdr_t),smb.shd_fp);
  994. fwrite(&hdr,1,sizeof(smbhdr_t),tmp_shd);
  995. fwrite(&(smb.status),1,sizeof(smbstatus_t),tmp_shd);
  996. for(l=sizeof(smbhdr_t)+sizeof(smbstatus_t);l<smb.status.header_offset;l++) {
  997.     fread(&ch,1,1,smb.shd_fp);            /* copy additional base header records */
  998.     fwrite(&ch,1,1,tmp_shd); }
  999. fseek(smb.sid_fp,0L,SEEK_SET);
  1000. total=0;
  1001. for(l=0;l<smb.status.total_msgs;l++) {
  1002.     printf("%lu of %lu\r",l+1,smb.status.total_msgs);
  1003.     if(!fread(&msg.idx,1,sizeof(idxrec_t),smb.sid_fp))
  1004.         break;
  1005.     if(msg.idx.attr&MSG_DELETE) {
  1006.         printf("\nDeleted index.\n");
  1007.         continue; }
  1008.     i=smb_lockmsghdr(&smb,&msg);
  1009.     if(i) {
  1010.         printf("\nsmb_lockmsghdr returned %d\n",i);
  1011.         continue; }
  1012.     i=smb_getmsghdr(&smb,&msg);
  1013.     smb_unlockmsghdr(&smb,&msg);
  1014.     if(i) {
  1015.         printf("\nsmb_getmsghdr returned %d\n",i);
  1016.         continue; }
  1017.     if(msg.hdr.attr&MSG_DELETE) {
  1018.         printf("\nDeleted header.\n");
  1019.         smb_freemsgmem(&msg);
  1020.         continue; }
  1021.     if(msg.expiration.time && msg.expiration.time<=now) {
  1022.         printf("\nExpired message.\n");
  1023.         smb_freemsgmem(&msg);
  1024.         continue; }
  1025.     for(m=0;m<datoffsets;m++)
  1026.         if(msg.hdr.offset==datoffset[m].old)
  1027.             break;
  1028.     if(m<datoffsets) {                /* another index pointed to this data */
  1029.         printf("duplicate index\n");
  1030.         msg.hdr.offset=datoffset[m].new;
  1031.         smb_incdat(&smb,datoffset[m].new,smb_getmsgdatlen(&msg),1); }
  1032.     else {
  1033.  
  1034.         if(!(smb.status.attr&SMB_HYPERALLOC))
  1035.             datoffset[datoffsets].old=msg.hdr.offset;
  1036.  
  1037.         fseek(smb.sdt_fp,msg.hdr.offset,SEEK_SET);
  1038.  
  1039.         m=smb_getmsgdatlen(&msg);
  1040.         if(m>16L*1024L*1024L) {
  1041.             printf("\nInvalid data length (%lu)\n",m);
  1042.             continue; }
  1043.  
  1044.         if(!(smb.status.attr&SMB_HYPERALLOC)) {
  1045.             datoffset[datoffsets].new=msg.hdr.offset
  1046.                 =smb_fallocdat(&smb,m,1);
  1047.             datoffsets++;
  1048.             fseek(tmp_sdt,msg.hdr.offset,SEEK_SET); }
  1049.         else {
  1050.             fseek(tmp_sdt,0L,SEEK_END);
  1051.             msg.hdr.offset=ftell(tmp_sdt); }
  1052.  
  1053.         /* Actually copy the data */
  1054.  
  1055.         n=smb_datblocks(m);
  1056.         for(m=0;m<n;m++) {
  1057.             fread(buf,1,SDT_BLOCK_LEN,smb.sdt_fp);
  1058.             if(!m && *(ushort *)buf!=XLAT_NONE && *(ushort *)buf!=XLAT_LZH) {
  1059.                 printf("\nUnsupported translation type (%04X)\n"
  1060.                     ,*(ushort *)buf);
  1061.                 break; }
  1062.             fwrite(buf,1,SDT_BLOCK_LEN,tmp_sdt); }
  1063.         if(m<n)
  1064.             continue; }
  1065.  
  1066.     /* Write the new index entry */
  1067.     length=smb_getmsghdrlen(&msg);
  1068.     if(smb.status.attr&SMB_HYPERALLOC)
  1069.         msg.idx.offset=ftell(tmp_shd);
  1070.     else
  1071.         msg.idx.offset=smb_fallochdr(&smb,length)+smb.status.header_offset;
  1072.     msg.idx.number=msg.hdr.number;
  1073.     msg.idx.attr=msg.hdr.attr;
  1074.     msg.idx.time=msg.hdr.when_imported.time;
  1075.     sprintf(str,"%.128s",msg.subj);
  1076.     strlwr(str);
  1077.     remove_re(str);
  1078.     msg.idx.subj=crc16(str);
  1079.     if(smb.status.attr&SMB_EMAIL) {
  1080.         if(msg.to_ext)
  1081.             msg.idx.to=atoi(msg.to_ext);
  1082.         else
  1083.             msg.idx.to=0;
  1084.         if(msg.from_ext)
  1085.             msg.idx.from=atoi(msg.from_ext);
  1086.         else
  1087.             msg.idx.from=0; }
  1088.     else {
  1089.         sprintf(str,"%.128s",msg.to);
  1090.         strlwr(str);
  1091.         msg.idx.to=crc16(str);
  1092.         sprintf(str,"%.128s",msg.from);
  1093.         strlwr(str);
  1094.         msg.idx.from=crc16(str); }
  1095.     fwrite(&msg.idx,1,sizeof(idxrec_t),tmp_sid);
  1096.  
  1097.     /* Write the new header entry */
  1098.     fseek(tmp_shd,msg.idx.offset,SEEK_SET);
  1099.     fwrite(&msg.hdr,1,sizeof(msghdr_t),tmp_shd);
  1100.     for(n=0;n<msg.hdr.total_dfields;n++)
  1101.         fwrite(&msg.dfield[n],1,sizeof(dfield_t),tmp_shd);
  1102.     for(n=0;n<msg.total_hfields;n++) {
  1103.         fwrite(&msg.hfield[n],1,sizeof(hfield_t),tmp_shd);
  1104.         fwrite(msg.hfield_dat[n],1,msg.hfield[n].length,tmp_shd); }
  1105.     while(length%SHD_BLOCK_LEN) {    /* pad with NULLs */
  1106.         fputc(0,tmp_shd);
  1107.         length++; }
  1108.     total++;
  1109.     smb_freemsgmem(&msg); }
  1110.  
  1111. if(datoffset)
  1112.     LFREE(datoffset);
  1113. if(!(smb.status.attr&SMB_HYPERALLOC)) {
  1114.     smb_close_ha(&smb);
  1115.     smb_close_da(&smb); }
  1116.  
  1117. /* Change *.SH$ into *.SHD */
  1118. fclose(smb.shd_fp);
  1119. fclose(tmp_shd);
  1120. sprintf(fname,"%s.SHD",smb.file);
  1121. remove(fname);
  1122. sprintf(tmpfname,"%s.SH$",smb.file);
  1123. rename(tmpfname,fname);
  1124.  
  1125. /* Change *.SD$ into *.SDT */
  1126. fclose(smb.sdt_fp);
  1127. fclose(tmp_sdt);
  1128. sprintf(fname,"%s.SDT",smb.file);
  1129. remove(fname);
  1130. sprintf(tmpfname,"%s.SD$",smb.file);
  1131. rename(tmpfname,fname);
  1132.  
  1133. /* Change *.SI$ into *.SID */
  1134. fclose(smb.sid_fp);
  1135. fclose(tmp_sid);
  1136. sprintf(fname,"%s.SID",smb.file);
  1137. remove(fname);
  1138. sprintf(tmpfname,"%s.SI$",smb.file);
  1139. rename(tmpfname,fname);
  1140.  
  1141. if((i=smb_open(&smb))!=0) {
  1142.     printf("Error %d reopening %s\n",i,smb.file);
  1143.     return; }
  1144.  
  1145. smb.status.total_msgs=total;
  1146. if((i=smb_putstatus(&smb))!=0)
  1147.     printf("\nsmb_putstatus returned %d\n",i);
  1148. printf("\nDone.\n\n");
  1149. }
  1150.  
  1151.  
  1152. /****************************************************************************/
  1153. /* Read messages in message base                                            */
  1154. /****************************************************************************/
  1155. void readmsgs(ulong start)
  1156. {
  1157.     char    str[128],HUGE16 *inbuf,*outbuf;
  1158.     int     i,ch,done=0,domsg=1,lzh;
  1159.     ushort    xlat;
  1160.     ulong    l,count,outlen;
  1161.     smbmsg_t msg;
  1162.  
  1163. if(start)
  1164.     msg.offset=start-1;
  1165. else
  1166.     msg.offset=0;
  1167. while(!done) {
  1168.     if(domsg) {
  1169.         fseek(smb.sid_fp,msg.offset*sizeof(idxrec_t),SEEK_SET);
  1170.         if(!fread(&msg.idx,1,sizeof(idxrec_t),smb.sid_fp))
  1171.             break;
  1172.         i=smb_lockmsghdr(&smb,&msg);
  1173.         if(i) {
  1174.             printf("smb_lockmsghdr returned %d\n",i);
  1175.             break; }
  1176.         i=smb_getmsghdr(&smb,&msg);
  1177.         if(i) {
  1178.             printf("smb_getmsghdr returned %d\n",i);
  1179.             break; }
  1180.  
  1181.         printf("\n%lu (%lu)\n",msg.hdr.number,msg.offset+1);
  1182.         printf("Subj : %s\n",msg.subj);
  1183.         printf("To   : %s",msg.to);
  1184.         if(msg.to_net.type)
  1185.             printf(" (%s)",msg.to_net.type==NET_FIDO
  1186.                 ? faddrtoa(*(fidoaddr_t *)msg.to_net.addr) : msg.to_net.addr);
  1187.         printf("\nFrom : %s",msg.from);
  1188.         if(msg.from_net.type)
  1189.             printf(" (%s)",msg.from_net.type==NET_FIDO
  1190.                 ? faddrtoa(*(fidoaddr_t *)msg.from_net.addr)
  1191.                     : msg.from_net.addr);
  1192. #if 1
  1193.         printf("\nDate : %.24s %s"
  1194.             ,timestr((time_t *)msg.hdr.when_written.time)
  1195.             ,zonestr(msg.hdr.when_written.zone));
  1196. #endif
  1197.         printf("\n\n");
  1198. #if 0
  1199.         for(i=0;i<msg.hdr.total_dfields;i++)
  1200.             switch(msg.dfield[i].type) {
  1201.                 case TEXT_BODY:
  1202.                 case TEXT_TAIL:
  1203.                     fseek(smb.sdt_fp,msg.hdr.offset+msg.dfield[i].offset
  1204.                         ,SEEK_SET);
  1205.                     fread(&xlat,2,1,smb.sdt_fp);
  1206.                     l=2;
  1207.                     lzh=0;
  1208.                     while(xlat!=XLAT_NONE) {
  1209.                         if(xlat==XLAT_LZH)
  1210.                             lzh=1;
  1211.                         fread(&xlat,2,1,smb.sdt_fp);
  1212.                         l+=2; }
  1213.                     if(lzh) {
  1214.                         if((inbuf=(char *)LMALLOC(msg.dfield[i].length))
  1215.                             ==NULL) {
  1216.                             printf("Malloc error of %lu\n"
  1217.                                 ,msg.dfield[i].length);
  1218.                             exit(1); }
  1219.                         fread(inbuf,msg.dfield[i].length-l,1,smb.sdt_fp);
  1220.                         outlen=*(long *)inbuf;
  1221.                         if((outbuf=(char *)LMALLOC(outlen))==NULL) {
  1222.                             printf("Malloc error of lzh %lu\n"
  1223.                                 ,outlen);
  1224.                             exit(1); }
  1225.                         lzh_decode(inbuf,msg.dfield[i].length-l,outbuf);
  1226.                         LFREE(inbuf);
  1227.                         for(l=0;l<outlen;l++)
  1228.                             putchar(outbuf[l]);
  1229.                         LFREE(outbuf); }
  1230.                     else {
  1231.                         for(;l<msg.dfield[i].length;l++) {
  1232.                             ch=fgetc(smb.sdt_fp);
  1233.                             if(ch)
  1234.                                 putchar(ch); } }
  1235.                     printf("\n");
  1236.                     break; }
  1237. #else
  1238.         if((inbuf=smb_getmsgtxt(&smb,&msg,GETMSGTXT_TAILS))!=NULL) {
  1239.             printf("%s",inbuf);
  1240.             FREE(inbuf); }
  1241. #endif
  1242.         i=smb_unlockmsghdr(&smb,&msg);
  1243.         if(i) {
  1244.             printf("smb_unlockmsghdr returned %d\n",i);
  1245.             break; }
  1246.         smb_freemsgmem(&msg); }
  1247.     domsg=1;
  1248.     printf("\nReading %s (?=Menu): ",smb.file);
  1249.     switch(toupper(getch())) {
  1250.         case '?':
  1251.             printf("\n"
  1252.                    "\n"
  1253.                    "(R)e-read current message\n"
  1254.                    "(L)ist messages\n"
  1255.                    "(T)en more titles\n"
  1256.                    "(V)iew message headers\n"
  1257.                    "(Q)uit\n"
  1258.                    "(+/-) Forward/Backward\n"
  1259.                    "\n");
  1260.             domsg=0;
  1261.             break;
  1262.         case 'Q':
  1263.             printf("Quit\n");
  1264.             done=1;
  1265.             break;
  1266.         case 'R':
  1267.             printf("Re-read\n");
  1268.             break;
  1269.         case '-':
  1270.             printf("Backwards\n");
  1271.             if(msg.offset)
  1272.                 msg.offset--;
  1273.             break;
  1274.         case 'T':
  1275.             printf("Ten titles\n");
  1276.             listmsgs(msg.offset+2,10);
  1277.             msg.offset+=10;
  1278.             domsg=0;
  1279.             break;
  1280.         case 'L':
  1281.             printf("List messages\n");
  1282.             listmsgs(1,-1);
  1283.             domsg=0;
  1284.             break;
  1285.         case 'V':
  1286.             printf("View message headers\n");
  1287.             viewmsgs(1,-1);
  1288.             domsg=0;
  1289.             break;
  1290.         case CR:
  1291.         case '+':
  1292.             printf("Next\n");
  1293.             msg.offset++;
  1294.             break; } }
  1295. }
  1296.  
  1297. /***************/
  1298. /* Entry point */
  1299. /***************/
  1300. int main(int argc, char **argv)
  1301. {
  1302.     char cmd[128]="",*p,*s;
  1303.     int i,j,x,y;
  1304.     ulong l;
  1305.  
  1306. #ifdef __TURBOC__
  1307.     timezone=0;         /* Fix for Borland C++ EST default */
  1308.     daylight=0;         /* Fix for Borland C++ EDT default */
  1309. #elif defined(__WATCOMC__)
  1310.     putenv("TZ=UCT0");  /* Fix for Watcom C++ EDT default */
  1311. #endif
  1312. setvbuf(stdout,0,_IONBF,0);
  1313.  
  1314. smb.file[0]=0;
  1315. printf("\nSMBUTIL Version %s (%s) SMBLIB %s ยท Synchronet Message Base "\
  1316.     "Utility\n\n"
  1317.     ,SMBUTIL_VER
  1318. #if defined(__OS2__)
  1319.     ,"OS/2"
  1320. #elif defined(__NT__)
  1321.     ,"Win32"
  1322. #elif defined(__DOS4G__)
  1323.     ,"DOS4G"
  1324. #elif defined(__FLAT__)
  1325.     ,"DOS32"
  1326. #else
  1327.     ,"DOS16"
  1328. #endif
  1329.     ,SMBLIB_VERSION
  1330.     );
  1331. for(x=1;x<argc;x++) {
  1332.     if(argv[x][0]=='/') {
  1333.         for(j=1;argv[x][j];j++)
  1334.             switch(toupper(argv[x][j])) {
  1335.                 case 'A':
  1336.                     mode|=NOANALYSIS;
  1337.                     break;
  1338.                 case 'Z':
  1339.                     if(isdigit(argv[x][j+1]))
  1340.                         tzone=atoi(argv[x]+j+1);
  1341.                     else if(!stricmp(argv[x]+j+1,"EST"))
  1342.                         tzone=EST;
  1343.                     else if(!stricmp(argv[x]+j+1,"EDT"))
  1344.                         tzone=EDT;
  1345.                     else if(!stricmp(argv[x]+j+1,"CST"))
  1346.                         tzone=CST;
  1347.                     else if(!stricmp(argv[x]+j+1,"CDT"))
  1348.                         tzone=CDT;
  1349.                     else if(!stricmp(argv[x]+j+1,"MST"))
  1350.                         tzone=MST;
  1351.                     else if(!stricmp(argv[x]+j+1,"MDT"))
  1352.                         tzone=MDT;
  1353.                     else if(!stricmp(argv[x]+j+1,"PST"))
  1354.                         tzone=PST;
  1355.                     else if(!stricmp(argv[x]+j+1,"PDT"))
  1356.                         tzone=PDT;
  1357.                     j=strlen(argv[x])-1;
  1358.                     break;
  1359.                 default:
  1360.                     printf("\nUnknown opt '%c'\n",argv[x][j]);
  1361.                 case '?':
  1362.                     printf("%s",usage);
  1363.                     exit(1);
  1364.                     break; } }
  1365.     else {
  1366.         if(!cmd[0])
  1367.             strcpy(cmd,argv[x]);
  1368.         else {
  1369.             sprintf(smb.file,"%.64s",argv[x]);
  1370.             p=strrchr(smb.file,'.');
  1371.             s=strrchr(smb.file,'\\');
  1372.             if(p>s) *p=0;
  1373.             strupr(smb.file);
  1374.             smb.retry_time=30;
  1375.             printf("Opening %s\r\n",smb.file);
  1376.             if((i=smb_open(&smb))!=0) {
  1377.                 printf("error %d opening %s message base\n",i,smb.file);
  1378.                 exit(1); }
  1379.             if(!filelength(fileno(smb.shd_fp))) {
  1380.                 printf("Empty\n");
  1381.                 smb_close(&smb);
  1382.                 continue; }
  1383.             for(y=0;cmd[y];y++)
  1384.                 switch(toupper(cmd[y])) {
  1385.                     case 'I':
  1386.                     case 'E':
  1387.                     case 'N':
  1388.                         strcpy(filein,cmd+1);
  1389.                         i=smb_locksmbhdr(&smb);
  1390.                         if(i) {
  1391.                             printf("smb_locksmbhdr returned %d\n",i);
  1392.                             return(1); }
  1393.                         postmsg(toupper(cmd[y]));
  1394.                         y=strlen(cmd)-1;
  1395.                         break;
  1396.                     case 'S':
  1397.                         showstatus();
  1398.                         break;
  1399.                     case 'C':
  1400.                         config();
  1401.                         break;
  1402.                     case 'L':
  1403.                         listmsgs(atol(cmd+1),-1L);
  1404.                         y=strlen(cmd)-1;
  1405.                         break;
  1406.                     case 'P':
  1407.                         packmsgs(atol(cmd+y+1));
  1408.                         y=strlen(cmd)-1;
  1409.                         break;
  1410.                     case 'R':
  1411.                         readmsgs(atol(cmd+1));
  1412.                         y=strlen(cmd)-1;
  1413.                         break;
  1414.                     case 'V':
  1415.                         viewmsgs(atol(cmd+1),-1L);
  1416.                         y=strlen(cmd)-1;
  1417.                         break;
  1418.                     case 'M':
  1419.                         maint();
  1420.                         break;
  1421.                     default:
  1422.                         printf("%s",usage);
  1423.                         break; }
  1424.             smb_close(&smb); } } }
  1425. if(!cmd[0])
  1426.     printf("%s",usage);
  1427. return(0);
  1428. }
  1429.