spector@acf4.UUCP (11/08/84)
Hi there, Yes, I do read net.micro.apple! Sorry you couldn't get to me.. There were a few people who sent mail to me via UUCPnet and to whom I couldn't reply because I couldn't get mail to'em, but heres the Macput/MacGet sources with the manual pages... ...Sorry they're not in Archive form..., I'll see about putting in archive form and then re-posting them to net.sources... -Enjoy Dave. This file contains the Following: Manual page for MACGET Manual page for MACPUT Corrected MacGet program (in C) Corrected MacPut program (in C) All of the above were skillfully crafted by Dave Johnson at Brown, and have been maintained (at New York University) by David Spector. ------------------------------------------------------------------------------ .TH MACGET local "31 July 1984" .UC 4 .SH NAME macget \- receive file from macintosh via Xmodem/macterminal .SH SYNOPSIS .B macget [ .B \-rdu ] [file] .SH DESCRIPTION .I Macget receives a file from a Macintosh running MacTerminal. The File Transfer settings should specify the "xModem" transfer method and a "MacTerminal" remote system. This program is designed for use with the 0.5 Beta and newer versions of MacTerminal, but includes a compatibility option for the older -0.15X Almost-Alpha version. .PP To use this program, log into the unix system using MacTerminal, start macget with the desired options, select "Send File..." from the "File" menu, and open the file you wish to send. If MacTerminal is properly configured, it will put up an indicator showing how much of the file has been transfered. Several Control-X's may be used to force macget to give up if the transfer fails. .PP The optional .I file parameter specifies the name to use when creating the unix files, otherwise the Mac file name is used (with spaces converted to underscores). .PP If none of the .B \-rdu flags are specified, .I macget receives three files from the Mac: .IB file .info , .IB file .data , and .IB file .rsrc . This mode is useful for storing Mac files so they can be restored later using .IR macput . .PP The .B \-r flag specifies .I resource mode. Only .IB file .rsrc will be created, from the Mac file's resource fork. .PP The .B \-d flag specifies .I data mode. Only .IB file .data will be created, containing the data fork of the Mac file. .PP The .B \-u flag requests .I unix mode, in which carriage returns are converted into unix newline characters, and the unix file .IB file .text is created. A file saved from Mac applications as "text only" can be transfered using this option to convert it to a normal unix text file. .PP The .B \-o flag specifies "old" (version -0.15X) MacTerminal compatibility mode. You must manually disable XON/XOFF flow control in this version to perform file transfer; this is done automatically in the newer versions. .SH SEE ALSO macput(local) .SH BUGS Doesn't work over flow controlled communication lines, or when using rlogin. .SH AUTHOR Dave Johnson, Brown 7/31/84 -----------------Manual Page for MacPut Follows------------------------------- .TH MACPUT local "31 July 1984" .UC 4 .SH NAME macput \- send file to macintosh via xmodem/macterminal .SH SYNOPSIS .B macput file .br .B macput [ .B \-rdu ] file [ .B \-t type ] [ .B \-a author ] [ .B \-n name ] .SH DESCRIPTION .I Macput sends a file to a Macintosh running MacTerminal. The File Transfer settings should specify the "Xmodem" transfer method and a "MacTerminal" remote system. This program is designed for use with the 0.5 Beta and newer versions of MacTerminal, but includes a compatibility option for the older -0.15X Almost-Alpha version. .PP To use this program, log into the unix system using MacTerminal, and run macput specifying the desired options and one file to be sent. If MacTerminal is properly configured, it will recognize that a file is arriving on the serial line and put up an indicator showing how much of the file has been sent. Several Control-X's may be used to force macput to give up if the transfer fails. .PP If none of the .B \-rdu flags are specified, .I macput sends three files to the mac: .IB file .info , .IB file .data , and .IB file .rsrc . This is useful for returning files to the mac which were stored using macget. .PP The .B \-r flag specifies .I resource mode. Either .IB file .rsrc or .I file will be sent to the Mac, along with a forged .B .info file and an empty .B .data file. The file sent becomes the resource fork of the Mac file. .PP The .B \-d flag specifies .I data mode. Either .IB file .data , .IB file .text or .I file will be sent to the Mac, along with a forged .B .info file and an empty .B .rsrc file. The file sent becomes the data fork of the Mac file. .PP The .B \-u flag requests .I unix mode, which is the same as .I data mode except unix newline characters are converted into carriage returns. Human-readable unix text files sent to the Mac using this option will be compatible with applications which expect "text only" files. .PP The .B \-o flag specifies "old" (version -0.15X) MacTerminal compatibility mode. You must manually disable XON/XOFF flow control in this version to perform file transfer; this is done automatically in the newer versions. .PP The remaining options serve to override the default file type, author, and file name to be used on the Mac. The default type and author for .I resource mode are "APPL" and "CCOM". .I data mode defaults are "TEXT", "????", and .I unix mode defaults are "TEXT" and "MACA". .SH SEE ALSO macget(local) .SH BUGS Doesn't work over flow controlled communication lines, or when using rlogin. .PP Doesn't set the bundle bit on resource files, to incorporate any icons into the Desk Top. Use setfile to set the bundle bit. .SH FEATURES Properly initializes the Creation Date. .SH AUTHOR Dave Johnson, Brown 7/31/84 ---------------------MacGet Program Follows---------------------------------- #include <stdio.h> #include <signal.h> #include <setjmp.h> #include <sgtty.h> #ifdef NO_RENAME #define rename(old, new) link(old, new); unlink(old) #endif /* Mac time of 00:00:00 GMT, Jan 1, 1970 */ #define TIMEDIFF 0x7c25b080 #define RECORDBYTES 132 #define DATABYTES 128 #define NAMEBYTES 63 #define RETRIES 10 #define SOHTIMO 10 #define LINTIMO 20 #define CHRTIMO 1 #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; int pre_beta; /* -o flag; for compatibility with MacTerminal Version -0.15X */ 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; char tmpname[16]; int lastack; char buf[DATABYTES]; /* * macget -- receive file from macintosh using xmodem protocol * Dave Johnson, Brown University Computer Science * * (c) 1984 Brown University * may be used but not sold without permission * * created ddj 5/22/84 * revised ddj 6/29/84 -- added [-rdu] options * revised ddj 7/16/84 -- protocol changes for MacTerminal Beta Version 0.5X * revised ddj 7/31/84 -- pre-4.2 signal bugs fixed in timedout() */ char usage[] = "usage: \"macget [-o] [-rdu] [filename]\"\n"; main(ac, av) char **av; { char *name; mode = FULL; name = ""; ac--; av++; while (ac) { if (av[0][0] == '-') { switch (av[0][1]) { case 'r': mode = RSRC; break; case 'd': mode = DATA; break; case 'u': mode = TEXT; break; case 'o': pre_beta++; break; default: fprintf(stderr, usage); exit(1); } } else { name = av[0]; } ac--; av++; } setup_tty(); if (send_sync() == ACK) { txtmode = 0; recv_hdr(name); if (mode == TEXT) txtmode++; recv_file(files.f_data, mh.m_datalen, 1); txtmode = 0; recv_file(files.f_rsrc, mh.m_rsrclen, 0); } reset_tty(); } recv_hdr(name) char *name; { long get4(); int n; FILE *fp; char *np; strcpy(tmpname, "#machdrXXXXXX"); mktemp(tmpname); recv_file(tmpname, (long)DATABYTES, 1); fp = fopen(tmpname, "r"); if (fp == NULL) { perror("temp file"); cleanup(-1); } fread(buf, 1, DATABYTES, fp); fclose(fp); if (name && *name) { n = strlen(name); if (n > NAMEBYTES) n = NAMEBYTES; strncpy(mh.m_name, name, n); mh.m_name[n] = '\0'; } else { n = buf[H_NLENOFF] & BYTEMASK; if (n > NAMEBYTES) n = NAMEBYTES; strncpy(mh.m_name, buf + H_NAMEOFF, n); mh.m_name[n] = '\0'; } for (np = mh.m_name; *np; np++) if (*np == ' ') *np = '_'; if (mode == FULL) { sprintf(files.f_info, "%s.info", mh.m_name); rename(tmpname, files.f_info); tmpname[0] = '\0'; sprintf(files.f_data, "%s.data", mh.m_name); sprintf(files.f_rsrc, "%s.rsrc", mh.m_name); } else { unlink(tmpname); tmpname[0] = '\0'; switch (mode) { case RSRC: sprintf(files.f_data, "/dev/null"); sprintf(files.f_rsrc, "%s.rsrc", mh.m_name); break; case DATA: sprintf(files.f_data, "%s.data", mh.m_name); sprintf(files.f_rsrc, "/dev/null"); break; case TEXT: sprintf(files.f_data, "%s.text", mh.m_name); sprintf(files.f_rsrc, "/dev/null"); break; } } strncpy(mh.m_type, buf + H_TYPEOFF, 4); strncpy(mh.m_author, buf + H_AUTHOFF, 4); if (pre_beta) { mh.m_datalen = get4(buf + H_OLD_DLENOFF); mh.m_rsrclen = get4(buf + H_OLD_RLENOFF); } else { mh.m_datalen = get4(buf + H_DLENOFF); mh.m_rsrclen = get4(buf + H_RLENOFF); mh.m_createtime = get4(buf + H_CTIMOFF); mh.m_modifytime = get4(buf + H_MTIMOFF); } } recv_file(fname, bytes, more) char *fname; long bytes; int more; { register int status, n; FILE *outf; int naks = 0; lastack = 0; outf = fopen(fname, "w"); if (outf == NULL) { perror(fname); cleanup(-1); } for (;;) { status = rec_read(buf, DATABYTES); switch (status) { case EOT: if (!pre_beta) tputc(ACK); if (more) tputc(NAK); fclose(outf); return; case ACK: tputc(ACK); naks = 0; n = (bytes > DATABYTES) ? DATABYTES : bytes; bytes -= n; fwrite(buf, n, 1, outf); break; case DUP: tputc(ACK); naks = 0; break; case NAK: purge(CHRTIMO); if (naks++ < RETRIES) { tputc(NAK); break; } /* fall through */ case CAN: tputc(CAN); fclose(outf); /* unlink fname? */ cleanup(-1); /* NOTREACHED */ } } } send_sync() { int c; for (;;) { c = tgetc(60); switch (c) { case ESC: break; case CAN: case EOT: case TMO: return c; default: continue; } c = tgetc(1); if (c != 'a') continue; tputc(ACK); return ACK; } } rec_read(buf, recsize) char buf[]; int recsize; { int c, rec, rec_bar, cksum; c = tgetc(SOHTIMO); switch (c) { case TMO: default: return NAK; case EOT: return EOT; case CAN: return CAN; case SOH: /* read header */ rec = tgetc(CHRTIMO); if (rec == TMO) return NAK; rec_bar = tgetc(CHRTIMO); if (rec_bar == TMO) return NAK; /* check header */ if (rec != MAXRECNO - rec_bar) return NAK; /* fill buffer */ cksum = tgetrec(buf, recsize, LINTIMO); if (cksum == TMO) return NAK; /* get checksum */ c = tgetc(CHRTIMO); if (c == TMO) return NAK; if (c != (cksum & BYTEMASK)) return NAK; /* check record number */ if (rec == lastack) return DUP; if (rec != ((lastack + 1) & MAXRECNO)) return CAN; else { lastack = rec; return ACK; } } /* NOTREACHED */ } purge(timeout) int timeout; { int c; do { c = tgetc(timeout); } while (c != TMO); } static int ttyfd; static FILE *ttyf; jmp_buf timobuf; tgetrec(buf, count, timeout) char *buf; int count, timeout; { char *bp; int i, cksum; if (setjmp(timobuf)) return TMO; alarm(timeout); i = fread(buf, 1, count, ttyf); alarm(0); if (i != count) return TMO; cksum = 0; bp = buf; for (i = 0; i < count; bp++, i++) { cksum += *bp; if (txtmode && *bp == '\r') *bp = '\n'; } return cksum; } 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; } tputc(c) char c; { write(ttyfd, &c, 1); } timedout() { signal(SIGALRM, timedout); /* for pre-4.2 systems */ longjmp(timobuf, 1); } static struct sgttyb otty, ntty; /* should turn messages off */ setup_tty() { int cleanup(); int timedout(); ttyf = stdin; ttyfd = fileno(stdin); ioctl(ttyfd, TIOCGETP, &otty); signal(SIGHUP, cleanup); signal(SIGINT, cleanup); signal(SIGQUIT, cleanup); signal(SIGTERM, cleanup); signal(SIGALRM, timedout); ntty = otty; ntty.sg_flags = RAW|ANYP; ioctl(ttyfd, TIOCSETP, &ntty); } reset_tty() { sleep(2); /* should wait for output to drain */ ioctl(ttyfd, TIOCSETP, &otty); } cleanup(sig) int sig; { if (tmpname[0] != '\0') unlink(tmpname); reset_tty(); exit(sig); } long get4(bp) char *bp; { register int i; long value = 0; for (i = 0; i < 4; i++) { value <<= 8; value |= (*bp & BYTEMASK); bp++; } return value; } ----------------------Macput Program Follows---------------------------------- #include <stdio.h> #include <signal.h> #include <setjmp.h> #include <sgtty.h> #include <time.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/timeb.h> /* Mac time of 00:00:00 GMT, Jan 1, 1970 */ #define TIMEDIFF 0x7c25b080 #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; int pre_beta; /* -o flag; for compatibility with MacTerminal Version -0.15X */ 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; char buf[DATABYTES]; /* * macput -- send file to macintosh using xmodem protocol * Dave Johnson, Brown University Computer Science * * (c) 1984 Brown University * may be used but not sold without permission * * created ddj 6/17/84 * revised ddj 7/16/84 -- protocol changes for MacTerminal Beta Version 0.5X * revised ddj 7/31/84 -- pre-4.2 signal bugs fixed in timedout() * revised ddj 7/31/84 -- fixed timeout problem in initial handshake */ char usage[] = "usage: \"macput [-o] [-rdu] [-t type] [-a author] [-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, "APPL", 4); strncpy(mh.m_author, "CCOM", 4); break; case 'u': mode = TEXT; strncpy(mh.m_type, "TEXT", 4); strncpy(mh.m_author, "MACA", 4); break; case 'd': mode = DATA; strncpy(mh.m_type, "TEXT", 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 'a': if (ac > 1) { ac--; av++; strncpy(mh.m_author, av[0], 4); break; } else goto bad_usage; case 'o': pre_beta++; break; 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() == ACK) { txtmode = 0; sleep(1); 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 tm *tp; struct timeb tbuf; 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 (!pre_beta) { ftime(&tbuf); tp = localtime(&tbuf.time); tdiff = TIMEDIFF - tbuf.timezone * 60; if (tp->tm_isdst) tdiff += 60 * 60; mh.m_createtime = stbuf.st_mtime + tdiff; mh.m_modifytime = stbuf.st_mtime + tdiff; } 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); if (pre_beta) { put4(buf + H_OLD_DLENOFF, mh.m_datalen); put4(buf + H_OLD_RLENOFF, mh.m_rsrclen); } else { 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, i; for (i = 0; i < 3; i++) { tputc(ESC); tputc('a'); while ((c = tgetc(ACKTIMO)) != TMO) { switch (c) { case CAN: case EOT: case ACK: return c; default: continue; } } fprintf(stderr, "starting handshake timeout\r\n"); } fprintf(stderr, "giving up\r\n"); return CAN; } 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); } recno = 1; for (;;) { n = fread(buf, 1, DATABYTES, inf); if (n > 0) { for (i = 0; i < RETRIES; i++) { send_rec(buf, DATABYTES); status = tgetc(ACKTIMO); if (status != NAK) break; } if (status == NAK || status == CAN) { fclose(inf); cleanup(-1); /* NOTREACHED */ } } if (n < DATABYTES) { tputc(EOT); if (!pre_beta) { status = tgetc(ACKTIMO); } if (more) { status = tgetc(ACKTIMO); } return; } recno++; recno &= MAXRECNO; } } send_rec(buf, recsize) char buf[]; int recsize; { int i, cksum; char *bp; cksum = 0; bp = buf; for (i = 0; i < recsize; i++, bp++) { if (txtmode && *bp == '\n') *bp = '\r'; cksum += *bp; } tputc(SOH); tputc((char)recno); tputc((char)(MAXRECNO - recno)); tputrec(buf, recsize); 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); } static struct sgttyb otty, ntty; /* should turn messages off */ setup_tty() { int cleanup(); int timedout(); ttyf = stdin; ttyfd = fileno(stdin); ioctl(ttyfd, TIOCGETP, &otty); signal(SIGHUP, cleanup); signal(SIGINT, cleanup); signal(SIGQUIT, cleanup); signal(SIGTERM, cleanup); signal(SIGALRM, timedout); ntty = otty; ntty.sg_flags = RAW|ANYP; ioctl(ttyfd, TIOCSETP, &ntty); } reset_tty() { if (ttyf != NULL) { sleep(2); /* should wait for output to drain */ ioctl(ttyfd, TIOCSETP, &otty); } } 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; } }