home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / source / layers.zoo / layers.2 / macbput.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-11  |  9.2 KB  |  530 lines

  1. /*
  2.  * (originally macput) -- send file to Macintosh using MacBinary XMODEM protocol
  3.  * Dave Johnson, Brown University Computer Science
  4.  *
  5.  * (c) 1984 Brown University 
  6.  * may be used but not sold without permission
  7.  *
  8.  */
  9.  
  10. /* To compile:    
  11.                   cc -O -o macbput macbput.c
  12.     (Sun 4.2 BSD) cc -O -DSUNBSD42 -o macbput macbput.c
  13.     (System V)    cc -O -DSYSV -o macbput macbput.c
  14.  
  15.    Latest modifications 10/20/88 by Trissel -
  16.  
  17.  1. General cleanup by removal of unused definitions and headers.
  18.  2. Added #ifdefs to support System V and BSD 4.2 Sun compilation.
  19.  3. Removed ancient Macterminal Beta 0.5X code.
  20.  4. Fixed bad bug where XMODEM block count was not bumped up
  21.     after the first fork transfer.
  22.  
  23.     Dave Trissel
  24.     Motorola Inc.
  25.     ut-sally!oakhill!davet
  26.  
  27.    This code is fundamentally from two earlier programmers:
  28.  
  29.     Jon Hueras
  30.     Symantec/THINK Technologies
  31.     singer@endor.harvard.edu
  32.  
  33.     who added 2-Byte CRC capability to code from:
  34.  
  35.     Dave Johnson
  36.     ddj%brown@csnet-relay.arpa
  37.     Brown University Computer Science
  38.  
  39.    who did the initial MacTerminal 1.1 transfer protocol.
  40. */
  41.  
  42. /* If you have System V define the following: */
  43.     /* #define SYSV */
  44.  
  45. /* Sun BSD 4.2 systems should define the following: */
  46.     /* #define SUNBSD42 */
  47.  
  48. #include <stdio.h>
  49. #include <signal.h>
  50. #include <setjmp.h>
  51. #ifdef SYSV
  52. #include <termio.h>
  53. #else
  54. #include <sgtty.h>
  55. #endif
  56. #include <sys/types.h>
  57. #include <sys/stat.h>
  58.  
  59. #ifdef SUNBSD42
  60. /* RAW is no longer being found on latest Sun system (??) (Trissel) */
  61. #define RAW 0x20
  62. #endif
  63.  
  64. #define RECORDBYTES 132
  65. #define DATABYTES 128
  66. #define NAMEBYTES 63
  67.  
  68. #define RETRIES 10
  69. #define ACKTIMO 10
  70.  
  71. #define MAXRECNO 0xff
  72. #define BYTEMASK 0xff
  73.  
  74. #define TMO -1
  75. #define DUP '\000'
  76. #define SOH '\001'
  77. #define EOT '\004'
  78. #define ACK '\006'
  79. #define NAK '\025'
  80. #define CAN '\030'
  81. #define EEF '\032'
  82. #define ESC '\033'
  83.  
  84. #define H_NLENOFF 1
  85. #define H_NAMEOFF 2
  86. /* 65 <-> 80 is the FInfo structure */
  87. #define H_TYPEOFF 65
  88. #define H_AUTHOFF 69
  89.  
  90. #define H_LOCKOFF 81
  91. #define H_DLENOFF 83
  92. #define H_RLENOFF 87
  93. #define H_CTIMOFF 91
  94. #define H_MTIMOFF 95
  95.  
  96. #define H_OLD_DLENOFF 81
  97. #define H_OLD_RLENOFF 85
  98.  
  99. #define TEXT 0
  100. #define DATA 1
  101. #define RSRC 2
  102. #define FULL 3
  103.  
  104. int mode, txtmode;
  105.  
  106. struct macheader {
  107.     char m_name[NAMEBYTES+1];
  108.     char m_type[4];
  109.     char m_author[4];
  110.     long m_datalen;
  111.     long m_rsrclen;
  112.     long m_createtime;
  113.     long m_modifytime;
  114. } mh;
  115.  
  116. struct filenames {
  117.     char f_info[256];
  118.     char f_data[256];
  119.     char f_rsrc[256];
  120. } files;
  121.  
  122. int recno, crc;
  123. char buf[DATABYTES];
  124.  
  125. char usage[] =
  126.     "usage: \"macbput [-rdu] [-t type] [-c creator] [-n name] filename\"\n";
  127.  
  128. main(ac, av)
  129. char **av;
  130. {
  131.     int n;
  132.     char *filename;
  133.  
  134.     if (ac == 1) {
  135.         fprintf(stderr, usage);
  136.         exit(1);
  137.     }
  138.  
  139.     mode = FULL;
  140.     ac--; av++;
  141.     while (ac) {
  142.         if (av[0][0] == '-') {
  143.             switch (av[0][1]) {
  144.             case 'r':
  145.                 mode = RSRC;
  146.                 strncpy(mh.m_type, "????", 4);
  147.                 strncpy(mh.m_author, "????", 4);
  148.                 break;
  149.             case 'u':
  150.                 mode = TEXT;
  151.                 strncpy(mh.m_type, "TEXT", 4);
  152.                 strncpy(mh.m_author, "MACA", 4);
  153.                 break;
  154.             case 'd':
  155.                 mode = DATA;
  156.                 strncpy(mh.m_type, "????", 4);
  157.                 strncpy(mh.m_author, "????", 4);
  158.                 break;
  159.             case 'n':
  160.                 if (ac > 1) {
  161.                     ac--; av++;
  162.                     n = strlen(av[0]);
  163.                     if (n > NAMEBYTES) n = NAMEBYTES;
  164.                     strncpy(mh.m_name, av[0], n);
  165.                     mh.m_name[n] = '\0';
  166.                     break;
  167.                 }
  168.                 else goto bad_usage;
  169.             case 't':
  170.                 if (ac > 1) {
  171.                     ac--; av++;
  172.                     strncpy(mh.m_type, av[0], 4);
  173.                     break;
  174.                 }
  175.                 else goto bad_usage;
  176.             case 'c':
  177.                 if (ac > 1) {
  178.                     ac--; av++;
  179.                     strncpy(mh.m_author, av[0], 4);
  180.                     break;
  181.                 }
  182.                 else goto bad_usage;
  183.             default:
  184. bad_usage:
  185.                 fprintf(stderr, usage);
  186.                 exit(1);
  187.             }
  188.         }
  189.         else {
  190.             filename = av[0];
  191.         }
  192.         ac--; av++;
  193.     }
  194.  
  195.     setup_tty();
  196.     find_files(filename, mode);
  197.     if (mode != FULL)
  198.         forge_info();
  199.  
  200.     if (send_sync()) {
  201.         recno = 1;
  202.         txtmode = 0;
  203.         send_file(files.f_info, 1);
  204.  
  205.         if (mode != FULL)
  206.             unlink(files.f_info);
  207.  
  208.         if (mode == TEXT) txtmode++;
  209.         send_file(files.f_data, 1);
  210.  
  211.         txtmode = 0;
  212.         send_file(files.f_rsrc, 0);
  213.     }
  214.     reset_tty();
  215. }
  216.  
  217. find_files(filename, mode)
  218. char *filename;
  219. {
  220.     int n, tdiff;
  221.     struct stat stbuf;
  222.  
  223.     sprintf(files.f_data, "%s.data", filename);
  224.     sprintf(files.f_rsrc, "%s.rsrc", filename);
  225.  
  226.     if (mode == FULL) {
  227.         sprintf(files.f_info, "%s.info", filename);
  228.         if (stat(files.f_info, &stbuf) != 0) {
  229.             perror(files.f_info);
  230.             cleanup(-1);
  231.         }
  232.         return;
  233.     }
  234.     else {
  235.         strcpy(files.f_info, "#machdrXXXXXX");
  236.         mktemp(files.f_info);
  237.     }
  238.  
  239.     if (mode == RSRC) {
  240.         strcpy(files.f_data, "/dev/null");
  241.         if (stat(files.f_rsrc, &stbuf) != 0) {
  242.             strcpy(files.f_rsrc, filename);
  243.             if (stat(files.f_rsrc, &stbuf) != 0) {
  244.                 perror(files.f_rsrc);
  245.                 cleanup(-1);
  246.             }
  247.         }
  248.         mh.m_datalen = 0;
  249.         mh.m_rsrclen = stbuf.st_size;
  250.     }
  251.     else {
  252.         strcpy(files.f_rsrc, "/dev/null");
  253.         if (stat(files.f_data, &stbuf) != 0) {
  254.             sprintf(files.f_data, "%s.text", filename);
  255.             if (stat(files.f_data, &stbuf) != 0) {
  256.                 strcpy(files.f_data, filename);
  257.                 if (stat(files.f_data, &stbuf) != 0) {
  258.                     perror(files.f_data);
  259.                     cleanup(-1);
  260.                 }
  261.             }
  262.         }
  263.         mh.m_datalen = stbuf.st_size;
  264.         mh.m_rsrclen = 0;
  265.     }
  266.  
  267.     if (mh.m_name[0] == '\0') {
  268.         n = strlen(filename);
  269.         if (n > NAMEBYTES) n = NAMEBYTES;
  270.         strncpy(mh.m_name, filename, n);
  271.         mh.m_name[n] = '\0';
  272.     }
  273. }
  274.  
  275. forge_info()
  276. {
  277.     int n;
  278.     char *np;
  279.     FILE *fp;
  280.  
  281.     for (np = mh.m_name; *np; np++)
  282.         if (*np == '_') *np = ' ';
  283.  
  284.     buf[H_NLENOFF] = n = np - mh.m_name;
  285.     strncpy(buf + H_NAMEOFF, mh.m_name, n);
  286.     strncpy(buf + H_TYPEOFF, mh.m_type, 4);
  287.     strncpy(buf + H_AUTHOFF, mh.m_author, 4);
  288.     put4(buf + H_DLENOFF, mh.m_datalen);
  289.     put4(buf + H_RLENOFF, mh.m_rsrclen);
  290.     put4(buf + H_CTIMOFF, mh.m_createtime);
  291.     put4(buf + H_MTIMOFF, mh.m_modifytime);
  292.     fp = fopen(files.f_info, "w");
  293.     if (fp == NULL) {
  294.         perror("temp file");
  295.         cleanup(-1);
  296.     }
  297.     fwrite(buf, 1, DATABYTES, fp);
  298.     fclose(fp);
  299. }
  300.  
  301. send_sync()
  302.     {
  303.         int c;
  304.         
  305.         tputc(ESC);
  306.         tputc('b');
  307.  
  308.         for (;;) {
  309.  
  310.             if ((c = tgetc(ACKTIMO)) == TMO)
  311.               {
  312.                 return(0);
  313.                 }
  314.  
  315.             if (c == NAK)
  316.               {
  317.                 return(1);
  318.                 }
  319.  
  320.             if (c == 'C') {
  321.                 crc++;
  322.                 return(1);
  323.             }
  324.         }
  325.     }
  326.  
  327. send_file(fname, more)
  328. char *fname;
  329. int more;
  330. {
  331.     register int status, i, n;
  332.     FILE *inf;
  333.  
  334.     inf = fopen(fname, "r");
  335.     if (inf == NULL) {
  336.         perror(fname);
  337.         cleanup(-1);
  338.     }
  339.     for (;;) {
  340.         n = fread(buf, 1, DATABYTES, inf);
  341.         if (n > 0) {
  342.             for (i = 0; i < RETRIES; i++) {
  343.                 send_rec(buf, DATABYTES);
  344.                 while ((status = tgetc(ACKTIMO)) != ACK && status != NAK && status != CAN);
  345.                 if (status != NAK)
  346.                     break;
  347.             } 
  348.             if (status != ACK) {
  349.                 if (status != CAN)
  350.                     while ((status = tgetc(ACKTIMO)) != CAN);
  351.                 fclose(inf);
  352.                 cleanup(-1);
  353.                 /* NOTREACHED */
  354.             }
  355.         }
  356.         if (n < DATABYTES) {
  357.             if (!more) {
  358.                 tputc(EOT);
  359.                 tgetc(ACKTIMO);
  360.             }
  361.             return;
  362.         }
  363.         recno++;
  364.         recno &= MAXRECNO;
  365.     }
  366. }
  367.  
  368. send_rec(buf, recsize)
  369. char buf[];
  370. int recsize;
  371. {
  372.     int i, cksum;
  373.     char *bp;
  374.  
  375.     if (txtmode || !crc) {
  376.         cksum = 0;
  377.         bp = buf;
  378.         for (i = 0; i < recsize; i++, bp++) {
  379.             if (txtmode && *bp == '\n')
  380.                 *bp = '\r';
  381.             cksum += *bp;
  382.         }
  383.     }
  384.  
  385.     if (crc)
  386.         cksum = calcrc(buf, recsize);
  387.  
  388.     tputc(SOH);
  389.     tputc((char) recno);
  390.     tputc((char) (MAXRECNO - recno));
  391.     tputrec(buf, recsize);
  392.     
  393.     if (crc) {
  394.         tputc((char) (cksum >> 8));
  395.         tputc((char) cksum);
  396.     } else
  397.         tputc((char) cksum);
  398. }
  399.  
  400. static int ttyfd;
  401. static FILE *ttyf;
  402. static jmp_buf timobuf;
  403.  
  404. tgetc(timeout)
  405. int timeout;
  406. {
  407.     int c;
  408.  
  409.     if (setjmp(timobuf))
  410.         return TMO;
  411.  
  412.     alarm(timeout);
  413.     c = getc(ttyf);
  414.     alarm(0);
  415.  
  416.     if (c == -1)    /* probably hung up or logged off */
  417.         return EOT;
  418.     else
  419.         return c & BYTEMASK;
  420. }
  421.  
  422. tputrec(buf, count)
  423. char *buf;
  424. int count;
  425. {
  426.     write(ttyfd, buf, count);
  427. }
  428.  
  429. tputc(c)
  430. char c;
  431. {
  432.     write(ttyfd, &c, 1);
  433. }
  434.  
  435. timedout()
  436. {
  437.     signal(SIGALRM, timedout);    /* for pre-4.2 systems */
  438.     longjmp(timobuf, 1);
  439. }
  440.  
  441. #ifdef SYSV
  442. static struct termio otty, ntty;
  443. #else
  444. static struct sgttyb otty, ntty;
  445. #endif
  446.  
  447. /* should turn messages off */
  448.  
  449. setup_tty()
  450. {
  451.     int cleanup();
  452.     int timedout();
  453.  
  454.     ttyf = stdin;
  455.     ttyfd = fileno(stdout);
  456. #ifdef SYSV
  457.     ioctl(ttyfd, TCGETA, &otty);        /* get termio info */
  458. #else
  459.     ioctl(ttyfd, TIOCGETP, &otty);
  460. #endif
  461.     signal(SIGHUP, cleanup);
  462.     signal(SIGINT, cleanup);
  463.     signal(SIGQUIT, cleanup);
  464.     signal(SIGTERM, cleanup);
  465.     signal(SIGALRM, timedout);
  466.     ntty = otty;
  467. #ifdef SYSV
  468.     ntty.c_iflag = BRKINT;                /* only interrupt on break */
  469.     ntty.c_oflag = 0;                    /* no output processing */
  470.     ntty.c_cflag |= CS8;                /* 8 bit characters */
  471.     ntty.c_lflag = 0;                    /* no echoing */
  472.     ntty.c_cc[VEOF] = 1;                /* "MIN" minimum chars before input */
  473.     ntty.c_cc[VEOL] = 1;                /* "TIME" maximum .1 secs before feed */
  474.     ioctl(ttyfd, TCSETAF, &ntty);        /* set mode and flush input */
  475. #else
  476.     ntty.sg_flags = RAW;
  477.     ioctl(ttyfd, TIOCSETP, &ntty);
  478. #endif
  479. }
  480.  
  481. reset_tty()
  482. {
  483.     if (ttyf != NULL) {
  484. #ifdef SYSV
  485.         ioctl(ttyfd, TCSETAF, &otty);    /* reset after output drains */
  486. #else
  487.         sleep (5);                        /* wait for output to drain */
  488.         ioctl(ttyfd, TIOCSETP, &otty);
  489. #endif
  490.     }
  491. }
  492.  
  493. cleanup(sig)
  494. int sig;
  495. {
  496.     reset_tty();
  497.     exit(sig);
  498. }
  499.  
  500. put4(bp, value)
  501. char *bp;
  502. long value;
  503. {
  504.     register int i, c;
  505.  
  506.     for (i = 0; i < 4; i++) {
  507.         c = (value >> 24) & BYTEMASK;
  508.         value <<= 8;
  509.         *bp++ = c;
  510.     }
  511. }
  512.  
  513. int calcrc(ptr,    count)
  514. char *ptr;
  515. int count;
  516.     {
  517.         int    crc, i;
  518.  
  519.         crc    = 0;
  520.         while (--count >= 0) {
  521.          crc ^= ((int) *ptr++) << 8;
  522.          for (i = 0; i < 8; ++i)
  523.                  if (crc & 0x8000)
  524.              crc = crc <<    1 ^ 0x1021;
  525.                  else
  526.              crc <<= 1;
  527.          }
  528.         return (crc    & 0xFFFF);
  529.     }
  530.