home *** CD-ROM | disk | FTP | other *** search
/ kermit.columbia.edu / kermit.columbia.edu.tar / kermit.columbia.edu / uman1000 / umkerm.c < prev    next >
C/C++ Source or Header  |  1986-04-09  |  43KB  |  1,177 lines

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