home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_200 / 203_01 / yam2.c < prev    next >
Text File  |  1979-12-31  |  17KB  |  732 lines

  1. /*
  2. $title ('yam2.c: file transmission protocol handlers')
  3. $date (4 nov 85)
  4. */
  5. /*
  6.  * Ward Christensen Protocol handler for sending and receiving
  7.  * ascii and binary files.  Modified for choice of checksum or crc.
  8.  */
  9.  
  10. #include "yam.h"
  11. #define WCEOT (-10)
  12.  
  13. #ifdef DEFBYTL
  14. long Modtime;        /* Unix style mod time for incoming file */
  15. int Filemode;        /* Unix style mode for incoming file */
  16. #endif
  17.  
  18. /****************************************************************************
  19. FUNCTION:
  20.     Ward Christensen modem 7 protocol file tranmission handler
  21.  
  22. CALLING PARAMETERS:
  23.     argc:
  24.         count of command line arguments.
  25.     argp:
  26.         pointer to string of command line arguments.
  27. ===========================================================================*/
  28. wcsend(argc, argp)
  29. char **argp;
  30. {
  31.     int wcs();
  32.  
  33. #ifdef IBMPC
  34.         /* enbable raw mode */
  35.     enblcm(FALSE);
  36. #endif
  37.  
  38.     Crcflg=FALSE;
  39.     firstsec=TRUE;
  40.  
  41.     if (Batch)
  42.     {
  43.         printf("Sending in Batch Mode\n");
  44.  
  45.             /* send files, batch mode */
  46.         if (expand(wcs, argc, argp)==ERROR)
  47.             goto fubar;
  48.             /* transmit null path name for end of data */
  49.         if (wctxpn("")==ERROR)
  50.             goto fubar;
  51.     }
  52.         /* send file, not batch mode */
  53.     else
  54.     {
  55.         for (; --argc>=0;)
  56.         {
  57.                 /* open file to transmit. open will compute file size */
  58.             if (opentx(1,NULL,*argp++)==ERROR)
  59.                 goto fubar;
  60.                 /* Ward Christensen transmit */
  61.             if (wctx()==ERROR)
  62.                 goto fubar;
  63.         }
  64.     }
  65.     return OK;
  66.  
  67.     /* error, close files and send CAN to other end */
  68. fubar:
  69.     closetx(TRUE);
  70.     canit();
  71.     return ERROR;
  72. } /* wcsend */
  73.  
  74.  
  75. /****************************************************************************
  76. FUNCTION:
  77.     Ward Christensen modem 7 protocol file transmission handler, batch
  78.     mode.
  79.  
  80. CALLING PARAMETERS:
  81.     f_buf:
  82.         pointer to a structure containing information about file
  83.     *pathname:
  84.         pointer to directory path name
  85. ===========================================================================*/
  86. wcs(f_buf,pathname)
  87. struct find_buf *f_buf;
  88. char *pathname;
  89. {
  90.  
  91.         /* open file, open uses f_buf for file size */
  92.     if (opentx(2,f_buf,pathname)==ERROR)
  93.         return OK;        /* skip over inaccessible files */
  94.     if (wctxpn(f_buf->pname)== ERROR)
  95.         return ERROR;
  96.     if (wctx()==ERROR)
  97.         return ERROR;
  98.     printf("\n");
  99.     return OK;
  100. } /* wcs */
  101.  
  102.  
  103. /****************************************************************************
  104. FUNCTION:
  105.     Ward Christensen modem 7 protocol file reception handler
  106.  
  107. CALLING PARAMETERS:
  108.     argc:
  109.         count of command line arguments.
  110.     argp:
  111.         pointer to string of command line arguments.
  112. ===========================================================================*/
  113. wcreceive(argc, argp)
  114. char **argp;
  115. {
  116.     int baslen;
  117.  
  118. #ifdef IBMPC
  119.         /* enbable raw mode */
  120.     enblcm(FALSE);
  121. #endif
  122.  
  123.     if (Batch)
  124.     {
  125.         printf("Receiving in Batch Mode\n");
  126.         for (;;)
  127.         {
  128.                 /* create the basename of pathname if one was specified */
  129.             if (argc > 0)
  130.             {
  131.                 strcpy(Utility.ubuf,*argp);
  132.                 baslen=strlen(Utility.ubuf);
  133.             }
  134.             else
  135.                 baslen = 0;
  136.  
  137.                 /* get file name for batch mode */
  138.             if (wcrxpn(&Utility.ubuf[baslen])== ERROR)
  139.                 goto fubar;
  140.             if (Utility.ubuf[baslen]==0)
  141.                 return OK;
  142.  
  143. #ifdef DEFBYTL
  144.             procheader(Utility.ubuf);
  145. #endif
  146.                 /* receive file */
  147.             if (wcrx(Utility.ubuf)==ERROR)
  148.                 goto fubar;
  149.         }
  150.     }
  151.     else
  152.     for (; --argc>=0;)
  153.     {
  154. #ifdef DEFBYTL
  155.         procheader(0);
  156. #endif
  157. #ifdef XMODEM
  158.         printf("Receive:'%s' FILE OPEN\n", *argp);
  159. #endif
  160.         if (wcrx(*argp++)==ERROR)
  161.         goto fubar;
  162.     }
  163.     return OK;
  164. fubar:
  165.     canit();
  166.     closerx(TRUE);
  167.     return ERROR;
  168. } /* wcreceive */
  169.  
  170.  
  171. /****************************************************************************
  172. FUNCTION:
  173.     Fetch a pathname from the other end as a C ctyle ASCII string.
  174.     Length is indeterminate as long as less than blklen
  175.     a null string represents no more files
  176.  
  177. CALLING PARAMETERS:
  178. ===========================================================================*/
  179. wcrxpn(rpn)
  180. char *rpn;    /* receive a pathname */
  181. {
  182.     purgeline();
  183.     firstsec=TRUE;
  184. #ifdef STATLINE
  185.     lpstat("Fetching pathname");
  186. #else
  187.     printf("\nFetching pathname ");
  188. #endif
  189.         /* slight pause to allow slow systems to get ready */
  190.     sleep(5);
  191.     totsecs = -1;
  192.     if (wcgetsec(rpn, 100, Crcflg?WANTCRC:NAK) != 0)
  193.         return ERROR;
  194.     sendbyte(ACK);
  195.         /* clear line of status message above */
  196. #ifndef STATLINE
  197.     printf("\r                   \r");
  198. #endif
  199.     return OK;
  200. } /* wcrxpn */
  201.  
  202.  
  203. /****************************************************************************
  204. FUNCTION:
  205.     transmit path name for batch mode transmission.
  206.  
  207. CALLING PARAMETERS:
  208.     name:
  209.         pointer to file name to transmit.
  210. ===========================================================================*/
  211. wctxpn(name)
  212. char *name;
  213. {
  214.     char *p;
  215.  
  216.         /*??????*/
  217.     totsecs = -1;
  218.  
  219. #ifdef STATLINE
  220.     pstat("Awaiting pathname NAK");
  221. #else
  222.     printf("Awaiting pathname NAK ");
  223. #endif
  224.     if ((firstch=readbyte(400))==TIMEOUT)
  225.         return ERROR;
  226.     if (firstch==WANTCRC)
  227.         Crcflg=TRUE;
  228.  
  229.         /* don't send drive specification */
  230.     if (p=index(':', name))
  231.         name = ++p;
  232.  
  233.         /* sector number 0 for pathname */
  234.     if (wcputsec(name, 0, SECSIZ)==ERROR)
  235.     {
  236.         printf("Can't send pathname %s\n", name);
  237.         return ERROR;
  238.     }
  239. #ifndef STATLINE
  240.     printf("\r                               \r");
  241. #endif
  242.     return OK;
  243. } /* wctxpn */
  244.  
  245.  
  246. /****************************************************************************
  247. FUNCTION:
  248.     Adapted from CMODEM13.C, written by    Jack M. Wierda and Roderick W. Hart
  249.  
  250. CALLING PARAMETERS:
  251. ===========================================================================*/
  252. wcrx(name)
  253. char *name;
  254. {
  255.     int sendchar, sectnum, sectcurr;
  256. #ifdef DEFBYTL
  257.     int cblklen;            /* bytes to dump this block */
  258. #endif
  259.  
  260.     if (openrx(name)==ERROR)
  261.         return ERROR;
  262.     firstsec=TRUE;
  263.     totsecs=sectnum=0;
  264.     sendchar=Crcflg?WANTCRC:NAK;
  265.  
  266.     for (;;)
  267.     {
  268. #ifdef STATLINE
  269.         if (!Quiet)
  270.             pstat("block %3d %2dk", totsecs, totsecs/8 );
  271. #else
  272.         if (!Quiet && !View)
  273.             printf("\rblock %3d %2dk ", totsecs, totsecs/8 );
  274. #endif
  275.         purgeline();
  276.         sectcurr=wcgetsec(Utility.ubuf, (sectnum&0177)?70:130,
  277.           sendchar);
  278.         if (sectcurr==(sectnum+1 &0xff))
  279.         {
  280.             sectnum++;
  281. /*
  282.  * if the compiler supports longs && the o/s blocks the
  283.  *  exact length of files then and only then use the file length
  284.  *  info (if transmitted).
  285.  */
  286. #ifdef DEFBYTL
  287. #ifdef BYTEFLENGTH
  288.             wcj = cblklen = Bytesleft>blklen ? blklen:Bytesleft;
  289. #else
  290.             wcj = cblklen = blklen;
  291. #endif
  292. #else
  293.             wcj = blklen;
  294. #endif
  295.             for (cp=Utility.ubuf; --wcj>=0; )
  296.                 if (fputc(*cp++, fout)==ERROR)
  297.                 {
  298.                     printf("\nDisk Full\n");
  299.                     return ERROR;
  300.                 }
  301. #ifndef XMODEM
  302.             if (View)
  303.             {
  304. #ifdef DEFBYTL
  305.                 wcj = cblklen;
  306. #else
  307.                 wcj = blklen;
  308. #endif
  309.                 for (cp=Utility.ubuf;--wcj>=0;)
  310.                     putchar(*cp++);
  311.             }
  312. #endif
  313. #ifdef DEFBYTL
  314.             if ((Bytesleft -= cblklen) < 0)
  315.                 Bytesleft = 0;
  316. #endif
  317.             totsecs += blklen/128;
  318.             sendchar=ACK;
  319.         }
  320.         else if (sectcurr==sectnum)
  321.         {
  322.             wcperr("received dup block\n");
  323.             sendchar=ACK;
  324.         }
  325.         else if (sectcurr==WCEOT)
  326.         {
  327.             sendbyte(ACK);
  328.             /* don't pad the file any more than it already is */
  329.             closerx(FALSE);
  330.             return OK;
  331.         }
  332.         else if (sectcurr==ERROR)
  333.             return ERROR;
  334.         else
  335.         {
  336.             printf(" Sync Error: got %d\n", sectcurr);
  337.             return ERROR;
  338.         }
  339.     }
  340. } /* wcrx */
  341.  
  342.  
  343. /****************************************************************************
  344. FUNCTION:
  345.     wcgetsec fetches a Ward Christensen type sector.
  346.     Returns sector number encountered or ERROR if valid sector not received,
  347.     or CAN CAN received    or WCEOT if eot sector.
  348.     time is timeout for first char, set to 4 seconds thereafter
  349.     *************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  350.        (Caller must do that when he is good and ready to get next sector)
  351.  
  352. CALLING PARAMETERS:
  353.     rxbuf:
  354.         pointer to buffer to place received data from modem
  355.     time:
  356.     sendchar:
  357. ===========================================================================*/
  358. wcgetsec(rxbuf, time, sendchar)
  359. char *rxbuf;
  360. int time;
  361. {
  362.     int sectcurr;
  363.  
  364.     for (Lastrx=errors=0; errors<RETRYMAX; ++errors, ++toterrs)
  365.     {
  366.             /* stop on user entered ^C */
  367.         if(CIREADY && getcty()==CAN)
  368.             return ERROR;
  369.  
  370.         sendbyte(sendchar);    /* send it now, we're ready! */
  371.             /* ingnore echo */
  372.         purgeline();
  373.  
  374.             /* special char for larger block size */
  375.         if ((firstch=readbyte(time))==STX)
  376.         {
  377.             blklen=KSIZE;
  378.             goto get2;
  379.         }
  380.             /* normal wc start char */
  381.         if (firstch==SOH)
  382.         {
  383.             blklen=SECSIZ;
  384. get2:
  385.                 /* verify sector number sent properly */
  386.             sectcurr=readbyte(50);
  387.             if ((sectcurr+readbyte(50))==0xff)
  388.             {
  389.                     /* rx block, compute checksum */
  390.                 oldcrc=checksum=0;
  391.                 for (cp=rxbuf,wcj=blklen; --wcj>=0; )
  392.                 {
  393.                     if ((firstch=readbyte(50)) < 0)
  394.                         goto bilge;
  395.                     oldcrc=updcrc(firstch, oldcrc);
  396.                     checksum += (*cp++ = firstch);
  397.                 }
  398.                     /* get first byte of check sum */
  399.                 if ((firstch=readbyte(50)) < 0)
  400.                     goto bilge;
  401.  
  402.                     /* calc crc if crc mode requested */
  403.                 if (Crcflg)
  404.                 {
  405.                     oldcrc=updcrc(firstch, oldcrc);
  406.                     if ((firstch=readbyte(50)) < 0)
  407.                         goto bilge;
  408.                     oldcrc=updcrc(firstch, oldcrc);
  409.                     if (oldcrc)
  410.                     {
  411.                         wcperr(NULL);
  412.                         printf("Bad CRC=0%o\n", oldcrc);
  413.                     }
  414.                     else
  415.                     {
  416.                         firstsec=FALSE;
  417.                             /* normal return (crc mode) with current block # */
  418.                         return sectcurr;
  419.                     }
  420.                 }
  421.                     /* not-crc. verify calcualted checksum to actual */
  422.                 else if (((checksum-firstch)&0xff)==0)
  423.                 {
  424.                     firstsec=FALSE;
  425.                         /* normal return with current block # */
  426.                     return sectcurr;
  427.                 }
  428.                 else
  429.                 {
  430.                     wcperr(NULL);
  431.                     printf("Checksum Bad rx=0%o cx=0%o\n",firstch, checksum);
  432.                 }
  433.             }
  434.             else
  435.                 wcperr("block number garbled\n");
  436.         }
  437.             /* make sure eot really is eot and not just mixmash */
  438.         else if (firstch==EOT && readbyte(2)==TIMEOUT)
  439.             return WCEOT;
  440.  
  441.             /* CANcel */
  442.         else if (firstch==CAN)
  443.         {
  444.             if (Lastrx==CAN)
  445.             {
  446.                 wcperr("Sender CANcelled\n");
  447.                 return ERROR;
  448.             }
  449.             else
  450.             {
  451.                 Lastrx=CAN;
  452.                 continue;
  453.             }
  454.         }
  455.         else if (firstch==TIMEOUT)
  456.         {
  457. bilge:
  458.             wcperr("Timeout\n");
  459.         }
  460.             /* display modem status register if supported in readbyte */
  461.         else if (firstch==ERROR)
  462.         {
  463.             wcperr(NULL);
  464.             printf("Modem SR=0%o\n", Mstatus);
  465.         }
  466.         else
  467.         {
  468.             wcperr(NULL);
  469.             printf("Got 0%o block header\n", firstch);
  470.         }
  471.         Lastrx=0;
  472.         while (readbyte(2)!=TIMEOUT)
  473.             ;
  474.         if (firstsec)
  475.             sendchar = Crcflg?WANTCRC:NAK;
  476.         else
  477.         {
  478.             time=40;
  479.             sendchar = NAK;
  480.         }
  481.     }
  482.     /* try to stop the bubble machine. */
  483.     canit(); return ERROR;
  484. } /* wcgetsec */
  485.  
  486.  
  487. /****************************************************************************
  488. FUNCTION:
  489.     print error message to console for block transmission or reception
  490.     error.
  491.  
  492. CALLING PARAMETERS:
  493.     *s:
  494.         pointers to string to display after error message
  495. ===========================================================================*/
  496. wcperr(s)
  497. char *s;
  498. {
  499.         /* block number is already displayed in normal mode */
  500.     if (View)
  501.         printf("block %3d ", totsecs);
  502.     printf("errors %d: ", toterrs);
  503.     printf(s);
  504. } /* wcperr */
  505.  
  506.  
  507. /****************************************************************************
  508. FUNCTION:
  509.     Ward Christensen modem 7 protocol file tranmission handler, pt 2
  510.  
  511. CALLING PARAMETERS:
  512.     none.
  513. ===========================================================================*/
  514. wctx()
  515. {
  516.     int sectnum;
  517.  
  518.     firstsec=TRUE;
  519.     totsecs=0;
  520. #ifdef STATLINE
  521.     pstat("Awaiting initial NAK");
  522. #else
  523.     printf("Awaiting NAK");
  524. #endif
  525.  
  526.         /* get the first char, it must be legal */
  527.     while ( ((firstch=readbyte(400))!=TIMEOUT) && (firstch!=WANTCRC)
  528.       && (firstch!=NAK) && (firstch!=CAN) )
  529.         printf("%c", firstch);    /* let user see it if strange char */
  530.  
  531.         /* CAN = abort */
  532.     if (firstch==CAN)
  533.         return ERROR;
  534.  
  535.         /* file transmission in CRC mode */
  536.     if (firstch==WANTCRC)
  537.         Crcflg=TRUE;
  538.  
  539.         /* NAK or WANTCRC rx */
  540.     sectnum=1;
  541.         /* fill buffer from input file */
  542.     while (filbuf(Utility.ubuf, blklen))
  543.     {
  544.         totsecs += (blklen/128);
  545.         if (!Quiet
  546. #ifdef STATLINE
  547.         )
  548.             pstat("block %3d %2dk", totsecs, totsecs/8 );
  549. #else
  550.         && !View)
  551.             printf("\rblock %3d %2dk ", totsecs, totsecs/8 );
  552. #endif
  553.             /* send buffered block to modem */
  554.         if (wcputsec(Utility.ubuf, sectnum, blklen)==ERROR)
  555.         {
  556.             return ERROR;
  557.         }
  558.             /* successful transfer */
  559.         else
  560.         {
  561.                 /* View can't be set in xyam, otherwise display transfer */
  562.             if (View)
  563.                 for (cp=Utility.ubuf,wcj=blklen;--wcj>=0;)
  564.                     putchar(*cp++);
  565.                 /* next sector(block) */
  566.             sectnum++;
  567.         }
  568.     }
  569.         /* finished, close files */
  570.     closetx(FALSE);
  571.  
  572.     for (errors=0; ++errors<RETRYMAX; )
  573.     {
  574.         sendbyte(EOT);
  575.         purgeline();
  576.         if(readbyte(100) == ACK)
  577.             return OK;
  578.     }
  579.     wcperr("No ACK on EOT\n");
  580.     return ERROR;
  581. } /* wctx */
  582.  
  583.  
  584. /****************************************************************************
  585. FUNCTION:
  586.     wcputsec outputs a Ward Christensen type sector.
  587.     Returns sector number encountered or ERROR if valid sector not received,
  588.     or CAN CAN received    or WCEOT if eot sector.
  589.     time is timeout for first char, set to 4 seconds thereafter
  590.     *************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  591.        (Caller must do that when he is good and ready to get next sector)
  592.  
  593. CALLING PARAMETERS:
  594.     txbuf:
  595.         pointer to buffer to send to modem
  596.     sectnum:
  597.         number of block to send per WC Xmodem protocol
  598.     reclen:
  599.         length of block.  Must = 128 to be xmodem compatible
  600. ===========================================================================*/
  601. wcputsec(txbuf, sectnum, reclen)
  602. char *txbuf;
  603. int sectnum;
  604. int reclen;    /* data length of this sector to send */
  605.  
  606. {
  607.     firstch=0;    /* part of logic to detect CAN CAN */
  608.  
  609.     for (errors=0; errors <= RETRYMAX; ++errors, ++toterrs)
  610.     {
  611.         Lastrx = firstch;
  612.             /* modified so if block length is <> 128 (default for modem7) STX
  613.                will be transmitted */
  614.         sendbyte(reclen==KSIZE?STX:SOH);
  615.         sendbyte(sectnum);
  616.         sendbyte(-sectnum-1);
  617.         oldcrc=checksum=0;
  618.  
  619.             /* send block */
  620.         for (wcj=reclen,cp=txbuf; --wcj>=0; )
  621.         {
  622.             sendbyte(*cp);
  623.             oldcrc=updcrc(*cp, oldcrc);
  624.             checksum += *cp++;
  625.         }
  626.             /* crc mode */
  627.         if (Crcflg)
  628.         {
  629.             oldcrc=updcrc(0,updcrc(0,oldcrc));
  630.             sendbyte(oldcrc>>8);
  631.             sendbyte(oldcrc);
  632.         }
  633.             /* checksum only transfer */
  634.         else
  635.             sendbyte(checksum);
  636.  
  637.             /* allow abort on ^c */
  638.         if(CIREADY && getcty()==CAN)
  639.             goto cancan;
  640.         purgeline();
  641.  
  642.         /* ignore line noise, esp. braces from 212's */
  643.         switch(firstch=readbyte(100))
  644.         {
  645.         case CAN:
  646.             /* CAN CAN - cancel */
  647.             if(Lastrx==CAN)
  648.             {
  649. cancan:
  650.                 printf("\nReceiver CANcelled\n");
  651.                 return ERROR;
  652.             }
  653.             break;
  654.         case ACK|0200: 
  655.         case ACK: 
  656.             firstsec=FALSE;
  657.             return OK;
  658.         case TIMEOUT:
  659.             wcperr("Timeout on block ACK\n");
  660.             break;
  661.         case WANTCRC:
  662.             if (firstsec)
  663.                 Crcflg=TRUE;
  664.         case NAK:
  665.             wcperr("NAK on block\n");
  666.             break;
  667.         default:
  668.             wcperr(NULL);
  669.             printf("Got 0%o for block ACK\n", firstch);
  670.             break;
  671.         }
  672.         for (;;)
  673.         {
  674.             Lastrx=firstch;
  675.             if ((firstch=readbyte(3))==TIMEOUT)
  676.                 break;
  677.             if (firstch==CAN && Lastrx==CAN)
  678.                 goto cancan;
  679.             /* let user see it if strange char */
  680.             printf("%c", firstch);
  681.         }
  682.     }
  683.     wcperr("No ACK on block; Abort\n");
  684.     return ERROR;
  685. } /* wcputsec */
  686.  
  687.  
  688. /****************************************************************************
  689. FUNCTION:
  690.     send 10 CAN's to try to get the other end to shut up
  691.  
  692. CALLING PARAMETERS:
  693. ===========================================================================*/
  694. canit()
  695. {
  696.     for (wcj=10; --wcj>=0; )
  697.         sendbyte(CAN);
  698. } /* canit */
  699.  
  700.  
  701. #ifdef DEFBYTL
  702. /****************************************************************************
  703. FUNCTION:
  704.     process incoming header for additional file info
  705.  
  706. CALLING PARAMETERS:
  707. ===========================================================================*/
  708. procheader(name)
  709. char *name;
  710. {
  711.     char *p;
  712.  
  713.         /* set default parameters */
  714.     Bytesleft = DEFBYTL;
  715.     Filemode = 0666;
  716.     Modtime = 0L;
  717.  
  718.     if (name)
  719.     {
  720.         p = name + 1 + strlen(name);
  721.             /* file coming from Unix type system */
  722.         if (*p)
  723.         {
  724.                 /* place additional info into file name string */
  725.             sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
  726.             printf("%s ", p);
  727.         }
  728.     }
  729.     return OK;
  730. } /* procheader */
  731. #endif
  732.