home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 098.lha / postb.c < prev    next >
C/C++ Source or Header  |  1986-11-20  |  22KB  |  881 lines

  1.  
  2.  
  3. /**
  4.  * Copyright (c) 1985 by Steve Wilhite, Worthington, Ohio
  5.  *
  6.  * Permission is granted to use or distribute this software without any
  7.  * restrictions as long as this entire copyright notice is included intact.
  8.  * You may include it in any software product that you sell for profit.
  9.  *
  10.  * This software is distributed as is, and is not guaranteed to work on any
  11.  * given hardware/software configuration.  Furthermore, no liability is
  12.  * granted with this software.
  13.  *
  14.  * ABSTRACT:
  15.  *
  16.  *   The function, Transfer_File, implements error-free file transfer using
  17.  *   CompuServe's "B" protocol.
  18.  *
  19.  *   It has been assumed that the start-of-packet sequence, DLE "B", has
  20.  *   been detected and the next byte not received yet is the packet
  21.  *   sequence number (an ASCII digit).
  22.  *
  23.  * ENVIRONMENT: Lattice "C", machine independent.
  24.  *
  25.  * AUTHOR: Steve Wilhite, CREATION DATE: 21-Jul-85
  26.  *
  27.  * REVISION HISTORY:
  28.  * Jan 1-3 1988 - Charles B. Blish - Formatted source properly. IMHO.
  29.  *                                   added 'short' specifier to vars,
  30.  *                                   removing 32 bit default of lattice.
  31.  *                           
  32.  *
  33.  **/
  34.  
  35. #include <lattice/stdio.h>
  36. #include <lattice/fcntl.h>
  37.  
  38. /* External Functions */
  39.  
  40. extern Delay();                /* Sleep for "n" milliseconds */
  41. extern Start_Timer();          /* Enable the timer for the specified number
  42.                                   seconds */
  43. extern int Timer_Expired();    /* Returns "true" if the timer has expired,
  44.                                  "false" otherwise */
  45. extern int Wants_To_Abort();   /* Returns "true" if the user wants to abort
  46.                                   the file transfer, "false" otherwise */
  47. extern int Read_Modem();       /* Read a character from the comm port.
  48.                    Returns -1     if no character available */
  49. extern int Write_Modem();      /* Send a character to the comm port. Returns
  50.                                   "true" is successful, "false" otherwise */
  51.  
  52. extern int open(), creat();    /* standard I/O functions */
  53. extern int read(), write();
  54. extern int close();
  55.  
  56. #define ETX   0x03
  57. #define ENQ   0x05
  58. #define DLE   0x10
  59. #define XON   0x11
  60. #define XOFF  0x13
  61. #define NAK   0x15
  62. #define NUL   0x00
  63.  
  64. #define True          1
  65. #define False         0
  66. #define Success      -1
  67. #define Failure       0
  68. #define Packet_Size   512
  69. #define Max_Errors    7
  70. #define Max_Time      15
  71. #define WACK          ';'      /* wait acknowledge */
  72.  
  73. /* Sender actions */
  74.  
  75. #define S_Send_Packet   0
  76. #define S_Get_DLE       1
  77. #define S_Get_Num       2
  78. #define S_Get_Seq       3
  79. #define S_Get_Data      4
  80. #define S_Get_Checksum  5
  81. #define S_Timed_Out     6
  82. #define S_Send_NAK      7
  83.  
  84. /* Receiver actions */
  85.  
  86. #define R_Get_DLE        0
  87. #define R_Get_B          1
  88. #define R_Get_Seq        2
  89. #define R_Get_Data       3
  90. #define R_Get_Checksum   4
  91. #define R_Send_NAK       5
  92. #define R_Send_ACK       6
  93.  
  94.  
  95. /* variables used by external routine that shows transfer status
  96.  * in window - provided by user: CBB, Jan/88
  97.  */
  98. extern int datablocks,dataretrys,oursize;
  99. /******************************************/
  100.  
  101. /* routines called for handling status window;
  102.  * provided by user: CBB Jan/88
  103.  */
  104.  
  105. extern int updl();            /* update download status window numbers */
  106. extern int svcdl();           /* check for wants to abort by windowclose */
  107.                               /* abort is forced by pushing ^C into the */
  108.                               /* users kbd input */
  109. extern int upul();            /* update upload status report window #'s */
  110. extern int svcup();           /* check for wants to abort by windowclose */
  111.                               /* abort is forced by pushing ^C into the */
  112.                               /* users kbd input */
  113. extern int showdownload();    /* opens window for status, calls recieve */
  114. extern int showupload();      /* opens window for status, calls transmit */
  115.  
  116. /******************************************/
  117.  
  118. static short Checksum;
  119.  
  120. static short
  121. Ch,
  122. Seq_Num,
  123. R_Size,            /* Size of receiver buffer */
  124. XOFF_Flag,
  125. Seen_ETX;
  126.  
  127. static unsigned char
  128. S_Buffer[Packet_Size],      /* Sender buffer */
  129. R_Buffer[Packet_Size];      /* Receiver buffer */
  130.  
  131. static Put_Msg(Text)
  132.  
  133. char *Text;
  134.   {
  135.     while (*Text != 0) Put_Char(*Text++);
  136.     Put_Char('\015');
  137.     Put_Char('\012');
  138.     return(0);
  139.   }
  140.  
  141.  
  142.  
  143. static Send_Byte(Ch)
  144. int Ch;
  145.   {
  146.     short TCh;
  147.     /* Listen for XOFF from the network */
  148.     do
  149.       {
  150.         while ((TCh = Read_Modem()) >= 0)
  151.           {
  152.             if (TCh == XON)
  153.               {
  154.                 XOFF_Flag = False;
  155.               }
  156.             else if (TCh == XOFF)
  157.               {
  158.                 XOFF_Flag = True;
  159.               }
  160.           }
  161.       } while (XOFF_Flag);
  162.     while (!Write_Modem(Ch));
  163.     return(0);
  164.   }
  165.  
  166.  
  167.  
  168. static Send_Masked_Byte(Ch)
  169. short Ch;
  170.   {
  171.     /* Mask any protocol or flow characters */
  172.     /*PutChar(Ch);*/
  173.     if (Ch == ETX || Ch == NUL || Ch == ENQ || Ch == DLE || Ch == NAK || Ch == XON || Ch == XOFF)
  174.       {
  175.         Send_Byte(DLE);
  176.         Send_Byte(Ch + '@');
  177.       }
  178.     else
  179.       {
  180.         Send_Byte(Ch);
  181.       }
  182.     return(0);
  183.   }
  184.  
  185.  
  186.  
  187. static Send_ACK()
  188.   {
  189.     Send_Byte(DLE);
  190.     Send_Byte(Seq_Num + '0');
  191.     return(0);
  192.   }
  193.  
  194.  
  195.  
  196. static Read_Byte()
  197.   {
  198.     if ((Ch = Read_Modem()) < 0)
  199.       {
  200.         Start_Timer(Max_Time);
  201.         do
  202.           {
  203.             if (Timer_Expired()) return Failure;
  204.           } while ((Ch = Read_Modem()) < 0);
  205.       }
  206.     return Success;
  207.   }
  208.  
  209.  
  210.  
  211. static Read_Masked_Byte()
  212.   {
  213.     Seen_ETX = False;
  214.     if (Read_Byte() == Failure) return Failure;
  215.     /*PutChar(Ch);*/
  216.     if (Ch == DLE)
  217.       {
  218.         if (Read_Byte() == Failure) return Failure;
  219.         Ch &= 0x1F;
  220.       }
  221.     else if (Ch == ETX) Seen_ETX = True;
  222.     return Success;
  223.   }
  224.  
  225.  
  226.  
  227.  
  228. static Do_Checksum(Ch)
  229. short Ch;
  230.   {
  231.     Checksum <<= 1;
  232.     if (Checksum > 255)
  233.       {
  234.         Checksum = (Checksum & 0xFF) + 1;
  235.       }
  236.     Checksum += Ch;
  237.     if (Checksum > 255)
  238.       {
  239.         Checksum = (Checksum & 0xFF) + 1;
  240.       }
  241.     return(0);
  242.   }
  243.  
  244.  
  245.  
  246. static int Read_Packet(Action)
  247. /**
  248.  * Function:
  249.  *   Receive a packet from the host.
  250.  *
  251.  * Inputs:
  252.  *   Action -- the starting action
  253.  *
  254.  * Outputs:
  255.  *   R_Buffer -- contains the packet just received
  256.  *   R_Size -- length of the packet
  257.  *
  258.  * Returns:
  259.  *   success/failure
  260.  **/
  261. int Action;
  262.   {
  263.     short Errors;
  264.     short Next_Seq;
  265.  
  266.     Errors = 0;
  267.     updl(); /* update download window */
  268.     svcdl(); /* watch for user close... */
  269.     while (Errors < Max_Errors)
  270.       {
  271.         switch (Action)
  272.           {
  273.             case R_Get_DLE:
  274.               {
  275.                 if (Read_Byte() == Failure)
  276.                   {
  277.                     Action = R_Send_NAK;
  278.                   }
  279.                 else if (Ch == DLE)
  280.                   {
  281.                     Action = R_Get_B;
  282.                   }
  283.                 else if (Ch == ENQ)
  284.                   {
  285.                     Action = R_Send_ACK;
  286.                   }
  287.                 break;
  288.               }
  289.             case R_Get_B:
  290.               {
  291.                 if (Read_Byte() == Failure)
  292.                   {
  293.                     Action = R_Send_NAK;
  294.                   }
  295.                 else if (Ch == 'B')
  296.                   {
  297.                     Action = R_Get_Seq;
  298.                   }
  299.                 else
  300.                   {
  301.                     Action = R_Get_DLE;
  302.                   }
  303.                 break;
  304.               }
  305.             case R_Get_Seq:
  306.               {
  307.                 if (Read_Byte() == Failure)
  308.                   {
  309.                     Action = R_Send_NAK;
  310.                   }
  311.                 else
  312.                   {
  313.                     Checksum = 0;
  314.                     Next_Seq = Ch - '0';
  315.                     Do_Checksum(Ch);
  316.                     R_Size = 0;
  317.                     Action = R_Get_Data;
  318.                   }
  319.                 break;
  320.               }
  321.             case R_Get_Data:
  322.               {
  323.                 if (Read_Masked_Byte() == Failure)
  324.                   {
  325.                     Action = R_Send_NAK;
  326.                   }
  327.                 else if (Seen_ETX)
  328.                   {
  329.                     Action = R_Get_Checksum;
  330.                   }
  331.                 else if (R_Size == Packet_Size)
  332.                   {
  333.                     Action = R_Send_NAK;
  334.                   }
  335.                 else
  336.                   {
  337.                     R_Buffer[R_Size++] = Ch;
  338.                     Do_Checksum(Ch);
  339.                   }
  340.                 break;
  341.               }
  342.             case R_Get_Checksum:
  343.               {
  344.                 Do_Checksum(ETX);
  345.                 if (Read_Masked_Byte() == Failure)
  346.                   {
  347.                     Action = R_Send_NAK;
  348.                   }
  349.                 else if (Checksum != Ch)
  350.                   {
  351.                     Action = R_Send_NAK;
  352.                   }
  353.                 else if (Next_Seq == Seq_Num)
  354.                   {
  355.                     Action = R_Send_ACK;   /* Ignore duplicate packet */
  356.                   }
  357.                 else if (Next_Seq != (Seq_Num + 1) % 10)
  358.                   {
  359.                     Action = R_Send_NAK;
  360.                   }
  361.                 else
  362.                   {
  363.                     Seq_Num = Next_Seq;
  364.                     datablocks++;
  365.                     return Success;
  366.                   }
  367.                 break;
  368.               }
  369.             case R_Send_NAK:
  370.               {
  371.                 Errors++;
  372.                 dataretrys++;
  373.                 Send_Byte(NAK);
  374.                 Action = R_Get_DLE;
  375.                 break;
  376.                 case R_Send_ACK:
  377.                 Send_ACK();
  378.                 Action = R_Get_DLE;
  379.                 break;
  380.               }
  381.           }
  382.       }
  383.  
  384.     return Failure;
  385.   }
  386.  
  387.  
  388.  
  389. static int Send_Packet(Size)
  390. /**
  391.  * Function:
  392.  *   Send the specified packet to the host.
  393.  *
  394.  * Inputs:
  395.  *   Size -- length of the packet
  396.  *   S_Buffer -- the packet to send
  397.  *
  398.  * Outputs:
  399.  *
  400.  * Returns:
  401.  *   success/failure
  402.  **/
  403. short Size;            /* size of packet to send */
  404.   {
  405.     short Action;
  406.     short Next_Seq;
  407.     short RCV_Num;
  408.     short I;
  409.     short Errors;
  410.     Next_Seq = (Seq_Num + 1) % 10;
  411.     Errors = 0;
  412.     Action = S_Send_Packet;
  413.     upul(); /* update download window */
  414.     svcdl(); /* watch for user close... */
  415.     while (Errors < Max_Errors)
  416.       {
  417.         switch (Action)
  418.           {
  419.             case S_Send_Packet:
  420.               {
  421.                 Checksum = 0;
  422.                 Send_Byte(DLE);
  423.                 Send_Byte('B');
  424.                 Send_Byte(Next_Seq + '0');
  425.                 Do_Checksum(Next_Seq + '0');
  426.                 for (I = 0; I < Size; I++)
  427.                   {
  428.                     Send_Masked_Byte(S_Buffer[I]);
  429.                     Do_Checksum(S_Buffer[I]);
  430.                   }
  431.                 Send_Byte(ETX);
  432.                 Do_Checksum(ETX);
  433.                 Send_Masked_Byte(Checksum);
  434.                 Action = S_Get_DLE;
  435.                 break;
  436.               }
  437.             case S_Get_DLE:
  438.               {
  439.                 if (Read_Byte() == Failure)
  440.                   {
  441.                     Action = S_Timed_Out;
  442.                   }
  443.                 else if (Ch == DLE)
  444.                   {
  445.                     Action = S_Get_Num;
  446.                   }
  447.                 else if (Ch == NAK)
  448.                   {
  449.                     Errors++;
  450.                     dataretrys++;
  451.                     Action = S_Send_Packet;
  452.                   }
  453.                 break;
  454.               }
  455.             case S_Get_Num:
  456.               {
  457.                 if (Read_Byte() == Failure)
  458.                   {
  459.                     Action = S_Timed_Out;
  460.                   }
  461.                 else if (Ch >= '0' && Ch <= '9')
  462.                   {
  463.                     if (Ch == Seq_Num + '0')
  464.                       {
  465.                         Action = S_Get_DLE;   /* Ignore duplicate ACK */
  466.                       }
  467.                     else if (Ch == Next_Seq + '0')
  468.                       {
  469.                         /* Correct sequence number */
  470.                         Seq_Num = Next_Seq;
  471.                         return Success;
  472.                       }
  473.                     else
  474.                       {
  475.                         if (Errors == 0)
  476.                           {
  477.                             Action = S_Send_Packet;
  478.                           }
  479.                         else
  480.                           {
  481.                             Action = S_Get_DLE;
  482.                           }
  483.                       }
  484.                   }
  485.                 else if (Ch == WACK)
  486.                   {
  487.                     /*Delay(50);    Sleep for 5 seconds */
  488.                     Action = S_Get_DLE;
  489.                   }
  490.                 else if (Ch == 'B')
  491.                   {
  492.                     Action = S_Get_Seq;
  493.                   }
  494.                 else
  495.                   {
  496.                     Action = S_Get_DLE;
  497.                   }
  498.                 break;
  499.               }
  500.             case S_Get_Seq:
  501.               {
  502.                 /**
  503.                * Start of a "B" protocol packet. The only packet that makes
  504.                * any sense here is a failure packet.
  505.                **/
  506.                 if (Read_Byte() == Failure)
  507.                   {
  508.                     Action = S_Send_NAK;
  509.                   }
  510.                 else
  511.                   {
  512.                     Checksum = 0;
  513.                     RCV_Num = Ch - '0';
  514.                     Do_Checksum(Ch);
  515.                     I = 0;
  516.                     Action = S_Get_Data;
  517.                   }
  518.                 break;
  519.               }
  520.             case S_Get_Data:
  521.               {
  522.                 if (Read_Masked_Byte() == Failure)
  523.                   {
  524.                     Action = S_Send_NAK;
  525.                   }
  526.                 else if (Seen_ETX)
  527.                   {
  528.                     Action = S_Get_Checksum;
  529.                   }
  530.                 else if (I == Packet_Size)
  531.                   {
  532.                     Action = S_Send_NAK;
  533.                   }
  534.                 else
  535.                   {
  536.                     R_Buffer[I++] = Ch;
  537.                     Do_Checksum(Ch);
  538.                   }
  539.                 break;
  540.               }
  541.             case S_Get_Checksum:
  542.               {
  543.                 Do_Checksum(ETX);
  544.                 if (Read_Masked_Byte() == Failure)
  545.                   {
  546.                     Action = S_Send_NAK;
  547.                   }
  548.                 else if (Checksum != Ch)
  549.                   {
  550.                     Action = S_Send_NAK;
  551.                   }
  552.                 else if (RCV_Num != (Next_Seq + 1) % 10)
  553.                   {
  554.                     Action = S_Send_NAK;
  555.                   }
  556.                 else
  557.                   {
  558.                     /**
  559.                     * Assume the packet is failure packet. It makes no
  560.                     * difference since any other type of packet would be
  561.                     * invalid anyway. Return failure to caller.
  562.                     **/
  563.                     Errors = Max_Errors;
  564.                   }
  565.                 break;
  566.               }
  567.             case S_Timed_Out:
  568.               {
  569.                 Errors++;
  570.                 dataretrys++;
  571.                 Action = S_Get_DLE;
  572.                 break;
  573.               }
  574.             case S_Send_NAK:
  575.               {
  576.                 Errors++;
  577.                 dataretrys++;
  578.                 Send_Byte(NAK);
  579.                 Action = S_Get_DLE;
  580.                 break;
  581.               }
  582.           }
  583.       }
  584.     toterm("");
  585.     toterm("Too many Errors!");
  586.     toterm("");
  587.     return Failure;
  588.   }
  589.  
  590.  
  591.  
  592. static Send_Failure(Code)
  593. /**
  594.  * Function:
  595.  *   Send a failure packet to the host.
  596.  *
  597.  * Inputs:
  598.  *   Code -- failure code
  599.  *
  600.  * Outputs:
  601.  *
  602.  * Returns:
  603.  **/
  604. char Code;
  605.   {
  606.     S_Buffer[0] = 'F';
  607.     S_Buffer[1] = Code;
  608.     Send_Packet(2);
  609.     return(0);
  610.   }
  611.  
  612.  
  613.  
  614. int Receive_File(Name)
  615. /**
  616.  * Function:
  617.  *   Download the specified file from the host.
  618.  *
  619.  * Inputs:
  620.  *   Name -- ptr to the file name string
  621.  *
  622.  * Outputs:
  623.  *
  624.  * Returns:
  625.  *   success/failure
  626.  **/
  627. char *Name;
  628.   {
  629.     int Data_File;
  630.     if ((Data_File = creat(Name, O_RAW)) == -1)
  631.       {
  632.         Put_Msg("Cannot create file");
  633.         Send_Failure('E');
  634.         return Failure;
  635.       }
  636.     Send_ACK();
  637.     for (;;)
  638.       {
  639.         if (Read_Packet(R_Get_DLE) == Success)
  640.           {
  641.             switch (R_Buffer[0])
  642.               {
  643.                 case 'N':      /* Data packet */
  644.                   {
  645.                     Send_ACK();
  646.                     if (write(Data_File, &R_Buffer[1], R_Size - 1) != R_Size - 1)
  647.                       {
  648.                         /* Disk write error */
  649.                         Put_Msg("Disk write error");
  650.                         Send_Failure('E');
  651.                         close(Data_File);
  652.                         return Failure;
  653.                       }
  654.                     if (Wants_To_Abort())
  655.                       {
  656.                         /* The user wants to kill the transfer */
  657.                         Send_Failure('A');
  658.                         close(Data_File);
  659.                         return Failure;
  660.                       }
  661.                     break;
  662.                   }
  663.                 case 'T':      /* Transfer packet */
  664.                   {
  665.                     if (R_Buffer[1] == 'C') /* Close file */
  666.                       {
  667.                         Send_ACK();
  668.                         close(Data_File);
  669.                         return Success;
  670.                       }
  671.                     else
  672.                       {
  673.                         /**
  674.                          * Unexpected "T" packet. Something is rotten on the
  675.                          * other end. Send a failure packet to kill the
  676.                          * transfer cleanly.
  677.                          **/
  678.                         Put_Msg("Unexpected packet type");
  679.                         Send_Failure('E');
  680.                         close(Data_File);
  681.                         return Failure;
  682.                       }
  683.                   }
  684.                 case 'F':      /* Failure packet */
  685.                   {
  686.                     Send_ACK();
  687.                     close(Data_File);
  688.                     return Failure;
  689.                   }
  690.                 default:
  691.                   {
  692.                     return Failure;
  693.                   }
  694.               }
  695.           }
  696.         else
  697.           {
  698.             close(Data_File);
  699.             return Failure;
  700.           }
  701.       }
  702.     return Failure;
  703.   }
  704.  
  705.  
  706.  
  707. int Send_File(Name)
  708. /**
  709.  * Function:
  710.  *   Send the specified file to the host.
  711.  *
  712.  * Inputs:
  713.  *   Name -- ptr to the file name string
  714.  *
  715.  * Outputs:
  716.  *
  717.  * Returns:
  718.  *   success/failure
  719.  **/
  720. char *Name;
  721.   {
  722.     int Data_File;
  723.     short N;
  724.     if ((Data_File = open(Name, O_RDONLY | O_RAW)) == -1)
  725.       {
  726.         Put_Msg("Cannot access that file");
  727.         Send_Failure('E');
  728.         return Failure;
  729.       }
  730.     do
  731.       {
  732.         S_Buffer[0] = 'N';
  733.         N = read(Data_File, &S_Buffer[1], Packet_Size - 1);
  734.         if (N > 0)
  735.           {
  736.             if (Send_Packet(N + 1) == Failure)
  737.               {
  738.                 close(Data_File);
  739.                 return Failure;
  740.               }
  741.             if (Wants_To_Abort())
  742.               {
  743.                 Send_Failure('A');
  744.                 close(Data_File);
  745.                 return Failure;
  746.               }
  747.             datablocks++;
  748.           }
  749.       } while (N > 0);
  750.     if (N == 0)            /* end of file */
  751.       {
  752.         close(Data_File);
  753.         S_Buffer[0] = 'T';
  754.         S_Buffer[1] = 'C';
  755.         return Send_Packet(2);
  756.       }
  757.     else
  758.       {
  759.         Put_Msg("Disk read error");
  760.         Send_Failure('E');
  761.         return Failure;
  762.       }
  763.     return Failure;
  764.   }
  765.  
  766.  
  767.  
  768.  
  769.  
  770. /*
  771.                                B PROTOCOL SUMMARY
  772.  
  773.  
  774.  
  775. Block Format:
  776.  
  777.      <DLE><B><blknum+48><command><contents><ETX><checksum>
  778.  
  779.  
  780. Defined commands are:
  781.  
  782.  Remote Memory Reference
  783.  
  784.      B      Load memory
  785.      G      Go execute at an address
  786.  
  787.  File Transfer Mode
  788.  
  789.      TE<file name>            Erase a file
  790.      TR<present><0><new>      Rename a file
  791.      TU<type><file name>      Transfer from Remote to Host
  792.      TD<type><file name>      Transfer from Host to Remote
  793.      N                        Next block of data
  794.      TC                       Close file
  795.  
  796.           <type> is:
  797.              A - ASCII
  798.              B - Binary
  799.              I - Image
  800.  
  801.  Failure Blocks
  802.  
  803.      FA Failure - Abort
  804.      FC Failure - capacity problem
  805.      FE Failure - error during processing of last block
  806.      FN Failure - function not implemented
  807. */
  808.  
  809. int Transfer_File()
  810. /**
  811.  * Function:
  812.  *   Transfer a file from/to the macro to/from the host.
  813.  *
  814.  * Inputs:
  815.  *
  816.  * Outputs:
  817.  *
  818.  * Returns:
  819.  *   success/failure
  820.  **/
  821.   {
  822.     short I, N,temp;
  823.     char Name[64];
  824.  
  825.     XOFF_Flag = False;
  826.     Seq_Num = 0;
  827.     nowindow();
  828.     if (Read_Packet(R_Get_Seq) == Success)
  829.       {
  830.         if (R_Buffer[0] == 'T')      /* transfer packet */
  831.           {
  832.             if (R_Buffer[1] != 'D' && R_Buffer[1] != 'U') /*Check drctchun*/
  833.               {
  834.                 Send_Failure('N');              /* not UPLOAD or DOWNLOAD */
  835.                 return Failure;
  836.               }
  837.             if (R_Buffer[2] != 'A' && R_Buffer[2] != 'B')/*Check file type*/
  838.               {
  839.                 Send_Failure('N');                 /* not ASCII or BINARY */
  840.                 return Failure;
  841.               }
  842.             if (R_Size - 3 > 63)              /* Get the file name length */
  843.               {
  844.                 N = 63;
  845.               }
  846.             else
  847.               {
  848.                 N = R_Size - 3;
  849.               }
  850.             for (I = 0; I < N; I++)    /* Now actually read the file name */
  851.               {
  852.                 Name[I] = R_Buffer[I + 3];
  853.               }
  854.             Name[I] = 0;                     /* NULL terminate the string */
  855.             if (R_Buffer[1] == 'U')                 /* Do Upload transfer */
  856.               {
  857.                 oursize = findsize(Name);
  858.                 temp = showupload(Name);
  859.               }
  860.             else                                  /* Do Download transfer */
  861.               {
  862.                 temp = showdownload(Name);
  863.               }
  864.             nowindow();
  865.             return((int)temp);
  866.           }
  867.         else
  868.           {
  869.             Send_Failure('E');                    /* wrong type of packet */
  870.             return Failure;
  871.           }
  872.       }
  873.     else                               /* didn't read packet successfully */
  874.       {
  875.         return Failure;
  876.       }
  877.     return Failure;
  878.   }
  879.  
  880.  
  881.