home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / zip / gnu / gemlib27.lzh / GEMLIB27 / KERMIT.C < prev    next >
C/C++ Source or Header  |  1993-07-30  |  40KB  |  1,165 lines

  1. #define EXTRADEBUG
  2. /*
  3.  *  K e r m i t  File Transfer Utility seriously hacked for local use with uw
  4.  *
  5.  *  Currently allows only one kermit session to exist in one window concurent.
  6.  *
  7.  *  Adapted from UNIX Kermit, Columbia University, 1981, 1982, 1983
  8.  *      Bill Catchings, Bob Cattani, Chris Maio, Frank da Cruz, Alan Crosswell
  9.  *
  10.  *  Also:   Jim Guyton, Rand Corporation
  11.  *          Walter Underwood, Ford Aerospace
  12.  *
  13.  */
  14.  
  15. /*
  16.  * March 28, 1988
  17.  *        Hacked into form usable in uw.  Converted fsm's to be driven
  18.  *        by received packet events.  Rewrote rpack routine.
  19.  */
  20.  
  21. #ifdef __GNUC__
  22. #  include <gemfast.h>
  23. #  include <aesbind.h>
  24. #  include <vdibind.h>
  25. #else
  26. #  include <obdefs.h>
  27. #  include <gemdefs.h>
  28. #endif
  29. #include <osbind.h>
  30. #include <stdio.h>          /* Standard UNIX definitions */
  31. #include <time.h>
  32. #include "wind.h"
  33. #include "windefs.h"
  34.  
  35. #define error printmsg
  36. #define chari int        /* items of type chari should be char, but, mwc
  37.                  insists on adjusting them to int anyway */
  38. /* Symbol Definitions */
  39.  
  40. #define MAXPACKSIZ  94      /* Maximum packet size */
  41. #define SOH         1       /* Start of header */
  42. #define CR          13      /* ASCII Carriage Return */
  43. #define SP          32      /* ASCII space */
  44. #define DEL         127     /* Delete (rubout) */
  45.  
  46. #define MAXTRY      10      /* Times to retry a packet */
  47. #define MYQUOTE     '#'     /* Quote character I will use */
  48. #define MYPAD       0       /* Number of padding characters I will need */
  49. #define MYPCHAR     0       /* Padding character I need (NULL) */
  50.  
  51. #define MYEOL       '\r'    /* End-Of-Line character I need */
  52.  
  53. #define MYTIME      10      /* Seconds after which I should be timed out */
  54. #define MAXTIM      60      /* Maximum timeout interval */
  55. #define MINTIM      10      /* Minumum timeout interval */
  56.  
  57. #ifndef TRUE
  58. #define TRUE        -1      /* Boolean constants */
  59. #endif
  60. #define FALSE       0
  61. #define GETPACK     2        /* return constant */
  62.  
  63. /* Macro Definitions */
  64.  
  65. /*
  66.  *  f l u s h i n p u t
  67.  *
  68.  *  Dump all pending input to clear stacked up NACK's.
  69.  */
  70.  
  71. #define flushinput()    /* no explicit call to flush needed for uw */
  72.  
  73. /*
  74.  * tochar: converts a control character to a printable one by adding a space.
  75.  *
  76.  * unchar: undoes tochar.
  77.  *
  78.  * ctl:    converts between control characters and printable characters by
  79.  *         toggling the control bit (ie. ^A becomes A and A becomes ^A).
  80.  */
  81. #define tochar(ch)  ((ch) + ' ')
  82. #define unchar(ch)  ((ch) - ' ')
  83. #define ctl(ch)     ((ch) ^ 64 )
  84. #define abs(exp) (((exp) >= 0) ? (exp) : -(exp))
  85.  
  86.  
  87. /* Global Variables */
  88.  
  89. extern int    mouse;                /* is mouse visible ? */
  90. extern    struct    wi_str    w[];
  91.  
  92. int     size,               /* Size of present data */
  93.         rpsiz,              /* Maximum receive packet size */
  94.         spsiz,              /* Maximum send packet size */
  95.         pad,                /* How much padding to send */
  96.         reqtimint,          /* timeout interval I request */
  97.         timint,             /* Timeout for foreign host on sends */
  98.         n,                  /* Packet number */
  99.         numtry,             /* Times this packet retried */
  100.         oldtry,             /* Times previous packet retried */
  101.         image,              /* -1 means 8-bit mode */
  102.         debug,              /* indicates level of debugging output (0=none) */
  103.         filnamcnv,          /* -1 means do file name case conversions */
  104.         filecount,          /* Number of files left to send */
  105.     kermwdes,        /* Window descripter for kermit window */
  106.     kermport;        /* port number for kermit window */
  107.  
  108. clock_t    timestamp;        /* Time last packet was received */
  109.  
  110. char    sflg, rflg;         /* flags for RECEIVE, SEND */
  111. char    state,              /* Present state of the automaton */
  112.         padchar,            /* Padding character to send */
  113.         eol,                /* End-Of-Line character to send */
  114.         quote,              /* Quote character in incoming data */
  115.         **filelist,         /* List of files to be sent */
  116.     *filnam,            /* Current file name */
  117.         recpkt[MAXPACKSIZ+1], /* Receive packet buffer */
  118.         packet[MAXPACKSIZ+1]; /* Packet buffer */
  119.  
  120. FILE    *fp,                /* File pointer for current disk file */
  121.         *log;               /* File pointer for Logfile */
  122.  
  123.  
  124. /*
  125.  *  kerminit
  126.  *
  127.  *  initalization routine - initalize and dispatch to the appropriate routine.
  128.  */
  129.  
  130. int kerminit(curwin)
  131. int curwin;
  132. {
  133.     OBJECT *obj_tmp;
  134.     static char path[40] = ".\\*.*";
  135.     static char file[40] = "";
  136.     static char filename[80];        /* space for file and directory */
  137.     int butt;
  138.  
  139. /*  Initialize these values and hope the first packet will get across OK */
  140.  
  141.     if (kermwdes && w[kermwdes].kerm_act) return (-1);
  142.     kermwdes = curwin;
  143.                         /* If kermit already active, return. */
  144.     w[kermwdes].kerm_act = TRUE;    /* mark current window to send output
  145.                            to kermit instead of emulator */
  146.     kermport = find_port(curwin);
  147.     eol = CR;                           /* EOL for outgoing packets */
  148.     quote = '#';                        /* Standard control-quote char "#" */
  149.     pad = 0;                            /* No padding */
  150.     padchar = '\0';                     /* Use null if any padding wanted */
  151.     timint = MYTIME;                    /* default timint */
  152.  
  153.  
  154. /*
  155.  * Set direction and paramaters debug, filnamcnv, image with dialog
  156.  */
  157.     rsrc_gaddr(R_TREE, KERMPARM, &obj_tmp);
  158.     if (obj_tmp[ASCIIMOD].ob_state == NORMAL &&
  159.       obj_tmp[IMAGEMOD].ob_state == NORMAL)
  160.     {                    /* initalize object and statics */
  161.         objc_change(obj_tmp, ASCIIMOD, 0, 0, 0, 0, 0, SELECTED, 0);
  162.         objc_change(obj_tmp, CONVNAME, 0, 0, 0, 0, 0, SELECTED, 0);
  163.         objc_change(obj_tmp, RECFILE, 0, 0, 0, 0, 0, SELECTED, 0);
  164.  
  165.     path[0] = Dgetdrv() + 'a';
  166.     path[1] = ':';
  167.     Dgetpath(path+2, 0);
  168.     strcat(path, "\\*.*");
  169.     }
  170.     if ((butt = s_dial(KERMPARM, 3)) == KERMEXIT) return(kermterm());
  171.     if (obj_tmp[DEBUGENA].ob_state == SELECTED)
  172.     {
  173.         debug = obj_tmp[DEBUG1].ob_state + obj_tmp[DEBUG2].ob_state
  174.     + obj_tmp[DEBUG3].ob_state;
  175.     }
  176.     if (butt == RECFILE) obj_tmp[RECFILE].ob_state = SELECTED;
  177.     if (butt == SENDFILE) obj_tmp[SENDFILE].ob_state = SELECTED;
  178.     rflg = obj_tmp[RECFILE].ob_state;
  179.     sflg = obj_tmp[SENDFILE].ob_state;
  180.     image = (obj_tmp[IMAGEMOD].ob_state == SELECTED);
  181.     filnamcnv = obj_tmp[CONVNAME].ob_state; /* conversion for UNIX systems */
  182.     
  183. /* All set up, now execute the command that was given. */
  184.  
  185.     if (debug)
  186.     {
  187.         printmsg("debuging level = %d\n",debug);
  188.  
  189.         if (sflg) printmsg("Send command\n");
  190.         if (rflg) printmsg("Receive command\n");
  191.     }
  192.   
  193.     if (sflg)                           /* Send command */ 
  194.     {
  195.         extern char * rindex();
  196.  
  197.     if (!mouse)
  198.     {
  199.         graf_mouse(M_ON, NULL);
  200.         ++mouse;
  201.     }
  202.         fsel_input(path, file, &butt);
  203.     if (! butt) return(kermterm()); 
  204.     strcpy(filename, path);
  205.     if (debug > 2) printmsg("directory %s", filename);
  206.     filnam = rindex(filename, '\\');
  207.     if (filnam) *(++filnam) = '\0';
  208.     strcat(filename, file);
  209.         filnam = filename;        /* Get file to send */
  210.         if (debug > 2) printmsg("sending %s",filnam);
  211.         fp = NULL;                      /* Indicate no file open yet */
  212.         filelist = NULL;                /* Set up the rest of the file list */
  213.         filecount = 0;                  /* Number of files left to send */
  214.     state = 'S';                    /* Send initiate is the start state */
  215.     n = 0;                          /* Initialize message number */
  216.     numtry = 0;                     /* Say no tries yet */
  217.         w[kermwdes].kerm_act = TRUE;    /* mark current window to send output
  218.                            to kermit instead of emulator */
  219.     timestamp = clock();        /* reset timer */
  220.     sendsw();
  221.     }
  222.  
  223.     if (rflg)                           /* Receive command */
  224.     {
  225.     state = 'R';                    /* Receive-Init is the start state */
  226.     n = 0;                          /* Initialize message number */
  227.     numtry = 0;                     /* Say no tries yet */
  228.     timestamp = clock();        /* reset timer */
  229.     }
  230.     
  231.     return(0);
  232. }
  233.  
  234. /*
  235.  * kermterm - Terminate kermit and tell uw not to call us again.
  236.  */
  237. kermterm()
  238. {
  239.     sflg = rflg = 0;
  240.     w[kermwdes].kerm_act = FALSE;
  241.     kermwdes = 0;
  242. }
  243.  
  244. kermtimchk()
  245. {
  246.     if (!w[kermwdes].kerm_act)    /* is kermit active? */
  247.     {
  248.     kermwdes = 0;
  249.     return;
  250.     }
  251.     if ((clock() - timestamp) / CLK_TCK > timint)    /* timeout ? */
  252.     {
  253.     rpack(NULL, "", "");    /* tell FSM about time out */
  254.     }
  255. }
  256.  
  257. /*
  258.  *  s e n d s w
  259.  *
  260.  *  Sendsw is the state table switcher for sending files.  It loops until
  261.  *  either it finishes, or an error is encountered.  The routines called
  262.  *  by sendsw are responsible for changing the state.
  263.  *
  264.  */
  265.  
  266. int sendsw()
  267. {
  268.     chari sinit(), sfile(), sdata(), seof(), sbreak(), nstate;
  269.  
  270.     nstate = state;
  271.     while(TRUE)                         /* Do this as long as necessary */
  272.     {
  273.         if (debug) printmsg("sendsw state: %c  nstate: %c\n",state,nstate);
  274.     while (nstate != 'I')
  275.     {
  276.             switch(nstate)
  277.             {
  278.                 case 'S':   nstate = sinit();  break; /* Send-Init */
  279.                 case 'F':   nstate = sfile();  break; /* Send-File */
  280.                 case 'D':   nstate = sdata();  break; /* Send-Data */
  281.                 case 'Z':   nstate = seof();   break; /* Send-End-of-File */
  282.                 case 'B':   nstate = sbreak(); break; /* Send-Break */
  283.             }
  284.         switch(nstate)
  285.         {
  286.                 case 'C':   printmsg("\aDone.\a");
  287.                     return (TRUE);           /* Complete */
  288.                 case 'A':   printmsg("Send Failed.");
  289.                     return (FALSE);          /* "Abort" */
  290.         }
  291.         if (nstate != 'I')
  292.         {
  293.             state = nstate;
  294.             if (numtry++ > MAXTRY) return(FALSE); /* If too many tries, give up */
  295.         }
  296.     }
  297.     return(GETPACK);
  298.     }
  299. }
  300.  
  301.  
  302. /*
  303.  *  s i n i t
  304.  *
  305.  *  Send Initiate: send this host's parameters and get other side's back.
  306.  */
  307.  
  308. chari sinit()
  309. {
  310.     int num, len;                       /* Packet number, length */
  311.     static int sent = 0;
  312.  
  313.     if (! sent) {
  314.     reqtimint = MYTIME;
  315.     spar(packet);                   /* Fill up init info packet */
  316.     flushinput();                   /* Flush pending input */
  317.     spack('S',n,6,packet);          /* Send an S packet */
  318.  
  319.     sent = 1;
  320.     return('I');            /* get packet to read */
  321.     }
  322.     sent = 0;
  323.     switch(rpack(&len,&num,recpkt))     /* What was the reply? */
  324.     {
  325.         case 'N':  return(state);       /* NAK, try it again */
  326.  
  327.         case 'Y':                       /* ACK */
  328.             if (n != num)               /* If wrong ACK, stay in S state */
  329.                 return(state);          /* and try again */
  330.             rpar(recpkt);               /* Get other side's init info */
  331.  
  332.             if (eol == 0) eol = '\n';   /* Check and set defaults */
  333.             if (quote == 0) quote = '#';
  334.             if(abs(timint - reqtimint) < 3) timint = reqtimint + 3;
  335.             /* guarentee diference of > 3 for sounds for timint */
  336.  
  337.             numtry = 0;                 /* Reset try counter */
  338.             n = (n+1)%64;               /* Bump packet count */
  339.             return('F');                /* OK, switch state to F */
  340.  
  341.         case 'E':                       /* Error packet received */
  342.             prerrpkt(recpkt);           /* Print it out and */
  343.             return('A');                /* abort */
  344.  
  345.         case FALSE: return(state);      /* Receive failure, try again */
  346.  
  347.         default: return('A');           /* Anything else, just "abort" */
  348.    }
  349.  }
  350.  
  351.  
  352. /*
  353.  *  s f i l e
  354.  *
  355.  *  Send File Header.
  356.  */
  357.  
  358. chari sfile()
  359. {
  360.     int num, len;                       /* Packet number, length */
  361.     char filnam1[50],                   /* Converted file name */
  362.         *newfilnam,                     /* Pointer to file name to send */
  363.         *cp;                            /* char pointer */
  364.     static int sent = 0;
  365.  
  366.     if (! sent) {
  367.         if (fp == NULL)                     /* If not already open, */
  368.         {   if (debug) printmsg("   Opening %s for sending.\n",filnam);
  369.             fp = fopen(filnam, image ? "rb" : "r");         /* open the file to be sent */
  370.             if (fp == NULL)                 /* If bad file pointer, give up */
  371.             {
  372.                 error("Cannot open file %s",filnam);
  373.                 return('A');
  374.             }
  375.         }
  376.  
  377.         strcpy(filnam1, filnam);            /* Copy file name */
  378.         newfilnam = cp = filnam1;
  379.         while (*cp != '\0')                 /* Strip off all leading directory */
  380.             if (*cp++ == '\\')               /* names (ie. up to the last /). */
  381.                 newfilnam = cp;
  382.  
  383.         if (filnamcnv)                      /* Convert lower case to upper  */
  384.             for (cp = newfilnam; *cp != '\0'; cp++)
  385.                 if (*cp >= 'a' && *cp <= 'z')
  386.                     *cp ^= 040;
  387.  
  388.         len = cp - newfilnam;               /* Compute length of new filename */
  389.  
  390.         printmsg("Sending %s as %s",filnam,newfilnam);
  391.  
  392.         spack('F',n,len,newfilnam);         /* Send an F packet */
  393.     sent = 1;
  394.     
  395.     return('I');            /* get packet to read */
  396.     }
  397.     sent = 0;
  398.     switch(rpack(&len,&num,recpkt))     /* What was the reply? */
  399.     {                   
  400.         case 'N':                       /* NAK, just stay in this state, */
  401.             num = (--num<0 ? 63:num);   /* unless it's NAK for next packet */
  402.             if (n != num)               /* which is just like an ACK for */ 
  403.                 return(state);          /* this packet so fall thru to... */
  404.  
  405.         case 'Y':                       /* ACK */
  406.             if (n != num) return(state); /* If wrong ACK, stay in F state */
  407.             numtry = 0;                 /* Reset try counter */
  408.             n = (n+1)%64;               /* Bump packet count */
  409.             size = bufill(packet);      /* Get first data from file */
  410.             return('D');                /* Switch state to D */
  411.  
  412.         case 'E':                       /* Error packet received */
  413.             prerrpkt(recpkt);           /* Print it out and */
  414.             return('A');                /* abort */
  415.  
  416.         case FALSE: return(state);      /* Receive failure, stay in F state */
  417.  
  418.         default:    return('A');        /* Something else, just "abort" */
  419.     }
  420. }
  421.  
  422.  
  423. /*
  424.  *  s d a t a
  425.  *
  426.  *  Send File Data
  427.  */
  428.  
  429. chari sdata()
  430. {
  431.     int num, len;                       /* Packet number, length */
  432.     static int sent = 0;
  433.  
  434.     if (! sent) {
  435.         spack('D',n,size,packet);           /* Send a D packet */
  436.     sent = 1;
  437.     return('I');            /* get packet to read */
  438.     }
  439.     sent = 0;
  440.     switch(rpack(&len,&num,recpkt))     /* What was the reply? */
  441.     {               
  442.         case 'N':                       /* NAK, just stay in this state, */
  443.             num = (--num<0 ? 63:num);   /* unless it's NAK for next packet */
  444.             if (n != num)               /* which is just like an ACK for */
  445.                 return(state);          /* this packet so fall thru to... */
  446.                 
  447.         case 'Y':                       /* ACK */
  448.             if (n != num) return(state); /* If wrong ACK, fail */
  449.             numtry = 0;                 /* Reset try counter */
  450.             n = (n+1)%64;               /* Bump packet count */
  451.             if ((size = bufill(packet)) == EOF) /* Get data from file */
  452.                 return('Z');            /* If EOF set state to that */
  453.             return('D');                /* Got data, stay in state D */
  454.  
  455.         case 'E':                       /* Error packet received */
  456.             prerrpkt(recpkt);           /* Print it out and */
  457.             return('A');                /* abort */
  458.  
  459.         case FALSE: return(state);      /* Receive failure, stay in D */
  460.  
  461.         default:    return('A');        /* Anything else, "abort" */
  462.     }
  463. }
  464.  
  465.  
  466. /*
  467.  *  s e o f
  468.  *
  469.  *  Send End-Of-File.
  470.  */
  471.  
  472. chari seof()
  473. {
  474.     int num, len;                       /* Packet number, length */
  475.     static int sent = 0;
  476.  
  477.     if (! sent) {
  478.         spack('Z',n,0,packet);              /* Send a 'Z' packet */
  479.  
  480.     sent = 1;
  481.     return('I');            /* get packet to read */
  482.     }
  483.     sent = 0;
  484.     switch(rpack(&len,&num,recpkt))     /* What was the reply? */
  485.     {
  486.         case 'N':                       /* NAK, just stay in this state, */
  487.             num = (--num<0 ? 63:num);   /* unless it's NAK for next packet, */
  488.             if (n != num)               /* which is just like an ACK for */
  489.                 return(state);          /* this packet so fall thru to... */
  490.  
  491.         case 'Y':                       /* ACK */
  492.             if (n != num) return(state); /* If wrong ACK, hold out */
  493.             numtry = 0;                 /* Reset try counter */
  494.             n = (n+1)%64;               /* and bump packet count */
  495.             if (debug) printmsg("   Closing input file %s, ",filnam);
  496.             fclose(fp);                 /* Close the input file */
  497.             fp = NULL;                  /* Set flag indicating no file open */ 
  498.  
  499.             if (debug) printmsg("looking for next file...\n");
  500.             if (gnxtfl() == FALSE)      /* No more files go? */
  501.                 return('B');            /* if not, break, EOT, all done */
  502.             if (debug) printmsg("   New file is %s\n",filnam);
  503.             return('F');                /* More files, switch state to F */
  504.  
  505.         case 'E':                       /* Error packet received */
  506.             prerrpkt(recpkt);           /* Print it out and */
  507.             return('A');                /* abort */
  508.  
  509.         case FALSE: return(state);      /* Receive failure, stay in Z */
  510.  
  511.         default:    return('A');        /* Something else, "abort" */
  512.     }
  513. }
  514.  
  515.  
  516. /*
  517.  *  s b r e a k
  518.  *
  519.  *  Send Break (EOT)
  520.  */
  521.  
  522. chari sbreak()
  523. {
  524.     int num, len;                       /* Packet number, length */
  525.     static int sent = 0;
  526.  
  527.     if (! sent) {
  528.         spack('B',n,0,packet);              /* Send a B packet */
  529.  
  530.     sent = 1;
  531.     return('I');            /* get packet to read */
  532.     }
  533.     sent = 0;
  534.     switch (rpack(&len,&num,recpkt))    /* What was the reply? */
  535.     {
  536.         case 'N':                       /* NAK, just stay in this state, */
  537.             num = (--num<0 ? 63:num);   /* unless NAK for previous packet, */
  538.             if (n != num)               /* which is just like an ACK for */
  539.                 return(state);          /* this packet so fall thru to... */
  540.  
  541.         case 'Y':                       /* ACK */
  542.             if (n != num) return(state); /* If wrong ACK, fail */
  543.             numtry = 0;                 /* Reset try counter */
  544.             n = (n+1)%64;               /* and bump packet count */
  545.             return('C');                /* Switch state to Complete */
  546.  
  547.         case 'E':                       /* Error packet received */
  548.             prerrpkt(recpkt);           /* Print it out and */
  549.             return('A');                /* abort */
  550.  
  551.         case FALSE: return(state);      /* Receive failure, stay in B */
  552.  
  553.         default:    return ('A');       /* Other, "abort" */
  554.    }
  555. }
  556.  
  557.  
  558. /*
  559.  *  r e c s w
  560.  *
  561.  *  This is the state table switcher for receiving files.
  562.  */
  563.  
  564.  
  565.  
  566.  
  567. recsw()
  568. {
  569.     chari rinit(), rfile(), rdata();     /* Use these procedures */
  570.  
  571.     if (debug) printmsg(" recsw state: %c\n",state);
  572.     switch(state)                   /* Do until done */
  573.     {
  574.         case 'R':   state = rinit(); break; /* Receive-Init */
  575.         case 'F':   state = rfile(); break; /* Receive-File */
  576.         case 'D':   state = rdata(); break; /* Receive-Data */
  577.     }
  578.     if (numtry++ > MAXTRY) return(FALSE); /* If too many tries, give up */
  579.     switch(state)                   /* Do until done */
  580.     {
  581.         case 'C':   printmsg("\aDone.\a");
  582.             return(TRUE);           /* Complete state */
  583.         case 'A':   printmsg("Receive Failed.");
  584.             return(FALSE);          /* "Abort" state */
  585.     }
  586.     return(GETPACK);                /* get the next packet */
  587. }
  588.  
  589.     
  590. /*
  591.  *  r i n i t
  592.  *
  593.  *  Receive Initialization
  594.  */
  595.   
  596. chari rinit()
  597. {
  598.     int len, num;                       /* Packet length, number */
  599.  
  600.     switch(rpack(&len,&num,packet))     /* Get a packet */
  601.     {
  602.         case 'S':                       /* Send-Init */
  603.             rpar(packet);               /* Get the other side's init data */
  604.             if (timint > MYTIME + 3) reqtimint = timint - 4;
  605.             else reqtimint = timint + 4;
  606.             spar(packet);               /* Fill up packet with my init info */
  607.             flushinput();               /* get rid of unwanted nak's */
  608.             spack('Y',n,6,packet);      /* ACK with my parameters */
  609.             oldtry = numtry;            /* Save old try count */
  610.             numtry = 0;                 /* Start a new counter */
  611.             n = (n+1)%64;               /* Bump packet number, mod 64 */
  612.             return('F');                /* Enter File-Receive state */
  613.  
  614.         case 'E':                       /* Error packet received */
  615.             prerrpkt(recpkt);           /* Print it out and */
  616.             return('A');                /* abort */
  617.  
  618.         case FALSE:                     /* Didn't get packet */
  619.             spack('N',n,0,NULL);        /* Return a NAK */
  620.             return(state);              /* Keep trying */
  621.  
  622.         default:     return('A');       /* Some other packet type, "abort" */
  623.     }
  624. }
  625.  
  626.  
  627. /*
  628.  *  r f i l e
  629.  *
  630.  *  Receive File Header
  631.  */
  632.  
  633. chari rfile()
  634. {
  635.     int num, len;                       /* Packet number, length */
  636.     char filnam1[50];                   /* Holds the converted file name */
  637.  
  638.     switch(rpack(&len,&num,packet))     /* Get a packet */
  639.     {
  640.         case 'S':                       /* Send-Init, maybe our ACK lost */
  641.             if (oldtry++ > MAXTRY) return('A'); /* If too many tries "abort" */
  642.             if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
  643.             {                           /* Yes, ACK it again with  */
  644.                 spar(packet);           /* our Send-Init parameters */
  645.                 spack('Y',num,6,packet);
  646.                 numtry = 0;             /* Reset try counter */
  647.                 return(state);          /* Stay in this state */
  648.             }
  649.             else return('A');           /* Not previous packet, "abort" */
  650.  
  651.         case 'Z':                       /* End-Of-File */
  652.             if (oldtry++ > MAXTRY) return('A');
  653.             if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
  654.             {                           /* Yes, ACK it again. */
  655.                 spack('Y',num,0,NULL);
  656.                 numtry = 0;
  657.                 return(state);          /* Stay in this state */
  658.             }
  659.             else return('A');           /* Not previous packet, "abort" */
  660.  
  661.         case 'F':                       /* File Header (just what we want) */
  662.             if (num != n) return('A');  /* The packet number must be right */
  663.             strcpy(filnam1, packet);    /* Copy the file name */
  664.  
  665.             if (filnamcnv)              /* Convert upper case to lower */
  666.                 for (filnam=filnam1; *filnam != '\0'; filnam++)
  667.                     if (*filnam >= 'A' && *filnam <= 'Z')
  668.                         *filnam |= 040;
  669.  
  670.             if ((fp=fopen(filnam1, image ? "wb" : "w"))==NULL) /* Try to open a new file */
  671.             {
  672.                 error("Cannot create %s",filnam1); /* Give up if can't */
  673.                 return('A');
  674.             }
  675.             else                        /* OK, give message */
  676.  
  677.                 printmsg("Receiving %s as %s",packet,filnam1);
  678.  
  679.             spack('Y',n,0,NULL);        /* Acknowledge the file header */
  680.             oldtry = numtry;            /* Reset try counters */
  681.             numtry = 0;                 /* ... */
  682.             n = (n+1)%64;               /* Bump packet number, mod 64 */
  683.             return('D');                /* Switch to Data state */
  684.  
  685.         case 'B':                       /* Break transmission (EOT) */
  686.             if (num != n) return ('A'); /* Need right packet number here */
  687.             spack('Y',n,0,NULL);        /* Say OK */
  688.             return('C');                /* Go to complete state */
  689.  
  690.         case 'E':                       /* Error packet received */
  691.             prerrpkt(recpkt);           /* Print it out and */
  692.             return('A');                /* abort */
  693.  
  694.         case FALSE:                     /* Didn't get packet */
  695.             spack('N',n,0,NULL);        /* Return a NAK */
  696.             return(state);              /* Keep trying */
  697.  
  698.         default:    return ('A');       /* Some other packet, "abort" */
  699.     }
  700. }
  701.  
  702.  
  703. /*
  704.  *  r d a t a
  705.  *
  706.  *  Receive Data
  707.  */
  708.  
  709. chari rdata()
  710. {
  711.     int num, len;                       /* Packet number, length */
  712.  
  713.     switch(rpack(&len,&num,packet))     /* Get packet */
  714.     {
  715.         case 'D':                       /* Got Data packet */
  716. #ifdef EXTRADEBUG
  717.         if (debug > 2) printmsg("Got Data Packet");
  718. #endif
  719.             if (num != n)               /* Right packet? */
  720.             {                           /* No */
  721.                 if (oldtry++ > MAXTRY)
  722.                     return('A');        /* If too many tries, abort */
  723.                 if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
  724.                 {                       /* Previous packet again? */
  725.                     spack('Y',num,6,packet); /* Yes, re-ACK it */
  726.                     numtry = 0;         /* Reset try counter */
  727.                     return(state);      /* Don't write out data! */
  728.                 }
  729.                 else return('A');       /* sorry, wrong number */
  730.             }
  731.             /* Got data with right packet number */
  732.             spack('Y',n,0,NULL);        /* Acknowledge the packet */
  733. #ifdef EXTRADEBUG
  734.         if (debug > 2) printmsg("Calling bufemp");
  735. #endif
  736.             bufemp(packet,len);         /* Write the data to the file */
  737.             oldtry = numtry;            /* Reset the try counters */
  738.             numtry = 0;                 /* ... */
  739.             n = (n+1)%64;               /* Bump packet number, mod 64 */
  740.             return('D');                /* Remain in data state */
  741.  
  742.         case 'F':                       /* Got a File Header */
  743.             if (oldtry++ > MAXTRY)
  744.                 return('A');            /* If too many tries, "abort" */
  745.             if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
  746.             {                           /* It was the previous one */
  747.                 spack('Y',num,0,NULL);  /* ACK it again */
  748.                 numtry = 0;             /* Reset try counter */
  749.                 return(state);          /* Stay in Data state */
  750.             }
  751.             else return('A');           /* Not previous packet, "abort" */
  752.  
  753.         case 'Z':                       /* End-Of-File */
  754.             if (num != n) return('A');  /* Must have right packet number */
  755.             spack('Y',n,0,NULL);        /* OK, ACK it. */
  756.             fclose(fp);                 /* Close the file */
  757.             n = (n+1)%64;               /* Bump packet number */
  758.             return('F');                /* Go back to Receive File state */
  759.  
  760.         case 'E':                       /* Error packet received */
  761.             prerrpkt(recpkt);           /* Print it out and */
  762.             return('A');                /* abort */
  763.  
  764.         case FALSE:                     /* Didn't get packet */
  765.             spack('N',n,0,NULL);        /* Return a NAK */
  766.             return(state);              /* Keep trying */
  767.  
  768.         default:     return('A');       /* Some other packet, "abort" */
  769.     }
  770. }
  771.  
  772.  
  773. /*
  774.  *      KERMIT utilities.
  775.  */
  776.  
  777.  
  778. /*
  779.  *  s p a c k
  780.  *
  781.  *  Send a Packet
  782.  */
  783.  
  784. spack(type,num,len,data)
  785. chari type;
  786. char  *data;
  787. int num, len;
  788. {
  789.     int i;                              /* Character loop counter */
  790.     char chksum, buffer[100];           /* Checksum, packet buffer */
  791.     register char *bufp;                /* Buffer pointer */
  792.  
  793.     if (debug>1)                        /* Display outgoing packet */
  794.     {
  795.         printmsg("  spack type: %c\n",type);
  796.         printmsg("         num:  %d\n",num);
  797.         printmsg("         len:  %d\n",len);
  798.         if (data != NULL)
  799.     {
  800.             data[len] = '\0';           /* Null-terminate data to print it */
  801.             printmsg("        data: \"%s\"\n",data);
  802.     }
  803.     }
  804.   
  805.     bufp = buffer;                      /* Set up buffer pointer */
  806.     for (i=1; i<=pad; i++) proto_out(kermport,&padchar,1); /* Issue any padding */
  807.  
  808.     *bufp++ = SOH;                      /* Packet marker, ASCII 1 (SOH) */
  809.     *bufp++ = tochar(len+3);            /* Send the character count */
  810.     chksum  = tochar(len+3);            /* Initialize the checksum */
  811.     *bufp++ = tochar(num);              /* Packet number */
  812.     chksum += tochar(num);              /* Update checksum */
  813.     *bufp++ = type;                     /* Packet type */
  814.     chksum += type;                     /* Update checksum */
  815.  
  816.     for (i=0; i<len; i++)               /* Loop for all data characters */
  817.     {
  818.         *bufp++ = data[i];              /* Get a character */
  819.         chksum += data[i];              /* Update checksum */
  820.     }
  821.     chksum = (((chksum&0300) >> 6)+chksum)&077; /* Compute final checksum */
  822.     *bufp++ = tochar(chksum);           /* Put it in the packet */
  823.     *bufp = eol;                        /* Extra-packet line terminator */
  824.     proto_out(kermport, buffer, bufp-buffer+1);
  825.                         /* Send the packet */
  826. #ifdef EXTRADEBUG
  827.     if (debug > 2) printmsg("Returning from spack");
  828. #endif
  829. }
  830.  
  831. /*
  832.  *  r p a c k
  833.  *
  834.  *  Read a Packet
  835.  *  This routine is called both to buffer data from the host to the kermit
  836.  *  window and to retreive those buffers once they contain a packet.  This
  837.  *  routine calls the kermit state machine when it has a complete packet.
  838.  *  The kermit state machine in turn calls this routine to retreive the packet.
  839.  *  Thus, this routine is indirectly recursive to two levels.  Receive timeouts
  840.  *  and bad packets cause FALSE to be returned to the state machine.  The uw
  841.  *  control loop calls us with num == NULL to pass us a string of data from
  842.  *  the host.  The uw control loop calls us with len == NULL if the timout
  843.  *  counter (kerm_time) exceeds timint without us reseting it.
  844.  */
  845. #ifdef EXTRADEBUG
  846. #define getnext {t = *dptr++; \
  847.             if (debug>2) printmsg( "char %d state %c", t, recstate);\
  848.         if ((t & 0177) == SOH) { \
  849.             recstate = 'L'; /* restart packet collection */\
  850.             break; } \
  851.         if (!image) t &= 0177;    /* Handle parity */ \
  852.         if (t == 0) break; /* end of this input buffer */ }
  853. #else
  854. #define getnext {t = *dptr++; \
  855.         if ((t & 0177) == SOH) { \
  856.             recstate = 'L'; /* restart packet collection */\
  857.             break; } \
  858.         if (!image) t &= 0177;    /* Handle parity */ \
  859.         if (t == 0) break; /* end of this input buffer */ }
  860. #endif
  861. rpack(len,num,data)
  862. int *len, *num;                         /* Packet length, number */
  863. char *data;                             /* Packet data */
  864. {
  865.     static int i;                       /* Data character number */
  866.     static int leng;            /* length of data packet in buffer */
  867.     static char type;            /* packet type */
  868.     static int numb;            /* number of data packet in buffer */
  869.     static int timedout = 0;        /* did we time out? */
  870.     char t;                             /* Current input character */
  871.     static char cchksum,                        /* Our (computed) checksum */
  872.         rchksum;                        /* Checksum received from other host */
  873.     char *dptr;                /* pointer to next data byte */
  874.     static char mybuf[MAXPACKSIZ];    /* buffer used to acumulate packet */
  875.     static char recstate = 'S';        /* start with S state */
  876.  
  877.     if (len == NULL) {    /* timed out */
  878.         timedout = TRUE;
  879.     if (sflg)
  880.     {
  881.         if (sendsw() != GETPACK)    /* Send the file(s) */
  882.                 return(kermterm());
  883.     }
  884.     else if (rflg)
  885.     {
  886.             if (recsw() != GETPACK)     /* Receive the file(s) */
  887.                 return(kermterm());
  888.     }
  889.         return (0);
  890.     }
  891.     if (len != NULL && num != NULL)    /* received packet or timed out */
  892.     {
  893.     *len = leng;
  894.     *num = numb;
  895.     timestamp = clock();        /* reset timer */
  896.     if (timedout)
  897.     {
  898.         printmsg("Timeout.");
  899.         timedout = 0;
  900.         return(FALSE);
  901.     }
  902.     for (i=0; i<leng; i++)
  903.         data[i] = mybuf[i];
  904.         if (data != NULL)
  905.             data[*len] = '\0';          /* Null-terminate data to print it */
  906.         if (debug>1)                    /* Display incoming packet */
  907.         {
  908.             printmsg("  rpack type: %c\n",type);
  909.             printmsg("         num:  %d\n",*num);
  910.             printmsg("         len:  %d\n",*len);
  911.             if (data != NULL)
  912.                 printmsg("        data: \"%s\"\n",data);
  913.         }
  914.                                         /* Fold in bits 7,8 to compute */
  915.         cchksum = (((cchksum&0300) >> 6)+cchksum)&077; /* final checksum */
  916.  
  917.         if (cchksum != rchksum) return(FALSE);
  918.  
  919.         return(type);                       /* All OK, return packet type */
  920.     }
  921.     /* num == NULL so collect data for kermit */
  922.     dptr = data;
  923.     t = -1;
  924.     while (t)
  925.     {
  926.       switch(recstate)
  927.       {
  928.         case 'S':
  929.         while (1)            /* Wait for packet header */
  930.             getnext;
  931.         break;
  932.     case 'L':            /* get packet length */
  933.             getnext;            /* get next character */
  934.             cchksum = t;                    /* Start the checksum */
  935.             leng = unchar(t)-3;             /* Character count */
  936.         if (leng > MAXPACKSIZ)
  937.             leng = MAXPACKSIZ;
  938.         i = 0;
  939.         recstate = 'N';
  940.         /* Fall Through */
  941.  
  942.     case 'N':                /* get packet number */
  943.             getnext
  944.             cchksum = cchksum + t;          /* Update checksum */
  945.             numb = unchar(t);               /* Packet number */
  946.         recstate = 'T';
  947.         /* Fall Through */
  948.  
  949.     case 'T':                /* get packet type */
  950.             getnext;
  951.             cchksum = cchksum + t;          /* Update checksum */
  952.             type = t;                       /* Packet type */
  953.         recstate = 'D';
  954.         /* Fall Through */
  955.  
  956.     case 'D':                /* get packet data */
  957.             for (; i<leng; i++)             /* The data itself, if any */
  958.             {                               /* Loop for character count */
  959.                 getnext;
  960.                 cchksum = cchksum + t;      /* Update checksum */
  961.                 mybuf[i] = t;                /* Put it in the data buffer */
  962.             }
  963.         if (i == leng) 
  964.             recstate = 'C';
  965.         break;
  966.  
  967.     case 'C':
  968.             mybuf[leng] = 0;                 /* Mark the end of the data */
  969.             getnext;
  970.             rchksum = unchar(t);            /* Convert to numeric */
  971.         recstate = 'E';            /* Done with packet receipt */
  972.         t = 0;                /* Dispose of remaining data */
  973.       }
  974.     }
  975.     if (recstate == 'E') {
  976.         recstate = 'S';
  977.     if (sflg)
  978.     {
  979.         if (sendsw() != GETPACK)        /* Send the file(s) */
  980.                 return(kermterm());
  981.     }
  982.     else if (rflg)
  983.     {
  984.             if (recsw() != GETPACK)         /* Receive the file(s) */
  985.                 return(kermterm());
  986.     }
  987.     }
  988.     return(0);
  989. }
  990.  
  991.  
  992. /*
  993.  *  b u f i l l
  994.  *
  995.  *  Get a bufferful of data from the file that's being sent.
  996.  *  Only control-quoting is done; 8-bit & repeat count prefixes are
  997.  *  not handled.
  998.  */
  999.  
  1000. bufill(buffer)
  1001. char buffer[];                          /* Buffer */
  1002. {
  1003.     int i,                              /* Loop index */
  1004.         t;                              /* Char read from file */
  1005.     char t7;                            /* 7-bit version of above */
  1006.  
  1007.     i = 0;                              /* Init data buffer pointer */
  1008.     while((t = getc(fp)) != EOF)        /* Get the next character */
  1009.     {
  1010.         t7 = t & 0177;                  /* Get low order 7 bits */
  1011.  
  1012.         if (t7 < SP || t7==DEL || t7==quote) /* Does this char require */
  1013.         {                                   /* special handling? */
  1014.             if (t=='\n' && !image)
  1015.             {                           /* Do LF->CRLF mapping if !image */
  1016.                 buffer[i++] = quote;
  1017.                 buffer[i++] = ctl('\r');
  1018.             }
  1019.             buffer[i++] = quote;        /* Quote the character */
  1020.             if (t7 != quote)
  1021.             {
  1022.                 t = ctl(t);             /* and uncontrolify */
  1023.                 t7 = ctl(t7);
  1024.             }
  1025.         }
  1026.         if (image)
  1027.             buffer[i++] = t;            /* Deposit the character itself */
  1028.         else
  1029.             buffer[i++] = t7;
  1030.  
  1031.         if (i >= spsiz-8) return(i);    /* Check length */
  1032.     }
  1033.     if (i==0) return(EOF);              /* Wind up here only on EOF */
  1034.     return(i);                          /* Handle partial buffer */
  1035. }
  1036.  
  1037.  
  1038. /*
  1039.  *      b u f e m p
  1040.  *
  1041.  *  Put data from an incoming packet into a file.
  1042.  */
  1043.  
  1044. bufemp(buffer,len)
  1045. char  buffer[];                         /* Buffer */
  1046. int   len;                              /* Length */
  1047. {
  1048.     int i;                              /* Counter */
  1049.     char t;                             /* Character holder */
  1050.  
  1051. #ifdef EXTRADEBUG
  1052.         if (debug > 2) printmsg("Entered bufemp");
  1053. #endif
  1054.     for (i=0; i<len; i++)               /* Loop thru the data field */
  1055.     {
  1056.         t = buffer[i];                  /* Get character */
  1057.         if (t == MYQUOTE)               /* Control quote? */
  1058.         {                               /* Yes */
  1059.             t = buffer[++i];            /* Get the quoted character */
  1060.             if ((t & 0177) != MYQUOTE)  /* Low order bits match quote char? */
  1061.                 t = ctl(t);             /* No, uncontrollify it */
  1062.         }
  1063.         if (t==CR && !image)            /* Don't pass CR if not in image mode */
  1064.             continue;
  1065. #ifdef EXTRADEBUG
  1066.         if (debug > 2) printmsg("writing t=%c", t);
  1067. #endif
  1068.         putc(t,fp);
  1069.     }
  1070. }
  1071.  
  1072.  
  1073.  
  1074. /*
  1075.  *  g n x t f l
  1076.  *
  1077.  *  Get next file in a file group
  1078.  */
  1079.  
  1080. gnxtfl()
  1081. {
  1082.     if (filecount-- == 0) return FALSE; /* If no more, fail */
  1083.     if (debug) printmsg("   gnxtfl: filelist = \"%s\"\n",*filelist);
  1084.     filnam = *(filelist++);
  1085.     return TRUE;                   /* else succeed */
  1086. }
  1087.  
  1088.  
  1089. /*
  1090.  *  s p a r
  1091.  *
  1092.  *  Fill the data array with my send-init parameters
  1093.  *
  1094.  */
  1095.  
  1096. spar(data)
  1097. char data[];
  1098. {
  1099.     data[0] = tochar(MAXPACKSIZ);          /* Biggest packet I can receive */
  1100.     data[1] = tochar(reqtimint);           /* When I want to be timed out */
  1101.     data[2] = tochar(MYPAD);            /* How much padding I need */
  1102.     data[3] = ctl(MYPCHAR);             /* Padding character I want */
  1103.     data[4] = tochar(MYEOL);            /* End-Of-Line character I want */
  1104.     data[5] = MYQUOTE;                  /* Control-Quote character I send */
  1105. }
  1106.  
  1107.  
  1108. /*  r p a r
  1109.  *
  1110.  *  Get the other host's send-init parameters
  1111.  *
  1112.  */
  1113.  
  1114. rpar(data)
  1115. char data[];
  1116. {
  1117.     spsiz = unchar(data[0]);            /* Maximum send packet size */
  1118.     timint = unchar(data[1]);           /* When I should time out */
  1119.     if (timint > MAXTIM) timint = MAXTIM;
  1120.     if (timint < MINTIM) timint = MINTIM;
  1121.     pad = unchar(data[2]);              /* Number of pads to send */
  1122.     padchar = ctl(data[3]);             /* Padding character to send */
  1123.     eol = unchar(data[4]);              /* EOL character I must send */
  1124.     quote = data[5];                    /* Incoming data quote character */
  1125. }
  1126.  
  1127.  
  1128. /*
  1129.  *  Kermit printing routines:
  1130.  *
  1131.  *  printmsg -  like printf with "Kermit: " prepended
  1132.  *  prerrpkt - print contents of error packet received from remote host
  1133.  */
  1134.  
  1135.  
  1136. /*
  1137.  *  p r i n t m s g
  1138.  *
  1139.  *  Print message kermit window
  1140.  */
  1141.  
  1142. /*VARARGS1*/
  1143. printmsg(fmt, a1, a2, a3, a4, a5)
  1144. char *fmt;
  1145. {
  1146.     char *sbuf[100];
  1147.         w_output(kermwdes,"Kermit: ");
  1148.         sprintf(sbuf,fmt,a1,a2,a3,a4,a5);
  1149.         w_output(kermwdes,sbuf);
  1150.         w_output(kermwdes,"\n\r");
  1151. }
  1152.  
  1153.  
  1154. /*
  1155.  *  p r e r r p k t
  1156.  *
  1157.  *  Print contents of error packet received from remote host.
  1158.  */
  1159. prerrpkt(msg)
  1160. char *msg;
  1161. {
  1162.     printmsg("Kermit aborting with following error from remote host:\n%s",msg);
  1163.     return;
  1164. }
  1165.