chuqui@nsc.UUCP (Chuqui Q. Koala) (01/05/85)
This is a shar file of useful programs for the Macintosh. I wrote none of them, but there have been requests for them. See the article in net.micro.mac for more details. chuq --- cut here --- (ouch!) #! /bin/sh # The rest of this file is a shell script which will extract: # BinHex.hex README README.xbin fromhexu.c macget.c macput.c tohexu.c xbin.c echo x - BinHex.hex cat >BinHex.hex <<'!!ChuquiCo!!Software!!' #APPLBNHX$2000 ***COMPRESSED ***RESOURCE FORK ( 0 !2! 3@0 3+M_,Y"J ,0^P "B%) !(Q (&P !@ 6$6P "0 :3G5AX!% !LA2@ <H P* 8/B@ (!!.=6'*$4 &R%* !R@"C H !@^* 03G5![?S.0J@ ( PQ0 8H $^* 09@ ! $*H !(Q; & !:@$SXH !!F ( [$YU88B@"#XH !!F #>3G5A /]Z0F@ '* ,/B@ (!!G"@Q'_]5G'& ,(^//_3""@ !P H9@ M* )/B@ (!!F "J3G5A /]&0F@ '* ,/B@ $&8 )9.=4'M_,Y" (*@ ##%M_=8 %C%\ ( +$*H "Z@1#XH !!F !R3G5* ( !@70FEN2&5X(%8R+C @+2T@,3 O,CDO.#0 $ ( ___@ ( , " "@ @ 0D ( &(@"'_R$ A_^_@(?_ ( ( AP8 @(<$ ("' " AP @(< ("' " AP/P@)_$"( ( CX@$@(<3 H""'(& @.?P\$ C ' @$ !P$ @ < @& ' ( ! '^< ( (? ! $!P (" !! (@ !0 ( ( ___@ /__\ #___@ ___\ /___@#___\ ____@/___X ( ____@/___X#___^ ____@/___X#___^ ____@/___X ( ____@/___X#___^ ____\'____ ____P'___\ ____ ( !___\ /_X? !_\!P /^ !_ /@ !P ( ( =!4%!, '$).2%@ !24-.(P ((!&4D5& " *0 ! #____[ 10- ($%B;W5T($)I;DAE>,D 2T )8 @ ( /___M<$1FEL915!<'!L:6-A=&EO;B M/B!5 ('!L;V%D !55<&QO860@+3X@07!P;&EC871I;VX ( $M M415A4(&9I;'1E<@ $@ !+0 * ($-O;7!R97-S960 !( #U-E;F0@;&EN92!F965D<P ( 2T !%%U:70 40 !4 9 R ,@!S ! ( $ ! @ $ !& 50 6@&0! )/ ($L H "@ : 9"(.$)I;DAE>" R+C L("!W<FET ('1E;B!B>2!9=F5S($QE;7!E<F5U<B![0TE3(#<T,#$V ("PQ-S0Q?2 !H "@ J 9"(-'=I=&@@36%C05-- (*HL(&%N($5D:71O<B]!<W-E;6)L97(@9F]R('1H92!- (&%C:6YT;W-H+@ .@ * $H!+(@J1F]R(&9U<G1H (&5R(&EN9F]R;6%T:6]N(&-O;G1A8W0@36%I;G-T87DL (" $H "@!: 2R((GM#25,@-S W-C4L-S,T?2!O ('(@*#@Q."D@.3DQ+38U-# N %0!D &0 O@&0 $ ( @ J $ #P Y@!0 2($ D]+ ( % 4 #L!&(@*7C @97)R;W(N( !4 9 !D ( "^ 9 0 , = ! \ .8 (% !(@0"3TL H "@ Z 2*(5$-O;G9E<G-I;VX@ (&]F($%P<&QI8V%T:6]N(&1O8W5M96YT('1O(&%N(%5P (&QO860@9F]R;6%T(&1O8W5M96YT(&AA<R!B965N(&-O (&UP;&5T960A( !4 9 !D +@!F@ ! ( 0 D # V / 2@$L! )/2P "@ * ( J 2R(4$-O;G9E<G-I;VX@;V8@57!L;V%D(&9O<FUA ('0@9&]C=6UE;G0@=&\@07!P;&EC871I;VX@9&]C=6UE (&YT(&AA<R!B965N(&-O;7!L971E9"$ "H "@ Z ( #FB )>, .@ * $H YH@"7C$ 3 &0 9 #8 ( &5 $! Z4 4AM__RH;JC^J1*I (#!"IZE[80 , B \ #__Z R/SP JGI/SP ZEY/SP ( 2I>6$ # H;? !_?P;? !_?^H4"M/_<*IM$(G/SS_ (/](;?VRJ7 0'V?N,"W]LM! ,#L !D[[ +_X R_^ (!C_X/_@_^ !8/_@_^#_X/_@,"W]P @ AGOD*G("W] (+0_ *D^(!]@ R0F<O+?V\2&W]QJDL,!_00# [ 9. (/L O^6 X!"/^6_Y;_EO^60J<O+?V\J3T@'RM _<HP ("W]RM! ,#L !D[[ ( !@ . &9"9ZDX8 #_8# M_<P, ($ 68P0J<_/ !0J<O//____^I?"M7_<ZI%4*G2&W] (-*ID3 M_=(,0 !9NXO+?W.J8-@OD*G/SP :E)/RW] (,Q(;?O.J49"9TAM^\ZIMC ?8* P+?W,T$ P.P &3OL ( +_D@": ^3_D@ 4_Y( , !,_Y( : HM ']_$*G/SP ( *I23\\ 0?+?W\J45@ /]D"BT ?W_0J<_/ "J4D_ (#P !A\M_?^I16 _T@*+0 !_?U"IS\\ *I23\\ <? ("W]_:E%8 #_+*GT2&W]LB\M_<:ILV _H(P+?VT9P#^ ('I"9S\\ &0_/ !D+RW]M#\\ "IZ3 ?8 #^8#\\ $8_ (#P 1DAZ"F!"IS\\__]"IT*G2&W]'C\\ *IZDHM_1YG ( #^TC\\ $8_/ !&2'H, TAZ"C1"ITAM_6@_/ !J>I* ("W]:&< _JY)[?UH80 (AF$ "'1A BR(7Q415A4 " A ('P@(" @ "2@#3XH !!F D^< ))[?UH1>WYQ&$ !_ [ ($#]UAM\ ']^TI'9@ )(&$ !DA)[?T>80 (;BMH "#] (. K: D_>0P* H D#P #M _>@K: ! _=@K: V_=QA ( !\$HM_?]G"$'Z"<UA &X80 '*$)M_?)"+?WT/SP ( H_/ !&J)-*K?W89RA"K?W82&W]<JB$2'H*;JB$0?H) (*=A &$< %)[?T>1?@ &$ !W)@+$JM_=QG8D*M_=Q( (&W]<JB$2'H*,ZB$0?H)BF$ 59P 4GM_1Y%^ 80 ' ("X[0/W4&WP ?WZ2D=F A>80 !M$HM^\YG!F$ )A@ (/!!^@EA80 !($GM_1XP+?W480 ')D(M_?I@ /]B2BW] (/]F$D'Z"59A $6$"W]]&$ 61@$$'Z"3QA $$,"W] (/)A %(80 Y&$ !/A)[?UH,"W]UF$ !N)"+?W[+RW] (,:I%$*G/SP T*G+SS_____J7PK5_W.J15"ITAM_=*I ()$P+?W2#$ 6;N+RW]SJF#8 #] $'M^\Y"01(82BW] (/]G+D('$ %A X8"1"0! 8T2W]]#0M_?+40.=:.T+] (/)*+?W_9@9A #,8 1A 24<G_VDHM_?]G!&$ "I@ ($IT!PP' 9F$@(& #\&!@ @P49A 0TP49"!^,0XQ92 ( =1RO_@3G5*!V<:# < !F<&XPY2!V#T @8 /P8& " 0 ( 9A 0&3G5A 6< UA /Z2BW]_6<&< IA /N3G5" ($$2&& &$!AA /@4<G_^$YU0?H'LV'0<"-A /.("W] (.!A :("W]Y&$ !)P)&$ [@P+?WH80 $F"N<@/A ()AA .F4<G_^$YU/P#@2&$ 0P'Q\ Z AA $$!]A ( $.& X1![?S.0J@ ##%M_=0 &$/M^\\A20 @(7P ( ( D0F@ +$*H "Z@ CXH !!G" Q'_]EF 9R&V@ ("O[SDYU/SP 1C\\ $9(>@<60J=*+?W\9@@_//__0J=@ ( @_/ !2'H&^D*G2&W]'C\\ *IZDHM_1YG /MX/SP ($8_/ !&2'H(J4AZ!MI"ITAM_6@_/ !J>I*+?UH9P#[ (%1)[?T>80 %8' !1?@ &$ !+P[0/W4&WP ?WZ2D=F ( %[$(M_?XK?%1%6%3]X"M\(" @(/WD0FW]Z$)M_?)" ("W]]&$ !8A"04'M^\X2&&< ?Y@!@P8 "-G!E')__A@ (.(,00 (929A +>*T#]X&$ M8K0/WD#$$ !640#!@ ("1F"F$ M!E!#M _>AA -Z2>W]:&$ !)QA 2*80 $ (,@A;?W@ " A;?WD "0P+?WH@6@ ** -/B@ $&8 !5!A ( %#$/Z!C-A +X9@H;? !_?YA 3X/SP "C\\ $:H ()-(;?URJ(1#^@8N80 "U&8,2'H&QZB$80 $U& D0_H& ( =A *^9AI(>@:^J(1A 2^< ))[?UH1>WYQ&$ \9@ ( YP DGM_6A%[?G$80 #H#M _=8;? !_?M*1V8 !-!A ( $.F$ ?1@!&$ !()*+?O.9QY#^@6?80 ":&<&80 ! ( 1@YD/Z!;]A )89@1A 1>80 !D$GM_6@P+?W680 # ('I"+?W[0_H%D&$ C9G /](0_H%<V$ BIG /\\2>W] (!XP+?W480 #4D(M_?HO+?W&J11"IS\\ 1"IR\\____ (/^I?"M?_<Y#^@5R80 !]&8.0_H&%Q-8 !,36 48#1# (/H%4F$ =QF)D/Z!>T36 .$U@ #Q-8 ! 36 11?H& (!U'Z@ 1,"W]\F$ 7A@%$/Z!>Y%^@8<1^H %A M_?1A ( !:B\)+PI"IT*GJ8LO+?W.J15"ITAM_=*ID3 M_=(, ($ 6;N+RW]SJF#8 #Y!DGM_1XP+?W480 "H$(M_?I@ ( #X\F$ 49*+?W^9B0, 0 "94A"0&$ .)E0-$M_?0T ("W]\M1 YUH[0OWR80 7&#<0@=A H92(R & :80 (!YE&-$M_?0T+?WRU$#G6CM"_?)A T4<G_Y$YU= =* ( =F%AP8! 8 ( P& $!E!@ \ %.=>4.?@;C%N,04P=1 (,K_W@(\ /Y.=2)M_>H2P"M)_>I2K?WN#*T " _>YD ( ).=4CGPX!![?S.0J@ ##%M_=8 &$/MV<0A20 @(6W] (.X )$)H "Q"J NH ,^* 09@ "VDS? <-#[=G$*TG] (.I"K?WN3G5T ^&($!A305'*__A.=6$ )A "%!A3 ($$* @ P# ( "F4*!@( B0P" /IE# (" _I2( " CP (/Y.=3\ X$AA C ?'P#H"&$"$!]A!!; 3G4" / (# , Z90)> $YU0>W[SA(89PP,$ *9@92B%,!9O1. ('5AZ$)"%!FR F4,8 2S"&8&4<K_^D) 3G5"IS\\ %" (*<O//____^IO2M7_<:H<S\\ "HAS\\ RHBC\\ "H ((@_/ J(E.=6'./SP "C\\ !:HDTAZ S&HA!M\ 3] (/4K;?W@_?9(;?WUJ(0_/ */SP )JB32'H#-:B$*VW] (.3]]DAM_?6HA#\\ H_/ !FJ)-(>@,\J(1.=6$ _WP_ (#P "C\\ !:HDTAZ ]ZHA!M\ 3]]2MM_>#]]DAM_?6H ((0_/ */SP )JB32'H#WJB$*VW]Y/WV2&W]]:B$/SP ( H_/ !FJ)-(>@+HJ(1.=4'M_,Y"J ,0^P "B%) !(Q (&P !@ 6$6P "0 :3G5AX!% !LA2@ <H P* 8/B@ (!!.=6'*$4 &R%* !R@"C H !@^* 03G5![?S.0J@ ( PQ0 8H $^* 09@ ! $*H !(Q; & !:@$SXH !!F ( [$YU88B@"#XH !!F #>3G5A /]Z0F@ '* ,/B@ (!!G"@Q'_]5G'& ,(^//_3""@ !P H9@ M* )/B@ (!!F "J3G5A /]&0F@ '* ,/B@ $&8 )9.=4'M_,Y" (*@ ##%M_=8 %C%\ ( +$*H "Z@1#XH !!F !R3G5* ("W]^F<00BW]^DGM_1XP+?W480#_1DHM_?MG$$(M_?M) (.W]:# M_=9A /\P3G5![?S.0J@ ##%M_=0 &$/M^\\A ($D ("%\ _P D,7P-@ L0J@ +J "/B@ $&<(#$?_ (-EF *&V@ *_O.3G4_!V&.0J>I)" ?9PJPK?W&9@0O ( "I%$*G/SP D*G+SS_____J7PK7_W./A]A N+RW] (,ZI%3\\ 2IR$*G2&W]TJF1,"W]T@Q %F[B\M_<ZI ((,N;?W"8 #T[$'Z C="0! 89PJ^ &<&$!C0P&#R+PA" (*="IT*GJ8M.=4*G/SP :F_+Q="9ZDU+SQ$4E92J4U" (*<_/ "J;]"9ZDUJ3=.=4'MV<0P/"0\8 )"&%'(__Q. ('5415A4 "TH5&AI<R!F:6QE(&UU<W0@8F4@8V]N=F5R ('1E9"!W:71H($)I;DAE>"Y(97@I RHJ*@TJ*BI#3TU0 (%)%4U-%1! J*BI215-/55)#12!&3U)+#"HJ*D1!5$$@ ($9/4DL.*BHJ14Y$($]&($1!5$$'*BHJ0U)#.@PJ*BI# ($A%0TM354TZ)5194$4@;V8@;F5W(&9I;&4@:7,N+BXN ("XN+BXN+BXN+BXN+CH@(D-214%43U(@;V8@;F5W(&9I (&QE(&ES+BXN+BXN+BXN+CH@*$-O;G9E<G-I;VX@:6X@ ('!R;V-E<W,@+2!0;&5A<V4@<W1A;F0@8GG)#" Z($1A ('1A($9O<FL0(#H@4F5S;W5R8V4@1F]R:Q%#4D,@:6X@ (&9I;&4Z(# P,# 40VAE8VMS=6T@:6X@9FEL93H@,# < ($YO(&-H96-K<W5M('!R97-E;G0@:6X@9FEL9<D40V%L (&-U;&%T960@0U)#.B P,# P%T-A;&-U;&%T960@0VAE (&-K<W5M.B P,"%465!%(&]F($%P<&QI8V%T:6]N(&1O (&-U;65N="!I<SH@)$-214%43U(@;V8@07!P;&EC871I (&]N(&1O8W5M96YT(&ES.B 14V%V92!D;V-U;65N="!A (',ZWPY$:7)E8W1O<GD@9G5L;-X)1&ES:R!F=6QLW -) ("]/U!A7<FET92!P<F]T96-T960@9&ES:V5T=&73"T9I (&QE(&QO8VME9-(-5F]L=6UE(&QO8VME9 +1FEL92!S ('ES=&5M & "@ "8\ " " #\\ &I (/ $ 4@0 $X$ $R !.' !< ' $R A" ($Y(6 $I)0TXC 5D92148 !B0DY$3 &Y- ($5.50 ! 'I$3$]' , DD1)5$P P#"5TE.1 /)# ($]$10 ! /X /__ 3=@ @/__ ' 3=0 ((#__P 2 $W0 (#__P 2L $W, +__P 7@ ( !-Q !__\ %+ !-R $__\ 0) !-J #__\ ( #> 3; O__ #,0 3;@ ?__ "$@ 3< ( 3__P !"( $VD /__P Y$ $VL +__P TH ( !-M !__\ (K !-O !__\ 2V !-H __\@ $P 390 39@ ?__- $S0 39P ***END OF DATA ***CRC:609E !!ChuquiCo!!Software!! echo x - README cat >README <<'!!ChuquiCo!!Software!!' This directory contains the following files: BinHex.hex -- binhex version of binhex. This should be converted by xbin into a .rsrc file and downloaded to the mac. It can be used to convery binhex format files to their component parts on the mac and to generate binhex format files for uploading to unix and transport through the net. README - this file README.xbin - description of the xbin program. fromhexu.c - unix based program to decode .dl (an alternate form of network transmission) format files into .rsrc files for downloading. It is a filter, use it in the form 'fromhexu <file.dl >file.rsrc' macget.c- unix side of the download program. Set up macterminal to be an 8 bit path, no XON/XOFF, and that the computer on the other side is another Mac and then type macget on unix. Use the mouse to execute 'send file' from the 'File' menu. by default macget will get all three parts of the file (data, rsrc and info), but the -d -r and -i flags override that. The -u flag is used to download a text file (.data part) while doing neccessary translation of \r to \n to make it useful on a unix site. macput.c- unix side of the upload program. Same setup and option flags as macget, simply type 'macput <file>' to start, and macterminal will recognize it automatically. 'macput -u <file>' will do carriage return mapping from unix to the mac for you. tohexu.c - opposite of fromhexu. takes a .rsrc file and converts it to a .dl format for transmission. xbin.c - converts a BinHex format file to the component parts on the unix end. Equivalent to BinHex on the Macintosh end-- useful for bootstrapping BinHex to the Mac and doing the conversions before downloading (which shrinks the files somewhat). !!ChuquiCo!!Software!! echo x - README.xbin cat >README.xbin <<'!!ChuquiCo!!Software!!' This program will convert a file in BinHex format into binary files suitable for downloading via Macterminal / macput from a un*x host. It creates all three forks (.info, .data, and .rsrc), so that the filetype, author, create/modify times and eventually the file flags (ie the Bundle Bit) are all passed on to MacTerminal when the file is created on the Mac. When you receive a BinHex file in the mail or news, save the message in a file with extension ".hex" -- for example "freeware.hex". Then invoke "xbin freeware". This reads freeware.hex and creates freeware.data, freeware.rsrc, and freeware.info. When this is done, you can download through MacTerminal by running "macput freeware". The compressed data format is almost identical to that used by uuencode/uudecode. They both store 6 bits of data per byte, both offset the binary data by 0x20 (' '), and both have the number of bytes in the record at the beginning of each record. The difference is exactly 2 bits. In uuencode format the first byte contains the entire (6 bit) byte count, but in BinHex format the byte count is 8 bits -- 6 from the first byte, and 2 from the second. Note that the problem of trailing spaces has been worked around in this program -- short buffers are filled out with spaces as needed. So there is no need to manually restore lost spaces as before. As soon as I can figure out how the crc is computed I will post a new version of xbin which actually verifies the crc value. For now the crc line is ignored completely. Given the crc formula, it will be straightforward to write the complementary encoding program. How about calling it bhex? As usual, I'm open to suggestions and bug reports. I hope this will save a lot of people the trouble I went through to figure out the format . . . enjoy! Dave Johnson Brown University Computer Science ddj%brown@csnet-relay.ARPA {ihnp4,decvax,allegra,linus}!brunix!ddj !!ChuquiCo!!Software!! echo x - fromhexu.c cat >fromhexu.c <<'!!ChuquiCo!!Software!!' /* fromhex.c, UNIX version */ #include <stdio.h> int bytes,sum; main() { register i,v; register n; n = 0; v = 0; while ((i = getchar()) != EOF) { i &= 0177; if (i == '|') break; if (i < 0100 || i > 0117) continue; v = (v << 4) | (i & 0xF); if ((++n & 1) == 0) { putchar(v); sum += v; v = 0; bytes++; } } n = 0; for (i = 0 ; i < 8 ; i++) n = (n << 4) | (getchar() & 0xF); if (n != (bytes + sum)) fprintf(stderr, "bad checksum\n"); else fprintf(stderr, "checksum good!\n"); exit(0); } !!ChuquiCo!!Software!! echo x - macget.c cat >macget.c <<'!!ChuquiCo!!Software!!' #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 2 #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() * revised ddj 11/7/84 -- renamed send_sync() -> get_sync() */ 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 (get_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 */ } } } get_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(stdout); 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; } !!ChuquiCo!!Software!! echo x - macput.c cat >macput.c <<'!!ChuquiCo!!Software!!' /* Here is the source for the current incarnation of macput . . . . It is now compatible with the 0.5 Beta version of MacTerminal, and in case you still need to use the -0.15X version, there's the "-o" option to provide compatibility. Some minor bug fixes have been made, as well as a couple of changes for portability to non-4.2 systems. Please pass any improvements/bug fixes on to me, and if you know of any good protocols for use on a flow-controlled line, let me know. Dave Johnson ddj%brown@csnet-relay.arpa Brown University Computer Science */ #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; } } !!ChuquiCo!!Software!! echo x - tohexu.c cat >tohexu.c <<'!!ChuquiCo!!Software!!' #include <stdio.h> char hex[] = "@ABCDEFGHIJKLMNO"; int bytes,sum; unsigned long htonl(); main(argc,argv) char **argv; { register i,len; register char *cp; len = 0; while ((i = getchar()) != EOF) { bytes++; sum += i; putchar(hex[i>>4]); putchar(hex[i&0xF]); if (++len > 32) { putchar('\n'); len = 0; } } fprintf(stderr, "bytes %d, sum %d\n", bytes, sum); putchar('|'); sum += bytes; sum = htonl(sum); cp = (char *)∑ for (len = 0 ; len < 4 ; len++) { i = (*cp++ & 0xff); putchar(hex[i>>4]); putchar(hex[i&0xF]); } putchar('\n'); exit(0); } #define nohtonl #ifdef nohtonl /* if not in library */ /* * "Host" to "net" byte order swappers. */ unsigned short htons(a) unsigned short a; { unsigned short result; register char *sp = (char *)&a; register char *dp = (char *)&result; dp[1] = *sp++; dp[0] = *sp; return (result); } unsigned long htonl(a) unsigned long a; { unsigned long result; register char *sp = (char *)&a; register char *dp = (char *)&result; dp[3] = *sp++; dp[2] = *sp++; dp[1] = *sp++; dp[0] = *sp; return (result); } #endif !!ChuquiCo!!Software!! echo x - xbin.c cat >xbin.c <<'!!ChuquiCo!!Software!!' #include <stdio.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 DATABYTES 128 #define BYTEMASK 0xff #define NAMEBYTES 63 #define H_NLENOFF 1 #define H_NAMEOFF 2 /* 65 <-> 80 is the FInfo structure */ #define H_TYPEOFF 65 #define H_AUTHOFF 69 #define H_FLAGOFF XXX #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 struct macheader { char m_name[NAMEBYTES+1]; char m_type[4]; char m_author[4]; long m_flags; 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; FILE *ifp; int pre_beta; int compressed; /* * xbin -- unpack BinHex style .HEX file into suitable * format for downloading with macput * Dave Johnson, Brown University Computer Science * * (c) 1984 Brown University * may be used but not sold without permission * * created ddj 12/16/84 */ char usage[] = "usage: \"xbin [-o] [-n name] filename\"\n"; main(ac, av) char **av; { char *filename, *macname; filename = ""; macname = ""; ac--; av++; while (ac) { if (av[0][0] == '-') { switch (av[0][1]) { case 'o': pre_beta++; break; case 'n': if (ac > 1) { ac--; av++; macname = av[0]; break; } else goto bad_usage; default: goto bad_usage; } } else { if (*filename == '\0') filename = av[0]; else goto bad_usage; } ac--; av++; } if (*filename == '\0') { bad_usage: fprintf(stderr, usage); exit(1); } setup_files(filename, macname); parse_file(); forge_info(); /* now that we know the size of the forks */ } setup_files(filename, macname) char *filename; /* input file name -- .hex extension optional */ char *macname; /* name to use on the mac side of things */ { char namebuf[256]; int n, tdiff; struct tm *tp; struct timeb tbuf; struct stat stbuf; /* find input .hex file and open it */ sprintf(namebuf, "%s.hex", filename); if (stat(namebuf, &stbuf) != 0) { strcpy(namebuf, filename); if (stat(namebuf, &stbuf) != 0) { perror(namebuf); exit(-1); } } ifp = fopen(namebuf, "r"); if (ifp == NULL) { perror(namebuf); exit(-1); } /* set up names for output files and create them */ if (macname[0] == '\0') { macname = filename; } n = strlen(macname); if (n > NAMEBYTES) n = NAMEBYTES; strncpy(mh.m_name, macname, n); mh.m_name[n] = '\0'; sprintf(files.f_data, "%s.data", mh.m_name); close(creat(files.f_data, 0666)); sprintf(files.f_rsrc, "%s.rsrc", mh.m_name); close(creat(files.f_rsrc, 0666)); sprintf(files.f_info, "%s.info", mh.m_name); /* info file gets created later */ /* get file times and convert to mac time format */ 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; } forge_info() { char buf[DATABYTES]; char *np; FILE *fp; int n; 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_FLAGOFF, mh.m_flag); XXX */ 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("info file"); exit(-1); } fwrite(buf, 1, DATABYTES, fp); fclose(fp); } parse_file() { char ibuf[BUFSIZ]; int compressed = 0; int forks = 0; int n; while (fgets(ibuf, BUFSIZ, ifp) != NULL) { n = strlen(ibuf); if (n >= 7 && ibuf[0] == '#' || ibuf[n-6] == '$') { if (n >= 11) strncpy(mh.m_type, &ibuf[1], 4); if (n >= 15) strncpy(mh.m_author, &ibuf[5], 4); sscanf(&ibuf[n-5], "%4x", &mh.m_flags); break; } } while (forks < 2 && fgets(ibuf, BUFSIZ, ifp) != NULL) { if (forks == 0 && strncmp(ibuf, "***COMPRESSED", 13) == 0) { compressed++; continue; } if (strncmp(ibuf, "***DATA", 7) == 0) { mh.m_datalen = make_file(files.f_data, compressed); forks++; continue; } if (strncmp(ibuf, "***RESOURCE", 11) == 0) { mh.m_rsrclen = make_file(files.f_rsrc, compressed); forks++; continue; } } } static int crc; make_file(fname, compressed) char *fname; int compressed; { register int n; char ibuf[BUFSIZ]; FILE *outf; int nbytes = 0; outf = fopen(fname, "w"); if (outf == NULL) { perror(fname); exit(-1); } while (fgets(ibuf, BUFSIZ, ifp) != NULL) { if (strncmp(ibuf, "***END", 6) == 0) break; if (compressed) nbytes += comp_to_bin(ibuf, outf); else nbytes += hex_to_bin(ibuf, outf); } /* XXX read crc record and do crc check */ return nbytes; } #define SIXB(c) (((c)-0x20) & 0x3f) comp_to_bin(ibuf, outf) char ibuf[]; FILE *outf; { char obuf[BUFSIZ]; register char *ip = ibuf; register char *op = obuf; register int n, outcount; int numread, incount; numread = strlen(ibuf); ip[numread-1] = ' '; /* zap out the newline */ outcount = (SIXB(ip[0]) << 2) | (SIXB(ip[1]) >> 4); incount = ((outcount / 3) + 1) * 4; for (n = numread; n < incount; n++) /* restore lost spaces */ ibuf[n] = ' '; n = 0; while (n <= outcount) { *op++ = SIXB(ip[0]) << 2 | SIXB(ip[1]) >> 4; *op++ = SIXB(ip[1]) << 4 | SIXB(ip[2]) >> 2; *op++ = SIXB(ip[2]) << 6 | SIXB(ip[3]); ip += 4; n += 3; } fwrite(obuf+1, 1, outcount, outf); return outcount; } hex_to_bin(ibuf, outf) char ibuf[]; FILE *outf; { register char *ip = ibuf; register int n, outcount; int c; n = strlen(ibuf) - 1; outcount = n / 2; for (n = 0; n < outcount; n++) { c = hexit(*ip++); c = (c << 4) | hexit(*ip++); fputc(c , outf); } return outcount; } hexit(c) int c; { if ('0' <= c && c <= '9') return c - '0'; if ('A' <= c && c <= 'F') return c - 'A' + 10; } 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; } } !!ChuquiCo!!Software!! -- From the ministry of silly talks: Chuq Von Rospach {allegra,cbosgd,decwrl,hplabs,ihnp4,seismo}!nsc!chuqui nsc!chuqui@decwrl.ARPA Deadbone erotica is the prickly panic of forgotten milleniums, it is the moldy billion year madness that creeps deep along the spinal behind of my mind.