home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / c / umkermit.sou < prev    next >
Text File  |  2020-01-01  |  45KB  |  1,240 lines

  1. * KERMIT FOR U-MAN 1000 UNDER CP/M-68k
  2. * ====================================
  3. *
  4. *
  5. * This is a concatenation of the source files for U-MAN Kermit. Each file
  6. * begins with a line of the form
  7. *
  8. * **** <name> ******.....
  9. *
  10. * where <name> is the name the file should have on the U-MAN discs. End of 
  11. * file is marked by a line
  12. *
  13. * **** END OF FILE *****.......
  14. *
  15. **** FILE UMBDOS.S *************************************************************
  16.     .globl _bdos
  17.  
  18. _bdos:    move.w    4(sp),d0
  19.     move.l    6(sp),d1
  20.     trap    #2
  21.     rts
  22.  
  23.     .globl    _bios
  24. _bios:    move.w    4(sp),d0
  25.     move.l    6(sp),d1
  26.     move.l    10(sp),d2
  27.     trap    #3
  28.     rts
  29.     .end
  30. **** FILE UMTERM.C *************************************************************
  31. /* This is a very simple terminal program for the UMAN */
  32.  
  33. main()
  34. {
  35.     register long iobyte;
  36.     iobyte=bios(19) & ~3;        /* Get iobyte */
  37.     while (1)
  38.     {
  39.         iobyte |=1;
  40.         bios(20,iobyte);    /* Set console device to keyboard */
  41.         if (bios(2)) bios(6,(long)readcon());    /* Check for input */
  42.         iobyte &= ~3;         /* Set console device to serial */
  43.         bios(20,iobyte);
  44.         if (bios(2))        /* There is a character at serial */
  45.             {
  46.             iobyte |=1;
  47.             bios(20,iobyte);
  48.             bios(4,(long)(bios(7)& 0x7f));
  49.             }
  50.     }
  51. }
  52.  
  53. readcon()
  54. {
  55.     /* This reads the console */
  56.     register int c;
  57.     c=bios(3);    /* Read the keyboard */
  58.     if (c!=0x1d) return(c);     /* If not CTRL ] */
  59.     exit(0);
  60. }
  61. **** FILE UMKERM.C *************************************************************
  62. /*
  63. *      K e r m i t     File Transfer Utility
  64. *
  65. */
  66.  
  67. #include <stdio.h>
  68.  
  69. /* Symbol Definitions */
  70.  
  71. #define MAXPACKSIZ      94      /* Maximum packet size */
  72. #define MYPACKSIZ       94      /* My packet size */
  73. #define SOH             1       /* Start of header */
  74. #define CR              13      /* ASCII Carriage Return */
  75. #define SP              32      /* ASCII space */
  76. #define DEL             127     /* Delete (rubout) */
  77. #define ESCCHR          '^'     /* Default escape character for CONNECT */
  78. #define DEFPAR          '\0'     /* Default no parity */
  79.  
  80. #define MAXTRY          10      /* Times to retry a packet */
  81. #define MYQUOTE         '#'     /* Quote character I will use */
  82. #define MYPAD           0       /* Number of padding characters I will need */
  83. #define MYPCHAR         0       /* Padding character I need (0) */
  84. #define DEFMAXL         80      /* Default packer size */
  85. #define DEFTIME         5       /* Default timeout */
  86. #define DEFPAD          0       /* Default pad characters */
  87. #define DEFPADC         0       /* Default pad character */
  88. #define DEFEOL          '\r'    /* Default EOL character */
  89. #define DEFQUOTE        '#'     /* Default QUOTE character */
  90. #define DEFQBIN         'N'     /* Default QBIN character */
  91.  
  92. #define QBIN            '&'     /* Character for binary quoting */
  93.  
  94. #define MYEOL           '\n'    /* End-Of-Line character I need */
  95.  
  96. #define MYTIME          10      /* Seconds after which I should be timed out */
  97. #define MAXTIM          60      /* Maximum timeout interval */
  98. #define MINTIM          2       /* Minumum timeout interval */
  99.  
  100. #define TRUE            -1      /* Boolean constants */
  101. #define FALSE           0
  102.  
  103.  
  104. /* Macro Definitions */
  105.  
  106. /*
  107. * tochar: converts a control character to a printable one by adding a space.
  108. *
  109. * unchar: undoes tochar.
  110. *
  111. * ctl:         converts between control characters and printable characters by
  112. *              toggling the control bit (ie. ^A becomes A and A becomes ^A).
  113. */
  114. #define tochar(ch)      ((ch) + ' ')
  115. #define unchar(ch)      ((ch) - ' ')
  116. #define ctl(ch)         ((ch) ^ 64 )
  117.  
  118.  
  119. /* Global Variables */
  120.  
  121. char version[]="Uman Kermit. Version 0.02\n";
  122.  
  123. int     size,           /* Size of present data */
  124.         spsiz,          /* Maximum send packet size */
  125.         pad,            /* How much padding to send */
  126.         timint,         /* Timeout for foreign host on sends */
  127.         n,              /* Packet number */
  128.         numtry,         /* Times this packet retried */
  129.         oldtry,         /* Times previous packet retried */
  130.         parity,         /* o,e,s,m or 0 */
  131.         debug,          /* indicates level of debugging output (0=none) */
  132.         qflag,          /* -1 if doing 8 bit quoting */
  133.         filecount;      /* Number of files left to send */
  134.  
  135. char    state,          /* Present state of the automaton */
  136.         padchar,        /* Padding character to send */
  137.         eol,            /* End-Of-Line character to send */
  138.         escchr,         /* Connect command escape character */
  139.         quote,          /* Quote character in incoming data */
  140.         qbin,           /* character for binary quoting */
  141.         **filelist,     /* List of files to be sent */
  142.         *filnam,        /* Current file name */
  143.         recpkt[MAXPACKSIZ],     /* Receive packet buffer */
  144.         packet[MAXPACKSIZ];     /* Packet buffer */
  145.  
  146. FILE    *fp,*fopen();            /* File pointer for current disk file */
  147. FILE    *fopenb(),*(*kfopen)();   /* jgc dec 25th 1985 */
  148. /*
  149. *      m a i n
  150. *
  151. * Main routine - parse command and options, set up the
  152. * tty lines, and dispatch to the appropriate routine.
  153. */
  154.  
  155. main(argc,argv)
  156. int     argc;                   /* Character pointers to and count of */
  157. char    **argv;                 /* command line arguments */
  158. {
  159.         char *cp;                       /* char pointer */
  160.         int cflg, rflg, sflg;   /* flags for CONNECT, RECEIVE, SEND */
  161.  
  162.         printf("%s",version);   /* Print out the version number */
  163.         if (argc < 2) usage();  /* Make sure there's a command line */
  164.  
  165.         cp = *++argv;
  166.         argv++;
  167.         argc -= 2;                      /* Set up pointers to args */
  168.  
  169.         /* Initialize these values */
  170.         /* Hope the first packet will get across OK */
  171.  
  172.         eol = CR;                       /* EOL for outgoing packets */
  173.         quote = '#';                    /* Standard control-quote char "#" */
  174.         pad = 0;                        /* No padding */
  175.         padchar = '\0';                 /* Use null if any padding wanted */
  176.         timint = DEFTIME ;              /* Default timeout */
  177.  
  178.         cflg = sflg = rflg = 0;         /* Turn off all parse flags */
  179.       /*  qflag = FALSE; */ en8quote(FALSE);         /* jgc dec 25th. 1985 */
  180.                  /* and not 8 bit quoting */
  181.  
  182.         escchr = ESCCHR;                /* Default escape character */
  183.         parity = DEFPAR;                /* Default to no parity */
  184.  
  185.         while ((*cp) != NULLPTR)           /* Parse characters in first arg. */
  186.                 switch (*cp++)
  187.                 {
  188.                 case 'c':               /* C = Connect command */
  189.                         cflg++;
  190.                         break;
  191.                 case 's':               /* S = Send command */
  192.                         sflg++;
  193.                         break;
  194.                 case 'r':               /* R = Receive command */
  195.                         rflg++;
  196.                         break;
  197.  
  198.                 case 'd':               /* D = Increment debug mode count */
  199.                         debug++;
  200.                         break;
  201.  
  202.                 case 'p':               /* P = Set parity */
  203.                         parity = *cp++;
  204.                         if ((parity=='n')||(parity=='N')) parity='\0';
  205.                         if (!parity) break;      /* jgc dec 25th. 1985 */
  206.  
  207.                 case 'q':               /* q = Do 8 bit quoting */
  208.                      /*   qflag = TRUE; */ en8quote(TRUE);     /* jgc dec 25th. 1985 */
  209.                         break;
  210.  
  211.                 }
  212.  
  213.         /* Done parsing */
  214.  
  215.         if ((cflg+sflg+rflg) != 1) usage();     /* Only one command allowed */
  216.  
  217.         /* All set up, now execute the command that was given. */
  218.  
  219.         if (debug)
  220.         {
  221.                 printf("Debugging level = %d\n\n",debug);
  222.                 if (cflg) printf("Connect command\n\n");
  223.                 if (sflg) printf("Send command\n\n");
  224.                 if (rflg) printf("Receive command\n\n");
  225.         }
  226.  
  227.         if (cflg) connect();            /* Connect command */
  228.  
  229.         if (sflg)                       /* Send command */
  230.         {
  231.                 if (argc--) filnam = *argv++;           /* Get file to send */
  232.                 else
  233.                 {
  234.                         usage();
  235.                 }
  236.                 fp = NULLPTR;              /* Indicate no file open yet */
  237.                 filelist = argv;        /* Set up the rest of the file list */
  238.                 filecount = argc;       /* Number of files left to send */
  239.                 if (sendsw() == FALSE)                  /* Send the file(s) */
  240.                         printmsg("Send failed.");       /* Report failure */
  241.                 else /* or */
  242.                         printmsg("done.");              /* success */
  243.         }
  244.  
  245.         if (rflg)                       /* Receive command */
  246.         {
  247.                 if (recsw() == FALSE)           /* Receive the file(s) */
  248.                         printmsg("Receive failed.");
  249.                 else /* Report failure */
  250.                         printmsg("done.");      /* or success */
  251.         }
  252.         /* Restore controlling tty's modes */
  253. }
  254.  
  255.  
  256. /*
  257. *      s e n d s w
  258. *
  259. * Sendsw is the state table switcher for sending files. It loops until
  260. * either it finishes, or an error is encountered. The routines called
  261. * by sendsw are responsible for changing the state.
  262. *
  263. */
  264.  
  265. sendsw()
  266. {
  267.         char sinit(), sfile(), sdata(), seof(), sbreak();
  268.  
  269.         state = 'S';            /* Send initiate is the start state */
  270.         n = 0;                  /* Initialize message number */
  271.         numtry = 0;             /* Say no tries yet */
  272.         while(TRUE)             /* Do this as long as necessary */
  273.         {
  274.                 if (debug) printf("sendsw state: %c\n",state);
  275.                 switch(state)
  276.                 {
  277.                 case 'S': 
  278.                         state = sinit(); 
  279.                         break; /* Send-Init */
  280.                 case 'F': 
  281.                         state = sfile(); 
  282.                         break; /* Send-File */
  283.                 case 'D': 
  284.                         state = sdata(); 
  285.                         break; /* Send-Data */
  286.                 case 'Z': 
  287.                         state = seof(); 
  288.                         break; /* Send-End-of-File */
  289.                 case 'B': 
  290.                         state = sbreak(); 
  291.                         break; /* Send-Break */
  292.                 case 'C': 
  293.                         return (TRUE);          /* Complete */
  294.                 case 'A': 
  295.                         return (FALSE);         /* "Abort" */
  296.                 default: 
  297.                         return (FALSE);         /* Unknown, fail */
  298.                 }
  299.         }
  300. }
  301.  
  302.  
  303. /*
  304. *      s i n i t
  305. *
  306. * Send Initiate: send this host's parameters and get other side's back.
  307. */
  308.  
  309. char sinit()
  310. {
  311.         int num, len;                   /* Packet number, length */
  312.         /* If too many tries, give up */
  313.         if (numtry++ > MAXTRY) return('A');
  314.         len = spar(packet);                     /* Fill up init info packet */
  315.  
  316.         flushinput();                   /* Flush pending input */
  317.  
  318.         spack('S',n,len,packet);                /* Send an S packet */
  319.         switch(rpack(&len,&num,recpkt)) /* What was the reply? */
  320.         {
  321.         case 'N':
  322.                 return(state);          /* NAK, try it again */
  323.  
  324.         case 'Y':                       /* ACK */
  325.                 if (n != num)           /* If wrong ACK, stay in S state */
  326.                         return(state);  /* and try again */
  327.                 rpar(recpkt,len);       /* Get other side's init info */
  328.  
  329.                 numtry = 0;             /* Reset try counter */
  330.                 n = (n+1)%64;           /* Bump packet count */
  331.                 return('F');            /* OK, switch state to F */
  332.  
  333.         case 'E':                       /* Error packet received */
  334.                 prerrpkt(recpkt);       /* Print it out and */
  335.                 return('A');            /* abort */
  336.  
  337.         case FALSE:
  338.                 return(state);          /* Receive failure, try again */
  339.  
  340.         default:
  341.                 return('A');            /* Anything else, just "abort" */
  342.         }
  343. }
  344.  
  345.  
  346. /*
  347. *      s f i l e
  348. *
  349. * Send File Header.
  350. */
  351.  
  352. char sfile()
  353. {
  354.         int num, len;                   /* Packet number, length */
  355.         char filnam1[50],               /* Converted file name */
  356.         *newfilnam,                     /* Pointer to file name to send */
  357.         *cp;                            /* char pointer */
  358.         /* If too many tries, give up */
  359.         if (numtry++ > MAXTRY) return('A');
  360.  
  361.         if (fp == NULLPTR)                 /* If not already open, */
  362.         {
  363.                 if (debug) printf("\tOpening %s for sending.\n",filnam);
  364.                 fp = (*kfopen)(filnam,"r");         /* open the file to be sent */
  365.                 if (fp == NULLPTR)         /* If bad file pointer, give up */
  366.                 {
  367.                         error("Cannot open file %s",filnam);
  368.                         return('A');
  369.                 }
  370.         }
  371.  
  372.         strcpy(filnam1, filnam);                /* Copy file name */
  373.         newfilnam = cp = filnam1;
  374.         while (*cp != '\0')             /* Strip off all leading directory */
  375.                 if (*cp++ == '/')       /* names (ie. up to the last /). */
  376.                         newfilnam = cp;
  377.  
  378.         for (cp = newfilnam; *cp != '\0'; cp++)
  379.                 if (*cp >= 'a' && *cp <= 'z')
  380.                         *cp ^= 040;
  381.  
  382.         len = (int)(cp - newfilnam);    /* Compute length of new filename */
  383.  
  384.         printmsg("Sending %s as %s",filnam,newfilnam);
  385.  
  386.         spack('F',n,len,newfilnam);             /* Send an F packet */
  387.         switch(rpack(&len,&num,recpkt))         /* What was the reply? */
  388.         {
  389.         case 'N':                       /* NAK, just stay in this state, */
  390.                 /* unless it's NAK for next packet */
  391.                 num = (--num<0 ? 63:num);
  392.                 if (n != num)           /* which is just like an ACK for */
  393.                         return(state);  /* this packet so fall thru to... */
  394.  
  395.         case 'Y':                       /* ACK */
  396.                 if (n != num) return(state); /* If wrong ACK, stay in F state */
  397.                 numtry = 0;             /* Reset try counter */
  398.                 n = (n+1)%64;           /* Bump packet count */
  399.                 size = bufill(packet);  /* Get first data from file */
  400.                 return('D');            /* Switch state to D */
  401.  
  402.         case 'E':                       /* Error packet received */
  403.                 prerrpkt(recpkt);       /* Print it out and */
  404.                 return('A');            /* abort */
  405.  
  406.         case FALSE:
  407.                 return(state);          /* Receive failure, stay in F state */
  408.  
  409.         default:
  410.                 return('A');            /* Something else, just "abort" */
  411.         }
  412. }
  413.  
  414.  
  415. /*
  416. *      s d a t a
  417. *
  418. * Send File Data
  419. */
  420.  
  421. char sdata()
  422. {
  423.         int num, len;                   /* Packet number, length */
  424.  
  425.         if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
  426.  
  427.         spack('D',n,size,packet);               /* Send a D packet */
  428.         switch(rpack(&len,&num,recpkt))         /* What was the reply? */
  429.         {
  430.         case 'N':                       /* NAK, just stay in this state, */
  431.                 /* unless it's NAK for next packet */
  432.                 num = (--num<0 ? 63:num);
  433.                 if (n != num)           /* which is just like an ACK for */
  434.                         return(state);  /* this packet so fall thru to... */
  435.  
  436.         case 'Y':                       /* ACK */
  437.                 if (n != num) return(state); /* If wrong ACK, fail */
  438.                 numtry = 0;             /* Reset try counter */
  439.                 n = (n+1)%64;           /* Bump packet count */
  440.                 if ((size = bufill(packet)) == EOF) /* Get data from file */
  441.                         return('Z');    /* If EOF set state to that */
  442.                 return('D');            /* Got data, stay in state D */
  443.  
  444.         case 'E':                       /* Error packet received */
  445.                 prerrpkt(recpkt);       /* Print it out and */
  446.                 return('A');            /* abort */
  447.  
  448.         case FALSE:
  449.                 return(state);          /* Receive failure, stay in D */
  450.  
  451.         default:
  452.                 return('A');    /* Anything else, "abort" */
  453.         }
  454. }
  455.  
  456.  
  457. /*
  458. *      s e o f
  459. *
  460. * Send End-Of-File.
  461. */
  462.  
  463. char seof()
  464. {
  465.         int num, len;                   /* Packet number, length */
  466.         if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
  467.  
  468.         spack('Z',n,0,packet);          /* Send a 'Z' packet */
  469.         switch(rpack(&len,&num,recpkt))         /* What was the reply? */
  470.         {
  471.         case 'N':                       /* NAK, just stay in this state, */
  472.                 /* unless it's NAK for next packet, */
  473.                 num = (--num<0 ? 63:num);
  474.                 if (n != num)           /* which is just like an ACK for */
  475.                         return(state);  /* this packet so fall thru to... */
  476.  
  477.         case 'Y':                       /* ACK */
  478.                 if (n != num) return(state); /* If wrong ACK, hold out */
  479.                 numtry = 0;                     /* Reset try counter */
  480.                 n = (n+1)%64;                   /* and bump packet count */
  481.                 if (debug) printf("\tClosing input file %s, ",filnam);
  482.                 fclose(fp);                     /* Close the input file */
  483.                 fp = NULLPTR;              /* Set flag indicating no file open */
  484.  
  485.                 if (debug) printf("looking for next file...\n");
  486.                 if (gnxtfl() == FALSE)          /* No more files go? */
  487.                         return('B');    /* if not, break, EOT, all done */
  488.                 if (debug) printf("\tNew file is %s\n",filnam);
  489.                 return('F');            /* More files, switch state to F */
  490.  
  491.         case 'E':                       /* Error packet received */
  492.                 prerrpkt(recpkt);       /* Print it out and */
  493.                 return('A');            /* abort */
  494.  
  495.         case FALSE:
  496.                 return(state);          /* Receive failure, stay in Z */
  497.  
  498.         default:
  499.                 return('A');    /* Something else, "abort" */
  500.         }
  501. }
  502.  
  503.  
  504. /*
  505. *      s b r e a k
  506. *
  507. * Send Break (EOT)
  508. */
  509.  
  510. char sbreak()
  511. {
  512.         int num, len;                   /* Packet number, length */
  513.         if (numtry++ > MAXTRY) return('A'); /* If too many tries "abort" */
  514.  
  515.         spack('B',n,0,packet);          /* Send a B packet */
  516.         switch (rpack(&len,&num,recpkt))        /* What was the reply? */
  517.         {
  518.         case 'N':                       /* NAK, just stay in this state, */
  519.                 /* unless NAK for previous packet, */
  520.                 num = (--num<0 ? 63:num);
  521.                 if (n != num)           /* which is just like an ACK for */
  522.                         return(state);  /* this packet so fall thru to... */
  523.  
  524.         case 'Y':                       /* ACK */
  525.                 if (n != num) return(state); /* If wrong ACK, fail */
  526.                 numtry = 0;             /* Reset try counter */
  527.                 n = (n+1)%64;           /* and bump packet count */
  528.                 return('C');            /* Switch state to Complete */
  529.  
  530.         case 'E':                       /* Error packet received */
  531.                 prerrpkt(recpkt);       /* Print it out and */
  532.                 return('A');            /* abort */
  533.  
  534.         case FALSE:
  535.                 return(state);          /* Receive failure, stay in B */
  536.  
  537.         default:
  538.                 return ('A');           /* Other, "abort" */
  539.         }
  540. }
  541.  
  542.  
  543. /*
  544. *      r e c s w
  545. *
  546. * This is the state table switcher for receiving files.
  547. */
  548.  
  549. recsw()
  550. {
  551.         char rinit(), rfile(), rdata();         /* Use these procedures */
  552.  
  553.         state = 'R';                    /* Receive-Init is the start state */
  554.         n = 0;                          /* Initialize message number */
  555.         numtry = 0;                     /* Say no tries yet */
  556.  
  557.         while(TRUE)
  558.         {
  559.                 if (debug) printf("\trecsw state: %c\n",state);
  560.                 switch(state)                   /* Do until done */
  561.                 {
  562.                 case 'R':
  563.                         state = rinit();
  564.                         break; /* Receive-Init */
  565.                 case 'F':
  566.                         state = rfile();
  567.                         break; /* Receive-File */
  568.                 case 'D':
  569.                         state = rdata();
  570.                         break; /* Receive-Data */
  571.                 case 'C':
  572.                         return(TRUE);           /* Complete state */
  573.                 case 'A':
  574.                         return(FALSE);          /* "Abort" state */
  575.                 }
  576.         }
  577. }
  578.  
  579.  
  580. /*
  581. *      r i n i t
  582. *
  583. * Receive Initialization
  584. */
  585.  
  586. char rinit()
  587. {
  588.         int len, num;                   /* Packet length, number */
  589.  
  590.         if (numtry++ > MAXTRY) return('A');     /* If too many tries, "abort" */
  591.  
  592.         switch(rpack(&len,&num,packet))         /* Get a packet */
  593.         {
  594.         case 'S':                       /* Send-Init */
  595.                 rpar(packet,len);       /* Get the other side's init data */
  596.                 len = spar(packet);     /* Fill up packet with my init info */
  597.                 spack('Y',n,len,packet);        /* ACK with my parameters */
  598.                 oldtry = numtry;                /* Save old try count */
  599.                 numtry = 0;                     /* Start a new counter */
  600.                 n = (n+1)%64;           /* Bump packet number, mod 64 */
  601.                 return('F');            /* Enter File-Receive state */
  602.  
  603.         case 'E':                       /* Error packet received */
  604.                 prerrpkt(recpkt);       /* Print it out and */
  605.                 return('A');            /* abort */
  606.  
  607.         case FALSE:                     /* Didn't get packet */
  608.                 spack('N',n,0,NULLPTR);    /* Return a NAK */
  609.                 return(state);          /* Keep trying */
  610.  
  611.         default:
  612.                 return('A');            /* Some other packet type, "abort" */
  613.         }
  614. }
  615.  
  616.  
  617. /*
  618. *      r f i l e
  619. *
  620. * Receive File Header
  621. */
  622.  
  623. char rfile()
  624. {
  625.         int num, len;                   /* Packet number, length */
  626.         char filnam1[50];               /* Holds the converted file name */
  627.  
  628.         if (numtry++ > MAXTRY) return('A');     /* "abort" if too many tries */
  629.  
  630.         switch(rpack(&len,&num,packet))         /* Get a packet */
  631.         {
  632.         case 'S':                       /* Send-Init, maybe our ACK lost */
  633.                 /* If too many tries "abort" */
  634.                 if (oldtry++ > MAXTRY) return('A');
  635.                 if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
  636.                 {                               /* Yes, ACK it again with */
  637.                         len = spar(packet);     /* our Send-Init parameters */
  638.                         spack('Y',num,len,packet);
  639.                         numtry = 0;             /* Reset try counter */
  640.                         return(state);          /* Stay in this state */
  641.                 }
  642.                 else return('A');       /* Not previous packet, "abort" */
  643.  
  644.         case 'Z':                       /* End-Of-File */
  645.                 if (oldtry++ > MAXTRY) return('A');
  646.                 if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
  647.                 {                               /* Yes, ACK it again. */
  648.                         spack('Y',num,0,NULLPTR);
  649.                         numtry = 0;
  650.                         return(state);          /* Stay in this state */
  651.                 }
  652.                 else return('A');       /* Not previous packet, "abort" */
  653.  
  654.         case 'F':                       /* File Header (just what we want) */
  655.                 /* The packet number must be right */
  656.                 if (num != n) return('A');
  657.                 strcpy(filnam1, packet);        /* Copy the file name */
  658.  
  659.                 if ((fp=(*kfopen)(filnam1,"w"))==NULLPTR) /* Try to open a new file */
  660.                 {                               /* Give up if can't */
  661.                         error("Cannot create %s",filnam1);
  662.                         return('A');
  663.                 }
  664.                 else /* OK, give message */
  665.                         printmsg("Receiving %s as %s",packet,filnam1);
  666.  
  667.                 spack('Y',n,0,NULLPTR);    /* Acknowledge the file header */
  668.                 oldtry = numtry;        /* Reset try counters */
  669.                 numtry = 0;
  670.                 n = (n+1)%64;           /* Bump packet number, mod 64 */
  671.                 return('D');            /* Switch to Data state */
  672.  
  673.         case 'B':                       /* Break transmission (EOT) */
  674.                 if (num != n) return ('A'); /* Need right packet number here */
  675.                 spack('Y',n,0,NULLPTR);            /* Say OK */
  676.                 return('C');            /* Go to complete state */
  677.  
  678.         case 'E':                       /* Error packet received */
  679.                 prerrpkt(recpkt);       /* Print it out and */
  680.                 return('A');            /* abort */
  681.  
  682.         case FALSE:                     /* Didn't get packet */
  683.                 spack('N',n,0,NULLPTR);    /* Return a NAK */
  684.                 return(state);          /* Keep trying */
  685.  
  686.         default:
  687.                 return ('A');           /* Some other packet, "abort" */
  688.         }
  689. }
  690.  
  691.  
  692. /*
  693. *      r d a t a
  694. *
  695. * Receive Data
  696. */
  697.  
  698. char rdata()
  699. {
  700.         int num, len;                   /* Packet number, length */
  701.         if (numtry++ > MAXTRY) return('A');     /* "abort" if too many tries */
  702.  
  703.         switch(rpack(&len,&num,packet))         /* Get packet */
  704.         {
  705.         case 'D':                       /* Got Data packet */
  706.                 if (num != n)           /* Right packet? */
  707.                 {                               /* No */
  708.                         if (oldtry++ > MAXTRY)
  709.                                 return('A');    /* If too many tries, abort */
  710.                         if (num == ((n==0) ? 63:n-1))
  711.                         { /* Else check previous packet again? */
  712.                                 spack('Y',num,0,NULLPTR); /* Yes, re-ACK it */
  713.                                 numtry = 0;     /* Reset try counter */
  714.                                 return(state);  /* Don't write out data! */
  715.                         }
  716.                         else return('A');       /* sorry, wrong number */
  717.                 }
  718.                 /* Got data with right packet number */
  719.                 bufemp(packet,len);             /* Write the data to the file */
  720.                 spack('Y',n,0,NULLPTR);            /* Acknowledge the packet */
  721.                 oldtry = numtry;                /* Reset the try counters */
  722.                 numtry = 0;                     /* ... */
  723.                 n = (n+1)%64;           /* Bump packet number, mod 64 */
  724.                 return('D');            /* Remain in data state */
  725.  
  726.         case 'F':                       /* Got a File Header */
  727.                 if (oldtry++ > MAXTRY)
  728.                         return('A');            /* If too many tries, "abort" */
  729.                 if (num == ((n==0) ? 63:n-1))   /* Else check packet number */
  730.                 {                               /* It was the previous one */
  731.                         spack('Y',num,0,NULLPTR);  /* ACK it again */
  732.                         numtry = 0;             /* Reset try counter */
  733.                         return(state);          /* Stay in Data state */
  734.                 }
  735.                 else return('A');       /* Not previous packet, "abort" */
  736.  
  737.         case 'Z':                       /* End-Of-File */
  738.                 /* Must have right packet number */
  739.                 if (num != n) return('A');
  740.                 spack('Y',n,0,NULLPTR);            /* OK, ACK it. */
  741.                 fclose(fp);                     /* Close the file */
  742.                 n = (n+1)%64;           /* Bump packet number */
  743.                 return('F');            /* Go back to Receive File state */
  744.  
  745.         case 'E':                       /* Error packet received */
  746.                 prerrpkt(recpkt);               /* Print it out and */
  747.                 return('A');            /* abort */
  748.  
  749.         case FALSE:                     /* Didn't get packet */
  750.                 spack('N',n,0,NULLPTR);            /* Return a NAK */
  751.                 return(state);          /* Keep trying */
  752.  
  753.         default:
  754.                 return('A');            /* Some other packet, "abort" */
  755.         }
  756. }
  757.  
  758. /*
  759. *      c o n n e c t
  760. *
  761. * Establish a virtual terminal connection with the remote host, over an
  762. * assigned tty line.
  763. */
  764.  
  765. connect()
  766. {
  767. /* This routine assumes that iobyte has been fully implemented */
  768. /* so that the program can check for input at the serial port. */
  769. /* It assumes that the normal keyboard is the CRT: device. */
  770. /* and the serial port is the TTY: device */
  771. /* This routine is the one most likely to need changing for other machines */
  772.         register long iobyte;
  773.         iobyte=bios(19) & ~3;
  774.         printf("Connected\n");
  775.         while (1)
  776.         {
  777.                 iobyte |=1;
  778.                 bios(20,iobyte);        /* Set console device to keyboard */
  779.                                 /* Check for console input */
  780.                 if (bios(2)) readcon();
  781.                 iobyte &= ~3;            /* Set console device to serial */
  782.                 bios(20,iobyte);
  783.                 if (bios(2))
  784.                 {
  785.                         iobyte |=1;
  786.                         bios(20,iobyte);
  787.                         bios(4,(long)(bios(7)& 0x7f));
  788.                 }
  789.         }
  790. }
  791.  
  792. readcon()
  793. {
  794.         /* This reads the console */
  795.         register int c;
  796.         c=bios(3);      /* Read the keyboard */
  797.         if (c!=0x1d) sendaux(c);        /* If not CTRL ] */
  798.         else exit(0);
  799. }
  800.  
  801. /*
  802. *      KERMIT utilities.
  803. */
  804.  
  805. /*
  806. *      s p a c k
  807. *
  808. * Send a Packet
  809. */
  810.  
  811. spack(type,num,len,data)
  812. char type, *data;
  813. int num, len;
  814. {
  815.         int i;                          /* Character loop counter */
  816.         char chksum, buffer[100];       /* Checksum, packet buffer */
  817.         register char *bufp;            /* Buffer pointer */
  818.  
  819.         if (debug>1)                    /* Display outgoing packet */
  820.         {                       /* Null-terminate data to print it */
  821.                 if (data != NULLPTR) data[len] = '\0';
  822.                 printf("\tspack type: %c\n",type);
  823.                 printf("\t\tnum: %d\n",num);
  824.                 printf("\t\tlen: %d\n",len);
  825.                 if (data != NULLPTR)
  826.                         printf("\tdata: \"%s\"\n",data);
  827.         }
  828.  
  829.         bufp = buffer;                  /* Set up buffer pointer */
  830.         for (i=1; i<=pad; i++) sendaux(padchar); /* Issue any padding */
  831.  
  832.         *bufp++ = SOH;                  /* Packet marker, ASCII 1 (SOH) */
  833.         *bufp++ = tochar(len+3);        /* Send the character count */
  834.         chksum = tochar(len+3);         /* Initialize the checksum */
  835.         *bufp++ = tochar(num);          /* Packet number */
  836.         chksum += tochar(num);          /* Update checksum */
  837.         *bufp++ = type;                 /* Packet type */
  838.         chksum += type;                 /* Update checksum */
  839.  
  840.         for (i=0; i<len; i++)           /* Loop for all data characters */
  841.         {
  842.                 *bufp++ = data[i];              /* Get a character */
  843.                 chksum += data[i];              /* Update checksum */
  844.         }
  845.         chksum = (((chksum&0300) >> 6)+chksum)&077; /* Compute final checksum */
  846.         *bufp++ = tochar(chksum);       /* Put it in the packet */
  847.         *bufp = eol;                    /* Extra-packet line terminator */
  848.         sauxstr( buffer,(int)(bufp-buffer+1)); /* Send the packet */
  849. }
  850.  
  851. /*
  852. *      r p a c k
  853. *
  854. * Read a Packet
  855. */
  856.  
  857. rpack(len,num,data)
  858. int *len, *num;                         /* Packet length, number */
  859. char *data;                             /* Packet data */
  860. {
  861.         int i, done;                    /* Data character number, loop exit */
  862.         char t,                         /* Current input character */
  863.         type,                   /* Packet type */
  864.         cchksum,                /* Our (computed) checksum */
  865.         rchksum;                        /* Checksum received from other host */
  866.  
  867.         do
  868.         {
  869.                 t=readaux()& 0x7f;
  870.         }while (t != SOH);                      /* Wait for packet header */
  871.  
  872.         done = FALSE;                   /* Got SOH, init loop */
  873.         while (!done)                   /* Loop to get a packet */
  874.         {
  875.                 t=readaux();            /* Get character */
  876.                 if (t == SOH) continue;         /* Resynchronize if SOH */
  877.                 cchksum = t;                    /* Start the checksum */
  878.                 *len = unchar(t)-3;             /* Character count */
  879.  
  880.                 t=readaux();            /* Get character */
  881.                 if (t == SOH) continue;         /* Resynchronize if SOH */
  882.                 cchksum += t;                   /* Update checksum */
  883.                 *num = unchar(t);               /* Packet number */
  884.  
  885.                 t=readaux();            /* Get character */
  886.                 if (t == SOH) continue;         /* Resynchronize if SOH */
  887.                 cchksum += t;                   /* Update checksum */
  888.                 type = t;                       /* Packet type */
  889.  
  890.                 for (i=0; i<*len; i++)          /* The data itself, if any */
  891.                 {                               /* Loop for character count */
  892.                         t=readaux();    /* Get character */
  893.                         if (t == SOH) continue; /* Resynch if SOH */
  894.                         cchksum += t;           /* Update checksum */
  895.                         data[i] = t;            /* Put it in the data buffer */
  896.                 }
  897.                 data[*len] = 0;                 /* Mark the end of the data */
  898.  
  899.                 t=readaux();            /* Get last character (checksum) */
  900.                 rchksum = unchar(t);            /* Convert to numeric */
  901.                 t=readaux();            /* get EOL character and toss it */
  902.                 if (t == SOH) continue;         /* Resynchronize if SOH */
  903.                 done = TRUE;                    /* Got checksum, done */
  904.         }
  905.         if (debug>1)                    /* Display incoming packet */
  906.         {
  907.                 data[*len] = '\0';      /* Null-terminate data to print it */
  908.                 printf("\trpack type: %c\n",type);
  909.                 printf("\t\tnum: %d\n",*num);
  910.                 printf("\t\tlen: %d\n",*len);
  911.                 printf("\tdata: \"%s\"\n",data);
  912.         }
  913.         /* Fold in bits 7,8 to compute */
  914.         cchksum = (((cchksum&0300) >> 6)+cchksum)&077; /* final checksum */
  915.  
  916.         if (cchksum != rchksum) return(FALSE);
  917.         return(type);                   /* All OK, return packet type */
  918. }
  919.  
  920.  
  921. /*
  922. *      b u f i l l
  923. *
  924. * Get a bufferful of data from the file that's being sent.
  925. * Only control-quoting and 8-bit quoting is done;
  926. * repeat count prefixes are not handled.
  927. */
  928.  
  929. bufill(buffer)
  930. char buffer[];                          /* Buffer */
  931. {
  932.         register int t;                         /* Char read from file */
  933.         register char t7;                       /* 7-bit version of above */
  934.         register char *buffend;                 /* End of buffer pointer */
  935.         register char *buffp;                   /* Pointer into buffer */
  936.         register int unprintable;               /* Is a character printable ?*/
  937.  
  938.         buffend = &buffer[spsiz-9];     /* set up end of buffer pointer */
  939.         buffp=buffer;                   /* and the current position */
  940.  
  941.         while((t = getc(fp)) != EOF)         /* Get the next character */
  942.         { 
  943.                 t7 = t & 0177;                  /* Get low order 7 bits */
  944.  
  945.                 /* If doing 8-bit quoting, then quote if needed */
  946.                 if ((t != t7) && qflag) *buffp++ = qbin;
  947.                 unprintable = ((t7<SP)||(t7==DEL));
  948.                 /* Does this char require special handling? */
  949.                 if ((unprintable) || t7==quote ||(qflag && (t7==qbin)))
  950.                 {
  951.                         *buffp++ = quote;       /* Quote the character */
  952.                         if (unprintable)
  953.                         {       /* will be printable if a quote char */
  954.                                 t = ctl(t);             /* and uncontrolify */
  955.                                 t7 = ctl(t7);
  956.                         }
  957.                 }
  958.                 *buffp++ = t;
  959.                 /* Check length */
  960.                 if (buffp >=buffend) return((int)(buffp-buffer));
  961.         }
  962.         if (buffp == buffer) return(EOF);       /* Wind up here only on EOF */
  963.         return((int)(buffp - buffer));                 /* Handle partial buffer */
  964. }
  965.  
  966.  
  967. /*
  968. *      b u f e m p
  969. *
  970. * Put data from an incoming packet into a file.
  971. */
  972.  
  973. bufemp(buffer,len)
  974. char buffer[];                          /* Buffer */
  975. int len;                                /* Length */
  976. {
  977.         register int i;                 /* Counter */
  978.         register char t;                /* Character holder */
  979.         register int highbit;           /* place to hold quoted highbit */
  980.  
  981.         highbit = 0;
  982.         for (i=0; i<len; i++)           /* Loop thru the data field */
  983.         {
  984.                 t = buffer[i];                  /* Get a character */
  985.                 /* If doing 8-bit quoting and this is such a quote
  986.         then note it */
  987.                 if (qflag && (t==qbin)) {
  988.                         highbit = 0x80;
  989.                         t=buffer[++i];
  990.                 }
  991.                 if (t == MYQUOTE)               /* Control quote? */
  992.                 {                               /* Yes */
  993.                         t = buffer[++i];        /* Get the quoted character */
  994.                         /* Low order bits match quote char? */
  995.                         if (((t & 0177) != MYQUOTE) &&
  996.                             (!qflag || ((t & 0x7F)!=qbin)))
  997.                                 t = ctl(t);     /* No, uncontrollify it */
  998.                 }
  999.                 t |= highbit;   /* set top bit if needed */
  1000.                 highbit=0;
  1001.                 putc(t,fp);
  1002.         }
  1003. }
  1004.  
  1005.  
  1006. /*
  1007. *      g n x t f l
  1008. *
  1009. * Get next file in a file group
  1010. */
  1011.  
  1012. gnxtfl()
  1013. {
  1014.         filnam = *(filelist++);
  1015.         if (filecount-- == 0) return FALSE; /* If no more, fail */
  1016.         else return TRUE;                       /* else succeed */
  1017. }
  1018.  
  1019.  
  1020. /*
  1021. *      s p a r
  1022. *
  1023. * Fill the data array with my send-init parameters
  1024. *
  1025. */
  1026.  
  1027. int
  1028. spar(data)
  1029. char data[];
  1030. {
  1031.         data[0] = tochar(MYPACKSIZ);    /* Biggest packet I can receive */
  1032.         data[1] = tochar(MYTIME);       /* When I want to be timed out */
  1033.         data[2] = tochar(MYPAD);        /* How much padding I need */
  1034.         data[3] = ctl(MYPCHAR);         /* Padding character I want */
  1035.         data[4] = tochar(MYEOL);        /* End-Of-Line character I want */
  1036.         data[5] = MYQUOTE;              /* Control-Quote character I send */
  1037.         data[6] = qflag?QBIN:'Y';       /* Request 8 bit quoting */
  1038.         return (7);                     /* return number of parameters */
  1039. }
  1040.  
  1041.  
  1042. /*      r p a r
  1043. *
  1044. * Get the other host's send-init parameters
  1045. *
  1046. */
  1047.  
  1048. rpar(data,len)
  1049. char data[];
  1050. int len;
  1051. {
  1052.         spsiz = DEFMAXL;        /* default packet size */
  1053.         timint = DEFTIME;
  1054.         pad = DEFPAD;
  1055.         padchar = DEFPADC;
  1056.         eol = DEFEOL;
  1057.         quote = DEFQUOTE;
  1058.         qbin = DEFQBIN;
  1059.         switch (len){
  1060.         default:
  1061.         case 10:        /* attributes */
  1062.         case 9:         /* repeat count */
  1063.         case 8:         /* Check type */
  1064.         case 7:         /* 8 bit quoting */
  1065.                 qbin = data[6];
  1066.                 if (((qbin >='!') && (qbin <= '>'))
  1067.                     || ((qbin >= '`')&&(qbin <= '~')))
  1068.                      /*   qflag = TRUE; */ en8quote(TRUE);     /* jgc dec 25th. 1985 */
  1069.         case 6:         /* Incoming data quote character */
  1070.                 quote = data[5];
  1071.         case 5:         /* EOL character I must send */
  1072.                 eol = unchar(data[4]);
  1073.         case 4:         /* Padding character I must send */
  1074.                 padchar = ctl(data[3]);
  1075.         case 3:         /* Number of pads to send */
  1076.                 pad = unchar(data[2]);
  1077.         case 2:         /* When I should time out */
  1078.                 timint = unchar(data[1]);
  1079.                 if ((timint > MAXTIM) || (timint < MINTIM)) timint = MYTIME;
  1080.         case 1:         /* Maximum send packet size */
  1081.                 spsiz = unchar(data[0]);
  1082.         case 0:
  1083.                 break;
  1084.         }
  1085.         if (qflag) {
  1086.                 if (qbin == 'N') error("Can't do 8 bit quoting\n");
  1087.                 else if (qbin == 'Y') qbin = QBIN;
  1088.         }
  1089. }
  1090.  
  1091. int
  1092. readaux()
  1093. {
  1094.         int c;
  1095.         c=bios(7);
  1096.         if (parity) c &= 0x7f;
  1097.         return (c);
  1098. }
  1099.  
  1100. sauxstr(buf,len)
  1101. char *buf;
  1102. int len;
  1103. {
  1104.         for(;len>0;len--)
  1105.                 sendaux(*buf++);
  1106. }
  1107.  
  1108. sendaux(c)
  1109. int c;
  1110. {
  1111.         /* A table giving even parity, used also to get odd parity */
  1112.         static char partab[128]={
  1113.                 0x00,0x81,0x82,0x03,0x84,0x05,0x06,0x87,
  1114.                 0x88,0x09,0x0A,0x8B,0x0C,0x8D,0x8E,0x0F,
  1115.                 0x90,0x11,0x12,0x93,0x14,0x95,0x96,0x17,
  1116.                 0x18,0x99,0x9A,0x1B,0x9C,0x1D,0x1E,0x9F,
  1117.                 0xA0,0x21,0x22,0xA3,0x24,0xA5,0xA6,0x27,
  1118.                 0x28,0xA9,0xAA,0x2B,0xAC,0x2D,0x2E,0xAF,
  1119.                 0x30,0xB1,0xB2,0x33,0xB4,0x35,0x36,0xB7,
  1120.                 0xB8,0x39,0x3A,0xBB,0x3C,0xBD,0xBE,0x3F,
  1121.                 0xC0,0x41,0x42,0xC3,0x44,0xC5,0xC6,0x47,
  1122.                 0x48,0xC9,0xCA,0x4B,0xCC,0x4D,0x4E,0xCF,
  1123.                 0x50,0xD1,0xD2,0x53,0xD4,0x55,0x56,0xD7,
  1124.                 0xD8,0x59,0x5A,0xDB,0x5C,0xDD,0xDE,0x5F,
  1125.                 0x60,0xE1,0xE2,0x63,0xE4,0x65,0x66,0xE7,
  1126.                 0xE8,0x69,0x6A,0xEB,0x6C,0xED,0xEE,0x6F,
  1127.                 0xF0,0x71,0x72,0xF3,0x74,0xF5,0xF6,0x77,
  1128.                 0x78,0xF9,0xFA,0x7B,0xFC,0x7D,0x7E,0xFF
  1129.         };
  1130.  
  1131.         if (parity)
  1132.         {
  1133.                 c &= 0x7f;
  1134.                 switch(parity)
  1135.                 {
  1136.                 case 'o':
  1137.                 case 'O':
  1138.                         c=partab[c] ^ 0x80;
  1139.                         break;
  1140.                 case 'e':
  1141.                 case 'E':
  1142.                         c=partab[c];
  1143.                         break;
  1144.                 case 'm':
  1145.                 case 'M':
  1146.                         c |= 0x80;
  1147.                         break;
  1148.                         /* Otherwise assume space parity */
  1149.                 }
  1150.         }
  1151.         bios(6,(long)c);        /* Send character */
  1152. }
  1153.  
  1154. /*
  1155. *      f l u s h i n p u t
  1156. *
  1157. * Dump all pending input to clear stacked up NACK's.
  1158. * (Implemented only for Berkeley Unix at this time).
  1159. */
  1160.  
  1161. flushinput()            /* Null version for non-Berkeley Unix */
  1162. {
  1163. }
  1164.  
  1165.  
  1166. /*
  1167. *      Kermit printing routines:
  1168. *
  1169. * usage - print command line options showing proper syntax
  1170. * printmsg - like printf with "Kermit: " prepended
  1171. * error - like printmsg
  1172. * prerrpkt - print contents of error packet received from remote host
  1173. */
  1174.  
  1175. /*
  1176. *      u s a g e
  1177. *
  1178. * Print summary of usage info and quit
  1179. */
  1180.  
  1181. usage()
  1182. {
  1183.         printf("Usage: kermit c[p[msoeN]]\t\t(connect mode)\n");
  1184.         printf("or:\tkermit s[dqp[msoeN]] file ...\t\t(send mode)\n");
  1185.         printf("or:\tkermit r[dqp[msoeN]]\t\t\t(receive mode)\n");
  1186.         exit(1);
  1187. }
  1188.  
  1189. /*
  1190. *      p r i n t m s g
  1191. *
  1192. * Print message on standard output if not remote.
  1193. */
  1194.  
  1195. /*VARARGS1*/
  1196. printmsg(fmt, a1, a2, a3, a4, a5)
  1197. char *fmt;
  1198. {
  1199.         printf("Kermit: ");
  1200.         printf(fmt,a1,a2,a3,a4,a5);
  1201.         printf("\n");
  1202.         fflush(stdout);         /* force output (UTS needs it) */
  1203. }
  1204.  
  1205. /*
  1206. *      e r r o r
  1207. *
  1208. * Print error message.
  1209. *
  1210. * If local, print error message with printmsg.
  1211. * If remote, send an error packet with the message.
  1212. */
  1213.  
  1214. /*VARARGS1*/
  1215. error(fmt, a1, a2, a3, a4, a5)
  1216. char *fmt;
  1217. {
  1218.         printmsg(fmt, a1, a2, a3, a4, a5);
  1219. }
  1220.  
  1221. /*
  1222. *      p r e r r p k t
  1223. *
  1224. * Print contents of error packet received from remote host.
  1225. */
  1226. prerrpkt(msg)
  1227. char *msg;
  1228. {
  1229.         printf("Kermit aborting with following error from remote host:\n%s\n",
  1230.             msg);
  1231.         return;
  1232. }
  1233.  
  1234. en8quote(t) int t; {                            /* jgc dec 25th. 1985 */
  1235.         if (qflag = t) kfopen = fopenb;         /* jgc dec 25th. 1985 */
  1236.         else kfopen = fopen;                    /* jgc dec 25th. 1985 */
  1237. }                                               /* jgc dec 25th. 1985 */
  1238. }                                               /* jgc dec
  1239. **** END OF FILE ***************************************************************
  1240.