home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / intelmdsb / mdsrcv.p80 < prev    next >
Text File  |  2020-01-01  |  14KB  |  566 lines

  1. $TITLE ('RECV - RECEIVES FILES FROM REMOTE KERMIT')
  2. recv$module:
  3.  
  4. /* COPYRIGHT (C) 1985, Trustees of Columbia University in the City of New */
  5. /* York.  Permission is granted to any individual or institution to use,  */
  6. /* copy, or redistribute this software so long as it is not sold for      */
  7. /* profit, provided this copyright notice is retained. /*
  8.  
  9. /* Contains the following public routines: */
  10. /*      movevar, rdata, ready, rechelp, recv, and rfile */
  11. do;
  12.  
  13. declare true literally '0FFH';
  14. declare false literally '00H';
  15.  
  16. declare port1cmd literally '0F5H';
  17. declare port2cmd literally '0F7H';
  18. declare rx$rdy literally '02H';
  19.  
  20. declare null literally '00';
  21. declare cr literally '0DH';
  22. declare lf literally '0AH';
  23. declare crlf literally 'cr,lf,null';
  24. declare bel literally '07H';
  25. declare myquote literally '023H';
  26. declare chrmsk literally '07FH';
  27.  
  28. declare readonly literally '1';
  29. declare writeonly literally '2';
  30. declare noedit literally '0';
  31.  
  32. declare state byte external;
  33. declare msgnum byte external;
  34. declare tries byte external;
  35. declare oldtry byte external;
  36.  
  37. declare pktcnt address;
  38. declare errcnt address;
  39.  
  40. declare port byte external;
  41. declare debug byte external;
  42. declare maxtry byte external;
  43. declare warning$flag byte external;
  44. declare def$drive(5) byte external;
  45. declare localname(20) byte;
  46. declare filename address external;
  47.  
  48. declare pksize literally '94';
  49. declare packet(pksize) byte external;
  50. declare (jfn, count, status) address;
  51.  
  52. /* Current Kermit parameters */
  53. declare spsize byte external;    /* the present packet size */
  54. declare timeint byte external;    /* the present time out */
  55. declare numpads byte external;    /* how many pads to send */
  56. declare padchar byte external;    /* the present pad character */
  57. declare eol byte external;        /* the present eol character */
  58. declare quote byte external;    /* the present quote character */
  59.  
  60. ci:    procedure byte external;
  61. end ci;
  62.  
  63. csts:    procedure byte external;
  64. end csts;
  65.  
  66. co:    procedure(char)external;
  67.     declare char byte;
  68. end co;
  69.  
  70. print:  procedure(string)external;
  71.     declare string address;
  72. end print;
  73.  
  74. nout:     procedure(num)external;
  75.     declare num address;
  76. end nout;
  77.  
  78. newline: procedure external; end newline;
  79.  
  80. token:    procedure address external;    end token;
  81.  
  82. open:    procedure(jfn, file, access, mode, status) external;
  83.     declare (jfn, file, access, mode, status) address;
  84. end open;
  85.  
  86. write:     procedure(jfn, buffer, count, status) external;
  87.     declare (jfn, buffer, count, status) address;
  88. end write;
  89.  
  90. close:    procedure(jfn, status) external;
  91.     declare (jfn, status) address;
  92. end close;
  93.  
  94. delete:    procedure(file, status) external;
  95.     declare (file, status) address;
  96. end delete;
  97.  
  98. exit:    procedure external;
  99. end exit;
  100.  
  101. getc:    procedure(port) byte external;
  102.     declare port byte;
  103. end getc;
  104.  
  105. ctl:    procedure(char) byte external;
  106.     declare char byte;
  107. end ctl;
  108.  
  109. spack:     procedure(type, pknum, length, packet) external;
  110.     declare (type, pknum, length, packet) address;
  111. end spack;
  112.  
  113. rpack:     procedure(length, pknum, packet) byte external;
  114.     declare (length, pknum, packet) address;
  115. end rpack;
  116.  
  117. spar:    procedure (a) external;
  118.     declare a address;
  119. end spar;
  120.  
  121. rpar:    procedure (a) external;
  122.     declare a address;
  123. end rpar;
  124.  
  125. /* Print an error packet */
  126. prerrpkt: procedure (pkt) external;
  127.     declare pkt address;
  128. end prerrpkt;
  129.  
  130. /* Move a variable string from source to dest until a null is found. */
  131. /*   The value of offset defines the starting point in dest of the move */
  132. movevar: procedure (offset, source, dest) byte public;
  133.     declare offset byte;
  134.     declare (source, dest) address;
  135.     declare schr based source byte;
  136.     declare dchr based dest byte;
  137.     dest = dest + offset;
  138.     do while schr <> null;
  139.       dchr = schr;
  140.       source = source + 1;
  141.       dest = dest + 1;
  142.       offset = offset + 1;
  143.     end;
  144.     dchr = null; /* append a null */
  145.     return offset;
  146. end movevar;
  147.  
  148. /* Alter the local file name in an effort to create a unique name */
  149. altername:    procedure (flname);
  150.     declare flname address;
  151.     declare (fnchar based flname)(20) byte;
  152.     declare (basestart, perloc, stopper) byte;
  153.     declare (adjusted, offset) byte;
  154.     declare (i, j) byte;
  155.  
  156.     /* Locate the start of the root name */
  157.     if fnchar(0) = ':' then basestart = 4; /* skip drive spec */
  158.     else basestart = 0;
  159.     i = basestart;
  160.     perloc = 0;
  161.     do while fnchar(i) <> null;
  162.       if fnchar(i) = '.' then /* found a period */
  163.         if perloc = 0 then perloc = i;
  164.       i = i + 1;
  165.     end;
  166.     stopper = i;
  167.     if perloc = 0 then
  168.       do; /* name has no extension, so add an extension of "0" */
  169.         fnchar(stopper) = '.';
  170.         fnchar(stopper+1) = '0';
  171.         fnchar(stopper+2) = null;
  172.         stopper = stopper + 2;
  173.       end;
  174.     else
  175.       if (perloc - basestart) < 6 then
  176.         do; /* the base name is shorter than 6 chars */
  177.           i = stopper;
  178.           do while i >= perloc; /* shift the extension right 1 char */
  179.             fnchar(i+1) = fnchar(i);
  180.             i = i - 1;
  181.           end;
  182.           fnchar(perloc) = '0'; /* insert a zero before the period */
  183.           perloc = perloc + 1; /* Adjust the */
  184.           stopper = stopper + 1; /*  pointers */
  185.         end;
  186.       else
  187.         if (stopper - perloc) < 4 then
  188.           do; /* Extension is short, so add a zero */
  189.             fnchar(stopper) = '0';
  190.             stopper = stopper + 1;
  191.             fnchar(stopper) = null;
  192.           end;
  193.         else /* Both parts of the name are full */
  194.           do;
  195.             i = perloc - 1; /* point to end of base name */
  196.             adjusted = false;
  197.             do while not adjusted;
  198.               if fnchar(i) < 'Z' then
  199.                 do;
  200.                   fnchar(i) = fnchar(i) + 1;
  201.                   adjusted = true;
  202.                 end;
  203.               else
  204.                 if fnchar(i) >= 'a' and fnchar(i) < 'z' then
  205.                   do;
  206.                     fnchar(i) = fnchar(i) + 1;
  207.                     adjusted = true;
  208.                   end;
  209.                 else
  210.                   do;
  211.                     if i <= basestart then i = stopper - 1;
  212.                     else i = i - 1;
  213.                     if i = perloc then
  214.                       do;
  215.                         offset = movevar(0,
  216.                           .('A00000.000',null), flname);
  217.                         adjusted = true;
  218.                       end;
  219.                   end;
  220.             end;
  221.           end;
  222. end altername;
  223.  
  224. /* Find a local file name which doesn't conflict with existing files */
  225. find$good$name:    procedure (flname);
  226.     declare flname address;
  227.     declare successful byte;
  228.  
  229.     successful = false;
  230.     do while not successful;
  231.       call altername(flname);
  232.       call open(.jfn, flname, readonly, noedit, .status);
  233.       if status = 0 then call close(jfn, .status); /* still a duplicate */
  234.       else successful = true;
  235.     end;
  236. end find$good$name;
  237.  
  238. ready:    procedure (port) byte public;
  239.     declare (port, status) byte;
  240.     do case port;
  241.       do;
  242.         status = csts;
  243.       end;
  244.       do;
  245.         status = input(port1cmd) and rx$rdy;
  246.       end;
  247.       do;
  248.         status = input(port2cmd) and rx$rdy;
  249.       end;
  250.     end;
  251.     return status;
  252. end ready;
  253.  
  254. bufemp:    procedure(packet, len);
  255.     declare packet address;
  256.     declare inchar based packet byte;
  257.     declare (i, char, len) byte;
  258.  
  259.     if debug then call print(.('Writing to disk...',null));
  260.     i = 0;
  261.     do while (i < len);
  262.       char  = inchar;
  263.       if char = myquote then do;
  264.         packet = packet + 1;
  265.         i = i + 1;
  266.         char = inchar;
  267.         if (char and chrmsk) <> myquote then char = ctl(char);
  268.       end;
  269.       if debug then call co(char);
  270.       call write(jfn, .char, 1, .status);
  271.       if status > 0 then do;
  272.         call print(.('Write error ',null));
  273.         call nout(status);
  274.         call newline;
  275.       call exit;
  276.       end;
  277.       packet = packet + 1;
  278.       i = i + 1;
  279.     end;
  280.     if debug then call newline;
  281. end bufemp;
  282.  
  283. rinit:     procedure byte;
  284.     declare (len, num, retc) byte;
  285.  
  286.     if tries > maxtry then return 'A';
  287.     else tries = tries + 1;
  288.  
  289.     if debug then call print(.('rinit...',crlf));
  290.  
  291.     retc = rpack(.len, .num, .packet);
  292.     if (retc = 'S') then /* send init received */
  293.       do;
  294.         call rpar(.packet);
  295.         call spar(.packet);
  296.         call spack('Y', msgnum, 6, .packet);
  297.         oldtry = tries;
  298.         tries = 0;
  299.         msgnum = (msgnum + 1) mod 64;
  300.         return 'F';
  301.       end;
  302.  
  303.     if (retc = 'E') then do; /* Error packet received */
  304.       call prerrpkt(.packet);
  305.       return 'A';
  306.     end;
  307.  
  308.     if (retc = false) then
  309.       do;
  310.         call spack('N', msgnum, 0, 0);
  311.         return state;
  312.       end;
  313.  
  314.     return 'A';
  315. end rinit;
  316.  
  317. rfile:    procedure byte public;
  318.     declare (len, num, retc) byte;
  319.     declare foffset byte;
  320.     declare fnptr address;
  321.     declare fnchr based fnptr byte;
  322.  
  323.     if tries > maxtry then return 'A';
  324.     else tries = tries + 1;
  325.  
  326.     if debug then call print(.('rfile...',crlf));
  327.  
  328.     retc = rpack(.len, .num, .packet);
  329.  
  330.     if retc = 'S' then do;
  331.       if (oldtry > maxtry) then return 'A';
  332.         else oldtry = oldtry + 1;
  333.       if (((num + 1) mod 64) = msgnum) then /* previous packet again */
  334.         do;
  335.           call spar(.packet);
  336.            call spack('Y', num, 6, .packet); /* re-ACK it */
  337.           tries = 0;
  338.           return state;
  339.         end;
  340.       else return 'A';
  341.     end;
  342.  
  343.     if retc = 'Z' then do;
  344.       if (oldtry > maxtry) then return 'A';
  345.         else oldtry = oldtry + 1;
  346.       if (num = msgnum - 1) then
  347.         do;
  348.           call spack('Y', num, 0, 0);
  349.           tries = 0;
  350.           return state;
  351.         end;
  352.       else return 'A';
  353.     end;
  354.  
  355.     if retc = 'F' then do;
  356.       if (num <> msgnum) then return 'A';
  357.       call print(.(cr,lf,'Receiving ',null));
  358.       /* Construct the (local) ISIS file name */
  359.       if (filename = 0) then /* Use the remote name if no operand */
  360.         do;
  361.           foffset = movevar(0,.def$drive,.localname);
  362.           foffset = movevar(foffset,.packet,.localname);
  363.         end;
  364.       else
  365.         do;
  366.           call print(.packet);
  367.           call print(.(' to $'));
  368.           fnptr = filename;
  369.           if fnchr = ':' then /* File name on command line has a drive */
  370.             foffset = movevar(0, filename, .localname);
  371.           else
  372.             do; /* Build file name from default drive */
  373.               foffset = movevar(0, .def$drive, .localname);
  374.               foffset = movevar(foffset, filename, .localname);
  375.             end;
  376.         end;
  377.       call print(.localname);
  378.       call print(.(crlf));
  379.       if warning$flag then
  380.         do; /* Check for a pre-existing local file */
  381.           call open(.jfn, .localname, readonly, noedit, .status);
  382.           if status = 0 then
  383.             do; /* the file already exists */
  384.               call close(jfn, .status);
  385.               call find$good$name(.localname); /* Mod file name */
  386.               call print(.('Using local file name of $'));
  387.               call print(.localname);
  388.               call print(.('; other name already in use.\$'));
  389.             end;
  390.         end;
  391.       call open(.jfn, .localname, writeonly, noedit, .status);
  392.       if status > 0 then
  393.         do;
  394.           call print (.('Unable to create file, error ', null));
  395.           call nout(status);
  396.           call newline;
  397.           return 'A';
  398.         end;
  399.       call spack('Y', msgnum, 0, 0);
  400.       oldtry = tries;
  401.       tries = 0;
  402.       msgnum = (msgnum + 1) mod 64;
  403.       pktcnt = 0;
  404.       errcnt = 0;
  405.       return 'D';
  406.     end;
  407.  
  408.     if retc = 'B' then do;
  409.       if (num <> msgnum) then return 'A';
  410.       call spack('Y', msgnum, 0, 0);
  411.       return 'C';
  412.     end;
  413.  
  414.     if retc = 'E' then do; /* Error packet received */
  415.       call prerrpkt(.packet);
  416.       return 'A';
  417.     end;
  418.  
  419.     return state;
  420. end rfile;
  421.  
  422. rdata:     procedure byte public;
  423.     declare (num, len, retc, retst, c) byte;
  424.  
  425.     if tries > maxtry then return 'A';
  426.       else tries = tries + 1;
  427.  
  428.     if debug then call print(.('rdata...',crlf));
  429.  
  430.     retc = rpack(.len, .num, .packet);
  431.  
  432.     if retc = 'D' then do;
  433.       if (num <> msgnum) then
  434.         do;
  435.           if (oldtry > maxtry) then return 'A';
  436.           oldtry = oldtry + 1;
  437.           if (((num + 1) mod 64) = msgnum) then /* prev packet again */
  438.             do;
  439.               call spar(.packet);
  440.               call spack('Y', num, 6, .packet); /* re-ACK it */
  441.               tries = 0;
  442.               retst = state;
  443.             end;
  444.           else return 'A';
  445.         end;
  446.       else
  447.         do; /* correct packet */
  448.           call bufemp(.packet, len);
  449.           if ready(0) = 0 then /* no console input */
  450.             call spack('Y', msgnum, 0, 0);
  451.           else
  452.             do; /* There is a keystroke ready */
  453.               c = getc(0);
  454.               if (c = 24 or c = 26) then /* ctrl-X or ctrl-Z */
  455.                 do; /* Send the char with the ACK */
  456.                   packet(0) = ctl(c);
  457.                   call spack('Y', msgnum, 1, .packet);
  458.                 end;
  459.               else /* Ignore the keystroke */
  460.                 call spack('Y', msgnum, 0, 0);
  461.             end;
  462.           oldtry = tries;
  463.           pktcnt = pktcnt + 1;
  464.            tries = 0;
  465.            msgnum = (msgnum + 1) mod 64;
  466.           retst = 'D';
  467.         end;
  468.       end;
  469.  
  470.     else if retc = 'F' then do;
  471.       if (oldtry > maxtry) then return 'A';
  472.         else oldtry = oldtry + 1;
  473.       if (num = msgnum - 1) then
  474.         do;
  475.           call spack('Y', num, 0, 0);
  476.           tries = 0;
  477.           retst = state;
  478.         end;
  479.       else return 'A';
  480.       end;
  481.  
  482.     else if retc = 'Z' then do;
  483.       if (num <> msgnum) then return 'A';
  484.       call spack('Y', msgnum, 0, 0);
  485.       call close(jfn, .status);
  486.       if status > 0 then call print(.(cr,lf,'Unable to close file',null));
  487.       if len > 0 then /* There was data with the packet */
  488.         if packet(0) = 'D' then
  489.           do; /* File deletion requested by remote Kermit */
  490.             call delete(.localname, .status);
  491.             if status = 0 then
  492.               do;
  493.                 call print(.(cr,lf,'File $'));
  494.                 call print(.localname);
  495.                 call print(.(' deleted on request from remote Kermit',crlf));
  496.               end;
  497.             else
  498.               call print(.('Requested file delete failed',crlf));
  499.           end;
  500.       msgnum = (msgnum + 1) mod 64;
  501.       retst = 'F';
  502.       end;
  503.  
  504.     else if retc = 'E' then /* Error packet received */
  505.       do;
  506.         call prerrpkt(.packet);
  507.         return 'A';
  508.       end;
  509.  
  510.     else if retc = false then /* Reception error */
  511.       do;
  512.         errcnt = errcnt + 1;
  513.         call spack('N', msgnum, 0, 0);
  514.         retst = state;
  515.       end;
  516.     if retst <> 'A' and retst <> 'F' then
  517.       do;
  518.         /* Report transfer progress */
  519.         call print(.(cr,'Packets received: $'));
  520.         call nout(pktcnt);
  521.         call print(.('; number of retries: $'));
  522.         call nout(errcnt);
  523.         if debug then call print(.(crlf));
  524.       end;
  525.     return retst;
  526.  
  527. end rdata;
  528.  
  529. /* Display help for the RECEIVE command */
  530. rechelp:procedure public;
  531.     call print(.('\RECEIVE\\$'));
  532.     call print(.('  The RECEIVE command causes KERMIT to wait for $'));
  533.     call print(.('a file to be sent by the\$'));
  534.     call print(.('remote Kermit.\\$'));
  535.     call print(.('Syntax:\\$'));
  536.     call print(.('    RECEIVE [local-file]\\$'));
  537.     call print(.('If the "local-file" is not specified, Kermit will $'));
  538.     call print(.('name the local file with\$'));
  539.     call print(.('the file name sent by the remote Kermit.\\$'));
  540. end rechelp;
  541.  
  542. recv:   procedure public;
  543.  
  544.     if debug then call print(.('Receive a file',crlf));
  545.     state = 'R';
  546.     msgnum = 0;
  547.     tries = 0;
  548.     oldtry = 0;
  549.     filename = token; /* Capture operand, if any */
  550.     do while (state <> true and state <> false);
  551.       if state = 'D' then state = rdata;
  552.       else
  553.          if state = 'F' then state = rfile;
  554.          else
  555.             if state = 'R' then state = rinit;
  556.         else
  557.             if state = 'C' then state = true;
  558.             else state = false;
  559.     end;
  560.     if state then call print(.('\OK',bel,crlf));
  561.     else call print(.('receive failed\$'));
  562.  
  563. end recv;
  564.  
  565. end recv$module;
  566.