home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume15 / xmodem3.6 / part04 < prev    next >
Text File  |  1988-06-13  |  16KB  |  623 lines

  1. Subject:  v15i073:  Xmodem release 3.6, Part04/05
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Steve Grandi <grandi@noao.arizona.edu>
  7. Posting-number: Volume 15, Issue 73
  8. Archive-name: xmodem3.6/part04
  9.  
  10. : This is a shar archive.  Extract with sh, not csh.
  11. echo x - batch.c
  12. sed -e 's/^X//' > batch.c << '!Funky!Stuff!'
  13. X/*
  14. X *  Various routines for batch transfer
  15. X */
  16. X
  17. X#include "xmodem.h"
  18. X
  19. X/* make sure filename sent or received in YMODEM batch is canonical. */
  20. X
  21. X/* Incoming: Turn Unix '/' into CP/M ':' and translate to all lower case.
  22. X * Remove trailing dot.
  23. X */
  24. X
  25. Xunixify (name)
  26. Xchar *name;
  27. X    {
  28. X    char *ptr;
  29. X
  30. X    /* change '/' to ':' and convert to lower case */
  31. X    for (ptr=name; *ptr; ++ptr)
  32. X        {
  33. X        if (*ptr == '/')
  34. X            *ptr = ':';
  35. X        if (isupper (*ptr))
  36. X            *ptr |= 040;
  37. X        }
  38. X
  39. X    /* remove trailing dot if present */
  40. X    ptr--;
  41. X    if (*ptr == '.')
  42. X        *ptr = '\0';
  43. X    }
  44. X
  45. X/* make sure filename sent or received in YMODEM batch is canonical. */
  46. X
  47. X/* Outgoing: Turn ':' into '/' (for symmetry!) and turn into all lower case.
  48. X * Remove everything before last '/'.  Use "filename" to hold final name.
  49. X */
  50. X
  51. Xchar *
  52. Xcpmify (name)
  53. Xchar *name;
  54. X    {
  55. X    char *ptr, *slash;
  56. X    char *strcpy();
  57. X
  58. X    /* find last '/' and copy rest of name */
  59. X
  60. X    slash = name;
  61. X    for (ptr=name; *ptr; ++ptr)
  62. X        if (*ptr == '/')
  63. X            slash = ptr + 1;
  64. X    strcpy (filename, slash);
  65. X
  66. X    /* change ':' to '/' and covert to all lower case */
  67. X
  68. X    for (ptr=filename; *ptr; ++ptr)
  69. X        {
  70. X        if (*ptr == ':')
  71. X            *ptr = '/';
  72. X        if (isupper (*ptr))
  73. X            *ptr |= 040;
  74. X        }
  75. X    return (filename);
  76. X    }
  77. X
  78. X
  79. X/* convert a CP/M file name received in a MODEM7 batch transfer
  80. X * into a unix file name mapping '/' into ':', converting to all
  81. X * upper case and adding dot in proper place.  
  82. X * Use "filename" to hold name.
  83. X * Code stolen from D. Thompson's (IRTF) xmodem.c
  84. X */
  85. X
  86. Xchar *
  87. Xcpm_unix (string)
  88. Xunsigned char *string;
  89. X{
  90. X    register int i;
  91. X    unsigned char *iptr, temp;
  92. X    register char *optr;
  93. X
  94. X    if (*string == '\0')
  95. X        error("Null file name in MODEM7 batch receive", TRUE);
  96. X
  97. X    for (iptr=string; (temp = *iptr) ; ) {
  98. X        temp &= 0177;            /* strips bit 7 */
  99. X        if (isupper(temp))
  100. X            temp |= 040;        /* set bit 5 for lower case */
  101. X        if (temp == '/') 
  102. X            temp=':';        /* map / into : */
  103. X        *iptr++ = temp;
  104. X    }
  105. X
  106. X    /* put in main part of name */
  107. X    iptr=string;
  108. X    optr=filename;
  109. X    for (i=0; i<8; i++) {
  110. X        if (*iptr != ' ')
  111. X            *optr++ = *iptr++;
  112. X    }
  113. X
  114. X    /* add dot if necessary */
  115. X    if (string[8] != ' ' || string[9] != ' ' || string[10] != ' ')
  116. X        *optr++ = '.';
  117. X
  118. X    /* put in extension */
  119. X    iptr = &string[8];
  120. X    for (i=0; i<3; i++) {
  121. X        if (*iptr != ' ')
  122. X            *optr++ = *iptr++;
  123. X    }
  124. X
  125. X    *optr++ = '\000';
  126. X    return (filename);
  127. X}
  128. X
  129. X/* Send 11 character CP/M filename for MODEM7 batch transmission
  130. X * Returns -1 for a protocol error; 0 if successful
  131. X * NOTE: we tromp a little on the argument string!
  132. X * code stolen from D. Thompson's (IRTF) xmodem.c
  133. X */
  134. X
  135. Xsend_name(name)
  136. Xchar *name;
  137. X{
  138. X    register int cksum;
  139. X    register char *ptr;
  140. X
  141. X    xmdebug("send_name");
  142. X
  143. X    /* append cp/m EOF */
  144. X    name[NAMSIZ] = CTRLZ;
  145. X    name[NAMSIZ+1] = '\000';
  146. X
  147. X    /* create checksum */
  148. X    ptr = name;
  149. X    cksum = 0;
  150. X    while (*ptr)
  151. X        cksum += *ptr++;
  152. X    cksum &= 0x00FF;
  153. X
  154. X    /* send filename */
  155. X
  156. X    sendbyte(ACK);
  157. X    ptr = name;
  158. X    sendbyte(*ptr++);
  159. X
  160. X    while (*ptr) {
  161. X
  162. X            switch (readbyte(15)) {
  163. X
  164. X            case ACK: break;
  165. X
  166. X            case TIMEOUT: {
  167. X                logit("Timeout while sending MODEM7 filename\n");
  168. X                sendbyte(BAD_NAME);
  169. X                return (-1);
  170. X            }
  171. X
  172. X            default: {
  173. X                logit("Error while sending MODEM7 filename\n");
  174. X                sendbyte(BAD_NAME);
  175. X                return (-1);
  176. X            }
  177. X        }    
  178. X
  179. X        sendbyte (*ptr++);
  180. X    }
  181. X
  182. X    /* Check checksum returned by other side against my value */
  183. X    if (readbyte(16) != cksum) {
  184. X        logit("Bad checksum while sending MODEM7 filename\n");
  185. X        sendbyte(BAD_NAME);
  186. X        return (-1);
  187. X    }
  188. X
  189. X    sendbyte(ACK);
  190. X    return (0);
  191. X}
  192. X
  193. X/* Convert Unix filename to 11 character CP/M file name (8 char name,
  194. X * 3 char extension, dot in between is not included).
  195. X * map ':' into '/'; Use filename to hold name.
  196. X * code stolen from D. Thompson's (IRTF) xmodem.c
  197. X */
  198. X
  199. Xchar *
  200. Xunix_cpm(string)
  201. Xchar *string;
  202. X{
  203. X    register char *iptr, *optr, temp;
  204. X    int i;
  205. X
  206. X    char *rindex();
  207. X    char *strcpy();
  208. X
  209. X    /* blank 11 character name */
  210. X    (void) strcpy (filename,"           ");
  211. X
  212. X    /* strip off any path name */
  213. X    if ((iptr = rindex(string,'/')))
  214. X        iptr++;
  215. X    else
  216. X        iptr=string;
  217. X
  218. X    /* skip leading '.'s */
  219. X    while (*iptr == '.')
  220. X        iptr++;
  221. X
  222. X    /* copy main part of name */
  223. X    optr = filename;
  224. X    i = 8;
  225. X    while ((i--) && (*iptr) && (*iptr != '.'))
  226. X        *optr++ = *iptr++;
  227. X
  228. X    /* advance to unix extension, or end of unix name */
  229. X    while ((*iptr != '.') && (*iptr))
  230. X        iptr++;
  231. X
  232. X    /* skip over the  '.' */
  233. X    while (*iptr == '.')
  234. X        iptr++;
  235. X
  236. X    /* copy extension */
  237. X    optr = &filename[8];
  238. X    i=3;
  239. X    while ((i--) && (*iptr) && (*iptr != '.'))
  240. X        *optr++ = *iptr++;
  241. X
  242. X    filename[NAMSIZ] = '\000';
  243. X
  244. X    /* Fuss with name */
  245. X    for (iptr=filename; (temp = *iptr) ;) {
  246. X        temp &= 0177;            /* strip bit 7 (parity bit) */
  247. X        if (islower(temp))
  248. X            temp &= ~040;        /* make upper case */
  249. X        if (temp == ':')
  250. X            temp ='/';        /* map ':' into '/' */
  251. X        *iptr++ = temp;
  252. X    }
  253. X
  254. X    if (DEBUG)
  255. X        fprintf (LOGFP, "DEBUG: File %s sent as %s\n", string, filename);
  256. X
  257. X    return(filename);
  258. X}
  259. !Funky!Stuff!
  260. echo x - send.c
  261. sed -e 's/^X//' > send.c << '!Funky!Stuff!'
  262. X/**  send a file  **/
  263. X
  264. X/*
  265. X * Operation of this routine depends on on MDM7BAT and YMDMBAT flags.
  266. X *
  267. X * If "name" is NULL; close out the BATCH send.
  268. X */
  269. X
  270. X#include "xmodem.h"
  271. X
  272. Xsfile(name)
  273. Xchar *name;
  274. X    {
  275. X
  276. X    char *sectdisp();
  277. X    time_t time();
  278. X    char *strcpy();
  279. X    char *unix_cpm();
  280. X    char *cpmify();
  281. X    long countnl();
  282. X
  283. X    extern unsigned short crctab[1<<B];    /* CRC-16 constant values, see getput.c */
  284. X
  285. X    register int bufctr,         /* array index for data buffer */
  286. X    sectnum;            /* packet number for packet header */
  287. X
  288. X    register unsigned short checksum;     /* checksum/crc */
  289. X
  290. X    char blockbuf[BBUFSIZ+6];    /* holds packet as it is constructed */
  291. X
  292. X    struct stat filestatbuf;    /* file status info */
  293. X
  294. X    int fd,         /* file descriptor for file being transmitted */
  295. X    attempts,        /* number of attempts made to transmit a packet */
  296. X    nlflag,         /* flag that we have to send a LF in next packet */
  297. X    sendfin,         /* flag that we are sending the last packet */
  298. X    closeout,        /* flag that we are closing out batch send */
  299. X    startup,        /* flag that we are starting batch send */
  300. X    tmode,            /* TRUE for text mode */
  301. X    amode,            /* TRUE for apple mode */
  302. X    filepack,        /* TRUE when sending first packet */
  303. X    buf1024,        /* TRUE when sending 1K packets */
  304. X    bbufcnt,        /* array index for packet */
  305. X    firstchar,        /* first character in protocol transaction */
  306. X    bufsize,        /* packet size (128 or 1024) */
  307. X    sendresp;          /* response char to sent block received from remote*/
  308. X    long sentsect;        /* count of 128 byte sectors actually sent */
  309. X    long expsect;        /* count of 128 byte sectors expected to be sent */
  310. X    time_t start;        /* starting time of transfer */
  311. X    char c;
  312. X
  313. X    nbchr = 0;  /* clear buffered read char count */
  314. X
  315. X    CRCMODE = FALSE;    /* Receiver determines use of crc or checksum */
  316. X
  317. X    buf1024 = LONGPACK;    /* set packet size flag to command line switch */
  318. X
  319. X    closeout = FALSE; startup = TRUE; filepack = FALSE;    /* indicate state of batch transfer */
  320. X
  321. X    tmode = (XMITTYPE == 't') ? TRUE : FALSE;    /* set text mode */
  322. X    amode = (XMITTYPE == 'a') ? TRUE : FALSE;    /* set apple mode */
  323. X
  324. X    /* Check on NULL file name */
  325. X    if (strcmp(name,"") == 0)
  326. X        {
  327. X        if (BATCH)
  328. X            closeout = TRUE;
  329. X        else
  330. X            {
  331. X            sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
  332. X            error("NULL file name in send", TRUE);
  333. X            }
  334. X        }
  335. X
  336. X    if (!closeout)        /* Are we closing down batch? */
  337. X        {            /* no; let's send a file */
  338. X        logit("----\nXMODEM Send Function\n");
  339. X
  340. X        if ((fd = open(name, 0)) < 0)    
  341. X            {  
  342. X            sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
  343. X                    error("Can't open file for send", TRUE);
  344. X            }
  345. X    
  346. X        stat(name, &filestatbuf);  /* get file status bytes */
  347. X        if (tmode)           /* count up NLs */
  348. X            filestatbuf.st_size += countnl(fd);
  349. X        expsect = (filestatbuf.st_size/128) + 1;
  350. X    
  351. X        if (LOGFLAG)
  352. X            {   
  353. X                fprintf(LOGFP, "File Name: %s\n", name);
  354. X              fprintf(LOGFP,"File Size %ldK, %ld Records, %ld Bytes\n",
  355. X                (filestatbuf.st_size/1024)+1, expsect, filestatbuf.st_size);
  356. X            projtime(expsect, LOGFP);
  357. X            }
  358. X        }
  359. X    else
  360. X        {
  361. X        logit("----\nXMODEM Send Function\n");
  362. X        logit("Closing down Batch Transmission\n");
  363. X        }
  364. X
  365. X
  366. X    bufsize = buf1024 ? 1024 : 128;        /* set sector size */
  367. X    if (buf1024 && !closeout)
  368. X        logit("1K packet mode chosen\n");
  369. X
  370. X        sendfin = nlflag = FALSE;
  371. X      attempts = 0;
  372. X
  373. X    /* wait for and read startup character */
  374. Xrestart:
  375. X    do
  376. X        {
  377. X        while (((firstchar=readbyte(1)) != NAK) && (firstchar != CRCCHR) && (firstchar != CAN))
  378. X            if (++attempts > NAKMAX)
  379. X                {
  380. X                if (MDM7BAT && startup)
  381. X                    {
  382. X                    sendbyte(ACK); sendbyte(EOT);
  383. X                    }
  384. X                error("Remote System Not Responding", TRUE);
  385. X                }
  386. X
  387. X        if ((firstchar & 0x7f) == CAN)
  388. X            if (readbyte(3) == CAN)
  389. X                error("Send cancelled at user's request",TRUE);
  390. X
  391. X        if (firstchar == CRCCHR)
  392. X            {
  393. X            CRCMODE = TRUE;
  394. X            if (!closeout)
  395. X                logit("CRC mode requested\n");
  396. X            if (readbyte(1) == KCHR)
  397. X                {
  398. X                buf1024 = TRUE;
  399. X                logit("Receiver invoked 1K packet mode\n");
  400. X                }
  401. X            }
  402. X        }
  403. X    while (firstchar != NAK && firstchar != CRCCHR);
  404. X
  405. X    if (MDM7BAT && closeout)    /* close out MODEM7 batch */
  406. X        {
  407. X        sendbyte(ACK); sendbyte (EOT);
  408. X        flushin(); readbyte(2);     /* flush junk */
  409. X        return;
  410. X        }
  411. X
  412. X    if (MDM7BAT && startup)        /* send MODEM7 file name */
  413. X        {
  414. X        if (send_name(unix_cpm(name)) == -1)
  415. X            {
  416. X            attempts = 0;
  417. X            goto restart;
  418. X            }
  419. X        startup = FALSE;
  420. X        attempts = 0;
  421. X        goto restart;
  422. X        }
  423. X
  424. X    sectnum = 1;
  425. X
  426. X    if (YMDMBAT)    /* Fudge for YMODEM transfer (to send name packet) */
  427. X        {
  428. X        sectnum = 0;
  429. X        bufsize = 128;
  430. X        filepack = TRUE;
  431. X        }
  432. X
  433. X    attempts = sentsect = 0;
  434. X    start = time((time_t *) 0);
  435. X
  436. X        do             /* outer packet building/sending loop; loop till whole file is sent */
  437. X        {   
  438. X
  439. X        if (closeout && YMDMBAT && sectnum == 1)    /* close out YMODEM */
  440. X            return;
  441. X
  442. X        if (YMDMBAT && sectnum == 1)            /* get set to send YMODEM data packets */
  443. X            {
  444. X            bufsize = buf1024 ? 1024 : 128;
  445. X
  446. X            do        /* establish handshaking again */
  447. X                {
  448. X                while (((firstchar=readbyte(2)) != CRCCHR) && (firstchar != NAK) && (firstchar != CAN))
  449. X                    if (++attempts > ERRORMAX)
  450. X                        error("YMODEM protocol botch, C expected", TRUE);
  451. X                if ((firstchar&0x7f) == CAN)
  452. X                    if (readbyte(3) == CAN)
  453. X                        error("Send cancelled at User's request", TRUE);
  454. X                }
  455. X            while ((firstchar != CRCCHR) && (firstchar != NAK));
  456. X
  457. X            attempts = 0;
  458. X            }
  459. X
  460. X        if ((bufsize == 1024) && (attempts > KSWMAX))
  461. X            {
  462. X            logit("Reducing packet size to 128 due to excessive errors\n");
  463. X            bufsize = 128;
  464. X            }
  465. X
  466. X        if ((bufsize == 1024) && ((expsect - sentsect) < 8))
  467. X            {
  468. X            logit("Reducing packet size to 128 for tail end of file\n");
  469. X            bufsize = 128;
  470. X            }
  471. X
  472. X        if (sectnum > 0)    /* data packet */
  473. X            {
  474. X            for (bufctr=0; bufctr < bufsize;)
  475. X                    {
  476. X                if (nlflag)
  477. X                            {  
  478. X                    buff[bufctr++] = LF;  /* leftover newline */
  479. X                               nlflag = FALSE;
  480. X                        }
  481. X                if (getbyte(fd, &c) == EOF)
  482. X                    { 
  483. X                    sendfin = TRUE;  /* this is the last sector */
  484. X                       if (!bufctr)  /* if EOF on sector boundary */
  485. X                              break;  /* avoid sending extra sector */
  486. X                          buff[bufctr++] = CTRLZ;  /* pad with Ctrl-Z for CP/M EOF (even do for binary files) */
  487. X                       continue;
  488. X                          }
  489. X    
  490. X                if (tmode && c == LF)  /* text mode & Unix newline? */
  491. X                        {
  492. X                    buff[bufctr++] = CR;  /* insert carriage return */
  493. X                         if (bufctr < bufsize)
  494. X                                buff[bufctr++] = LF;  /* insert LF */
  495. X                           else
  496. X                            nlflag = TRUE;  /* insert on next sector */
  497. X                       }    
  498. X                else if (amode && c == LF)   /* Apple mode & Unix newline? */
  499. X                    buff[bufctr++] = CR; /* substitute CR */
  500. X                else
  501. X                    buff[bufctr++] = c;  /* copy the char without change */
  502. X                    }
  503. X
  504. X                if (!bufctr)  /* if EOF on sector boundary */
  505. X                          break;  /* avoid sending empty sector */
  506. X            }    
  507. X
  508. X        else        /* YMODEM filename packet */
  509. X            {
  510. X            for (bufctr=0; bufctr<bufsize; bufctr++)  /* zero packet */
  511. X                buff[bufctr]=0;
  512. X            if (!closeout)
  513. X                {
  514. X                strcpy((char *)buff, cpmify(name));
  515. X                
  516. X                    /* put in file name, length, mode */
  517. X                    {
  518. X                    register char *p;
  519. X                    p = (char *)buff + strlen(name) + 1;
  520. X                    sprintf(p, "%lu %lo %o", filestatbuf.st_size, 
  521. X                      filestatbuf.st_mtime, filestatbuf.st_mode);
  522. X                    if (DEBUG)
  523. X                        fprintf(LOGFP, "DEBUG: YMODEM header information: %s\n", p);
  524. X                    }
  525. X                buff[bufsize-2]    = (expsect & 0xff);        /* put in KMD kludge information */
  526. X                buff[bufsize-1] = ((expsect >> 8) & 0xff);
  527. X                }
  528. X            }
  529. X
  530. X        bbufcnt = 0;        /* start building block to be sent */
  531. X        blockbuf[bbufcnt++] = (bufsize == 1024) ? STX : SOH;    /* start of packet char */
  532. X        blockbuf[bbufcnt++] = sectnum;        /* current sector # */
  533. X        blockbuf[bbufcnt++] = ~sectnum;   /* and its complement */
  534. X
  535. X                   checksum = 0;  /* initialize checksum */
  536. X                   for (bufctr=0; bufctr < bufsize; bufctr++)
  537. X                   {
  538. X            blockbuf[bbufcnt++] = buff[bufctr];
  539. X
  540. X            if (CRCMODE)
  541. X                checksum = (checksum<<B) ^ crctab[(checksum>>(W-B)) ^ buff[bufctr]];
  542. X
  543. X            else
  544. X                           checksum = ((checksum+buff[bufctr]) & 0xff);
  545. X                 }
  546. X
  547. X        if (CRCMODE)        /* put in CRC */
  548. X            {
  549. X            checksum &= 0xffff;
  550. X            blockbuf[bbufcnt++] = ((checksum >> 8) & 0xff);
  551. X            blockbuf[bbufcnt++] = (checksum & 0xff);
  552. X            }
  553. X        else            /* put in checksum */
  554. X            blockbuf[bbufcnt++] = checksum;
  555. X
  556. X                attempts = 0;
  557. X    
  558. X                do                /* inner packet loop */
  559. X                    {
  560. X
  561. X            writebuf(blockbuf, bbufcnt);    /* write the block */
  562. X            flushin();                      /* purge anything in input queue */
  563. X
  564. X            if (DEBUG)
  565. X                fprintf (LOGFP, "DEBUG: %d byte Packet %02xh (%02xh) sent, checksum %02xh %02xh\n", 
  566. X                bbufcnt, blockbuf[1]&0xff, blockbuf[2]&0xff, blockbuf[bufsize+3]&0xff, blockbuf[bufsize+4]&0xff);
  567. X
  568. X                    attempts++;
  569. X            sendresp = readbyte(10);  /* get response from remote */
  570. X
  571. X            if (sendresp != ACK)
  572. X                   {
  573. X                if (sendresp == TIMEOUT)
  574. X                    {
  575. X                       logitarg("Timeout on sector %s\n",sectdisp(sentsect,bufsize,1));
  576. X                    }
  577. X                else if (sendresp == NAK)
  578. X                    {
  579. X                       logitarg("NAK on sector %s\n",sectdisp(sentsect,bufsize,1));
  580. X                    }
  581. X                else
  582. X                    {
  583. X                       logitarg("Non-ACK on sector %s\n",sectdisp(sentsect,bufsize,1));
  584. X                    }
  585. X                   }
  586. X                    }
  587. X            while((sendresp != ACK) && (attempts < ERRORMAX));    /* close of inner loop */
  588. X
  589. X               sectnum++;  /* increment to next sector number */
  590. X        if (!filepack)
  591. X            sentsect += (bufsize == 128) ? 1 : 8;
  592. X        filepack = FALSE;
  593. X            }
  594. X        while (!sendfin && ( attempts < ERRORMAX));    /* end of outer loop */
  595. X
  596. X    if (attempts >= ERRORMAX)
  597. X        {
  598. X        sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
  599. X        error ("Too many errors in transmission", TRUE);
  600. X        }
  601. X
  602. X        attempts = 0;
  603. X        sendbyte(EOT);  /* send 1st EOT to close down transfer */
  604. X    
  605. X        while ((readbyte(15) != ACK) && (attempts++ < EOTMAX))     /* wait for ACK of EOT */
  606. X        {
  607. X        if (attempts > 1)
  608. X            logitarg("EOT not ACKed, try %d\n", attempts);
  609. X           sendbyte(EOT);
  610. X        }
  611. X
  612. X        if (attempts >= RETRYMAX)
  613. X           error("Remote System Not Responding on Completion", TRUE);
  614. X
  615. X        close(fd);
  616. X
  617. X        logit("Send Complete\n");
  618. X    prtime(sentsect, time((time_t *) 0) - start);
  619. X    }
  620. !Funky!Stuff!
  621. exit
  622.  
  623.