davet@oakhill.UUCP (David Trissel) (10/21/88)
[Sorry for posting here but our mailer refuses to send to comp.sources.mac]
What follows is my version of Macbinput which is a MacBinary XMODEM download
program. This is an alteration of "Mbput.c" which was posted on the net
some time ago. The only difference is a name change to "Macbinput" and ifdefs
for System V and Sun 4.2 BSD compilation (and some cleanup.)
A companion posting is being done for my version of "Macbinget" which supports
faster uploading as an option as well as compilation on System V machines.
-- Dave Trissel Motorola Austin ut-sally!cs.utexas.edu!oakhill!davet
************** Cut Here *****************
/*
* (originally macput) -- send file to Macintosh using MacBinary XMODEM protocol
* Dave Johnson, Brown University Computer Science
*
* (c) 1984 Brown University
* may be used but not sold without permission
*
*/
/* To compile:
cc -O -o macbinput macbinput.c
(Sun 4.2 BSD) cc -O -DSUNBSD42 -o macbinput macbinput.c
(System V) cc -O -DSYSV -o macbinput macbinput.c
Latest modifications 10/20/88 by Trissel -
1. General cleanup by removal of unused definitions and headers.
2. Added #ifdefs to support System V and BSD 4.2 Sun compilation.
3. Removed ancient Macterminal Beta 0.5X code.
4. Changed name to less cryptic "macbinput" from "mbput".
Dave Trissel
Motorola Inc.
ut-sally!oakhill!davet
This code is fundamentally from two earlier programmers:
Jon Hueras
Symantec/THINK Technologies
singer@endor.harvard.edu
who added 2-Byte CRC capability to code from:
Dave Johnson
ddj%brown@csnet-relay.arpa
Brown University Computer Science
who did the initial MacTerminal 1.1 transfer protocol.
*/
/* If you have System V define the following: */
/* #define SYSV */
/* Sun BSD 4.2 systems should define the following: */
/* #define SUNBSD42 */
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#ifdef SYSV
#include <termio.h>
#else
#include <sgtty.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifdef SUNBSD42
/* RAW is no longer being found on latest Sun system (??) (Trissel) */
#define RAW 0x20
#endif
#define RECORDBYTES 132
#define DATABYTES 128
#define NAMEBYTES 63
#define RETRIES 10
#define ACKTIMO 10
#define MAXRECNO 0xff
#define BYTEMASK 0xff
#define TMO -1
#define DUP '\000'
#define SOH '\001'
#define EOT '\004'
#define ACK '\006'
#define NAK '\025'
#define CAN '\030'
#define EEF '\032'
#define ESC '\033'
#define H_NLENOFF 1
#define H_NAMEOFF 2
/* 65 <-> 80 is the FInfo structure */
#define H_TYPEOFF 65
#define H_AUTHOFF 69
#define H_LOCKOFF 81
#define H_DLENOFF 83
#define H_RLENOFF 87
#define H_CTIMOFF 91
#define H_MTIMOFF 95
#define H_OLD_DLENOFF 81
#define H_OLD_RLENOFF 85
#define TEXT 0
#define DATA 1
#define RSRC 2
#define FULL 3
int mode, txtmode;
struct macheader {
char m_name[NAMEBYTES+1];
char m_type[4];
char m_author[4];
long m_datalen;
long m_rsrclen;
long m_createtime;
long m_modifytime;
} mh;
struct filenames {
char f_info[256];
char f_data[256];
char f_rsrc[256];
} files;
int recno, crc;
char buf[DATABYTES];
char usage[] =
"usage: \"macbinput [-rdu] [-t type] [-c creator] [-n name] filename\"\n";
main(ac, av)
char **av;
{
int n;
char *filename;
if (ac == 1) {
fprintf(stderr, usage);
exit(1);
}
mode = FULL;
ac--; av++;
while (ac) {
if (av[0][0] == '-') {
switch (av[0][1]) {
case 'r':
mode = RSRC;
strncpy(mh.m_type, "????", 4);
strncpy(mh.m_author, "????", 4);
break;
case 'u':
mode = TEXT;
strncpy(mh.m_type, "TEXT", 4);
strncpy(mh.m_author, "EDIT", 4);
break;
case 'd':
mode = DATA;
strncpy(mh.m_type, "????", 4);
strncpy(mh.m_author, "????", 4);
break;
case 'n':
if (ac > 1) {
ac--; av++;
n = strlen(av[0]);
if (n > NAMEBYTES) n = NAMEBYTES;
strncpy(mh.m_name, av[0], n);
mh.m_name[n] = '\0';
break;
}
else goto bad_usage;
case 't':
if (ac > 1) {
ac--; av++;
strncpy(mh.m_type, av[0], 4);
break;
}
else goto bad_usage;
case 'c':
if (ac > 1) {
ac--; av++;
strncpy(mh.m_author, av[0], 4);
break;
}
else goto bad_usage;
default:
bad_usage:
fprintf(stderr, usage);
exit(1);
}
}
else {
filename = av[0];
}
ac--; av++;
}
setup_tty();
find_files(filename, mode);
if (mode != FULL)
forge_info();
if (send_sync()) {
recno = 1;
txtmode = 0;
send_file(files.f_info, 1);
if (mode != FULL)
unlink(files.f_info);
if (mode == TEXT) txtmode++;
send_file(files.f_data, 1);
txtmode = 0;
send_file(files.f_rsrc, 0);
}
reset_tty();
}
find_files(filename, mode)
char *filename;
{
int n, tdiff;
struct stat stbuf;
sprintf(files.f_data, "%s.data", filename);
sprintf(files.f_rsrc, "%s.rsrc", filename);
if (mode == FULL) {
sprintf(files.f_info, "%s.info", filename);
if (stat(files.f_info, &stbuf) != 0) {
perror(files.f_info);
cleanup(-1);
}
return;
}
else {
strcpy(files.f_info, "#machdrXXXXXX");
mktemp(files.f_info);
}
if (mode == RSRC) {
strcpy(files.f_data, "/dev/null");
if (stat(files.f_rsrc, &stbuf) != 0) {
strcpy(files.f_rsrc, filename);
if (stat(files.f_rsrc, &stbuf) != 0) {
perror(files.f_rsrc);
cleanup(-1);
}
}
mh.m_datalen = 0;
mh.m_rsrclen = stbuf.st_size;
}
else {
strcpy(files.f_rsrc, "/dev/null");
if (stat(files.f_data, &stbuf) != 0) {
sprintf(files.f_data, "%s.text", filename);
if (stat(files.f_data, &stbuf) != 0) {
strcpy(files.f_data, filename);
if (stat(files.f_data, &stbuf) != 0) {
perror(files.f_data);
cleanup(-1);
}
}
}
mh.m_datalen = stbuf.st_size;
mh.m_rsrclen = 0;
}
if (mh.m_name[0] == '\0') {
n = strlen(filename);
if (n > NAMEBYTES) n = NAMEBYTES;
strncpy(mh.m_name, filename, n);
mh.m_name[n] = '\0';
}
}
forge_info()
{
int n;
char *np;
FILE *fp;
for (np = mh.m_name; *np; np++)
if (*np == '_') *np = ' ';
buf[H_NLENOFF] = n = np - mh.m_name;
strncpy(buf + H_NAMEOFF, mh.m_name, n);
strncpy(buf + H_TYPEOFF, mh.m_type, 4);
strncpy(buf + H_AUTHOFF, mh.m_author, 4);
put4(buf + H_DLENOFF, mh.m_datalen);
put4(buf + H_RLENOFF, mh.m_rsrclen);
put4(buf + H_CTIMOFF, mh.m_createtime);
put4(buf + H_MTIMOFF, mh.m_modifytime);
fp = fopen(files.f_info, "w");
if (fp == NULL) {
perror("temp file");
cleanup(-1);
}
fwrite(buf, 1, DATABYTES, fp);
fclose(fp);
}
send_sync()
{
int c;
tputc(ESC);
tputc('b');
for (;;) {
if ((c = tgetc(ACKTIMO)) == TMO)
{
return(0);
}
if (c == NAK)
{
return(1);
}
if (c == 'C') {
crc++;
return(1);
}
}
}
send_file(fname, more)
char *fname;
int more;
{
register int status, i, n;
FILE *inf;
inf = fopen(fname, "r");
if (inf == NULL) {
perror(fname);
cleanup(-1);
}
for (;;) {
n = fread(buf, 1, DATABYTES, inf);
if (n > 0) {
for (i = 0; i < RETRIES; i++) {
send_rec(buf, DATABYTES);
while ((status = tgetc(ACKTIMO)) != ACK && status != NAK && status != CAN);
if (status != NAK)
break;
}
if (status != ACK) {
if (status != CAN)
while ((status = tgetc(ACKTIMO)) != CAN);
fclose(inf);
cleanup(-1);
/* NOTREACHED */
}
}
if (n < DATABYTES) {
if (!more) {
tputc(EOT);
tgetc(ACKTIMO);
}
return;
}
recno++;
recno &= MAXRECNO;
}
}
send_rec(buf, recsize)
char buf[];
int recsize;
{
int i, cksum;
char *bp;
if (txtmode || !crc) {
cksum = 0;
bp = buf;
for (i = 0; i < recsize; i++, bp++) {
if (txtmode && *bp == '\n')
*bp = '\r';
cksum += *bp;
}
}
if (crc)
cksum = calcrc(buf, recsize);
tputc(SOH);
tputc((char) recno);
tputc((char) (MAXRECNO - recno));
tputrec(buf, recsize);
if (crc) {
tputc((char) (cksum >> 8));
tputc((char) cksum);
} else
tputc((char) cksum);
}
static int ttyfd;
static FILE *ttyf;
static jmp_buf timobuf;
tgetc(timeout)
int timeout;
{
int c;
if (setjmp(timobuf))
return TMO;
alarm(timeout);
c = getc(ttyf);
alarm(0);
if (c == -1) /* probably hung up or logged off */
return EOT;
else
return c & BYTEMASK;
}
tputrec(buf, count)
char *buf;
int count;
{
write(ttyfd, buf, count);
}
tputc(c)
char c;
{
write(ttyfd, &c, 1);
}
timedout()
{
signal(SIGALRM, timedout); /* for pre-4.2 systems */
longjmp(timobuf, 1);
}
#ifdef SYSV
static struct termio otty, ntty;
#else
static struct sgttyb otty, ntty;
#endif
/* should turn messages off */
setup_tty()
{
int cleanup();
int timedout();
ttyf = stdin;
ttyfd = fileno(stdout);
#ifdef SYSV
ioctl(ttyfd, TCGETA, &otty); /* get termio info */
#else
ioctl(ttyfd, TIOCGETP, &otty);
#endif
signal(SIGHUP, cleanup);
signal(SIGINT, cleanup);
signal(SIGQUIT, cleanup);
signal(SIGTERM, cleanup);
signal(SIGALRM, timedout);
ntty = otty;
#ifdef SYSV
ntty.c_iflag = BRKINT; /* only interrupt on break */
ntty.c_oflag = 0; /* no output processing */
ntty.c_cflag |= CS8; /* 8 bit characters */
ntty.c_lflag = 0; /* no echoing */
ntty.c_cc[VEOF] = 1; /* "MIN" minimum chars before input */
ntty.c_cc[VEOL] = 1; /* "TIME" maximum .1 secs before feed */
ioctl(ttyfd, TCSETAF, &ntty); /* set mode and flush input */
#else
ntty.sg_flags = RAW;
ioctl(ttyfd, TIOCSETP, &ntty);
#endif
}
reset_tty()
{
if (ttyf != NULL) {
#ifdef SYSV
ioctl(ttyfd, TCSETAF, &otty); /* reset after output drains */
#else
sleep (5); /* wait for output to drain */
ioctl(ttyfd, TIOCSETP, &otty);
#endif
}
}
cleanup(sig)
int sig;
{
reset_tty();
exit(sig);
}
put4(bp, value)
char *bp;
long value;
{
register int i, c;
for (i = 0; i < 4; i++) {
c = (value >> 24) & BYTEMASK;
value <<= 8;
*bp++ = c;
}
}
int calcrc(ptr, count)
char *ptr;
int count;
{
int crc, i;
crc = 0;
while (--count >= 0) {
crc ^= ((int) *ptr++) << 8;
for (i = 0; i < 8; ++i)
if (crc & 0x8000)
crc = crc << 1 ^ 0x1021;
else
crc <<= 1;
}
return (crc & 0xFFFF);
}