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

  1. $TITLE ('SEND - HANDLES PACKET TRANSFER BETWEEN LOCAL AND HOST SYSTEM')
  2. send$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. /*      ctl, getc, prerrpkt, putc, rpack, rpar, send, senhelp, spack, */
  11. /*        spar, tochar, and unchar */
  12. do;
  13.  
  14. /* Global declarations for the communication module */
  15.  
  16. declare true literally '0FFH';
  17. declare false literally '00H';
  18.  
  19. declare port1cmd literally '0F5H';
  20. declare port2cmd literally '0F7H';
  21. declare port1dat literally '0F4H';
  22. declare port2dat literally '0F6H';
  23.  
  24. declare tx$rdy literally '01H';
  25. declare rx$rdy literally '02H';
  26. declare chrmsk literally '07FH';
  27.  
  28. declare space literally '020H';
  29. declare cr literally '0DH';
  30. declare lf literally '0AH';
  31. declare null literally '00H';
  32. declare crlf literally 'cr,lf,null';
  33. declare bel literally '07H';
  34. declare soh literally '1';
  35. declare eofl literally '0';
  36. declare delete literally '07FH';
  37.  
  38. declare myquote literally '023H';
  39. declare mynumpads literally '0';
  40. declare mypadchr literally '0';
  41. declare myeol literally 'cr';
  42. declare mytime literally '5';
  43.  
  44. declare readonly literally '1';
  45. declare writeonly literally '2';
  46. declare rdwr literally '3';
  47. declare noedit literally '0';
  48.  
  49. declare pksize literally '94';
  50. declare packet(pksize) byte public;    /* buffer for packets */
  51. declare input$and byte external;        /* Mask for comm input bytes */
  52. declare output$and byte external;        /* Mask for comm output bytes */
  53. declare output$or byte external;        /* Mask for comm output bytes */
  54.  
  55. declare state byte external;        /* FSM last state */
  56. declare msgnum byte external;        /* message number */
  57. declare tries byte external;        /* max number of retries */
  58.  
  59. /* Current Kermit parameters */
  60. declare spsize byte external;    /* the present packet size */
  61. declare timeint byte external;    /* the present time out */
  62. declare numpads byte external;    /* how many pads to send */
  63. declare padchar byte external;    /* the present pad character */
  64. declare eol byte external;        /* the present eol character */
  65. declare quote byte external;    /* the present quote character */
  66.  
  67. declare pktcnt address;            /* tally of good blocks sent */
  68. declare errcnt address;            /* tally of error transfers */
  69.  
  70. declare port byte external;        /* the port to use */
  71. declare maxtry byte external;    /* the number of retries to attempt */
  72. declare def$drive(5) byte external;     /* the default local drive */
  73. declare filename address external;    /* the address of the filename */
  74. declare localfile(15) byte;        /* full name of file on the local disk */
  75. declare remotefile(11) byte;        /* file name sent to remote host */
  76. declare fnptr address;
  77. declare fnchr based fnptr byte;
  78. declare (jfn, status, pklen) address;
  79.  
  80. declare debug byte external;
  81.  
  82. /* here are the subroutines */
  83.  
  84. exit:    procedure external;
  85. end exit;
  86.  
  87. co:    procedure(char) external;
  88.     declare char byte;
  89. end co;
  90.  
  91. print:     procedure(string) external;
  92.     declare string address;
  93. end print;
  94.  
  95. nout:    procedure(n) external;
  96.     declare n address;
  97. end nout;
  98.  
  99. ci:    procedure byte external;
  100. end ci;
  101.  
  102. open:     procedure(jfn, filenm, access, mode, status) external;
  103.     declare (jfn, filenm, access, mode, status) address;
  104. end open;
  105.  
  106. read:     procedure(jfn, buffer, count, actual, status) external;
  107.     declare (jfn, buffer, count, actual, status) address;
  108. end read;
  109.  
  110. close:     procedure(jfn, status) external;
  111.     declare (jfn, status) address;
  112. end close;
  113.  
  114. ready:     procedure(port) byte external;
  115.     declare (port) byte;
  116. end ready;
  117.  
  118. newline: procedure external; end newline;
  119.  
  120. token:    procedure address external; end token;
  121.  
  122. movevar: procedure(offset, source, dest) byte external;
  123.     declare offset byte;
  124.     declare (source, dest) address;
  125. end movevar;
  126.  
  127. /* GNXTFN: this routine returns a pointer to the next file in a file     */
  128. /* list, or false if there are none.                                    */
  129. gnxtfn:    procedure address;
  130.     filename = token;
  131.     return (filename > 0);
  132. end gnxtfn;
  133.  
  134. /* PUTC: takes a character and a port, waits for transmit ready from    */
  135. /* port and then sends the character to it.  Doesn't return a result       */
  136. putc:   procedure (c, port) public;
  137.     declare (c, status, port) byte;
  138.  
  139.     status = 0;
  140.     do case port;
  141.       do;
  142.         call co(c);
  143.       end;
  144.       do;
  145.         do while (status := input(port1cmd) and tx$rdy) = 0; end;
  146.         output(port1dat) = ((c and output$and) or output$or);
  147.       end;
  148.       do;
  149.         do while (status := input(port2cmd) and tx$rdy) = 0; end;
  150.         output(port2dat) = ((c and output$and) or output$or);
  151.       end;
  152.     end;
  153. end putc;
  154.  
  155. /* GETC: this routine waits for something from the receive port then     */
  156. /* brings in the character and returns as a result.            */
  157. getc:     procedure (port) byte public;
  158.     declare (c, status, port) byte;
  159.  
  160.     status = 0;
  161.     do case port;
  162.       do;
  163.         c = ci;
  164.       end;
  165.       do;
  166.         do while status = 0;
  167.           status = (input(port1cmd) and rx$rdy);
  168.         end;
  169.         c = (input(port1dat) and input$and);
  170.       end;
  171.       do;
  172.         do while status = 0;
  173.           status = (input(port2cmd) and rx$rdy);
  174.         end;
  175.         c = (input(port2dat) and input$and);
  176.       end;
  177.     end;
  178.     return c;
  179. end getc;
  180.  
  181. /* TOCHAR: takes a character and converts it to a printable character      */
  182. /*         by adding a space                        */
  183. tochar: procedure(char) byte public;
  184.     declare char byte;
  185.     return (char + space);
  186. end tochar;
  187.  
  188. /* UNCHAR: undoes 'tochar' */
  189. unchar:    procedure(char) byte public;
  190.     declare char byte;
  191.     return (char - space);
  192. end unchar;
  193.  
  194. /* CTL: this routine takes a character and toggles the control bit    */
  195. /* (ie. ^A becomes A and A becomes ^A).                    */
  196. ctl:     procedure(char) byte public;
  197.     declare char byte;
  198.     declare cntrlbit literally '040H';
  199.     return (char xor cntrlbit);
  200. end ctl;
  201.  
  202. /* Print the contents of an error packet received from the remote host */
  203. prerrpkt: procedure (pkt) public;
  204.     declare pkt address;
  205.     declare pkbyte based pkt byte;
  206.  
  207.     call print(.(cr,lf,'Error from remote KERMIT',null));
  208.     if pkbyte = null then call newline; /* no message text */
  209.     else
  210.       do; /* display the message */
  211.         call print(.(':\$'));
  212.         call print(pkt);
  213.       end;
  214.     call newline;
  215. end prerrpkt;
  216.  
  217. /* Close the disk input file */
  218. closeup: procedure;
  219.     call close(jfn, .status);
  220.     if status > 0 then call print(.('\Unable to close file\$'));
  221. end closeup;
  222.  
  223. /* spar: Build a Kermit initialization packet */
  224. spar:     procedure (a) public;
  225.     declare a address;
  226.     declare b based a byte;
  227.  
  228.     b = tochar(pksize);        /* set up header */
  229.     a = a + 1;
  230.     b = tochar(mytime);
  231.     a = a + 1;
  232.     b = tochar(mynumpads);
  233.     a = a + 1;
  234.     b = ctl(mypadchr);
  235.     a = a + 1;
  236.     b = tochar(myeol);
  237.     a = a + 1;
  238.     b = myquote;
  239. end spar;
  240.  
  241. /* rpar: Extract information from a Kermit initialization packet */
  242. rpar:    procedure (addr) public;
  243.     declare addr address;
  244.     declare item based addr byte;
  245.  
  246.     spsize = unchar(item);        /* isn't plm wonderful? */
  247.     addr = addr + 1;
  248.     timeint = unchar(item);
  249.     addr = addr + 1;
  250.     numpads = unchar(item);
  251.     addr = addr + 1;
  252.     padchar = ctl(item);
  253.     addr = addr + 1;
  254.     eol = unchar(item);
  255.     addr = addr + 1;
  256.     quote = item;
  257. end rpar;
  258.  
  259. bufill:    procedure (packet) byte;
  260.     declare packet address;
  261.     declare (pp, maxpp) address;
  262.     declare (i, c, done) byte;
  263.     declare chr based pp byte;
  264.     declare count address;
  265.  
  266.     done = false;
  267.     pp = packet;
  268.     maxpp = pp + spsize - 8;
  269.     do while not done;
  270.       call read(jfn, .c, 1, .count, .status);
  271.       if status > 0 then
  272.         do;
  273.           call print(.('Error reading file\$'));
  274.           call exit;
  275.         end;
  276.       if count = 0 then
  277.         done = true;
  278.       else
  279.         do;
  280.           if ((c and chrmsk) < space) or
  281.           ((c and chrmsk) = delete) then
  282.             do;
  283.               chr = quote;
  284.               pp = pp + 1;
  285.               chr = ctl(c);
  286.             end;
  287.           else
  288.           if (c and chrmsk) = quote then
  289.             do;
  290.               chr = quote;
  291.               pp = pp + 1;
  292.               chr = c;
  293.             end;
  294.           else
  295.             chr = c;
  296.           pp = pp + 1;
  297.           if pp >= maxpp then done = true;
  298.         end;
  299.     end;
  300.     return (pp - packet);
  301. end bufill;
  302.  
  303. /* SPACK: this routine sends a packet of data to the host.  It takes    */
  304. /* four parameters, the type of packet, message number, packet length   */
  305. /* and a pointer to a buffer containing what is to be output. It does    */
  306. /* not return a value.                            */
  307. spack:    procedure(type, pknum, length, packet) public;
  308.     declare (type, pknum, length) byte;
  309.     declare packet address;
  310.     declare char based packet byte;
  311.     declare (i, chksum) byte;
  312.  
  313.     if debug then do;
  314.       call print(.('Sending packet ',null));
  315.       call nout(pknum);
  316.       call print(.(', total packet length is ',null));
  317.       call nout(length + 5);  /* +5 for soh, count, seq, type, & chksum */
  318.       call newline;
  319.     end;
  320.  
  321.     i = 1;                    /* do padding */
  322.     do while (i <= numpads);
  323.       call putc(padchar, port);
  324.       if debug then call co('p');
  325.       i = i + 1;
  326.     end;
  327.  
  328.     chksum = 0;
  329.     /* send the packet header */
  330.  
  331.     call putc(soh, port);            /* send packet marker (soh) */
  332.     if debug then call co('s');
  333.     i = tochar(length + 3);
  334.     chksum = i;
  335.     call putc(i, port);            /* send character count     */
  336.     if debug then call co('c');
  337.     i = tochar(pknum);
  338.     chksum = chksum + i;            /* add in packet number     */
  339.     call putc(i, port);            /* send packet number        */
  340.     if debug then call co('n');
  341.     chksum = chksum + type;            /* add in packet type        */
  342.     call putc(type, port);            /* send the packet type        */
  343.     if debug then call co(type);
  344.  
  345.     /* now send the data */
  346.     do i = 1 to length;
  347.       chksum = chksum + char;
  348.       call putc(char, port);
  349.       if debug then call co(char); /* was co('.') */
  350.       packet = packet + 1;
  351.     end;
  352.  
  353.     /* check sum generation */
  354.  
  355.     chksum = ((chksum + (chksum and 192) / 64) and 63);
  356.     chksum = tochar(chksum);
  357.     call putc(chksum, port);        /* send the chksum */
  358.     if debug then call co('c');
  359.  
  360.     call putc(eol, port);            /* terminate the packet */
  361.     if debug then do;
  362.       call print(.('e\$'));
  363.       call co('.');
  364.     end;
  365. end spack;
  366.  
  367. /* RPACK: this routine receives a packet from the host.  It takes three    */
  368. /* parameters: the address of where to put the length of the packet,    */
  369. /* the address of where to put the packet number and the address of the */
  370. /* buffer to receive the data.  It returns true for a positive reply or */
  371. /* false for a NEGative reply.                        */
  372. rpack:     procedure(length, pknum, packet) byte public;
  373.     declare (length, pknum, packet, pkptr) address;
  374.  
  375.     declare len based length byte;
  376.     declare num based pknum byte;
  377.     declare pk based pkptr byte;
  378.     declare (i, index, chksum, hischksum, type, inchar, msglen) byte;
  379.  
  380.     declare buffer(128) byte;
  381.  
  382.     if debug then call print(.('rpack | ',null));
  383.  
  384.     inchar = 0;            /* wait for a header */
  385.     do while inchar <> soh; inchar = getc(port); end;
  386.     index = 0;
  387.     inchar = getc(port);
  388.     do while (inchar <> myeol);
  389.       buffer(index) = inchar;
  390.       index = index + 1;
  391.       inchar = getc(port);
  392.     end;
  393.     buffer(index) = null;
  394.     if debug then
  395.       do;
  396.         call print(.('Received packet: [',null));
  397.         call print(.buffer);
  398.         call print(.(']\Length of message: $'));
  399.       end;
  400.     msglen = index - 1;
  401.     if debug then
  402.       do;
  403.         call nout(msglen);
  404.         call newline;
  405.         call print(.('Length field: $'));
  406.         call nout(buffer(0));
  407.         call co('_');
  408.   end;
  409.     len = unchar(buffer(0)-3);
  410.     if debug then
  411.       do;
  412.         call nout(len);
  413.         call print(.('\Message number: $'));
  414.         call nout(buffer(1));
  415.         call co('_');
  416.       end;
  417.     num = unchar(buffer(1));
  418.     if debug then
  419.       do;
  420.         call nout(num);
  421.         call print(.('\Type: $'));
  422.       end;
  423.     type = buffer(2);
  424.     if debug then
  425.       do;
  426.         call co(type);
  427.         call newline;
  428.       end; /* debug */
  429.  
  430.     pkptr = packet;
  431.     chksum = buffer(0) + buffer(1) + buffer(2);
  432.  
  433.     i = 3;                /* index of first data character */
  434.     do while (i < msglen);
  435.       chksum = (pk := buffer(i)) + chksum;
  436.       pkptr = pkptr+1;
  437.       i = i + 1;
  438.     end;
  439.     pk = null;        /* terminate with null for printing */
  440.  
  441.     chksum = (chksum + ((chksum and 192) / 64)) and 63;
  442.     if debug then
  443.       do;
  444.         call print(.('His checksum: $'));
  445.         call nout(buffer(msglen));
  446.         call co('_');
  447.       end; /* debug */
  448.     hischksum = unchar(buffer(msglen));
  449.     if debug then
  450.       do;
  451.         call nout(hischksum);
  452.         call print(.('\Our checksum: $'));
  453.         call nout(chksum);
  454.         call newline;
  455.       end; /* debug */
  456.     if chksum <> hischksum then
  457.       do;
  458.         if debug then call print(.('Bad checksum received\$'));
  459.         return false;
  460.       end;
  461.     return type;
  462. end rpack;
  463.  
  464. /* SDATA: this routine sends the data from the buffer area to the host.    */
  465. /* It takes no parameters but returns the next state depending on the    */
  466. /* type of acknowledgement.                        */
  467. sdata:     procedure byte;
  468.     declare (num, length, retc, retst, c) byte;
  469.  
  470.     if debug then call print(.('sdata...\$'));
  471.  
  472.     if tries > maxtry then return 'A';
  473.       else tries = tries + 1;
  474.  
  475.     if ready(0) > 0 then
  476.       do; /* There is a keystroke ready */
  477.         c = getc(0);
  478.         if (c = 24 or c = 26) then /* ctrl-X or ctrl-Z */
  479.           do;
  480.             call closeup;
  481.             packet(0) = 'D'; /* Delete this file */
  482.             call spack('Z', msgnum, 1, .packet);
  483.             if c = 26 then /* ctrl-Z means stop all */
  484.               do;
  485.                 msgnum = (msgnum + 1) mod 64;
  486.                 return 'B';
  487.               end;
  488.             else
  489.               do;
  490.                 if gnxtfn = false then /* No more file names */
  491.                   do;
  492.                     msgnum = (msgnum + 1) mod 64;
  493.                     return 'B';
  494.                   end;
  495.                 else return 'S';    
  496.               end;
  497.           end;
  498.       end;
  499.  
  500.     call spack('D', msgnum, pklen, .packet);
  501.  
  502.     retc = rpack(.length, .num, .packet);
  503.     if (retc = 'N') then
  504.       do;
  505.         if (((msgnum + 1) mod 64) = num) then /* NAK for next packet */
  506.           retc = 'Y'; /* force into next test */
  507.         else
  508.           do;
  509.             errcnt = errcnt + 1;
  510.             retst = state; /* establish return state */
  511.           end;
  512.       end;
  513.  
  514.     if (retc = 'Y') then
  515.       do;
  516.         tries = 0;
  517.         pktcnt = pktcnt + 1;
  518.         msgnum = (msgnum + 1) mod 64;
  519.         pklen = bufill(.packet);
  520.         if pklen > 0 then retst = 'D';
  521.         else retst = 'Z';
  522.       end;
  523.  
  524.     else if (retc = 'E') then
  525.       do;
  526.         call prerrpkt(.packet);
  527.         return 'A';
  528.       end;
  529.  
  530.     else if (retc = false) then retst = state;
  531.       
  532.     else return 'A';
  533.  
  534.     /* Report transfer progress */
  535.     call print(.(cr,'Packets sent: $'));
  536.     call nout(pktcnt);
  537.     call print(.('; number of retries: $'));
  538.     call nout(errcnt);
  539.     if debug then call print(.(crlf));
  540.     return retst;
  541. end sdata;
  542.  
  543. /* SFILE: this routine sends a packet to the host which contains the     */
  544. /* filename of the file being sent so that the file can be created at    */
  545. /* the host end. It returns a new state depending on the nature of the    */
  546. /* the host's acknowledgement.                        */
  547. sfile:     procedure byte;
  548.     declare (num, length, retc) byte;
  549.  
  550.     if debug then call print(.('sfile...\$'));
  551.  
  552.     if tries > maxtry then return 'A';
  553.       else tries = tries + 1;
  554.  
  555.     length = 0;            /* count characters in filename */
  556.     fnptr = .remotefile;
  557.     do while fnchr > space;
  558.       length = length + 1;
  559.       fnptr = fnptr + 1;
  560.     end;
  561.     if debug then call print(.('\Filename is: $'));
  562.     call print(.localfile);
  563.     if (filename > 0) then
  564.       do;
  565.         call print(.(' to $'));
  566.         call print(.remotefile);
  567.       end;
  568.     call newline;
  569.     if debug then
  570.       do;
  571.         call print(.('File name length is: $'));
  572.         call nout(length);
  573.         call newline;
  574.       end; /* debug */
  575.     call spack('F', msgnum, length, .remotefile);
  576.     retc = rpack(.length, .num, .packet);
  577.  
  578.     if (retc = 'N') then return state;
  579.     if (retc = 'E') then
  580.       do;
  581.         call prerrpkt(.packet);
  582.         return 'A';
  583.       end;
  584.     if (retc <> 'Y') then return 'A';
  585.     /* here on valid acknowledgement */
  586.     tries = 0;
  587.     msgnum = (msgnum + 1) mod 64;
  588.     pktcnt = 0;
  589.     errcnt = 0;
  590.     pklen = bufill(.packet);
  591.     if pklen > 0 then return 'D';
  592.       else return 'Z';
  593. end sfile;
  594.  
  595. /* SEOF: this routine is used when eof is detected, it closes up and    */
  596. /* returns the new state as usual.    */
  597. seof:    procedure byte;
  598.     declare (num, length, retc) byte;
  599.  
  600.     if debug then call print(.('seof...\$'));
  601.  
  602.     if tries > maxtry then return 'A';
  603.       else tries = tries + 1;
  604.  
  605.     call spack('Z', msgnum, 0, .packet);
  606.     retc = rpack(.length, .num, .packet);
  607.     if (retc = 'N') then return state;
  608.     if (retc = 'E') then
  609.       do;
  610.         call prerrpkt(.packet);
  611.         return 'A';
  612.       end;
  613.     if (retc <> 'Y') then return 'A';
  614.     /* here on valid acknowledgement */
  615.     tries = 0;
  616.     call closeup;
  617.     if gnxtfn = false then
  618.       do;
  619.         msgnum = (msgnum + 1) mod 64;
  620.         return 'B';
  621.       end;
  622.     else return 'S';
  623. end seof;
  624.  
  625. /* SINIT: this routine does initializations and opens the file to be    */
  626. /* sent; it returns a new state depending on the outcome of trying to   */
  627. /* open the file. */
  628. sinit:    procedure byte;
  629.     declare (len, num, retc) byte;
  630.     declare foffset byte;
  631.  
  632.     call print(.('\Sending $'));
  633.  
  634.     if debug then call print(.('sinit...\$'));
  635.  
  636.     if tries  > maxtry then return 'A';
  637.       else tries = tries + 1;
  638.  
  639.     if filename = 0 then return 'A';
  640.     call spar(.packet);
  641.     call spack('S', msgnum, 6, .packet);    /* send start packet */
  642.  
  643.     retc = rpack(.len, .num, .packet);
  644.     if (retc = 'N') then return state;
  645.     if (retc = 'E') then
  646.       do;
  647.         call prerrpkt(.packet);
  648.         return 'A';
  649.       end;
  650.     if (retc <> 'Y') then return 'A';
  651.     /* here on valid acknowledgement */
  652.     call rpar(.packet);
  653.     if eol = 0 then eol = myeol;
  654.     if quote = 0 then quote = myquote;
  655.     tries = 0;
  656.     msgnum = (msgnum + 1) mod 64;
  657.     /* Crack the file name */
  658.     fnptr = filename;
  659.     if fnchr = ':' then
  660.       do; /* File name on command has a drive */
  661.         foffset = movevar(0,filename,.localfile); /* Use file name as-is */
  662.         foffset = movevar(0,filename+4,.remotefile); /* Strip drive */
  663.       end;
  664.     else
  665.       do;
  666.         foffset = movevar(0,.def$drive,.localfile); /* Build local file name */
  667.         foffset = movevar(foffset,filename,.localfile); /*  from default drive */
  668.         foffset = movevar(0,filename,.remotefile);
  669.       end;
  670.     filename = token; /* Check for second operand */
  671.     if (filename > 0) then /* use 2nd operand for remote file name */
  672.       foffset = movevar(0,filename,.remotefile);
  673.     call open(.jfn, .localfile, readonly, noedit, .status);
  674.     if (status > 0) then
  675.       do;
  676.         call print(.('\Cannot open file $'));
  677.         call print(.localfile);
  678.         call print(.(crlf));
  679.         return 'A';
  680.       end;
  681.     else return 'F';
  682. end sinit;
  683.  
  684. /* SBREAK: this module breaks the flow of control at the end of a     */
  685. /* transmission and allows the send routine to terminate by returning    */
  686. /* either a successful or failure condition to the main kermit routine. */
  687. sbreak:    procedure byte;
  688.     declare (num, length, retc) byte;
  689.  
  690.     if debug then call print(.('sbreak...\$'));
  691.  
  692.     if tries > maxtry then return 'A';
  693.       else tries = tries + 1;
  694.  
  695.     call spack('B', msgnum, 0, .packet);
  696.     retc = rpack(.length, .num, .packet);
  697.  
  698.     if (retc = 'N') then return state;
  699.     if (retc = 'E') then
  700.       do;
  701.         call prerrpkt(.packet);
  702.         return 'A';
  703.       end;
  704.     if (retc <> 'Y') then return 'A';
  705.     /* we only get here if we received a valid acknowledgement */
  706.     tries = 0;
  707.     msgnum = (msgnum + 1) mod 64;
  708.     return 'C';
  709. end sbreak;
  710.  
  711. /* Display help for the SEND command */
  712. senhelp: procedure public;
  713.     call print(.('\SEND\\$'));
  714.     call print(.('  The SEND command causes Kermit to send a file $'));
  715.     call print(.('to the remote Kermit.\\$'));
  716.     call print(.('Syntax:\\$'));
  717.     call print(.('    SEND file [remote-file]\\$'));
  718.     call print(.('If the "remote-file" is specified, that name will be $'));
  719.     call print(.('used by the remote\$'));
  720.     call print(.('Kermit.\\$'));
  721. end senhelp;
  722.  
  723. /* SEND: This is the main code for the send command.  It is an FSM for    */
  724. /* sending files. The main loop calls various routines until it     */
  725. /* finishes or an error occurs. */
  726. send:   procedure public;
  727.  
  728.     filename = token; /* Get the command line file name */
  729.     if (filename = 0) then
  730.       do;
  731.         call print(.('No files specified\$'));
  732.         return;
  733.       end;
  734.     state = 'S';                /* start in Send-Init state */
  735.     msgnum = 0;
  736.     tries = 0;
  737.  
  738.     do while (state <> true and state <> false);
  739.       if debug then
  740.         do;
  741.           call print(.('state : ',null));
  742.           call co(state);
  743.           call newline;
  744.         end;
  745.       if state = 'D' then state = sdata;
  746.       else
  747.         if state = 'F' then state = sfile;
  748.         else
  749.           if state = 'Z' then state = seof;
  750.           else
  751.             if state = 'S' then state = sinit;
  752.         else
  753.           if state = 'B' then state = sbreak;
  754.               else
  755.             if state = 'C' then state = true;
  756.             else
  757.               if state = 'A' then state = false;
  758.               else state = false;
  759.     end;
  760.     if state then call print(.('\OK',bel,crlf));
  761.     else call print(.('Send failed\$'));
  762.  
  763. end send;
  764.  
  765. end send$module;
  766.