home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / BBS / NETMAIL / PKTHDR2.ZIP / PKTHDR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-26  |  32.3 KB  |  978 lines

  1. /*
  2.      06/21/91:  Fixed dumb bug in buffer handling for msgs longer than 8K.
  3.                 Old BASIC habits die hard...
  4.      07/12/91:  You can now redirect stdout and get a "clean" (but not
  5.                 completely raw--hell, you've got the packet) dump of a
  6.                                 packet.
  7.                 Sped up unredirected OS/2 output w/ Vio call.
  8.      12/26/91:  Added resyncing for grunged packets instead of just dying
  9.                 More work on portability
  10. */
  11.  
  12. #ifdef OS2
  13.  #define INCL_DOS
  14.  #define INCL_VIO
  15.  #include <os2.h>
  16. #endif
  17.  #include <stdlib.h>
  18.  #include <stdio.h>
  19.  #include <io.h>
  20.  #include <fcntl.h>
  21.  #include <stdarg.h>
  22.  #include <string.h>
  23.  #include <ctype.h>
  24.  #include <conio.h>
  25.  #include <sys/types.h>
  26.  #include <sys/stat.h>
  27.  
  28. /*
  29.      This code released to public domain 06/16/91 by M. Kimes, who wrote it.
  30.      Compact or large model, byte alignment, unsigned chars.  No toupper()
  31.      macro.  The executables in the archive were compiled with MSC 6.0a
  32.      for MS-DOS and OS/2.  This code isn't extremely portable -- but I've
  33.      written worse... The FSC-0039 and FSC-0048 stuff is from the latest
  34.      info I have, which might well be out of date by now.
  35.      FSC-0045 is the way to go, anyway.  The code originally began
  36.      as just a way to list the addresses in a packet header.  It got out
  37.      of hand.  I figured the least I could do is share it with other
  38.      developers who might have similar needs, thereby saving them the time
  39.      of Yet Another Project.
  40.  
  41.  
  42.      Fingers down the throat of Echopol (or whatever name it masquerades
  43.      under these days)...an unpaid apolitical announcement.  And leave
  44.      my damn soul alone.  I'm saving it.
  45.  
  46.      A word to *ECs who might be tempted to use this program to prove
  47.      software brand x is non-compliant:  remember that the program that
  48.      created a packet isn't necessarily the program that made a "bad"
  49.      message, and that this program is not guaranteed to do more than
  50.      take up space on a disk until you delete it (it might be wrong).
  51.  
  52.      All opinions expressed are my own.  It'd be dumb if I expressed
  53.      yours, wouldn't it?
  54. */
  55.  
  56. #ifndef OS2
  57.     typedef struct {
  58.         char                 reserved[21];      /* reserved by MS-DOS */
  59.         char                 attrFile;          /* attributes */
  60.         unsigned             ftimeLastWrite;    /* time */
  61.         unsigned             fdateLastWrite;    /* date */
  62.         unsigned long        cbFile;            /* file size */
  63.         char                 achName[13];       /* file name */
  64.     } DOSFileData;
  65. #else
  66.     #define DOSFileData FILEFINDBUF
  67. #endif
  68.  
  69. /* include proper header files and create macros */
  70. #if defined OS2
  71.     #define FIND_FIRST(spec,attr,buf) DosFindFirst(spec,&search_handle,attr,buf,sizeof(FILEFINDBUF),&num_matches,0L)
  72.     #define FIND_NEXT(buf) DosFindNext(search_handle,buf,sizeof(FILEFINDBUF),&num_matches)
  73.     #define FIND_CLOSE() DosFindClose(search_handle)
  74.     char * searchpath (char *filename);
  75. #elif defined (_MSC_VER) || defined(_QC) || defined(__WATCOMC)
  76.     #include "direct.h"
  77.     #include "dos.h"
  78.     #define FIND_FIRST(spec, attr, buf) _dos_findfirst(spec, attr, (struct find_t *)buf)
  79.     #define FIND_NEXT(buf) _dos_findnext((struct find_t *)buf)
  80.     #define FIND_CLOSE()
  81.     char *searchpath(char *filename);
  82. #elif defined (__TURBOC__)
  83.     #include "dir.h"
  84.     #define FIND_FIRST(spec, attr, buf) findfirst(spec, (struct ffblk *)buf,attr)
  85.     #define FIND_NEXT(buf) findnext((struct ffblk *)buf)
  86.         #define FIND_CLOSE()
  87.         #ifdef putchar
  88.             #undef putchar
  89.             int putchar (int ch);
  90.         #endif
  91. #elif defined (__ZTC__)
  92.     #include "dos.h"
  93.     #define FIND_FIRST(spec, attr, buf) dos_findfirst(spec, attr, (struct DOS_FIND *)buf)
  94.     #define FIND_NEXT(buf) dos_findnext((struct DOS_FIND *)buf)
  95.     #define FIND_CLOSE(buf)
  96.     char *searchpath(char *filename);
  97. #endif
  98.  
  99. typedef struct  {     /* FSC-0045 */
  100.     unsigned int
  101.         onode,
  102.         dnode,
  103.         opoint,
  104.         dpoint;
  105.     char
  106.         zeros[8];
  107.     unsigned int
  108.         subver,       /* 2 */
  109.         version,      /* 2 */
  110.         onet,
  111.         dnet;
  112.     char
  113.         product,
  114.         rev_lev,
  115.         password[8];
  116.     unsigned int
  117.         ozone,
  118.         dzone;
  119.     char
  120.         odomain[8],
  121.         ddomain[8];
  122.     long
  123.         specific;
  124. } NEWPKTHDR;
  125.  
  126. typedef struct {               /* close to stoneage */
  127.     unsigned int
  128.         orig_node,             /* originating node */
  129.         dest_node,             /* destination node */
  130.         year,                  /* 1989 - nnnnn */
  131.         month,
  132.         day,
  133.         hour,
  134.         minute,
  135.         second,
  136.         rate,                  /* unused */
  137.         ver,                   /* 2 */
  138.         orig_net,              /* originating net */
  139.         dest_net;              /* destination net */
  140.      char
  141.         product,
  142.         rev_lev,               /* revision level */
  143.         password[8];
  144.      unsigned int
  145.         qm_orig_zone,
  146.         qm_dest_zone;
  147.      char
  148.                 domain[8];
  149.      unsigned int
  150.         orig_zone,             /* originating zone */
  151.         dest_zone,             /* destination zone */
  152.         orig_point,            /* originating point */
  153.         dest_point;            /* destination point */
  154.      long
  155.         pr_data;
  156. } OLDPKTHDR;
  157.  
  158. typedef struct {               /* FSC-0039 */
  159.     unsigned int
  160.         orig_node,             /* originating node */
  161.         dest_node,             /* destination node */
  162.         year,                  /* 1989 - nnnnn */
  163.         month,
  164.         day,
  165.         hour,
  166.         minute,
  167.         second,
  168.         rate,                  /* unused */
  169.         ver,                   /* 2 */
  170.         orig_net,              /* originating net */
  171.         dest_net;              /* destination net */
  172.      char
  173.         product,
  174.         rev_lev,               /* revision level */
  175.         password[8];
  176.      unsigned int
  177.         qm_orig_zone,
  178.         qm_dest_zone;
  179.      char
  180.         filler[2];
  181.      unsigned int
  182.         capword2;
  183.      char
  184.         product2,
  185.         rev_lev2;
  186.      unsigned int
  187.         capword,
  188.         orig_zone,             /* originating zone */
  189.         dest_zone,             /* destination zone */
  190.         orig_point,            /* originating point */
  191.         dest_point;            /* destination point */
  192.      long
  193.         pr_data;
  194. } MEDPKTHDR;
  195.  
  196. typedef struct {               /* FSC-0048 */
  197.     unsigned int
  198.         orig_node,             /* originating node */
  199.         dest_node,             /* destination node */
  200.         year,                  /* 1989 - nnnnn */
  201.         month,
  202.         day,
  203.         hour,
  204.         minute,
  205.         second,
  206.         rate,                  /* unused */
  207.         ver,                   /* 2 */
  208.         orig_net,              /* originating net */
  209.         dest_net;              /* destination net */
  210.      char
  211.         product,
  212.         rev_lev,               /* revision level */
  213.         password[8];
  214.      unsigned int
  215.         qm_orig_zone,
  216.         qm_dest_zone,
  217.         aux_net;
  218.      unsigned int
  219.         capword2;
  220.      char
  221.         product2,
  222.         rev_lev2;
  223.      unsigned int
  224.         capword,
  225.         orig_zone,             /* originating zone */
  226.         dest_zone,             /* destination zone */
  227.         orig_point,            /* originating point */
  228.         dest_point;            /* destination point */
  229.      long
  230.         pr_data;
  231. } MEDPKTHDR2;
  232.  
  233. /*--------------------------------------------------------------------------*/
  234. /* FIDO Message attributes (attr) (informational)                           */
  235. /*--------------------------------------------------------------------------*/
  236. #define MSGPRIVATE 0x0001  /* private message,          0000 0000 0000 0001 */
  237. #define MSGCRASH   0x0002  /* accept for forwarding     0000 0000 0000 0010 */
  238. #define MSGREAD    0x0004  /* read by addressee         0000 0000 0000 0100 */
  239. #define MSGSENT    0x0008  /* sent OK (remote)          0000 0000 0000 1000 */
  240. #define MSGFILE    0x0010  /* file attached to msg      0000 0000 0001 0000 */
  241. #define MSGFWD     0x0020  /* being forwarded           0000 0000 0010 0000 */
  242. #define MSGORPHAN  0x0040  /* unknown dest node         0000 0000 0100 0000 */
  243. #define MSGKILL    0x0080  /* kill after mailing        0000 0000 1000 0000 */
  244. #define MSGLOCAL   0x0100  /* FidoNet vs. local         0000 0001 0000 0000 */
  245. #define MSGXX1     0x0200  /*                           0000 0010 0000 0000 */
  246. #define MSGXX2     0x0400  /* STRIPPED by FidoNet<tm>   0000 0100 0000 0000 */
  247. #define MSGFRQ     0x0800  /* file request              0000 1000 0000 0000 */
  248. #define MSGRRQ     0x1000  /* receipt requested         0001 0000 0000 0000 */
  249. #define MSGCPT     0x2000  /* is a return receipt       0010 0000 0000 0000 */
  250. #define MSGARQ     0x4000  /* audit trail requested     0100 0000 0000 0000 */
  251. #define MSGURQ     0x8000  /* update request            1000 0000 0000 0000 */
  252.  
  253. typedef struct {
  254.     unsigned int onode,dnode,onet,dnet,attr;
  255.     int          cost;
  256. } MSGHDR;
  257.  
  258. /* functions in this module */
  259.  
  260. int                  printstring            (char *s);
  261. int                  printtext              (char *s);
  262. void                 pause                  (void);
  263. void                 deinit                 (void);
  264. void                 display_product        (unsigned int product,
  265.                                              unsigned int rev_lev);
  266. char *               stripcr                (char *a);
  267. int                  is_stdout_redirected   (void);
  268. int                  (*printfunc)(const char *fmt,...);
  269. int                  (*putfunc)(int c);
  270. #ifdef OS2
  271.     int              fake_printf (const char *szFormat,...);
  272.     int              fake_putchar (int c);
  273. #endif
  274.  
  275.  
  276. /* global variables declared here */
  277.  
  278. int stdout_redirected;  /* gets set if stdout is redirected */
  279.  
  280.  
  281.  
  282.  
  283.  
  284. int main (int argc,char *argv[]) {
  285.  
  286. #ifdef OS2
  287.     SHORT        search_handle;
  288.     USHORT       num_matches;
  289. #endif
  290.     static char  buffer[8194];
  291.     static char  attrstr[16][11] = {
  292.                  "MSGPRIVATE","MSGCRASH","MSGREAD","MSGSENT","MSGFILE","MSGFWD",
  293.                  "MSGORPHAN","MSGKILL","MSGLOCAL","MSGXX1","MSGXX2","MSGFRQ",
  294.                  "MSGRRQ","MSGCPT","MSGARQ","MSGURQ"};
  295.     FILE         *fp;
  296.     OLDPKTHDR    po;
  297.     NEWPKTHDR    *pn;
  298.     MEDPKTHDR    *pm;
  299.     MEDPKTHDR2   *pl;
  300.     DOSFileData  f;
  301.     MSGHDR       mh;
  302.     int          lastargc = 1,numsent,stopsending,retcode;
  303.     size_t       br;
  304.     char         *spec = "*.PKT",*p;
  305.     unsigned int ozone,dzone,anint,msgno,pktno = 0,x;
  306.     long         pos,totalmsgs = 0;
  307.  
  308.  
  309.     printfunc = printf;
  310.     putfunc = putchar;
  311.  
  312.     atexit(deinit);
  313.  
  314.     {
  315.         int handle;
  316.  
  317.         handle = fileno(stdout);
  318.         setmode(handle,O_BINARY);
  319.         handle = fileno(stderr);
  320.         setmode(handle,O_BINARY);
  321.     }
  322.  
  323.     stdout_redirected = is_stdout_redirected();
  324.  
  325. #ifdef OS2
  326.     if(!stdout_redirected) {
  327.         printfunc = fake_printf;
  328.         putfunc = fake_putchar;
  329.     }
  330. #endif
  331.  
  332.     if(!stdout_redirected) {
  333.         fprintf(stderr,"\x1b[0m\x1b[2J\x1b[0;1;34mPacket explorer for developers by M. Kimes  "__DATE__"  "__TIME__
  334.                        "\r\n ANSI emulation required\r\n\r\nControls:\r\n\r\n"
  335.                        "  [P]ause msg (or [Spacebar])\r\n  [S]kip msg\r\n"
  336.                        "  [A]bort pkt (next pkt)\r\n E[X]it\r\n\r\n"
  337.                        "Color codes:\r\n\r\n \x1b[0;1;5;31mSerious\x1b[0;1;31m Error\r\n"
  338.                        " \x1b[0;1;33mPacket header information\r\n"
  339.                        " \x1b[0;1;36mMsg header information\r\n"
  340.                        " \x1b[0mMsg text\r\n"
  341.                        " \x1b[0;1;30;47mHex control code representation\r\n"
  342.                        "\x1b[0;1;32m Summary information\r\n");
  343.     }
  344.     if(argc > 1) {
  345.         spec = argv[1];
  346.         fprintf(stderr,"\r\n Using command line filespec %s\r\n",argv[1]);
  347.         lastargc++;
  348.     }
  349.     else {
  350.         fprintf(stderr,"\r\n Using filespecs *.PKT and *.?U?");
  351. #ifdef OS2
  352.         fprintf(stderr," and P.*.*.*.*.*");
  353. #endif
  354.         if(!stdout_redirected)
  355.           fprintf(stderr,"\r\n\x1b[0;1;34m\r\nYou can also pass a filespec on the command line.\r\n");
  356.     }
  357.     if(!stdout_redirected) {
  358.         fprintf(stderr,"\r\n\x1b[0;1;34m[Any Key to begin]");
  359.         getch();
  360.         (*printfunc)("\x1b[2J");
  361.     }
  362.  
  363.     pn = (NEWPKTHDR *)&po;
  364.     pl = (MEDPKTHDR2 *)&po;
  365.     pm = (MEDPKTHDR *)&po;
  366.  
  367. OverAgain:
  368.  
  369. #ifdef OS2
  370.     search_handle = -1;
  371.     num_matches = 1;
  372. #endif
  373.  
  374.     do {
  375.         p = strchr(spec,'\\');
  376.         if(p) *p = '/';
  377.     } while(p);
  378.  
  379.     p = strrchr(spec,'/');
  380.     if(!p) p = strrchr(spec,':');
  381.     if(p) {
  382.         p++;
  383.     }
  384.  
  385.     if(!FIND_FIRST(spec,0,&f)) {
  386.         do {
  387.             pktno++;
  388.             msgno = 0;
  389.             if(p) {
  390.                 *p = 0;
  391.                 sprintf(buffer,"%s%s",spec,f.achName);
  392.             }
  393.             else strcpy(buffer,f.achName);
  394.             fp = fopen(buffer,"rb");
  395.             if(!stdout_redirected) (*printfunc)("\x1b[0;1;33m");
  396.             if(!fp) {
  397.                 (*printfunc)("\r\n");
  398.                 if(!stdout_redirected) (*printfunc)("\x1b[0;1;5;31m");
  399.                 (*printfunc)("Couldn't open packet \"%s\"\r\n",f.achName);
  400.                 if(!stdout_redirected) (*printfunc)("\x1b[0m");
  401.             }
  402.             else {
  403.                 br = fread(&po,1,sizeof(OLDPKTHDR),fp);
  404.                 if(br < sizeof(OLDPKTHDR)) {
  405.                     (*printfunc)("\r\n");
  406.                     if(!stdout_redirected) (*printfunc)("\x1b[0;1;5;31m");
  407.                     (*printfunc)("Packet %s short:  %u byte%s",f.achName,br,&"s"[1 == br]);
  408.                 }
  409.                 else if(po.ver != 2) {
  410.                     (*printfunc)("\r\n");
  411.                     if(!stdout_redirected) (*printfunc)("\x1b[0;1;5;31m");
  412.                     (*printfunc)("\"%s\" not version 2.x; may not be a packet",f.achName);
  413.                     pktno--;
  414.                 }
  415.                 else {
  416.                     if(po.rate == 2) {  /* preferred method */
  417.                         (*printfunc)("\r\nFSC-0045 (AKA version 2.2) packet:  \"%s\"",f.achName);
  418.                         (*printfunc)("\r\nFrom %u:%u/%u.%u@%0.8s to %u:%u/%u.%u@%0.8s",
  419.                                pn->ozone,pn->onet,pn->onode,pn->opoint,pn->odomain,
  420.                                pn->dzone,pn->dnet,pn->dnode,pn->dpoint,pn->ddomain);
  421.                         (*printfunc)("\r\nProduced by product #%hu.%hu   Password: \"%0.8s\"",
  422.                                pn->product,pn->rev_lev,pn->password);
  423.                         display_product(pn->product,pn->rev_lev);
  424.                     }
  425.                     else if(pm->capword && pm->capword == (~pm->capword2)) {
  426.                         (*printfunc)("\r\nFSC-0039 (AKA version 2.+) packet:  \"%s\"",f.achName);
  427.                         ozone = pm->orig_zone;
  428.                         dzone = pm->dest_zone;
  429.                         if(!ozone) ozone = pm->qm_orig_zone;
  430.                         if(!dzone) dzone = pm->qm_dest_zone;
  431.                         (*printfunc)("\r\nFrom %u:%u/%u.%u@???????? to %u:%u/%u.%u@????????",
  432.                                ozone,pm->orig_net,pm->orig_node,pm->orig_point,
  433.                                dzone,pm->dest_net,pm->dest_node,pm->dest_point);
  434.                         ozone = pm->product + (pm->product2 << 8);
  435.                         dzone = pm->rev_lev + (pm->rev_lev2 << 8);
  436.                         (*printfunc)("\r\nProduced by product #%u.%u  Password: \"%0.8s\"  Capword: %u",
  437.                                ozone,dzone,pm->password,pm->capword);
  438.                         display_product(ozone,dzone);
  439.                     }
  440.                     else if(pl->capword && pl->capword == pl->capword2) {
  441.                         (*printfunc)("\r\nFSC-0048 (AKA version 2.N) packet:  \"%s\"",f.achName);
  442.                         ozone = pl->orig_zone;
  443.                         dzone = pl->dest_zone;
  444.                         if(!ozone) ozone = pl->qm_orig_zone;
  445.                         if(!dzone) dzone = pl->qm_dest_zone;
  446.                         if(pl->orig_net == 65535U) {
  447.                             (*printfunc)("\r\nFrom %u:%u/%u.0@???????? to %u:%u/%u.%u@????????",
  448.                                    ozone,pl->orig_net,pl->orig_node,
  449.                                    dzone,pl->dest_net,pl->dest_node,pl->dest_point);
  450.                         }
  451.                         else {
  452.                             (*printfunc)("\r\nFrom %u:%u/%u.%u@???????? to %u:%u/%u.%u@????????",
  453.                                    ozone,pl->aux_net,pl->orig_node,pl->orig_point,
  454.                                    dzone,pl->dest_net,pl->dest_node,pl->dest_point);
  455.                         }
  456.                         ozone = pl->product + (pl->product2 << 8);
  457.                         dzone = pl->rev_lev + (pl->rev_lev2 << 8);
  458.                         (*printfunc)("\r\nProduced by product #%u.%u  Password: \"%0.8s\"  Capword: %u",
  459.                                ozone,dzone,pm->password,pm->capword);
  460.                         display_product(ozone,dzone);
  461.                     }
  462.                     else {
  463.                         (*printfunc)("\r\nStoneage (AKA version 2) packet:  \"%s\"",f.achName);
  464.                         ozone = po.qm_orig_zone;
  465.                         dzone = po.qm_dest_zone;
  466.                         if(!ozone) ozone = po.orig_zone;
  467.                         if(!dzone) dzone = po.dest_zone;
  468.                         (*printfunc)("\r\nFrom %u:%u/%u.%u@???????? to %u:%u/%u.%u@%0.8s",
  469.                                ozone,po.orig_net,po.orig_node,po.orig_point,
  470.                                dzone,po.dest_net,po.dest_node,po.dest_point,
  471.                                po.domain);
  472.                         (*printfunc)("\r\nProduced by #%hu.%hu  Password: \"%0.8s\"",
  473.                                po.product,po.rev_lev,po.password);
  474.                         display_product(po.product,po.rev_lev);
  475.                     }
  476.                     for(;;) {
  477. GrungeReSync:
  478.                         if(!fread(&anint,sizeof(int),1,fp)) {
  479.                             (*printfunc)("\r\n");
  480.                             if(!stdout_redirected) (*printfunc)("\x1b[0;1;5;31m");
  481.                             (*printfunc)("Unexpected end of packet");                           break;
  482.                         }
  483.                         if(!anint || anint != 2) {
  484.                             if(!anint) {
  485.                                 (*printfunc)("\r\n");
  486.                                 if(!stdout_redirected) (*printfunc)("\x1b[0;1;32m");
  487.                                 (*printfunc)("End of packet: %u msg%s",
  488.                                        msgno,&"s"[1 == msgno]);
  489.                             }
  490.                             else {
  491.                                 (*printfunc)("\r\n");
  492.                                 if(!stdout_redirected) (*printfunc)("\x1b[0;1;5;31m");
  493.                                 (*printfunc)("Grunged packet: attempting resync, expect some garbage");
  494.                                 if(kbhit() && toupper(getch()) == 'A') {
  495.                                     (*printfunc)("\r\nKeyboard abort\r\n");
  496.                                     break;
  497.                                 }
  498.                                 fseek(fp,-1L,SEEK_CUR);
  499.                                 goto GrungeReSync;
  500.                             }
  501.                             break;
  502.                         }
  503.                         br = fread(&mh,1,sizeof(mh),fp);
  504.                         if(br < sizeof(mh)) {
  505.                             (*printfunc)("\r\n");
  506.                             if(!stdout_redirected) (*printfunc)("\x1b[0;1;5;31m");
  507.                             (*printfunc)("Incomplete msg header");
  508.                             break;
  509.                         }
  510.                         (*printfunc)("\r\n\r\n");
  511.                         if(!stdout_redirected) (*printfunc)("\x1b[0;1;36m");
  512.                         (*printfunc)("Msg #%u from %u/%u to %u/%u",++msgno,
  513.                                mh.onet,mh.onode,mh.dnet,mh.dnode);
  514.                         (*printfunc)("  *  Attrib: %u  Cost: %d",mh.attr,mh.cost);
  515.                         totalmsgs++;
  516.                         if(mh.attr) {
  517.                             (*printfunc)("\r\n");
  518.                             for(x = 0;x < 16;x++) {
  519.                                 if(mh.attr & (1 << x)) (*printfunc)("%s ",attrstr[x]);
  520.                             }
  521.                         }
  522.                         pos = ftell(fp);
  523.                         br = fread(buffer,1,20,fp);
  524.                         if(br < 20) {
  525.                             (*printfunc)("\r\n");
  526.                             if(!stdout_redirected) (*printfunc)("\x1b[0;1;5;31m");
  527.                             (*printfunc)("Incomplete msg header");
  528.                             break;
  529.                         }
  530.                         for(x = 0;x < 19;x++) {
  531.                             if(buffer[x] == 0) break;
  532.                         }
  533.                         if(x == 19 && buffer[19] == 0) (*printfunc)("\r\nDate: ");
  534.                         else {
  535.                             (*printfunc)("\r\n");
  536.                             if(!stdout_redirected) (*printfunc)("\x1b[0;1;5;36m");
  537.                             (*printfunc)("Grunged");
  538.                             if(!stdout_redirected) (*printfunc)("\x1b[0;1;36m");
  539.                             (*printfunc)(" date: ");
  540.                         }
  541.                         buffer[19] = 0;
  542.                         if(printstring(buffer) == -1) goto NextPacket;
  543.                         fseek(fp,pos + (long)strlen(buffer) + 1L,SEEK_SET);
  544.                         pos = ftell(fp);
  545.                         if(!fread(buffer,1,36,fp)) {
  546.                             (*printfunc)("\r\n");
  547.                             if(!stdout_redirected) (*printfunc)("\x1b[0;1;5;31m");
  548.                             (*printfunc)("Incomplete msg header");
  549.                             break;
  550.                         }
  551.                         for(x = 0;x < 36;x++) {
  552.                             if(buffer[x] == 0) break;
  553.                         }
  554.                         if(x == 36) {
  555.                             (*printfunc)("\r\n");
  556.                             if(!stdout_redirected) (*printfunc)("\x1b[0;1;5;36m");
  557.                             (*printfunc)("Grunged");
  558.                             if(!stdout_redirected) (*printfunc)("\x1b[0;1;36m");
  559.                             (*printfunc)(" to: ");
  560.                         }
  561.                         else (*printfunc)("\r\nTo:   ");
  562.                         buffer[35] = 0;
  563.                         if(printstring(buffer) == -1) goto NextPacket;
  564.                         fseek(fp,pos + (long)strlen(buffer) + 1L,SEEK_SET);
  565.                         pos = ftell(fp);
  566.                         if(!fread(buffer,1,36,fp)) {
  567.                             (*printfunc)("\r\n");
  568.                             if(!stdout_redirected) (*printfunc)("\x1b[0;1;5;31m");
  569.                             (*printfunc)("Incomplete msg header");
  570.                             break;
  571.                         }
  572.                         for(x = 0;x < 36;x++) {
  573.                             if(buffer[x] == 0) break;
  574.                         }
  575.                         if(x == 36) {
  576.                             (*printfunc)("\r\n");
  577.                             if(!stdout_redirected) (*printfunc)("\x1b[0;1;5;36m");
  578.                             (*printfunc)("Grunged");
  579.                             if(!stdout_redirected) (*printfunc)("\x1b[0;1;36m");
  580.                             (*printfunc)(" from: ");
  581.                         }
  582.                         else (*printfunc)("\r\nFrom: ");
  583.                         buffer[35] = 0;
  584.                         if(printstring(buffer) == -1) goto NextPacket;
  585.                         fseek(fp,pos + (long)strlen(buffer) + 1L,SEEK_SET);
  586.                         pos = ftell(fp);
  587.                         if(!fread(buffer,1,72,fp)) {
  588.                             (*printfunc)("\r\n");
  589.                             if(!stdout_redirected) (*printfunc)("\x1b[0;1;5;31m");
  590.                             (*printfunc)("Incomplete msg header");
  591.                             break;
  592.                         }
  593.                         for(x = 0;x < 36;x++) {
  594.                             if(buffer[x] == 0) break;
  595.                         }
  596.                         if(x == 72) {
  597.                             (*printfunc)("\r\n");
  598.                             if(!stdout_redirected) (*printfunc)("\x1b[0;1;5;36m");
  599.                             (*printfunc)("Grunged");
  600.                             if(!stdout_redirected) (*printfunc)("\x1b[0;1;36m");
  601.                             (*printfunc)(" subj: ");
  602.                         }
  603.                         else (*printfunc)("\r\nSubj: ");
  604.                         buffer[71] = 0;
  605.                         if(printstring(buffer) == -1) goto NextPacket;
  606.                         fseek(fp,pos + (long)strlen(buffer) + 1L,SEEK_SET);
  607.                         pos = ftell(fp);
  608.                         memset(buffer,0,8193);
  609.                         if(!fread(buffer,1,8192,fp)) {
  610.                             (*printfunc)("\r\n");
  611.                             if(!stdout_redirected) (*printfunc)("\x1b[0;1;5;31m");
  612.                             (*printfunc)("No msg text");
  613.                             break;
  614.                         }
  615.                         stopsending = 0;
  616.                         do {
  617.                             for(x = 0;x < 8192;x++) {
  618.                                 if(buffer[x] == 0) break;
  619.                             }
  620.                             if(!x) break;
  621.                             buffer[8192] = 0;
  622.                             numsent = min(8192,x);
  623.                             if(!stdout_redirected) (*printfunc)("\x1b[0m");
  624.                             (*printfunc)("\r\n");
  625.                             if(!stopsending) {
  626.                                 retcode = printtext(buffer);
  627.                                 if(retcode == -1) goto NextPacket;
  628.                                 if(retcode < numsent) stopsending++;
  629.                             }
  630.                             if(x == 8192) {
  631.                                 pos = ftell(fp);
  632.                                 memset(buffer,0,8193);
  633.                                 if(!fread(buffer,1,8192,fp)) {
  634.                                     (*printfunc)("\r\n");
  635.                                     if(!stdout_redirected) (*printfunc)("\x1b[0;1;5;31m");
  636.                                     (*printfunc)("Premature end of message");
  637.                                     goto NextPacket;
  638.                                 }
  639.                             }
  640.                         } while(x == 8192);
  641.                         fseek(fp,pos + (long)strlen(buffer) + 1L,SEEK_SET);
  642.                         pos = ftell(fp);
  643.                     }
  644. NextMsg:
  645.                     if(!stdout_redirected) (*printfunc)("\x1b[0m");
  646.                     (*printfunc)("\r\n");
  647.                 }
  648. NextPacket:
  649.                 fclose(fp);
  650.             }
  651.  
  652. #ifdef OS2
  653.             num_matches = 1;
  654. #endif
  655.  
  656.         } while(!FIND_NEXT(&f));
  657.         FIND_CLOSE();
  658.     }
  659.  
  660.     if(!stricmp(spec,"*.PKT")) {
  661.         spec = "*.?U?";
  662.         goto OverAgain;
  663.     }
  664. #ifdef OS2
  665.     else if(!stricmp(spec,"*.?U?")) {
  666.         spec = "P.*.*.*.*.*";
  667.         goto OverAgain;
  668.     }
  669. #endif
  670.     else {
  671.         if(argc > lastargc) {
  672.             spec = argv[lastargc++];
  673.             fprintf(stderr,"\r\n\x1b[0;1;32m Using command line filespec %s",spec);
  674.             goto OverAgain;
  675.         }
  676.     }
  677.     if(!pktno) {
  678.         (*printfunc)("\r\n");
  679.         if(!stdout_redirected) (*printfunc)("\x1b[0;1;32m");
  680.         (*printfunc)("No packets were found.");
  681.     }
  682.     else {
  683.         (*printfunc)("\r\n");
  684.         if(!stdout_redirected) (*printfunc)("\x1b[0;1;32m");
  685.         (*printfunc)("Found %u packet%s w/ %lu msg%s",
  686.                pktno,&"s"[1 == pktno],totalmsgs,&"s"[1L == totalmsgs]);
  687.     }
  688.  
  689.     return 0;
  690. }
  691.  
  692.  
  693. int printstring (char *s) {
  694.  
  695.     unsigned int x;
  696.     int          kp;
  697.  
  698.  
  699.     (*putfunc)('\"');
  700.     for(x = 0; x < 8192;x++) {
  701.         if(!s[x]) break;
  702.         if(isprint(s[x])) (*putfunc)(s[x]);
  703.         else {
  704.             if(!stdout_redirected)
  705.               (*printfunc)("\x1b[0;1;30;46m%02hx\x1b[0;1;36m",s[x]);
  706.             else (*putfunc)(s[x]);
  707.         }
  708.     }
  709.     (*putfunc)('\"');
  710.     if(!stdout_redirected) {
  711.         if(kbhit()) {
  712.             kp = toupper(getch());
  713.             switch(kp) {
  714.                 case ' ':
  715.                 case 'P':   pause();
  716.                             break;
  717.                 case 'X':   exit(3);
  718.                 case 'A':   return -1;
  719.             }
  720.         }
  721.     }
  722.     return x;
  723. }
  724.  
  725.  
  726.  
  727. int printtext (char *s) {
  728.  
  729.     unsigned int x;
  730.     int          kp;
  731.  
  732.  
  733.     for(x = 0; x < 8192;x++) {
  734.         if(!s[x]) break;
  735.         if(isprint(s[x])) (*putfunc)(s[x]);
  736.         else if(s[x] == '\r' || !(x % 79)) {
  737.             if(s[x] == '\r') {
  738.                 if(!stdout_redirected)
  739.                   (*printfunc)("\x1b[0;30;47;1m%02hx\x1b[0m",s[x]);
  740.                 (*printfunc)("\r\n");
  741.             }
  742.             if(!stdout_redirected) {
  743.                 if(kbhit()) {
  744.                     kp = toupper(getch());
  745.                     switch(kp) {
  746.                         case ' ':
  747.                         case 'P':   pause();
  748.                                     break;
  749.                         case 'S':   goto BreakOut;
  750.                         case 'X':   exit(3);
  751.                         case 'A':   return -1;
  752.                     }
  753.                 }
  754.             }
  755.         }
  756.         else {
  757.             if(!stdout_redirected)
  758.               (*printfunc)("\x1b[0;30;47;1m%02hx\x1b[0m",s[x]);
  759.             else {
  760.                 if(s[x] != '\n') (*putfunc)(s[x]);
  761.             }
  762.         }
  763.     }
  764.  
  765. BreakOut:
  766.  
  767.     return x;
  768. }
  769.  
  770.  
  771.  
  772. void pause (void) {
  773.  
  774.     int kp;
  775.  
  776.  
  777.     if(stdout_redirected) return;
  778.     do {
  779.         while(kbhit()) getch();
  780.         kp = toupper(getch());
  781.     } while(kp == 'P');
  782. }
  783.  
  784.  
  785.  
  786. void deinit (void) {
  787.  
  788.     if(!stdout_redirected) printf("\x1b[0m");
  789.     printf("\r\n");
  790.     fcloseall();
  791. }
  792.  
  793.  
  794.  
  795. void display_product (unsigned int product,unsigned int rev_lev) {
  796.  
  797.     char          s[133],*p;
  798.     unsigned int  prod;
  799.     FILE          *fp;
  800.  
  801.  
  802.     if(!product) {
  803.         (*printfunc)("\r\nFido <tm> or an unregistered product rev %u",rev_lev);
  804.         return;
  805.     }
  806.  
  807.     p = searchpath("FTSCPROD.LST");
  808.     if(p) {
  809.         fp = fopen(p,"rt");
  810.         if(!fp) {
  811.             (*printfunc)("\r\n");
  812.             if(!stdout_redirected) (*printfunc)("\x1b[0;1;31m");
  813.             (*printfunc)("Couldn't open %s",p);
  814.             if(!stdout_redirected) (*printfunc)("\x1b[0;1;33m");
  815.             return;
  816.         }
  817.         while(!feof(fp)) {
  818.             if(!fgets(s,132,fp)) break;
  819.             if(*s != ';') {
  820.                 p = s;
  821.                 prod = (unsigned int)strtol(s,&p,16);
  822.                 if(prod == product) {
  823.                     if(*p) {
  824.                         p++;
  825.                         stripcr(p);
  826.                         (*printfunc)("\r\n%s rev %u",p,rev_lev);
  827.                     }
  828.                     else (*printfunc)("\r\n??? rev %u",rev_lev);
  829.                     fclose(fp);
  830.                     return;
  831.                 }
  832.             }
  833.         }
  834.         fclose(fp);
  835.     }
  836.     (*printfunc)("\r\nUnknown product rev %u",rev_lev);
  837. }
  838.  
  839.  
  840. #if defined OS2
  841. char * searchpath (char *filename) {
  842.  
  843.     static char fbuf[1027];
  844.  
  845.  
  846.     if(DosSearchPath(3,"PATH",filename,fbuf,1027)) {
  847.         return NULL;
  848.     }
  849.     return fbuf;
  850. }
  851.  
  852. #elif !defined __TURBOC__
  853.  
  854. char *searchpath (char *filename) {
  855.  
  856.     static char fbuf[153];
  857.     struct stat st;
  858.     char        *envbuf = NULL,*p,temp;
  859.  
  860.  
  861.     p = getenv("PATH");
  862.     if(!p) return filename;
  863.     envbuf = strdup(p);
  864.     if(!envbuf) return filename;
  865.  
  866.     p = strtok(envbuf,";");
  867.     do {
  868.         strncpy(fbuf,p,128);
  869.         fbuf[128] = 0;
  870.         temp = fbuf[strlen(fbuf) - 1];
  871.         if(temp != '/' && temp != '\\') strcat(fbuf,"\\");
  872.         strcat(fbuf,filename);
  873.         if(!stat(fbuf,&st)) {
  874.             if(envbuf) free(envbuf);
  875.             return fbuf;
  876.         }
  877.         p = strtok(0,";");
  878.     } while(p);
  879.     if(envbuf) free(envbuf);
  880.     return NULL;
  881. }
  882.  
  883. #endif
  884.  
  885.  
  886.  
  887. char * stripcr (char *a) {
  888.  
  889.     register int x;
  890.  
  891.  
  892.     x = strlen(a);
  893.     while (x && (a[x - 1] == '\n' || a[x - 1] == '\r')) a[--x] = 0;
  894.     return a;
  895.  
  896. }
  897.  
  898.  
  899. int is_stdout_redirected (void) {
  900.  
  901.     /* check to see if stdout is redirected.  return non-zero if so */
  902.  
  903. #ifdef OS2
  904.     unsigned int info,devhead;
  905. #else
  906.     union REGS   rg;
  907. #endif
  908.  
  909. #ifndef OS2
  910.  
  911.     rg.h.ah = 0x44;
  912.     rg.h.al = 0x00;
  913.     rg.x.bx = fileno(stdout);
  914.     int86(0x21,&rg,&rg);
  915.         if(!rg.x.cflag) {
  916.         if(rg.x.dx & 128) {
  917.            if(rg.x.dx & 2) return 0;
  918.         }
  919.     }
  920.     return 1;
  921.  
  922. #else
  923.  
  924.     DosQHandType(fileno(stdout),&info,&devhead);
  925.     if(((info & 255) == 1) && (devhead & 2)) return 0;
  926.     return 1;
  927.  
  928. #endif
  929. }
  930.  
  931.  
  932.  
  933. #ifdef OS2
  934.  
  935. int fake_printf (const char *szFormat,...) {
  936.  
  937.     /* print through ANSI but not necessarily stdout */
  938.  
  939.     int         len;
  940.     static char chBuffer[9000];     /* tacky, but who cares... */
  941.     va_list     pArguments;
  942.  
  943.  
  944.     va_start(pArguments,szFormat);
  945.     len = vsprintf(chBuffer,szFormat,pArguments);
  946.     va_end(pArguments);
  947.     VioWrtTTY(chBuffer,len,0);
  948.     return len;
  949. }
  950.  
  951.  
  952. int fake_putchar (int c) {
  953.  
  954.     /* print through ANSI but not necessarily stdout */
  955.  
  956.     char cc = (char)c;
  957.  
  958.  
  959.     VioWrtTTY(&cc,1,0);
  960.     return 1;
  961. }
  962.  
  963. #endif
  964.  
  965.  
  966.  
  967.  
  968.  
  969. #ifdef __TURBOC__
  970.  
  971.  
  972. int putchar (int ch) {
  973.  
  974.         return (putc(ch,stdout));
  975. }
  976.  
  977. #endif
  978.