home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / modem / byepc300.arc / BYEXMDM.ARC / XMDM.C < prev    next >
Text File  |  1987-10-28  |  29KB  |  1,097 lines

  1. /*
  2. ** Program:    <xmdm.c>
  3. **
  4. ** Purpose:    Allows XMDM file transmission for use with BYE-PC.
  5. **
  6. ** Date:    02/29/85
  7. **
  8. ** Requirments: Requires the following modules to compile and link:
  9. **
  10. **            <xmdm.c>        ;main xmodem source code module.
  11. **            <crc.asm>        ;crc & timing utilities.
  12. **            <byexface.c>    ;modem i/o interface to BYE-PC.
  13. ** Revisions:
  14. **
  15. **  Ver: 1.08    Modified 'xmdm_nak()' to switch receive modes
  16. **  03/15/87    after 10 retries in either CRC or Checksum.
  17. **
  18. **  Ver: 1.09    Modified 'get_a_block()' and 'put_a_block()' to clear
  19. **  03/15/87    the buffers before filling it with data. The old
  20. **        functions left trash in the buffer, which ended up
  21. **        in the last block of the file rather than nulls.
  22. **
  23. **  Ver: 1.10    Added 'drx_flush()' to handle resync after many
  24. **  05/21/87    severe noise errors. Added Ctrl-Break disable on
  25. **        local keyboard.
  26. **
  27. **  Ver: 1.11    Fixed bugs in xrecvbuf().
  28. **  06/01/87
  29. **
  30. **  Ver: 1.12    More bugs, version 1.11 would randomly lockup
  31. **  06/01/87    the system. I have trashed the C functions in
  32. **        'timer()' and 'getticks()' with an assembly
  33. **        timing function. This assembly function was added
  34. **        to the module 'crc.asm'.
  35. **
  36. **  Ver: 1.13    Tweaked the timing values used in 'xrecvbuf()'
  37. **  08/03/87    to offer better error recovery.
  38. **
  39. **  Ver: 1.14    Altered all function names used to access BYE-PC.
  40. **  08/08/87    All function that use BYE-PC functions are now
  41. **        preceeded by '_bye_".
  42. **
  43. **  Ver: 1.15    Moved carrier checking inside of tx and rx buffer
  44. **  08/08/87    routines. Modified the transmit block counter in
  45. **        the function 'xpreface()'.
  46. */
  47.  
  48.     /* Include Headers */
  49.  
  50. #include    <stdio.h>
  51. #include    <stdlib.h>
  52. #include    <conio.h>
  53. #include    <io.h>
  54. #include    <dos.h>
  55. #include    <ctype.h>
  56. #include    <string.h>
  57. #include    <process.h>
  58. #include    <fcntl.h>
  59. #include    <sys/types.h>
  60. #include    <sys/stat.h>
  61. #include    "byexface.h"
  62.  
  63.  
  64.     /* xmodem configuration */
  65.  
  66. #define P_UPLOAD    /* define for private uploads */
  67. #define C_STATUS    /* check status before uploading & dnloading */
  68. /* #define C_EXE    /* .COM & .EXE files are invalid to send */
  69.  
  70. #ifdef P_UPLOAD
  71.   #define P_PATH    "C:\\UPLOADS\\"   /* private upload path */
  72. #endif
  73.  
  74.     /* end xmodem configuration */
  75.  
  76. #define VER    1    /* XMODEM Version# */
  77. #define REV    16    /* XMODEM Revision# */
  78.  
  79. #define YES    1    /* generic defines */
  80. #define NO     0
  81. #define ON     1
  82. #define OFF    0
  83. #define TRUE   1
  84. #define FALSE  0
  85.  
  86. #define SOH 1        /* communications defines */
  87. #define CRC 'C'
  88. #define EOT 4
  89. #define ACK 6
  90. #define NAK 0x15
  91.  
  92. #define CTRL_X    0x18    /* xmdm abort keys */
  93. #define CTRL_C    0x03
  94.  
  95. #define BYE_VER 3    /* requires BYE-PC version 3.00 or greater */
  96. #define BYE_REV 0
  97.  
  98. #define BIT_4    16    /* xmdm send flag */
  99. #define BIT_5    32    /* xmdm receive flag */
  100.  
  101. #define BLKSIZ 128    /* xmdm block size */
  102.  
  103.     /* function declarations */
  104.  
  105. void xmodem_optns(), timer();
  106. void drx_flush();
  107. void xmdm_rxblk();
  108. void check_cd();
  109.  
  110. int xmdm_init();
  111. int xmdm_send(), get_a_block();
  112. int xmdm_receive(), put_a_block(), xpreface(), xsendbuf();
  113. int xrecvbuf(), xmdm_nak(), mdm_tgetc(), mdm_tputc();
  114. int executable();
  115.  
  116. long getticks();
  117.  
  118.     /* external assembler routines */
  119.  
  120. extern unsigned crc_value();
  121. extern void crc_init(), crc_sum(), ctrl_break();
  122.  
  123.  
  124.     /* static declarations */
  125.  
  126. char First;        /* first block sent flag */
  127. int Crcflg;        /* crc mode flag */
  128. int Blkcnt;        /* logical block counter  (no reset) */
  129. int Blkhdr;        /* physical block counter  (0 - 255) */
  130.  
  131.  
  132. /*-------------------------------------------------------------------*/
  133. /*  This function responds to xmdm commands and scans the file name  */
  134. /*  for correct format & paramters. If all is ok, then the send or   */
  135. /*  receive command is called with the given file name.          */
  136. /*-------------------------------------------------------------------*/
  137.  
  138. main(argc, argv)
  139.  
  140.  int argc;
  141.  char *argv[];
  142.     {
  143.     char fname[32], optns[3];
  144.     int rtn;
  145.     unsigned cstat;
  146.  
  147.     if (argc < 3)
  148.     {
  149.     xmodem_optns();             /* show error msg */
  150.     exit(1);                /* exit back to dos */
  151.     }
  152.     if (rtn = _bye_check(BYE_VER, BYE_REV))
  153.     {
  154.     printf("\nXMODEM ERROR: BYE-PC ");
  155.     switch(rtn)
  156.         {
  157.         case 1:
  158.         printf("is not loaded!\n");
  159.         break;
  160.         case 2:
  161.         printf("loaded is the wrong Version!\n");
  162.         break;
  163.         case 3:
  164.         printf("loaded is the wrong Revision!\n");
  165.         break;
  166.         default:
  167.         printf("returned invalid error code!\n");
  168.         break;
  169.         }
  170.     exit(1);
  171.     }
  172.  
  173.     ctrl_break(OFF);            /* disable local ctrl-break */
  174.     _bye_setbreak(CTRL_NOTRAP);     /* dont trap/filter ^C & ^S data */
  175.     _bye_setcd(OFF);            /* disable CD loss checking */
  176.  
  177.     strncpy(optns, argv[1], 2);     /* get xmdm options */
  178.     strncpy(fname, argv[2], 31);    /* get file name */
  179.     if (toupper((int)optns[1]) == 'C')    /* test for Checksum mode only */
  180.        Crcflg = NO;
  181.     else
  182.        Crcflg = YES;
  183.  
  184.     cstat = _bye_getcsw() & 0x003F;    /* get xmdm status bits */
  185.     switch(toupper((int)optns[0]))    /* Tx or Rx a file? */
  186.     {
  187.     case 'S':            /* is it send command? */
  188.       #ifdef C_STATUS
  189.         if (!(cstat & BIT_4))
  190.         {
  191.         printf("\nSorry, Uploads not permitted at this time...\n");
  192.         break;
  193.         }
  194.       #endif
  195.       #ifdef C_EXE
  196.         if (executable(fname) && (cstat != 0xffff))
  197.         {
  198.         printf("\nSorry, can't send .EXE and .COM files...\n");
  199.         break;
  200.         }
  201.       #endif
  202.         xmdm_send(fname);        /* try to send file */
  203.         break;
  204.  
  205.     case 'R':            /* is it receive command? */
  206.       #ifdef C_STATUS
  207.         if (!(cstat & BIT_5))
  208.         printf("\nSorry, Downloads not permitted at this time...\n");
  209.         else
  210.       #endif
  211.         xmdm_receive(fname);    /* try to receive a file */
  212.         break;
  213.  
  214.     default:
  215.         xmodem_optns();        /* show error msg */
  216.         break;
  217.     }
  218.     _bye_stdout(ON);        /* turn on console Rx & Tx */
  219.     _bye_stdin(ON);
  220.     _bye_setcd(ON);        /* enable carrier loss checking */
  221.     _bye_setbreak(CTRL_TRAP);    /* enable trap ^C & ^S data */
  222.     ctrl_break(ON);        /* reenable local ctrl-break */
  223.     exit(0);            /* exit back to DOS */
  224.     }
  225.  
  226. /*-------------------------------------------------------------------*/
  227. /*  Scan file name for a .COM or .EXE file extension             */
  228. /*-------------------------------------------------------------------*/
  229.  
  230. #ifdef C_EXE
  231. int executable(fname)
  232.  
  233.  char *fname;
  234.     {
  235.     char *p;
  236.  
  237.     if ((p = strchr(fname, '.')) == NULL)
  238.     return(0);
  239.     else
  240.     {
  241.     if (!strncmp(p, ".COM", 4))
  242.         return(1);
  243.     if (!strncmp(p, ".EXE", 4))
  244.         return(1);
  245.     }
  246.     return(0);
  247.     }
  248. #endif
  249.  
  250. /*-------------------------------------------------------------------*/
  251. /*  Show list of valid XMODEM options to user.                 */
  252. /*-------------------------------------------------------------------*/
  253.  
  254. void xmodem_optns()
  255.  {
  256.  printf("\nXMODEM for use with BYE-PC\n");
  257.  printf("Version %1d.%-2.2d Copyright (c) 1986, 1987, MCODE Software\n\n", VER, REV);
  258.  
  259.  printf("\tXMODEM S {d:filename} ---> Send file in CRC mode\n");
  260.  printf("\tXMODEM R {d:filename} ---> Receive file in CRC mode\n");
  261.  printf("\tXMODEM SC {d:filename} --> Send file in Checksum mode\n");
  262.  printf("\tXMODEM RC {d:filename} --> Receive File Checksum mode\n");
  263.  printf("\n[Only the above options are allowed at this time!]\n\n");
  264.  }
  265.  
  266.  
  267. /*-------------------------------------------------------------------*/
  268. /*  XMODEM  U P L O A D   -  S E N D   A   F I L E             */
  269. /*-------------------------------------------------------------------*/
  270. /*  This function is supplied a file name and a crc flag.  The         */
  271. /*  file is searched for on the disk, if the file name exists it     */
  272. /*  is opened for binary read and transmitted in XMODEM protocol.    */
  273. /*-------------------------------------------------------------------*/
  274.  
  275. int xmdm_send(fname)
  276.  
  277. char fname[];
  278.     {
  279.     char buf[BLKSIZ+10];
  280.     int result, igetret, iret, exit, c, bps;
  281.     long ksize, numblocks, stime;
  282.     FILE *fp;                /* file stream pointer */
  283.  
  284.     ksize = stime = numblocks = 0L;
  285.     if ((fp = fopen(fname, "rb")) == NULL)  /* open for binary read */
  286.     {
  287.     printf("\n+++ File Open Error! +++\n");
  288.     return(EOF);
  289.     }
  290.     if ((ksize = filelength(fileno(fp))) == EOF)    /* get file size */
  291.     {
  292.     printf("\n+++ File Length Read Error! +++\n");
  293.     return(EOF);
  294.     }
  295.     if (ksize < (long)BLKSIZ)
  296.     ksize = (long)BLKSIZ;
  297.     numblocks = (ksize / (long)BLKSIZ) + 1L;  /* calculate # of blocks */
  298.     switch(_bye_baud())               /* get baud rate from BYE */
  299.     {
  300.     case 0:
  301.         bps = 300;
  302.         break;
  303.     case 1:
  304.         bps = 1200;
  305.         break;
  306.     case 2:
  307.         bps = 2400;
  308.         break;
  309.     default:
  310.         bps = 9600;
  311.         break;
  312.     }
  313.     stime = ksize / (long)(bps / 10);        /* send time in secs */
  314.     printf("\nXMODEM for use with BYE-PC\n");
  315.     printf("Version %1d.%-2.2d Copyright (c) 1986, 1987, MCODE Software\n", VER, REV);
  316.     printf("[Use CTRL-X to cancel file send]\n\n");
  317.     printf("File Open : %s\n", fname);
  318.     printf("File Size : ");
  319.     if (ksize > 1024L)
  320.     printf("%ldk  (%ld blocks)\n", (ksize / 1024L) + 1L, numblocks);
  321.     else
  322.     printf("%ld bytes (%ld blocks)\n", ksize, numblocks);
  323.     printf("Send Time : ");
  324.     if (stime > 60L)
  325.     printf("%ld min(s) %ld sec(s)", stime/60L, stime%60L);
  326.     else
  327.     printf("%ld sec(s)", stime);
  328.     printf(" at %dbps\n", bps);
  329.  
  330.     if (Crcflg)
  331.     printf("(CRC Mode)\n\n");
  332.     else
  333.     printf("(Checksum Mode)\n\n");
  334.     printf("Ready to send...\n\n");
  335.  
  336.  /*------------------------------------------------------------------*/
  337.  /*  Major Loop: The file is open. While it is not EOF, get blocks   */
  338.  /*  of BLKSIZ bytes each and send them using xsendbuf().  If we hit */
  339.  /*  EOF in the middle of a buffer, (a) set a flag that indicates    */
  340.  /*  sending EOT after this block is succsessfully received, and (b) */
  341.  /*  zero pad the block out to BLKSIZ bytes.                 */
  342.  /*------------------------------------------------------------------*/
  343.  
  344.     timer(10*18);        /* wait 10 seconds before starting */
  345.     _bye_stdout(OFF);
  346.     _bye_stdin(OFF);        /* disable INT10 & INT16 merging */
  347.     exit = 1;
  348.     First = Blkcnt = Blkhdr = 1;
  349.  
  350.     while (exit)
  351.     {
  352.     memset(buf, '\0', BLKSIZ);        /* null out data buffer */
  353.     igetret = get_a_block(buf, fp);     /* get block from file   */
  354.     if (iret = xsendbuf(buf))
  355.         break;
  356.     if (First)                /* reset first block flag */
  357.         First = 0;
  358.     printf("Block Sent:%-5.5d  (%-4.4Xh)\r", Blkcnt, Blkcnt);
  359.     if(!iret && (igetret != 0))
  360.         {
  361.         while(TRUE)
  362.         {
  363.         if (mdm_tputc(EOT, 1) == EOF)    /* send an EOT */
  364.             break;
  365.         c = mdm_tgetc(2);        /* get return */
  366.         if (c == ACK || c == EOF)    /* ACK or error to end */
  367.             break;
  368.         }
  369.         exit = 0;            /* now exit */
  370.         }
  371.     ++Blkcnt;
  372.     }
  373.     fclose(fp);     /* close the file */
  374.     printf("\n\nEnd XMODEM Send...\n");
  375.     }
  376.         /* End of XMODEM SEND */
  377.  
  378.  
  379. /*
  380. **  Function:    int get_a_block(buf, fp)
  381. **
  382. **  Parms:    char *buf;  -> buffer to read data from
  383. **        FILE *fp;   -> file stream pointer
  384. **
  385. **  Purpose:    Reads a block of data into pointer 'buf' for BLKSIZ
  386. **        bytes.
  387. **
  388. **  Return:    1 = last block of data read.
  389. **        0 = more data to read from disk.
  390. */
  391.  
  392. int get_a_block(buf, fp)
  393.  
  394.  char *buf;
  395.  FILE *fp;
  396.     {
  397.     int bytes;
  398.  
  399.     bytes = fread(buf, sizeof(char), BLKSIZ, fp);
  400.     if (bytes < BLKSIZ)
  401.     return(1);
  402.     else
  403.     return(0);
  404.     }
  405.  
  406.  
  407. /*-------------------------------------------------------------------*/
  408. /*  XMODEM  D O W N L O A D   -   R E C E I V E   A   F I L E         */
  409. /*-------------------------------------------------------------------*/
  410. /*  The file is opened if does not currently exists and NAK's are    */
  411. /*  sent to the remote station to start the receive process. Each    */
  412. /*  block is written to disk as it is received. If more than 10      */
  413. /*  errors occurs in a single block, the fiel Rx is canceled and the */
  414. /*  incomplete file is deleted from disk.                 */
  415. /*-------------------------------------------------------------------*/
  416.  
  417. int xmdm_receive(file)
  418.  
  419.  char file[];
  420.     {
  421.     char fname[64], buf[BLKSIZ+10];
  422.     int iputret, iret, exit;
  423.     int cancel = YES;
  424.     FILE *fp;
  425.  
  426.   #ifdef P_UPLOAD
  427.     strcpy(fname, P_PATH);    /* get private upload path name */
  428.     strcat(fname, file);
  429.   #else
  430.     strcpy(fname, file);
  431.   #endif
  432.     if (!access(fname, 0))    /* check for file exsistance */
  433.     {
  434.     printf ("\n+++ File Already Exists! +++\n");
  435.     return (EOF);
  436.     }
  437.     if ((fp = fopen(fname, "wb")) == NULL)  /* open file to write to */
  438.     {
  439.     printf ("\n+++ File Open Error! +++\n");
  440.     return (EOF);
  441.     }
  442.     else
  443.     {
  444.     printf("\nXMODEM for use with BYE-PC\n");
  445.     printf("Version %1d.%-2.2d Copyright (c) 1986, 1987, MCODE Software\n", VER, REV);
  446.     printf("[Use CTRL-X to cancel file receive]\n\n");
  447.     printf("File Open: %s\n", file);
  448.     if (Crcflg)
  449.         printf("(CRC Mode)\n\n");
  450.     else
  451.         printf("(Checksum Mode)\n\n");
  452.     printf("Ready to receive...\n\n");
  453.     }
  454.  
  455. /*------------------------------------------------------------------*/
  456. /*  Major xmodem receive loop.    The file has been created.  Get the */
  457. /*  first block from the other end, store it; repeat this until the */
  458. /*  transmitter sends EOT.  Use xrecvbuf().    Check block numbers */
  459. /*------------------------------------------------------------------*/
  460.  
  461.     _bye_stdout(OFF);
  462.     _bye_stdin(OFF);
  463.     timer(10*18);            /* wait 10 secs before starting */
  464.     First = Blkcnt = Blkhdr = 1;
  465.     exit = 1;
  466.     while(exit)
  467.     {
  468.     memset(buf, '\0', BLKSIZ);
  469.     if ((iret = xrecvbuf(buf)) == 0)    /* attempt to Rx a block */
  470.         {
  471.         if (put_a_block(buf, fp) == EOF)
  472.         {
  473.         printf("\n+++ Disk Write Error! +++\n");
  474.         cancel = YES;
  475.         exit = 0;
  476.         break;
  477.         }
  478.         else
  479.         printf("Block Received:%-5.5d  (%-4.4Xh)\r", Blkcnt, Blkcnt);
  480.         }
  481.     else
  482.         {
  483.         switch(iret)
  484.         {
  485.         case 2:         /* EOT to end Rx */
  486.             cancel = NO;
  487.             break;
  488.         case 3:
  489.         case 9:
  490.             break;
  491.         default:        /* any error except EOT */
  492.             printf("\n+++ Too many errors - Aborting Receive! +++\n");
  493.             break;
  494.         }
  495.         exit = 0;
  496.         }
  497.     if (First)
  498.         First = 0;
  499.     ++Blkcnt;
  500.     }
  501.     fclose(fp);     /* close the file */
  502.     if (cancel)
  503.     {
  504.     unlink(fname);
  505.     printf("\n+++ Incomplete file deleted +++\n");
  506.     }
  507.     else
  508.     printf("\n\nEnd XMODEM Receive...\n");
  509.     }
  510.  
  511.  
  512. /*
  513. **  Function:    int put_a_block(buf, fp)
  514. **
  515. **  Parms:    char *buf;  -> buffer to read data from
  516. **        FILE *fp;   -> file stream pointer
  517. **
  518. **  Purpose:    Writes a block of data starting at pointer 'buf'
  519. **        for the xmdm block size .
  520. **
  521. **  Return:    EOF = Error writing data
  522. **        0 = data written disk
  523. */
  524.  
  525. int put_a_block(buf, fp)
  526.  
  527.  char *buf;
  528.  FILE *fp;
  529.     {
  530.     int bytes;
  531.  
  532.     bytes = fwrite(buf, sizeof(char), BLKSIZ, fp);
  533.     if (bytes < BLKSIZ)
  534.     return(EOF);
  535.     else
  536.     return(0);
  537.     }
  538.  
  539. /*-------------------------------------------------------------------*/
  540. /*         XMODEM  Send Data Block routines.             */
  541. /*-------------------------------------------------------------------*/
  542.  
  543. /*
  544. **
  545. **  (1) Send prefix (SOH, Block number, Block number XOR 255)
  546. **  (2) Send BLKSIZ bytes from User Buffer and compute checksum
  547. **  (3) Send Checksum
  548. **
  549. **  Returns:    0 =  Successful sending Block.
  550. **        1 =  I/O error to or from the modem.
  551. **        2 =  Initial NAK not received from receiver.
  552. **        3 =  Unable to send block after 10 retries.
  553. **        4 =  Remote station canceled file send.
  554. */
  555.  
  556. int xsendbuf(buf)
  557.  
  558.  char *buf;
  559.     {
  560.     char *p;
  561.     int c, i, chksum, errorcount, try;
  562.     unsigned crc;
  563.  
  564.     try = 0;            /* xmdm start tx attempt number */
  565.     errorcount = 10;        /* maximum error count */
  566.     while(errorcount)
  567.     {
  568.     check_cd();        /* make sure we still have carrier */
  569.     if(First && errorcount == 10)  /* if First time through wait for NAK */
  570.         {
  571.         _bye_rxflush();            /* clear rx-queue */
  572.         i = mdm_tgetc(30);            /* 30 sec timeout */
  573.         switch(i)
  574.         {
  575.         case EOF:
  576.             printf("[Initial NAK Timed out]\n");
  577.             if (try++ > 6)
  578.             return(2);
  579.             break;
  580.         case 'C':
  581.             Crcflg = YES;
  582.             First = 0;
  583.             printf("[CRC Requested]\n");
  584.             break;
  585.         case NAK:
  586.             Crcflg = NO;
  587.             First = 0;
  588.             printf("[Checksum Requested]\n");
  589.             break;
  590.         case CTRL_X:
  591.             printf("+++ Remote Station Canceled Send +++\n");
  592.             return(4);
  593.         default:
  594.             printf("[Initial NAK Missing] -- Received:%-2.2xh\n", i);
  595.             if (try++ > 6)
  596.             return(2);
  597.             break;
  598.         }
  599.         continue;        /* keep on trying till we error out */
  600.         }
  601.     p = buf;        /* pointer to buffer to send */
  602.     chksum = 0;        /* clear checksum & CRC storage */
  603.     crc_init();        /* clear the CRC accumlator */
  604.     drx_flush();            /* clear the rx queue */
  605.     if(xpreface() == EOF)        /* send prefix    */
  606.         return(1);
  607.     for (i = 1; i <= BLKSIZ; i++)
  608.         {
  609.         c = (int)*p++;
  610.         if(mdm_tputc(c, 1) == EOF)    /* send data byte */
  611.         return (1);
  612.         if (Crcflg)
  613.         crc_sum(c);        /* sum the CRC value */
  614.         else
  615.         chksum += c;        /* sum the Checksum value */
  616.         }
  617.     if (Crcflg)
  618.         {
  619.         crc_sum(0);         /* final CRC calculation */
  620.         crc_sum(0);
  621.         crc = crc_value();        /* get the CRC value */
  622.         if(mdm_tputc(crc >> 8, 1) == EOF)        /* send MSB of CRC */
  623.         return(1);
  624.         if(mdm_tputc(crc & 0x00ff, 1) == EOF)   /* send LSB of CRC */
  625.         return(1);
  626.         }
  627.     else
  628.         {
  629.         if(mdm_tputc(chksum, 1) == EOF)    /* send checksum */
  630.         return(1);
  631.         }
  632.  
  633.     /* wait for response back from remote */
  634.  
  635.     while(1)
  636.         {
  637.         if ((i = mdm_tgetc(5)) == ACK)    /* wait for response */
  638.         {
  639.         if (errorcount != 10)        /* newline if errors */
  640.             printf("\n");
  641.         Blkhdr++;            /* advance block ctr */
  642.         return(0);            /* received ACK */
  643.         }
  644.         else if (i == NAK)
  645.         {
  646.         printf("\n<Re-sending Block>");     /* transmit error */
  647.         break;
  648.         }
  649.         else if (i == EOF)
  650.         {
  651.         printf("\n<Sync Error>");
  652.         errorcount = 1;         /* last pass */
  653.         break;
  654.         }
  655.         }
  656.     --errorcount;
  657.     }
  658.     printf("\n+++ Too many errors - Aborting Send! +++\n");
  659.     return(3);                    /* indicate failure */
  660.     }
  661.  
  662.  
  663. /*
  664. **  Function:    int xpreface()
  665. **
  666. **  Parms:    void
  667. **
  668. **  Purpose:    sends the SOH, the block number and the complemented
  669. **        block number for a xmdm data block.
  670. **
  671. **  Return:    0   = preface sent
  672. **        EOF = i/o error
  673. */
  674.  
  675. int xpreface()
  676.  {
  677.  if (mdm_tputc(SOH, 1) == EOF)        /* send the SOH */
  678.      return(EOF);
  679.  if (Blkhdr > 0xff)            /* recycle block ctr */
  680.     Blkhdr = 0;
  681.  if (mdm_tputc(Blkhdr, 1) == EOF)        /* send block */
  682.      return(EOF);
  683.  if (mdm_tputc((255 - Blkhdr), 1) == EOF)   /* send compliment blk */
  684.      return(EOF);
  685.  return (0);
  686.  }
  687.  
  688. /*-------------------------------------------------------------------*/
  689. /*           XMODEM  Receive Data Block routines.             */
  690. /*-------------------------------------------------------------------*/
  691.  
  692. /*
  693. **  Receive XMODEM buffer to user buffer
  694. **
  695. **  This function must be called with enough time to spare before the
  696. **  application expects to receive the beginning of an XMODEM block.
  697. **
  698. **  (1)  Get a few characters from receive buffer.
  699. **  (2)  Test block number, inverse block number -
  700. **  (3)  Get BLKSIZ bytes data, calculate checksum on the fly.
  701. **  (4)  Receive checksum from other station, compare with computed.
  702. **
  703. **  Return:    0 - Received block correctly
  704. **        1 - timeout on tx or rx i/o attempt
  705. **        2 - EOT received from remote end
  706. **        3 - User cancelled with Ctrl-X or Ctrl-C
  707. **        4 - Missing SOH in block
  708. **        5 - Bad block number
  709. **        6 - Short block error
  710. **        7 - Long block error
  711. **        8 - Checksum or CRC error
  712. **        9 - No response after sending initial NAK's
  713. */
  714.  
  715. int xrecvbuf(buf)
  716.  
  717.  char *buf;
  718.     {
  719.     char *p;
  720.     int rxblk, rxnblk, chksum, stat;
  721.     int rstat, rxsize, rtn, bytes;
  722.     int i, c, errorcount;
  723.     unsigned crc;
  724.  
  725.     if (Crcflg)
  726.     bytes = BLKSIZ + 2;       /* CRC mode */
  727.     else
  728.     bytes = BLKSIZ + 1;       /* Checksum mode */
  729.     errorcount = 11;
  730.     while(errorcount--)
  731.     {
  732.     check_cd();        /* make sure we still have carrier */
  733.     if (First && errorcount == 10)
  734.         {
  735.         stat = xmdm_init();     /* initiate xmdm receive  */
  736.         if (Crcflg)         /* did we change modes?   */
  737.         bytes = BLKSIZ + 2;    /* reset to CRC mode */
  738.         else
  739.         bytes = BLKSIZ + 1;    /* reset to Checksum mode */
  740.         if (!stat)
  741.         goto start;        /* was xmdm rx initiated? */
  742.         else
  743.         return(stat);        /* no, return with error  */
  744.         }
  745.     else if (errorcount < 10)    /* is this a block resend? */
  746.         {
  747.         timer(18*2);            /* wait about 2 seconds */
  748.         drx_flush(1);            /* flush out stream data */
  749.         if (mdm_tputc(NAK, 1) == EOF)   /* now send the NAK.     */
  750.         return(1);
  751.         }
  752.     if ((c = mdm_tgetc(15)) == EOF)     /* 15 secs on 1st char */
  753.         return(9);
  754.     else if (c == EOT)            /* EOT to end xmdm rx */
  755.         {
  756.         if (mdm_tputc(ACK, 1) == EOF)   /* send back an ACK */
  757.         return(1);
  758.         else
  759.         return(2);
  760.         }
  761.     else if (c != SOH)            /* if SOH then ok */
  762.         {
  763.         rstat = 4;
  764.         printf("\n<Missing SOH>");
  765.         continue;
  766.         }
  767.  start: rstat = 5;                /* assume wrong block number */
  768.     if ((rxblk = mdm_tgetc(5)) == EOF)  /* get block number from sender */
  769.         return(1);
  770.     if ((rxnblk = mdm_tgetc(5)) == EOF) /* get not block number */
  771.         return(1);
  772.     if (((rxnblk & 0x00ff) + (rxblk & 0x00ff)) != 255)
  773.         {
  774.         printf("\n<Bad Block Number>");
  775.         continue;
  776.         }
  777.     xmdm_rxblk(5, bytes);         /* collect 'bytes' of data */
  778.     rstat = 6;
  779.     if(_bye_rxsize() < bytes)     /* short block error */
  780.         {
  781.         printf("\n<Short Block Error>");
  782.         continue;
  783.         }
  784.     rstat = 7;
  785.     if(_bye_rxsize() > bytes)        /* long block error */
  786.         {
  787.         printf("\n<Long Block Error>");
  788.         continue;
  789.         }
  790.     p=buf;                    /* correct byte count has now */
  791.     chksum = 0;                /* been received, get characters */
  792.     crc_init();                /* reset crc accumulator */
  793.     for(i = 1; i <= BLKSIZ; ++i)        /* from queue & put in user buffer */
  794.         {
  795.         if ((c = mdm_tgetc(5)) == EOF)  /* calculate checksum on the fly */
  796.         return(1);
  797.         *p++ = (char)c;
  798.         if (Crcflg)
  799.         crc_sum(c);
  800.         else
  801.         chksum += c;
  802.         }
  803.     rstat = 8;                    /* assume checksum/CRC error */
  804.     if (Crcflg)
  805.         {
  806.         crc_sum(0);                 /* finish CRC calc */
  807.         crc_sum(0);
  808.         if ((c = mdm_tgetc(5)) == EOF)        /* get LSB of CRC */
  809.         return(1);
  810.         crc = (c & 0x00ff);
  811.         if ((c = mdm_tgetc(5)) == EOF)
  812.          return(1);
  813.         crc = (crc << 8) + (c & 0x00ff);        /* get MSB of CRC */
  814.         if(crc != crc_value())            /* compare incoming with calculated */
  815.         {
  816.         printf("\n<CRC Error>");
  817.         continue;
  818.         }
  819.         }
  820.     else
  821.         {
  822.         if ((c = mdm_tgetc(5)) == EOF)        /* get first byte */
  823.         return(1);
  824.         if ((c & 0x00ff) != (chksum & 0x00ff))  /* compare incoming with calculated */
  825.         {
  826.         printf("\n<Check Sum Error>");
  827.         continue;
  828.         }
  829.         }
  830.     if (mdm_tputc(ACK, 1) == EOF)        /* send ACK to start other blocks */
  831.        return(1);
  832.     if (errorcount != 10)
  833.         printf("\n");
  834.     return(0);                /* success at last */
  835.     }
  836.     return(rstat);                /* return error */
  837.     }
  838.  
  839.  
  840. /*
  841. **  Function:    int xmdm_nak()
  842. **
  843. **  Parms:    <none>
  844. **
  845. **  Purpose:    Starts the begging of an xmdm transfer.
  846. **        Note: if 'l=4' this function will switch
  847. **        between CRC and Checksum mode two times while
  848. **        waiting for the first SOH character. The purpose
  849. **        of this function is to send out NAK's or C's to
  850. **        signal remote to begin sending. Once a SOH is
  851. **        received, the receive is ready to continue.
  852. **
  853. **  Returns:    0 = SOH received valid
  854. **        1 = port timeout errors in tx/rx.
  855. **        2 = no response back from remote.
  856. **        3 = user cancelled receive.
  857. */
  858.  
  859. int xmdm_nak()
  860.  {
  861.  int i, l, c, schr, trys;
  862.  
  863.  for (l = 1; l <= 2; l++)    /* If l=2, we will start with CRC and */
  864.     {                 /* switch to Checksum mode with up to */
  865.     if (Crcflg)          /* 10 time out errors in each mode.   */
  866.     {
  867.     schr = CRC;
  868.     if (l > 1)
  869.         {
  870.         printf("[Switching to Checksum mode]\n");
  871.         Crcflg = NO;
  872.         schr = NAK;
  873.         }
  874.     }
  875.     else
  876.     {
  877.     schr = NAK;
  878.     if (l > 1)
  879.         {
  880.         printf("[Switching to CRC mode]\n");
  881.         Crcflg = YES;
  882.         schr = CRC;
  883.         }
  884.     }
  885.     for (i = 1; i <= 10; ++i)
  886.     {
  887.     _bye_rxflush();         /* clear rx buffer */
  888.     if(mdm_tputc(schr, 1) == EOF)    /* send NAK for first block */
  889.         return(1);
  890.     c = mdm_tgetc(5);        /* wait for 5 seconds on SOH */
  891.     switch(c)
  892.         {
  893.         case EOF:        /* try again if timed out */
  894.         break;
  895.         case SOH:
  896.         if (Crcflg)
  897.             printf("[CRC Requested]\n");
  898.         else
  899.             printf("[Checksum Requested]\n");
  900.         return(0);
  901.         case CTRL_X:
  902.         printf("\n+++ Remote station canceled transfer +++\n");
  903.         return(3);
  904.         default:
  905.         printf("[Initial SOH Missing] -- Received: %-2.2xh\n", c);
  906.         timer(18*2);    /* wait 2 seconds */
  907.         break;
  908.         }
  909.     }
  910.     }
  911.  return(2);       /* something sent back */
  912.  }
  913.  
  914.  
  915. /*
  916. **  Function:    int xmdm_init()
  917. **
  918. **  Parms:    void
  919. **
  920. **  Purpose:    Initiates an xmodem receive.
  921. **
  922. **  Returns:    0 = SOH recieved rx data ready to begin
  923. **        1 = i/o errors occured
  924. **        3 = remote user canceled receive
  925. **        9 = no response to NAK's or C's
  926. */
  927.  
  928. int xmdm_init()
  929.  {
  930.  int stat;
  931.  
  932.  stat = xmdm_nak();        /* if first block and sent    */
  933.  switch(stat)            /* if first block and sent    */
  934.     {                /*    send out NAK's and wait */
  935.     case 0:            /*    a response from remote. */
  936.     First = NO;
  937.     break;
  938.     case 1:            /* any i/o errors? */
  939.     return(1);
  940.     case 2:            /* no reponse to NAK's? */
  941.     return(9);
  942.     default:            /* user cancel? */
  943.     return(3);
  944.     }
  945.  return(0);
  946.  }
  947.  
  948.  
  949. /*
  950. **  Function:    void xmdm_rxblk(s, n)
  951. **
  952. **  Parms:    int s;    -> # of secs to collect data
  953. **        int n;    -> bytes to collect
  954. **
  955. **  Purpose:    Waits for 'n' bytes to be received in the rx-queue
  956. **        or for 's' seconds to pass, whichever occurs first.
  957. **
  958. **  Returns:
  959. */
  960.  
  961. void xmdm_rxblk(s, n)
  962.  
  963.  int s, n;
  964.     {
  965.     int secs, size;
  966.  
  967.     secs = s * 10;            /* delay in terms of 18ms */
  968.     while(secs--)
  969.     {
  970.     if (_bye_rxsize() >= n)     /* break when count reached */
  971.         break;
  972.     timer(1);            /* wait for ~18ms & recheck */
  973.     }
  974.     }
  975.  
  976. /*-------------------------------------------------------------------*/
  977. /*       Timed Modem I/O and Hardware Timing Routines.         */
  978. /*-------------------------------------------------------------------*/
  979.  
  980. /*
  981. **  Function:    int mdm_tgetc(n)
  982. **
  983. **  Parms:    unsigned n -> maximun timeout in seconds.
  984. **
  985. **  Purpose:    Get a character from modem with timeout.
  986. **
  987. **  Returns:    Character or EOF if timeout waiting to get
  988. **        the character
  989. */
  990.  
  991. int mdm_tgetc(n)
  992.  
  993.  unsigned n;
  994.     {
  995.     unsigned s, c;
  996.  
  997.     n *= 18;            /* express in terms of 18ms */
  998.     for (s=0; s < n; ++s)
  999.     {
  1000.     if ((c = _bye_getc()) != EOF)
  1001.         return((int)c);
  1002.     timer(1);        /* wait 18ms and retry */
  1003.     }
  1004.     return(EOF);
  1005.     }
  1006.  
  1007.  
  1008. /*
  1009. **  Function:    int mdm_tputc(c, n)
  1010. **
  1011. **  Parms:    int c -> character to send to modem.
  1012. **        int n -> timeout count in seconds.
  1013. **
  1014. **  Purpose:    Send a character to modem with timeout.
  1015. **
  1016. **  Returns:    EOF if timeout waiting to send.
  1017. **
  1018. */
  1019.  
  1020. int mdm_tputc(c, n)
  1021.  
  1022.  int c, n;
  1023.     {
  1024.     int s;
  1025.  
  1026.     for (s=0; s < n; ++s)
  1027.     {
  1028.     if (_bye_putc(c) != EOF)
  1029.         return(0);
  1030.     timer(18);        /* wait 1 second */
  1031.     }
  1032.     return(EOF);
  1033.     }
  1034.  
  1035.  
  1036. /*
  1037. **  Function:    void drx_flush(d)
  1038. **
  1039. **  Parms:    int d;    -> delay pause between rx queue size check
  1040. **               in 18ms increments.
  1041. **
  1042. **  Purpose:    Flushes the rx-queue of data, pauses for the specified
  1043. **        delay time, and rechecks the rx-queue for more data to
  1044. **        flush. This is used to clear the rx-queue until the
  1045. **        stream of data halts. Primarilry used for re-sync'ing.
  1046. **
  1047. **  Return:    void
  1048. */
  1049.  
  1050. void drx_flush(d)
  1051.  
  1052.  int d;
  1053.     {
  1054.     unsigned size;
  1055.  
  1056.     while(_bye_rxsize())    /* loop while data is received */
  1057.     {
  1058.     _bye_rxflush();     /* clear out the rx-data queue */
  1059.     timer(d);        /* delay so more data may collect */
  1060.     }
  1061.     }
  1062.  
  1063.  
  1064. /*
  1065. **  Function:    void check_cd()
  1066. **
  1067. **  Parms:    void
  1068. **
  1069. **  Purpose:    This function checks to make sure carrier is still
  1070. **        found. If carrier is not found, the system is re-
  1071. **        booted to hang up for the next call.
  1072. **
  1073. **  Return:    void
  1074. */
  1075.  
  1076. void check_cd()
  1077.  {
  1078.  if (!_bye_getcd())        /* check carrier detect */
  1079.     {
  1080.     printf("\n+++ CARRIER LOST IN XMODEM! +++\n\b");
  1081.     fcloseall();        /* close any files open */
  1082.     timer(5*18);        /* wait five seconds  */
  1083.     _bye_warmboot();        /* re-boot the system */
  1084.  
  1085.     /* just in case we did'nt boot */
  1086.  
  1087.     _bye_stdout(ON);        /* turn on console Rx & Tx */
  1088.     _bye_stdin(ON);
  1089.     _bye_setcd(ON);        /* enable carrier loss checking */
  1090.     _bye_setbreak(CTRL_TRAP);    /* enable trap ^C & ^S data */
  1091.     ctrl_break(ON);        /* reenable local ctrl-break */
  1092.     exit(1);            /* exit with error level set */
  1093.     }
  1094.  }
  1095.  
  1096.  
  1097.