home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / progm / cpgms.zip / LMODEM.C < prev    next >
C/C++ Source or Header  |  1985-11-17  |  25KB  |  1,067 lines

  1. #define        CPM86    1
  2. #define        CPM80    0
  3. #define        DeSmet    1        /* using the DeSmet C compiler */
  4. #define        MSDOS    0        /* run under MSDOS op sys */
  5.  
  6. #if CPM86 
  7. #define        CPM        1        /* run under CPM op sys */
  8. #endif
  9.  
  10. #if CPM80 
  11. #define        CPM        1        /* run under CPM op sys */
  12. #endif
  13.  
  14. #define        DOTS    50    /* sector counting dots per line */
  15. #define     SPS    9500    /* loops per second  */
  16. #define     SECSIZ    0x80
  17. #define        DATMSK 0x7f
  18. #define        BUFSEC    128    /* number of filel sectors to buffer */
  19. #define        BUFSIZ    0x7f80    /* large text buffer (32k - 1 sector) */
  20. #define        ERRMAX 10    /* max errors before abort */
  21. #define        RETMAX 5    /* max retrys before abort */
  22.  
  23. #if    CPM
  24. #define        DIRCIO    6    /* cpm bdos direct console io cmd */
  25. #define        INPUT    0xff    /* direct-console io input */
  26. #define        GSUSER    31    /* cpm bdos get/set user */
  27. #define        GETUSR    0xff    /* get user number */
  28. #endif
  29.  
  30. #define        ERROR    0    /* bad open return */
  31. #define        FALSE    0    /* universal evil  */
  32. #define        TRUE    1    /* universal good  */
  33. #define        NULL    0    /* end of string, etc */
  34.  
  35.  
  36. /***********************************************************************/
  37. /*                                                                     */
  38. /*    Special characters used in the file transfer-protocol          */
  39. /*                                                                     */
  40. /***********************************************************************/
  41.  
  42. #define        TIMOUT    -1    /* timeout character */
  43. #define        SOH    1    /* start of sector character */
  44. #define        EOT    4    /* end of tranmission char */
  45. #define        ACK    6    /* Acknowledge sector transmission */
  46. #define        NAK    21    /* error in transmission detected */
  47. #define        CRCC    'C'    /* respond to force CRC checking */
  48.  
  49.  
  50. /***********************************************************************/
  51. /*                                                                     */
  52. /*    Miscellaneous ASCII characters                                 */
  53. /*                                                                     */
  54. /***********************************************************************/
  55.  
  56. #define        ESC    0x1b
  57. #define        TAB    9
  58. #define        LF    10
  59. #define        CR    13
  60. #define        CTRLZ    26    /* eof char */
  61.  
  62. /***********************************************************************/
  63. /*                                                                     */
  64. /*    These defines determine which keys will be interpreted        */
  65. /*        as command characters                                        */
  66. /*                                                                     */
  67. /***********************************************************************/
  68.  
  69. #define        CTRLA    01 
  70. #define        CTRLB    02
  71. #define        CTRLC    03
  72. #define        CTRLE    05
  73. #define        CTRLK    11
  74. #define        CTRLL    12
  75. #define        CTRLP    16
  76. #define        CTRLQ    17
  77. #define        CTRLR    18
  78. #define        CTRLS    19
  79. #define        CTRLV    22
  80. #define        CTRLX    24
  81. #define        CTRLY    25
  82.   /*  commands */
  83. #define        CMND    CTRLA
  84. #define        CAPTUR    'C'      /* toggle text capture */
  85. #define        KEEP    'K'      /* keep text buffer */
  86. #define        LITERL    CTRLL    /* send literal character */
  87. #define        BAUD    'B'      /* change the baud rate */
  88. #define        ECHO    CTRLE    /* local echo of keyboard data */
  89. #define        PRINT    CTRLP    /* echo to printer */
  90. #define        CANCEL    CTRLX    /* cancel file trans/recv */
  91. #define        QUIT    'Q'      /* quit */
  92. #define        RECV    'R'      /* receive file by sectors */
  93. #define        SEND    'S'      /* send file by sectors */
  94. #define        TERMNL    'T'    /* enter terminal mode */
  95.  
  96. #if    CPM
  97. #define        USER    'U'    /* change user number */
  98. #endif
  99.  
  100.  
  101. #define        VIEW    CTRLV    /* view data transferred */
  102.  
  103.  
  104. char ViewMd, BFlag, KbData, ModDat, Echofl;
  105. char ShowTr, ShowRc, View, Prntfl;
  106. char Commok;
  107. char *Bufr;
  108. char FileNm[15];
  109.  
  110. #if    CPM
  111. int Curusr, Oldusr;
  112. #endif
  113.  
  114.  
  115. char CmdBuf[60], strng[20];
  116. int Fd, PFd, CRCflg, Batflg;
  117. int TxtPtr, Abort;
  118. int brate = 1200;
  119.  
  120.  
  121. main(argc,argv)
  122. int argc;
  123. char *argv[];
  124. {
  125.     ShowRc = ShowTr = BFlag = View = Echofl = FALSE;
  126.     Prntfl = Commok = FALSE;
  127.     Fd = PFd = -1;   /* show file not open */
  128.     TxtPtr = 0;
  129.     ViewMd = KbData = CmdBuf[0] = NULL;
  130.  
  131. #if    CPM
  132.     Curusr = Oldusr = bdos(GSUSER, GETUSR);  /* save user # on entry */
  133.     puts(" Current user # is ");
  134.     itoa(Curusr,strng);
  135.     puts(strng);
  136.     puts("\n");
  137. #endif
  138.  
  139.  
  140.     if ((Bufr = calloc(BUFSIZ,1)) == ERROR) {
  141.         puts("Unable to acquire buffer\n");
  142.         return;      /* exit if no space for buffer */
  143.     }
  144.  
  145.     CmdBuf[0] = NULL;
  146.     evalcd(CmdBuf);
  147.  
  148.     initmd();
  149.  
  150.     /* the main loop */
  151.     while ((dcdrdy() || !Commok) && (CmdBuf[0] != QUIT)) {
  152.  
  153.         if (!Commok && dcdrdy())  /* we have a connection */
  154.             Commok = TRUE;
  155.  
  156.         if (KbData = kbdin()) /* get any char at kbd */
  157.             switch(KbData) {   /* eval term mode cmds */
  158.             
  159.             case CMND:  
  160.                 cmdmen();
  161.                 evalcd(CmdBuf);     /* eval cmd mode entry */
  162.                 break;
  163.  
  164.             case VIEW:
  165.                 View = ~View;
  166.                 if (View) 
  167.                     puts("Viewing enabled\n ");
  168.                 else
  169.                     puts("Viewing disabled\n");
  170.                 break;
  171.  
  172.             case LITERL:
  173.                 while (!(KbData = kbdin()));
  174.                 mcharo(KbData);
  175.                 break;
  176.  
  177.             case PRINT:
  178.                 Prntfl = ~Prntfl;
  179.                 if (Prntfl & (PFd == -1))
  180.                     PFd = fopen("LST:", "w");
  181.                 break;
  182.  
  183.             case ECHO:
  184.                 Echofl = ~Echofl;
  185.                 break;
  186.  
  187.             default:
  188.                 mcharo(KbData);
  189.                 if (Echofl) {
  190.                     putchar(KbData);
  191.                     if (Prntfl) {
  192.                         if (KbData == CR)
  193.                             KbData = '\n';
  194.                         putc(KbData, PFd);
  195.                     }
  196.                 }
  197.                 break;
  198.             }
  199.         if (minrdy()) {
  200.             ModDat = mchari();
  201.             if (BFlag && (TxtPtr < BUFSIZ))
  202.                 Bufr[TxtPtr++] = ModDat;
  203.             else if (BFlag)
  204.                 puts("Capture Bufr overflow\n");
  205.             putchar(ModDat);
  206.             if (ModDat == CR)
  207.                 ModDat = '\n';
  208.             if (Prntfl)
  209.                     putc(ModDat, PFd);
  210.         }
  211.     }
  212.     if (CmdBuf != QUIT)
  213.         puts("\nYou lost carrier detect");
  214. #if CPM
  215.     Curusr = Oldusr = bdos(GSUSER, Oldusr);  /* reset user # to entry */
  216. #endif
  217.  
  218. }
  219.  
  220.  
  221. evalcd(cbuf)
  222. char *cbuf;
  223. {
  224.     char Cmdchr, option[30], *savcbf;
  225.     int i, brate;
  226.  
  227.     savcbf = cbuf;    /* save start of original buffer */
  228.     Cmdchr = NULL;
  229.  
  230.     while ((Cmdchr != QUIT) && (Cmdchr != TERMNL)) {
  231.  
  232.         if (*cbuf == NULL) {    /* need new cmd input */
  233.             cbuf = savcbf;
  234.             cmdmen();
  235.             getstr(60,cbuf);
  236.             for (i=0; cbuf[i] != NULL; i++) /* cmd is upper */
  237.                 cbuf[i] = touppr(cbuf[i]);
  238.         }
  239.  
  240.         Cmdchr = *cbuf;
  241.  
  242.         /* skip command in buffer */
  243.         cbuf = skptok(cbuf);
  244.  
  245.         switch(Cmdchr) {   /* eval cmd mode cmds */
  246.             
  247.         case BAUD:
  248.             brate = atoi(cbuf);
  249.             if (brate = baudst(brate))
  250.                 initmd();
  251.             else
  252.                 puts("Invalid baud rate -- Command terminated.\n");
  253.             break;
  254.  
  255.         case CAPTUR:
  256.             BFlag = ~BFlag;
  257.             if (BFlag)
  258.                 puts("Capture initiated");
  259.             else
  260.                 puts("Capture terminated");
  261.             itoa(BUFSIZ - TxtPtr, strng);
  262.             puts(", ");
  263.             puts(strng);
  264.             puts(" bytes free\n");
  265.             break;
  266.     
  267.         case KEEP:
  268.             if (!TxtPtr)
  269.                 puts("Nothing to save\n");
  270.             else {
  271.                 if (*cbuf == ' ') {    /* user entered filename */
  272.                     cbuf++;
  273.                     mkstr(15,cbuf,FileNm);
  274.                 }
  275.                 else {
  276.                     puts("Save as what file? \n");
  277.                     getstr(15,FileNm);
  278.                 }
  279.                 Bufr[TxtPtr] = CTRLZ;
  280.                 Fd = fopen(FileNm, "w");
  281.                 if (Fd == ERROR) {
  282.                     puts("Cannot create ");
  283.                     puts(FileNm);
  284.                     puts("\n");
  285.                 }
  286.                 else {
  287.                     write(Fd, Bufr,
  288.                         1+(TxtPtr));
  289.                     fclose(Fd);
  290.                     BFlag = FALSE;
  291.                     TxtPtr = 0;
  292.                 }
  293.             }
  294.             break;
  295.  
  296.         case QUIT:
  297.             hangup();
  298.             break;
  299.  
  300.         case RECV:
  301.             if (*cbuf == ' ') {     /* check batch and CRC options */
  302.                 while ((*cbuf == ' ') && !*cbuf)    /* skip leading blanks */
  303.                     cbuf++;
  304.                 Batflg = (*cbuf == 'B') || (*(cbuf+1) == 'B');
  305.                 CRCflg = (*cbuf == 'C') || (*(cbuf+1) == 'C');
  306.                 cbuf += Batflg + CRCflg; /* skip options */
  307.             }
  308.  
  309.             if (*cbuf == ' ') {    /* user entered filename */
  310.                 while ((*cbuf == ' ') && !*cbuf)    /* skip leading blanks */
  311.                     cbuf++;
  312.                 mkstr(15,cbuf,FileNm);
  313.             }
  314.             else
  315.                 if (!Batflg) {
  316.                     puts("Receive what file? \n");
  317.                     getstr(15, FileNm);
  318.                 }
  319.             rdfile(FileNm);
  320.             break;
  321.  
  322.         case SEND:
  323.             if (*cbuf == ' ') {     /* check batch option */
  324.                 while ((*cbuf == ' ') && !*cbuf)    /* skip leading blanks */
  325.                     cbuf++;
  326.                 Batflg = (*cbuf == 'B');
  327.                 cbuf += Batflg; /* skip options */
  328.             }
  329.             if (*cbuf == ' ') {    /* user entered filename */
  330.                 while ((*cbuf == ' ') && !*cbuf)    /* skip leading blanks */
  331.                     cbuf++;
  332.                 mkstr(15,cbuf,FileNm);
  333.             }
  334.             else {
  335.                 puts("Send what file? \n");
  336.                 getstr(15, FileNm);
  337.             }
  338.             sdfile(FileNm);
  339.             break;
  340.     
  341.         case TERMNL:
  342.             break;
  343.  
  344. #if CPM
  345.         case USER:
  346.             if ((Curusr = atoi(cbuf)) <= 15)
  347.                 bdos(GSUSER, Curusr);
  348.             else
  349.                 puts("User number must be between 0 and 15.\n");
  350.             break;
  351. #endif
  352.  
  353.         default:
  354.             puts("Invalid Command, try again\n");
  355.         }
  356.     cbuf = skptok(cbuf);
  357.     }
  358. }
  359.  
  360. kbdin()
  361. {
  362. #if CPM
  363.     return(bdos(DIRCIO, INPUT));
  364. #endif
  365.  
  366. }
  367.  
  368.  
  369. skptok(cbuf)
  370. char *cbuf;
  371. {
  372.         /* skip token in buffer */
  373.     for(;(*cbuf != ' ') && (*cbuf != ';') && 
  374.         (*cbuf != NULL) && (*cbuf != CR);cbuf++)
  375.         ;
  376.     return (cbuf);
  377. }
  378.  
  379.  
  380. cmdmen()
  381. {
  382.     char OnOff[4];
  383.  
  384.     clrscr();  /* clear screen */
  385.     
  386.     puts("\t\t\t\tC Modem\n");
  387.     puts("\nCommand Mode Commands\n");
  388.  
  389.     itoa(brate,strng);
  390.     puts("Baud [rate]\t(");
  391.     puts(strng);
  392.     puts(")\t\tSet baud rate\n");
  393.  
  394.     if (BFlag)
  395.         strcpy(OnOff,"On ");
  396.     else
  397.         strcpy(OnOff,"Off");
  398.     puts("Capture\t\t(");
  399.     puts(OnOff);
  400.     puts(")\t\tCapture received data to buffer\n");
  401.  
  402.     puts("Dir [drive/filename]\t\t\tList directory\n");
  403.     puts("Keep [drive/filename]\t\t\tSave captured data\n");
  404.     puts("Quit\t\t\t\t\tExit program\n");
  405.     puts("Receive [b][c] [drive/filename]\t\tReceive file\n");
  406.     puts("\t\t\t\t\t\tb - batch mode, c - CRC check\n");
  407.     puts("Send [b] [drive/filename]\t\tSend file\n");
  408.     puts("Terminal\t\t\t\tEnter terminal mode\n");
  409.  
  410. #if CPM
  411.     itoa(Curusr,strng);
  412.     puts("User #\t(");
  413.     puts(strng);
  414.     puts(")\t\t\tChange CPM user #\n");
  415. #endif
  416.     
  417.     puts("\nTerminal Mode Commands\n");
  418.     puts("^C\t\t\tEnter command mode\n");
  419.  
  420.     if (Echofl)
  421.         strcpy(OnOff,"On ");
  422.     else
  423.         strcpy(OnOff,"Off");
  424.     puts("^E\t(");
  425.     puts(OnOff);
  426.     puts(")\tEcho On/Off\n");
  427.  
  428.     puts("^L\t\t\tSend next char as-is\n");
  429.  
  430.     if (Prntfl)
  431.         strcpy(OnOff,"On ");
  432.     else
  433.         strcpy(OnOff,"Off");
  434.     puts("^P\t(");
  435.     puts(OnOff);
  436.     puts(")\tPrinter On/Off\n");
  437.  
  438.     if (View)
  439.         strcpy(OnOff,"On ");
  440.     else
  441.         strcpy(OnOff,"Off");
  442.     puts("^V\t(");
  443.     puts(OnOff);
  444.     puts(")\tView of send/recv On/Off\n");
  445.  
  446.     puts("^X\t\t\tCancel send/recv\n");
  447.  
  448.     puts("\n\tCommand:  ");
  449.  
  450.     return;
  451. }
  452.  
  453.  
  454. rdfile(file)
  455. char *file;
  456. {
  457.     int rfd;
  458.  
  459.     if (View) {
  460.         ShowRc = TRUE;
  461.         ShowTr = FALSE;
  462.     }
  463.  
  464.     initmd();            /* initialize modem */
  465.  
  466.     if (Batflg)            /* if batch mode, receive mult files w/names */
  467.         while (recfn(file)) 
  468.             if (!Abort)
  469.                 if (rfd = recopn(file))
  470.                     rdtxt(rfd);
  471.     else                 /* if not batch mode, receive one file */
  472.         if (rfd = recopn(file))
  473.             rdtxt(rfd);
  474.     return;
  475. }
  476.  
  477.  
  478. recsyn()
  479. {
  480.     char chrin;
  481.     int errcnt;
  482.  
  483.     errcnt = 0;
  484.     chrin = NULL;
  485.  
  486.     while ((!Abort) && (chrin != ACK)) {
  487.         if (!CRCflg)
  488.             sdchar(NAK);   /* declare checksumming */
  489.         else
  490.             sdchar('C');   /* declare CRC checking */
  491.         chrin = rdchar(2);    /* wait for ACK */
  492.         if (chrin == CANCEL) {
  493.             Abort++;
  494.             puts("\n Receive cancelled by Sender \n");
  495.         }
  496.         if (CRCflg && (chrin != ACK)) {
  497.             errcnt++;
  498.             if (errcnt > 10) {
  499.                 puts("\n CRC not acknowledged, switching to checksum \n");
  500.                 CRCflg = 0;
  501.             }
  502.         }
  503.  
  504.         if (kbdin() == CANCEL) {
  505.             Abort++;
  506.             puts("\n Receive cancelled by You \n");
  507.         }
  508.     }
  509. }
  510.  
  511.  
  512. rdtxt(rfd)
  513. int rfd;
  514. {
  515.  
  516.     static int chrin, secnum, seccur, seccmp, errors;
  517.     static int chksum, tret;
  518.     static int errflg;
  519.     static int j, bufptr;
  520.     char itoaw[12];
  521.  
  522.     recsyn();        /* send NAK/'C' until in sync w/xmitter */
  523.  
  524.     if (Abort)
  525.         return FALSE;
  526.     else
  527.         puts("\n Awaiting Initial Sector ... ");
  528.  
  529.     secnum = errors = bufptr = 0;
  530.  
  531.     do {
  532.     while ((chrin = rdchar(10)) != SOH) {    /* wait for SOH */
  533.         if (chrin == CANCEL) {
  534.             Abort++;
  535.             return FALSE;
  536.         }
  537.         if (chrin == EOT)
  538.             return TRUE;
  539.         if (chrin == TIMOUT)
  540.             puts("\n Timeout waiting for SOH ++ ");
  541.         if ((chrin != SOH) && (chrin != TIMOUT)) {
  542.             puts("\n Received ");
  543.             itoa(chrin,strng);
  544.             puts(strng);
  545.             puts(", not SOH\n");
  546.             purgln();
  547.         }
  548.         if (kbdin() == CANCEL) {
  549.             puts("\n Receive cancelled by You\n");
  550.             Abort++;
  551.             return FALSE;
  552.         }
  553.     }
  554.  
  555.     if (chrin == SOH) {
  556.         seccur = rdchar(1);
  557.         seccmp = rdchar(1);
  558.         if ((seccur + seccmp) == 255) {
  559.             if (seccur == (secnum + 1 & 0xff)) {
  560.                 chksum = 0;
  561.  
  562.                    for (j=bufptr; j<(bufptr+SECSIZ); j++) { /* read a sector */
  563.                     Bufr[j] = rdchrc(1, chksum);
  564.                     if (Bufr[j] == TIMOUT) {
  565.                         errors++;
  566.                         break;
  567.                     }
  568.                 }
  569.  
  570.                 if (!errors) {
  571.                     if (CRCflg) {    /* force the CRC through the bucket */
  572.                         rdchrc(1, chksum);
  573.                         rdchrc(1, chksum);
  574.                     }
  575.                     else
  576.                         chksum = chksum - rdchar(1);
  577.                     if (!chksum) {
  578.                         errors = 0;
  579.                         secnum++;
  580.                         bufptr += SECSIZ;
  581.                         if ((secnum % BUFSEC) == 0) {
  582.                             bufptr = 0;
  583.                             if (write(rfd,Bufr,BUFSEC*SECSIZ) == ERROR) {
  584.                                 puts("\n Error writing file, Aborting\n");
  585.                                 fclose(rfd);
  586.                                 Abort++;
  587.                                 return FALSE;
  588.                             }
  589.                             /*  if sender times out while we
  590.                                 are writing the disk, it will
  591.                                 resend the sector.  Hang here
  592.                                 until it's done, then fall
  593.                                 through and acknowledge */
  594.                             do ; /* nothing */
  595.                             while (rdchar(1) != TIMOUT);
  596.                         }
  597.                         sdchar(ACK);
  598.                     }
  599.                     else {
  600.                         if (CRCflg == 0)
  601.                             puts("\nCRC error ");
  602.                         else
  603.                             puts("\nChecksum error ");
  604.                     }
  605.                 }
  606.             }
  607.             else if (seccur == (secnum & 0xff)) {
  608.                 puts("\nReceived duplicate sector ");
  609.                 itoa(itoaw,secnum);
  610.                 puts(itoaw);
  611.             /* wait for silence on the line */
  612.                 do ; /* nothing */
  613.                 while (rdchar(1) != TIMOUT);
  614.                 sdchar(ACK);
  615.             }
  616.             else 
  617.                 puts("\nSynchronization error\n");
  618.         }
  619.         else 
  620.             puts("\nSector number error\n");
  621.         }
  622.         if (kbdin() == CANCEL) {
  623.             errors = ERRMAX;
  624.             break;
  625.         }
  626.         if (errflg == TRUE) {
  627.             errors++;
  628.             puts("Error ");
  629.             itoa(errors,strng);
  630.             puts(strng);
  631.             puts("\n");
  632.             do ; /* nothing */
  633.             while (rdchar(1) != TIMOUT);
  634.             sdchar(NAK);
  635.         }
  636.     } while (chrin != EOT && errors != ERRMAX);
  637.  
  638.     if ((chrin == EOT) && (errors < ERRMAX)) {
  639.         sdchar(ACK);
  640.         write(rfd, Bufr, 1 + bufptr);
  641.         fclose(rfd);
  642.         puts("\nTransfer complete\n");
  643.     }
  644.     else
  645.         puts("\n\nAborting\n");
  646. }
  647.  
  648.  
  649. recfn(file)        /* receive filename in batch mode */
  650. char *file;        /* returns a FALSE if no more filenames */
  651. {
  652.     char chrin, *fptr;
  653.     int errcnt, errs, chksum;
  654.  
  655.     chrin = NULL;
  656.     errcnt = errs = 0;
  657.     fptr = file;    /* save start of filename */
  658.     
  659.     puts("\n Awaiting Filename from Sender ");
  660.  
  661.     while ((errs < ERRMAX) && chrin != CTRLZ) {
  662.  
  663.         recsyn();    /* send NAK/'C' until in sync */
  664.                     /*  may set Abort flag on error */
  665.  
  666.         while ((!Abort) && (chrin != CTRLZ)) {
  667.             chrin = rdchar(5);    /* get next filename character */
  668.             if (chrin == TIMOUT) {
  669.                 errs++;
  670.                 puts("\n Timeout on filename receive \n");
  671.                 break;
  672.             }
  673.             else
  674.                 errs = 0;
  675.  
  676.             if (chrin != CTRLZ) {
  677.                 *fptr++ = chrin;    /* accumulate filename */
  678.                 sdchar(ACK);        /* tell sender I got it */
  679.             }
  680.         }
  681.         *fptr = NULL;            /* end of string */
  682.  
  683.         if ((!Abort) && (!errs)) {
  684.             sdchar(chksum);            /* send received checksum (or CRC) */
  685.             chrin = rdchar(5);    /* wait for ACK */
  686.             if (chrin == TIMOUT) {
  687.                 errs++;
  688.                 puts("\n Timeout on filename receive \n");
  689.             }
  690.         }
  691.     }
  692.     if (errs == 0) 
  693.         return (TRUE);
  694.     else
  695.         return (FALSE);
  696. }
  697.  
  698.  
  699. recopn(file)        /* open a file for receiving */
  700. char *file;
  701. {    
  702.     int rfd;
  703.     char ans;
  704.  
  705.     ans = ' ';
  706.     rfd = 0;
  707.  
  708.     if(!(rfd = fopen(file, "r"))) {    /* file exists, check w/ user */
  709.         while ((ans != 'D') && (ans != 'N')) {
  710.             puts("\n\t==> File exists.  Enter D to delete or N for new filename: ");
  711.             getstr(1,ans);
  712.             ans = toupper(ans);
  713.         }
  714.         fclose(rfd);
  715.         rfd = 0;
  716.         if (ans == 'D') {
  717.             if (unlink(file) == -1) {
  718.                 puts("\n ==> File delete failed, Aborting\n");
  719.                 Abort++;
  720.             }
  721.         }
  722.         else if (ans == 'N') {
  723.             puts("\n Enter new filename: ");
  724.             getstr(15,file);
  725.         }
  726.     }
  727.  
  728.     if (!Abort)
  729.         if ((rfd = creat(file)) == -1) {
  730.             puts("\n ==> Cannot create file ");
  731.             Abort++;
  732.         }
  733.     return rfd;
  734. }
  735.  
  736.  
  737. rdchrc(secs, chksum)    /* read and compute checksum/CRC */
  738. int secs, chksum;
  739. {
  740.     int ret;
  741.  
  742.     ret = rdchar(secs);
  743.     if (ret != TIMOUT) 
  744.         if (CRCflg)
  745.             crc_update(chksum,ret);
  746.         else
  747.             chksum = (chksum + ret) & 0xff;
  748.     return (ret);
  749. }
  750.  
  751.     
  752. rdchar(secs)
  753. int secs;
  754. {
  755.     static char data;
  756.  
  757.     secs = secs*SPS;
  758.     while (!minrdy() && secs)  /* wait until input ready */
  759.         --secs;
  760.     if (!secs)
  761.         return TIMOUT;    /* nothing arrived in time */
  762.     data = mchari();    /* else, get it */
  763.     if (ShowRc) {
  764.         if(((data >= ' ') && (data <= DATMSK))
  765.            || data == LF || data == CR || data == TAB)
  766.             putchar(data);
  767.         else
  768.             puts(".");
  769.     }
  770.     return data;
  771. }
  772.  
  773.  
  774. sdfile(file)
  775. char *file;
  776. {
  777.     static int secnum, sects, tries;
  778.     static int chksum, sfd;
  779.     static int j, k, bufptr;
  780.  
  781.     if (View) {
  782.         ShowRc = FALSE;
  783.         ShowTr = TRUE;
  784.     }
  785.     sfd = fopen(file, "r");
  786.     if (sfd == ERROR) {
  787.         puts("Cannot open ");
  788.         puts(file);
  789.         puts("\n");
  790.         return;
  791.     }
  792.     else
  793.         puts("Sending ");
  794.         puts("\n\n");
  795.         puts(file);
  796.     initmd();
  797.     tries = 0;
  798.     secnum = 1;
  799.  
  800.     puts("\nWaiting a NAK\n\n");
  801.     do {
  802.         j = rdchar(10);
  803.         if (j == 'C')
  804.             CRCflg = 1;
  805.         else if (j == NAK)
  806.             CRCflg = 0;
  807.     } while ((j != NAK) && (j != 'C') && ((k = kbdin()) != CANCEL));
  808.  
  809.     while ((sects = read(sfd, Bufr, BUFSIZ/SECSIZ)) && (tries != RETMAX)) {
  810.         if (sects == ERROR) {
  811.             puts("\nError reading file\n");
  812.             fclose(sfd);
  813.             return;
  814.         }
  815.         else {
  816.             bufptr = 0;
  817.             do {
  818.                 tries = 0;
  819.                 do {
  820.                     if (!ShowTr)
  821.                         if (((secnum - 1) % DOTS) == 0)
  822.                             puts("\n<%4d>.", secnum);
  823.                         else
  824.                             puts(".");
  825.                     sdchar(SOH);
  826.                     sdchar(secnum);
  827.                     sdchar(~secnum);
  828.                     chksum = 0;
  829.                     for (j = bufptr; j < (bufptr + SECSIZ); j++) {
  830.                         sdchar(Bufr[j]);
  831.                         if (CRCflg == 0)
  832.                             chksum = (chksum + Bufr[j]) & 0xff;
  833.                     }
  834.                     if (CRCflg != 0)
  835.                         chksum = cmpcrc(bufptr,SECSIZ);
  836.                     sdchar(chksum);
  837.                     prglne();
  838.                     tries++;
  839.                 } while ((rdchar(10) != ACK) &&
  840.                      (tries != RETMAX));
  841.                 bufptr += SECSIZ;
  842.                 secnum++;
  843.                 sects--;
  844.             } while (sects && (tries != RETMAX));
  845.         }
  846.     }
  847.  
  848.     if (k == CANCEL)
  849.         puts("\nTransmission cancelled\n");
  850.     else     if (tries == RETMAX)
  851.         puts("\nNo acknowledgment of sector, aborting\n");
  852.     else {
  853.         tries = 0;
  854.         do {
  855.             sdchar(EOT);
  856.             prglne();
  857.             tries++;
  858.     } while ((rdchar(10) != ACK) && (tries != RETMAX));
  859.     if (tries == RETMAX) 
  860.         puts("\nNo acknowledgment of end of file, aborting\n");
  861.     else
  862.         puts("\nTransfer complete\n");
  863.     }
  864.     fclose(sfd);
  865.     return;
  866. }
  867.  
  868.  
  869. sdchar(data)
  870. char data;
  871. {
  872.     while (!motrdy());    /* wait until output ready */
  873.     
  874.     mcharo(data);        /* send it */
  875.  
  876.     if (ShowTr) {
  877.         if (((data >= ' ') && (data <= DATMSK))
  878.             || data == LF || data == CR || data == TAB)
  879.             putchar(data);
  880.         else
  881.             puts(".");
  882.     }
  883.     return;
  884. }
  885.  
  886.  
  887. touppr(ichar)
  888. char ichar;
  889. {
  890.     ichar = (ichar >= 'a' & ichar <= 'z') ? ichar - 32 : ichar;
  891. }
  892.  
  893.  
  894.  
  895. /******************************************************************************
  896. *                                                                             *
  897. *               Cyclic Redundancy Check (CRC) functions                       *
  898. *                                                                             *
  899. ******************************************************************************/
  900.  
  901. /*
  902. *   crc_clear:
  903. *    This function clears the CRC to zero. It should be called prior to
  904. *    the start of the processing of a block for both received messages,
  905. *    and messages to be transmitted.
  906. *
  907. *    Calling sequence:
  908. *
  909. *    short crc;
  910. *    crc = crc_clear();
  911. */
  912. short crc_clear()
  913. {
  914.     return(0);
  915. }
  916. /*
  917. *   crc_update:
  918. *    this function must be called once for each character which is
  919. *    to be included in the CRC for messages to be transmitted.
  920. *    This function is called once for each character which is included
  921. *    in the CRC of a received message, AND once for each of the two CRC
  922. *    characters at the end of the received message. If the resulting
  923. *    CRC is zero, then the message has been correctly received.
  924. *
  925. *   Calling sequence:
  926. *
  927. *    crc = crc_update(crc,next_char);
  928. */
  929. short crc_update(crc,crc_char)
  930. short crc;
  931. char crc_char;
  932. {
  933.     long x;
  934.     short i;
  935.  
  936. /* "x" will contain the character to be processed in bits 0-7 and the CRC    */
  937. /* in bits 8-23. Bit 24 will be used to test for overflow, and then cleared  */
  938. /* to prevent the sign bit of "x" from being set to 1. Bits 25-31 are not    */
  939. /* used. ("x" is treated as though it is a 32 bit register).                 */
  940.     x = ((long)crc << 8) + crc_char;    /* Get the CRC and the character */
  941.  
  942. /* Repeat the following loop 8 times (for the 8 bits of the character).      */
  943.     for(i = 0;i < 8;i++)
  944.     {
  945.  
  946. /* Shift the high-order bit of the character into the low-order bit of the   */
  947. /* CRC, and shift the high-order bit of the CRC into bit 24.                 */
  948.         x = x << 1;                        /* Shift "x" left one bit */
  949.  
  950. /* Test to see if the old high-order bit of the CRC was a 1.                 */
  951.         if(x & 0x01000000)                     /* Test bit 24 of "x" */
  952.  
  953. /* If the old high-order bit of the CRC was a 1, exclusive-or it with a one  */
  954. /* to set it to 0, and exclusive-or the CRC with hex 1021 to produce the     */
  955. /* CCITT-recommended CRC generator of: X**16 + X**12 + X**5 + 1. To produce  */
  956. /* the CRC generator of: X**16 + X**15 + X**2 + 1, change the constant from  */
  957. /* 0x01102100 to 0x01800500. This will exclusive-or the CRC with hex 8005    */
  958. /* and produce the same CRC that IBM uses for their synchronous transmission */
  959. /* protocols.                                                                */
  960.             x = x ^ 0x01102100;     /* Exclusive-or "x" with a...*/
  961.                                               /* ...constant of hex 01102100 */
  962. /* And repeat 8 times.                                                       */
  963.     }                                               /* End of "for" loop */
  964.  
  965. /* Return the CRC as the 16 low-order bits of this function's value.         */
  966.     return(((x & 0x00ffff00) >> 8)); /* AND off the unneeded bits and... */
  967.                                   /* ...shift the result 8 bits to the right */
  968.  
  969. }
  970. /*
  971. *   crc_finish:
  972. *    This function must be called once after all the characters in a block
  973. *    have been processed for a message which is to be TRANSMITTED. It
  974. *    returns the calculated CRC bytes, which should be transmitted as the
  975. *    two characters following the block. The first of these 2 bytes
  976. *    must be taken from the high-order byte of the CRC, and the second
  977. *    must be taken from the low-order byte of the CRC. This routine is NOT
  978. *    called for a message which has been RECEIVED.
  979. *
  980. *   Calling sequence:
  981. *
  982. *    crc = crc_finish(crc);
  983. */
  984. short crc_finish(crc)
  985. short crc;
  986. {
  987. /* Call crc_update twice, passing it a character of hex 00 each time, to     */
  988. /* flush out the last 16 bits from the CRC calculation, and return the       */
  989. /* result as the value of this function.                                     */
  990.     return(crc_update(crc_update(crc,NULL),NULL));
  991.  
  992. }
  993.  
  994. int baudrt = 05;  /* index for 1200 baud (baudtb[5]="1200") */
  995.  
  996. baudst(baudin)
  997. int baudin;
  998. {
  999.     static baudtb[] = {110,150,300,600,1200,2400,4800,9600};
  1000.  
  1001.     static int indx;
  1002.     static char baudsi[5];
  1003.  
  1004.     while (baudin == 0) {
  1005.         puts("\n\t 110,150,300,600,1200,2400,4800,9600");
  1006.         puts("\nEnter the required baud rate ");
  1007.         getstr(5,baudsi);
  1008.         baudin = atoi(baudsi);
  1009.     }
  1010.  
  1011.     for (indx=0; indx<=(sizeof(baudtb)/sizeof(baudtb[1])); indx++)
  1012.         if (baudin == baudtb[indx]) {
  1013.             baudrt = indx;
  1014.             return baudin;
  1015.         }
  1016.     return FALSE;
  1017. }
  1018.  
  1019.  
  1020. clrscr()
  1021. {
  1022.     scr_clr();
  1023. }
  1024.  
  1025.  
  1026. initmd()
  1027. {
  1028.     sioint(baudrt);
  1029.     prglne();
  1030. }
  1031.  
  1032. prglne()
  1033. {
  1034.     while (minrdy())    /* while there are characters... */
  1035.         mchari();    /* gobble them  */
  1036. }
  1037.  
  1038. mchari()
  1039. {
  1040.     while (!(inp(mstat) & rxrdy));
  1041.     return inp(mdata);
  1042. }
  1043.  
  1044. mcharo(c)
  1045. char c;
  1046. {
  1047.     while(!(inp(mstat) & txrdy));
  1048.     outp(mdata,c);
  1049. }
  1050.  
  1051. motrdy()
  1052. {
  1053.     return ((inp(mstat) & txrdy) > 0);
  1054. }
  1055.  
  1056. minrdy()
  1057. {
  1058.     return ((inp(mstat) & rxrdy) > 0);
  1059. }
  1060.  
  1061. dcdrdy()
  1062. {
  1063.     outp(mstat,rstext);  /* ext reset must be done b4 dcd is ok */
  1064.     return ((inp(mstat) & mdcd) > 0);
  1065. }
  1066.  
  1067.