Subject: v11i089: Transfer data (and mail) between SYSV and CMS Newsgroups: comp.sources.unix Sender: sources Approved: rs@uunet.UU.NET Submitted-by: Gary Mills Posting-number: Volume 11, Issue 89 Archive-name: diskdump [ These programs are used to transfer files (and files containing mail messages) between Unix (System V, but porting to BSD should be easy enough) and CMS, which I am led to believe is an operating system from the people responsible for the promulgation of MS-DOS. --r$ ] ================== #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file # 3. Execute the file with /bin/sh (not csh) to create the files: # # README # diskdump.mk # netdata.mk # diskdump.man # netdata.man # sendfile.man # diskdump.c # netdata.c # sendfile # if test -f 'README' then echo shar: will not over-write existing file "'README'" else echo extracting "'README'" sed 's/^X//' >README <<'SHAR_EOF' XDiskdump.c and netdata.c are written in C for System V. I use them Xas part of a mail gateway between CDNnet and Bitnet. They are Xuseful here because we run UTS unix under VM. The programs also Xcompile and run on our MVS system and are useful as a way to get Xfiles with lines longer than 80 characters out on Bitnet. X X-Gary Mills- SHAR_EOF if test 355 -ne "`wc -c < 'README'`" then echo shar: error transmitting "'README'" '(should have been 355 characters)' fi fi if test -f 'diskdump.mk' then echo shar: will not over-write existing file "'diskdump.mk'" else echo extracting "'diskdump.mk'" sed 's/^X//' >diskdump.mk <<'SHAR_EOF' X# %W% %G% %U% - Uofmcc/UTS XSHELL = /bin/sh XI = /usr/include X Xdiskdump: diskdump.c $I/stdio.h X $(CC) $(CFLAGS) -o diskdump diskdump.c -la X Xinstall: diskdump X /etc/install diskdump Xclean: Xclobber: clean X -rm -f diskdump SHAR_EOF if test 219 -ne "`wc -c < 'diskdump.mk'`" then echo shar: error transmitting "'diskdump.mk'" '(should have been 219 characters)' fi fi if test -f 'netdata.mk' then echo shar: will not over-write existing file "'netdata.mk'" else echo extracting "'netdata.mk'" sed 's/^X//' >netdata.mk <<'SHAR_EOF' X# %W% %G% %U% - Uofmcc/UTS XSHELL = /bin/sh XI = /usr/include X Xnetdata: netdata.c $I/stdio.h X $(CC) $(CFLAGS) -o netdata netdata.c -la X Xinstall: netdata X /etc/install netdata Xclean: Xclobber: clean X -rm -f netdata SHAR_EOF if test 212 -ne "`wc -c < 'netdata.mk'`" then echo shar: error transmitting "'netdata.mk'" '(should have been 212 characters)' fi fi if test -f 'diskdump.man' then echo shar: will not over-write existing file "'diskdump.man'" else echo extracting "'diskdump.man'" sed 's/^X//' >diskdump.man <<'SHAR_EOF' X.TH DISKDUMP 1 "LOCAL" X.SH NAME Xdiskdump \- produce CMS disk dump file X.SH SYNOPSIS Xdiskdump [-n -t ] X.SH DESCRIPTION XDiskdump converts a standard text file into CMS disk dump format Xand writes it to standard output as a Xstream of 80-byte binary and EBCDIC card images. XThis allows a text file with lines longer than 80 characters to be X"punched" to a CMS user. XIf is not specified, standard input is used. XThe command line options are: X.TP 12 X-n XSpecifies an internal filename for the CMS file. XThe default is "MAILER". X.TP 12 X-t XSpecifies an internal filetype for the CMS file. XThe default is "MAIL". X.SH EXAMPLES XSend a file to user MAILER on node UOFMCC: X.ti+8n Xdiskdump hello.c | lp -db -o"-r -v uofmcc.mailer" X.SH SEE ALSO Xlp(1), netdata(1x) X.SH BUGS XDiskdump will fold input lines longer than 254 characters. XIt will not handle binary files. XThe CMS file produced is always format V. XThe ASCII to EBCDIC translation may not conform to what is expected Xon the receiving system. SHAR_EOF if test 1025 -ne "`wc -c < 'diskdump.man'`" then echo shar: error transmitting "'diskdump.man'" '(should have been 1025 characters)' fi fi if test -f 'netdata.man' then echo shar: will not over-write existing file "'netdata.man'" else echo extracting "'netdata.man'" sed 's/^X//' >netdata.man <<'SHAR_EOF' X.TH NETDATA 1 "LOCAL" X.SH NAME Xnetdata \- produce CMS netdata file X.SH SYNOPSIS Xnetdata [-n -t -s -u -d -v ] X.SH DESCRIPTION XNetdata converts a standard text file into CMS netdata format Xand writes it to standard output Xas a stream of 80-byte binary and EBCDIC card images. XThis allows a text file with lines longer than 80 characters to be X"punched" to a CMS or TSO/E user. XIf is not specified, standard input is used. XThe command line options are: X.TP 12 X-n XSpecifies an internal file name for the CMS file. XThe default is "MAILER". X.TP 12 X-t XSpecifies an internal file type for the CMS file. XThe default is "MAIL". X.TP 12 X-s XSpecifies the approximate size of the file, for space allocation Xpurposes on the receiving system. XThis option is only needed when the input is standard input. XThe default is 2048 bytes. X.TP 12 X-u XSpecifies the origin user name. XThe default is "MAILER". X.TP 12 X-d XSpecifies the destination node name. XThe default is the local node. X.TP 12 X-v XSpecifies the destination user name. XThe default is "MAILER". X.SH EXAMPLES XSend a file to user MAILER on node UOFMCC: X.ti+2n Xnetdata -d uofmcc hello.c | lp -db -o"-r -v uofmcc.mailer" X.SH SEE ALSO Xlp(1), diskdump(1x) X.SH BUGS XNetdata will fold input lines longer than 253 characters. XIt will not handle binary files. XThe CMS file produced is always sequental and format V. XSpecifying wrong destination node or user names may confuse the Xreceiving system. XThe ASCII to EBCDIC translation may not conform to what is expected Xon the receiving system. SHAR_EOF if test 1645 -ne "`wc -c < 'netdata.man'`" then echo shar: error transmitting "'netdata.man'" '(should have been 1645 characters)' fi fi if test -f 'sendfile.man' then echo shar: will not over-write existing file "'sendfile.man'" else echo extracting "'sendfile.man'" sed 's/^X//' >sendfile.man <<'SHAR_EOF' X.TH SENDFILE 1 "LOCAL" X.SH NAME Xsendfile \- send a file to VM or to another node via RSCS X.SH SYNOPSIS Xsendfile [-v -d -o -p] X.SH DESCRIPTION XSendfile reads a text file, converts it to EBCDIC, and sends it Xto a VM user or, via RSCS, to a user at another NJE node. XThe default file format is CMS NETDATA. XThe command line options are: X.TP 12 X-d XSpecifies the destination node name. XThe default is the local node. X.TP 12 X-v XSpecifies the destination user name. XThe default is taken from the environment variable $VMID. X.TP 12 X-o XThe file will be sent in CMS DISK DUMP format. X.TP 12 X-p XThe file will be sent in CMS PUNCH format. X.SH EXAMPLES XSend a file to user MILLS on node UOFMCC: X.ti+2n Xsendfile -d uofmcc -v mills hello.c X.SH SEE ALSO Xlp(1), diskdump(1x), netdata(1x) X.SH BUGS XSendfile will not handle binary files. XThe CMS file produced is always sequental and format V. XThe ASCII to EBCDIC translation may not conform to what is expected Xon the receiving system. SHAR_EOF if test 1003 -ne "`wc -c < 'sendfile.man'`" then echo shar: error transmitting "'sendfile.man'" '(should have been 1003 characters)' fi fi if test -f 'diskdump.c' then echo shar: will not over-write existing file "'diskdump.c'" else echo extracting "'diskdump.c'" sed 's/^X//' >diskdump.c <<'SHAR_EOF' X/* diskdump.c: convert text file to CMS disk dump format */ X/* output is a stream of 80-byte card images */ X X/* Author: Gary Mills */ X/* */ X X/* Compilation Switches: */ X/* MVS: Waterloo C v1.3 for MVS */ X/* default: Amdahl UTS Unix System V */ X X/* #define MVS 1 */ X#include X#ifdef MVS X#define ATE(c) (c) X#else Xextern char atetab[128]; /* ASCII to EBCDIC translation table */ X X#define ATE(c) atetab[c] X#endif X#define NUL '\0' X#define SIZBUF 256 X#define CMSV struct cmsrec XCMSV X { X char dd_id[1]; /* 0x02 */ X char dd_cms[3]; /* "CMS" */ X char dd_fmt[1]; /* record format */ X char dd_data[50]; /* text */ X char dd_blk[2]; /* block count */ X char dd_fn[8]; /* file name */ X char dd_ft[8]; /* file type */ X char dd_fm[3]; /* file mode */ X char dd_seq[4]; /* sequence */ X }; X Xstatic char inbuf[SIZBUF]; Xstatic CMSV rec; Xstatic int recn, blkn; Xstatic int datax; Xstatic FILE *ofile; X Xmain(argc, argv) int argc; char **argv; X { X int n, num, max; X char *inpt; X FILE *ifile; X char c; X char *fname, *ftype, *pgm; X X ifile = stdin; X ofile = stdout; X fname = "mailer"; X ftype = "mail"; X pgm = *argv++; X --argc; X while ( argc ) X { X if ( **argv == '-' ) X { X c = tolower( (*argv)[1] ); X ++argv; X --argc; X if ( argc ) X { X --argc; X if ( c == 'n' ) X fname = *argv++; X else if ( c == 't' ) X ftype = *argv++; X else X { X ++argc; X break; X } X } X else X { X ++argc; X break; X } X } X else X { X if ( ( ifile = fopen(*argv, "r") ) == NULL ) X { X fprintf(stderr, "%s: cannot open %s\n", pgm, *argv); X return(1); X } X --argc; X break; X } X } X if ( argc ) X { X fprintf(stderr, "usage: %s [-n name -t type file]\n", pgm); X return(1); X } X#ifdef MVS X ofile = fopen("SYSUT2 ( bin", "w"); X#endif X num = max = 0; X iniout(fname, ftype); X while ( n = igets(ifile) ) X { X ++num; X while ( n > 1 && inbuf[n-1] == ' ' ) X --n; X inbuf[n] = NUL; X if ( n > max ) X max = n; X inpt = inbuf; X oput(n/256); X oput(n&255); X while ( n = *inpt++ ) X { X oput( ATE(n) ); X } X } X finout(num, max); X if ( ifile != stdin ) X fclose(ifile); X return 0; X } X X/* get input line, expanding tabs and padding null lines */ Xigets(fp) FILE *fp; X { X int c, col; X col = 0; X while ( ( c = getc(fp) ) != EOF ) X { X if ( c == '\t' ) X do X inbuf[col++] = ' '; X while ( col < SIZBUF-1 && col % 8 ); X else if ( c == '\n' ) X { X if ( col == 0 ) X inbuf[col++] = ' '; X break; X } X else X { X inbuf[col++] = c; X } X if ( !( col < SIZBUF-1 ) ) X break; X } X inbuf[col] = NUL; X return col; X } X X/* initialize output */ Xiniout(sn, st) char *sn, *st; X { X recn = blkn = 1; X datax = 0; X rec.dd_id[0] = 0x02; X mncopy(rec.dd_cms, "CMS", 3); X rec.dd_fmt[0] = ATE('V'); X memset(rec.dd_data, 0, 50); X mhalf(rec.dd_blk, blkn); X memset(rec.dd_fn, ATE(' '), 19); X mncopy(rec.dd_seq, "0001", 4); X mncopy(rec.dd_fn, sn, 8); X mncopy(rec.dd_ft, st, 8); X mncopy(rec.dd_fm, "A1", 3); X } X X/* finalize output */ Xfinout(n, m) int n, m; X { X oflush(); X oflush(); X rec.dd_fmt[0] = ATE('N'); X mhalf(&rec.dd_data[0], n+1); /* write pointer (number) */ X mhalf(&rec.dd_data[2], 1); /* read pointer (number) */ X mncopy(&rec.dd_data[4], "A1", 2); /* file mode */ X mhalf(&rec.dd_data[6], n); /* item count (number) */ X rec.dd_data[10] = ATE('V'); /* variable flag */ X mhalf(&rec.dd_data[14], m); /* max item length */ X mhalf(&rec.dd_data[16], blkn); /* number of blocks */ X mhalf(&rec.dd_data[26], blkn); /* alternate number of blocks */ X mhalf(&rec.dd_data[30], n); /* alternate item count */ X oflush(); X } X X/* add a byte to output */ Xoput(c) char c; X { X rec.dd_data[datax++] = c; X if ( datax >= 50 ) X { X oflush(); X datax = 0; X } X } X X/* write and re-initialize record */ Xoflush() X { X int n, r; X for ( n = 0; n < 80; ++n ) X putc(rec.dd_id[n], ofile); X memset(rec.dd_data, 0, 50); X if ( recn % 16 == 0 ) X ++blkn; X ++recn; X mhalf(rec.dd_blk, blkn); X r = recn; X for ( n = 3; n >= 0; --n ) X { X rec.dd_seq[n] = ATE(r % 10 + '0'); X r = r / 10; X } X } X X/* copy string to memory in upper case, not including NUL */ Xmncopy(s1, s2, n) char *s1, *s2; int n; X { X while ( --n >= 0 && *s2 ) X *s1++ = ATE( toupper(*s2++) ); X } X X/* copy two-byte integer to memory */ Xmhalf(s, n) char *s; int n; X { X s[0] = n/256; X s[1] = n&255; X } X X/**/ SHAR_EOF if test 4585 -ne "`wc -c < 'diskdump.c'`" then echo shar: error transmitting "'diskdump.c'" '(should have been 4585 characters)' fi fi if test -f 'netdata.c' then echo shar: will not over-write existing file "'netdata.c'" else echo extracting "'netdata.c'" sed 's/^X//' >netdata.c <<'SHAR_EOF' X/* netdata.c: convert text file to CMS netdata format */ X/* output is a stream of 80-byte card images */ X X/* Author: Gary Mills */ X/* */ X X/* Compilation Switches: */ X/* MVS: Waterloo C v1.3 for MVS */ X/* default: Amdahl UTS Unix System V */ X X/* #define MVS 1 */ X#include X#include X#ifdef MVS X#define ATE(c) (c) X#else X#include X#include Xextern long time(); Xextern struct tm *gmtime(); Xextern char atetab[128]; /* ASCII to EBCDIC translation table */ X X#define ATE(c) atetab[c] X#endif X#define NUL '\0' X#define TCAST (long *) X#define SIZBUF 254 X#define SIZREC 255 X#ifdef MVS X#define ONODE "UOFMCC" X#else X#define ONODE "UOFMCCX" X#endif X X/* control record identifiers */ X#define INMR01 "INMR01" X#define INMR02 "INMR02" X#define INMR03 "INMR03" X#define INMR06 "INMR06" X X/* text unit keys */ X#define INMLRECL 0x0042 X#define INMFNODE 0x1011 X#define INMFUID 0x1012 X#define INMTNODE 0x1001 X#define INMTUID 0x1002 X#define INMFTIME 0x1024 X#define INMNUMF 0x102f X#define INMSIZE 0x102c X#define INMDSORG 0x003c X#define INMUTILN 0x1028 X#define INMRECFM 0x0049 X#define INMTERM 0x0028 X#define INMDSNAM 0x0002 X#define INMFFM 0x102d X#define INMLCHG 0x1021 X Xstatic char inbuf[SIZBUF]; Xstatic char rec[SIZREC]; Xstatic char tvalue[21]; X#ifndef MVS Xstatic struct stat sbuf; X#endif Xstatic int count; /* output char count */ Xstatic FILE *ofile; /* output file */ X Xchar *acunit(), *abunit(), *acfield(), *inirec(), *membin(); X Xmain(argc, argv) int argc; char **argv; X { X int n; X char *pend, *pstar; X FILE *ifile; X char c; X char *ouser, *dnode, *duser; X char *tcurr, *tlast; X char *fname, *ftype, *pgm; X int fsize, maxl; X long tbuf; X struct tm *tpt; X X#ifdef MVS X tpt = localtime(); X#else X tbuf = time( TCAST 0 ); X tpt = gmtime(&tbuf); X#endif X sprintf(tvalue, "%04d%02d%02d%02d%02d%02d%06d", X tpt->tm_year+1900, tpt->tm_mon+1, tpt->tm_mday, X tpt->tm_hour, tpt->tm_min, tpt->tm_sec, 0); X tcurr = tlast = tvalue; X ifile = stdin; X ofile = stdout; X ouser = duser = fname = "MAILER"; X dnode = ONODE; X ftype = "MAIL"; X fsize = 0x0800; X maxl = SIZBUF-1; X X pgm = *argv++; X --argc; X while ( argc ) X { X if ( **argv == '-' ) X { X c = tolower( (*argv)[1] ); X ++argv; X --argc; X if ( argc ) X { X --argc; X if ( c == 'n' ) X fname = *argv++; X else if ( c == 't' ) X ftype = *argv++; X else if ( c == 'u' ) X ouser = *argv++; X else if ( c == 'd' ) X dnode = *argv++; X else if ( c == 'v' ) X duser = *argv++; X else if ( c == 's' ) X fsize = atoi(*argv++); X else X { X ++argc; X break; X } X } X else X { X ++argc; X break; X } X } X else X { X if ( ( ifile = fopen(*argv, "r") ) != NULL ) X { X#ifndef MVS X if ( 0 == fstat( fileno(ifile), &sbuf) ) X fsize = sbuf.st_size; X#endif X } X else X { X fprintf(stderr, "%s: cannot open %s\n", pgm, *argv); X return(1); X } X --argc; X break; X } X } X if ( argc ) X { X fprintf(stderr, "usage: %s [-n name -t type -u orig_user\n", pgm); X fprintf(stderr, " -d dest_node -v dest_user -s size file]\n"); X return(1); X } X#ifdef MVS X ofile = fopen("SYSUT2 ( bin", "w"); X if ( ofile == NULL ) X return 1; X#endif X X pend = inirec(rec, INMR01, -1); /* header */ X pend = abunit(pend, INMLRECL, 80, 2); X pend = acunit(pend, INMFNODE, ONODE); X pend = acunit(pend, INMFUID, ouser); X pend = acunit(pend, INMTNODE, dnode); X pend = acunit(pend, INMTUID, duser); X pend = acunit(pend, INMFTIME, tcurr); X pend = abunit(pend, INMNUMF, 1, 4); X finrec(rec, pend); X X pend = inirec(rec, INMR02, 1); /* output utility */ X pend = abunit(pend, INMSIZE, fsize, 8); X pend = abunit(pend, INMDSORG, 0x4000, 2); X pend = abunit(pend, INMLRECL, maxl, 4); X pend = acunit(pend, INMUTILN, "INMCOPY"); X pend = abunit(pend, INMRECFM, 0x0002, 2); X pstar = pend; X pend = acunit(pend, INMDSNAM, "A"); X pend = acfield(pend, fname); X pend = acfield(pend, ftype); X pstar[3] = 3; X pend = acunit(pend, INMFFM, "1"); X pend = acunit(pend, INMLCHG, tlast); X finrec(rec, pend); X X pend = inirec(rec, INMR03, -1); /* input data */ X pend = abunit(pend, INMSIZE, fsize, 8); X pend = abunit(pend, INMDSORG, 0x4000, 2); X pend = abunit(pend, INMLRECL, 80, 2); X pend = abunit(pend, INMRECFM, 0x0001, 2); X finrec(rec, pend); X X while ( n = igets(ifile) ) /* data records */ X { X while ( n > 1 && inbuf[n-1] == ' ' ) X --n; X inbuf[n] = NUL; X odata(n, inbuf); X } X X pend = inirec(rec, INMR06, -1); /* trailer */ X finrec(rec, pend); X X finout(); X return 0; X } X X/* get input line, expanding tabs and padding null lines */ Xigets(fp) FILE *fp; X { X int c, col; X col = 0; X while ( ( c = getc(fp) ) != EOF ) X { X if ( c == '\t' ) X do X inbuf[col++] = ' '; X while ( col < SIZBUF-1 && col % 8 ); X else if ( c == '\n' ) X { X if ( col == 0 ) X inbuf[col++] = ' '; X break; X } X else X { X inbuf[col++] = c; X } X if ( !( col < SIZBUF-1 ) ) X break; X } X inbuf[col] = NUL; X return col; X } X X/* initialize control record */ Xchar *inirec(pt, s, n) char *pt, *s; int n; X { X *pt++ = 0; /* length bythe */ X *pt++ = 0xe0; /* flag byte */ X while ( *s ) /* identifier */ X *pt++ = ATE( toupper(*s++) ); X if ( n > 0 ) /* number of files */ X pt = membin(pt, n, 4); X return pt; X } X X/* finalize control record */ Xfinrec(pt, pe) char *pt, *pe; X { X *pt = pe - pt; /* length byte */ X while ( pt < pe ) /* record */ X { X putc(*pt, ofile); X ++pt; X ++count; X } X } X X/* add a binary text unit */ Xchar *abunit(pt, k, v, n) char *pt; int k, v, n; X { X pt = membin(pt, k, 2); /* key */ X pt = membin(pt, 1, 2); /* count */ X pt = membin(pt, n, 2); /* length */ X pt = membin(pt, v, n); /* value */ X return pt; X } X X/* add a character text unit */ Xchar *acunit(pt, k, s) char *pt; int k; char *s; X { X pt = membin(pt, k, 2); /* key */ X pt = membin(pt, 1, 2); /* count */ X pt = membin(pt, strlen(s), 2); /* length */ X while ( *s ) /* value */ X *pt++ = ATE( toupper(*s++) ); X return pt; X } X X/* add a character field */ Xchar *acfield(pt, s) char *pt, *s; X { X pt = membin(pt, strlen(s), 2); /* length */ X while ( *s ) /* value */ X *pt++ = ATE( toupper(*s++) ); X return pt; X } X X/* add a binary item */ Xchar *membin(pt, v, n) char *pt; int v, n; X { X char *pe; X pe = pt + n; X while ( --pe >= pt ) X { X *pe = v; X v = v / 256; X } X return pt + n; X } X X/* write a data record */ Xodata(n, pt) int n; char *pt; X { X char *pe; X pe = pt + n; X putc(n+2, ofile); /* length byte */ X putc(0xc0, ofile); /* flag byte */ X count = count + 2; X while ( pt < pe ) /* data */ X { X putc(ATE(*pt), ofile); X ++pt; X ++count; X } X } X X/* pad last record */ Xfinout() X { X while ( count % 80 ) X { X putc(0, ofile); X ++count; X } X } X X/**/ SHAR_EOF if test 6988 -ne "`wc -c < 'netdata.c'`" then echo shar: error transmitting "'netdata.c'" '(should have been 6988 characters)' fi fi if test -f 'sendfile' then echo shar: will not over-write existing file "'sendfile'" else echo extracting "'sendfile'" sed 's/^X//' >sendfile <<'SHAR_EOF' X: X# Send a file to a user at another node XV="$VMID" XD="" XF="NETDATA" XCMD=$0 XL="/usr/cserv/mills/sendfile" XSKIP="" X Xfor ARG do X if [ "$SKIP" ]; then X SKIP="" X else X case $ARG in X -v) shift; V="$1"; SKIP="Y"; shift;; X -d) shift; D="$1"; SKIP="Y"; shift;; X -o) shift; F="DISK DUMP";; X -p) shift; F="PUNCH";; X -*) echo $CMD: invalid option \'$ARG\'; exit 1;; X esac X fi Xdone X Xif test ! -r $1; then X echo $CMD: file $1 is not readable; X exit 1; Xfi X Xif [ x"$D" = "x" ]; then X X="$V";D="UOMFCCX";echo Sending file $1 to $V in $F format.; Xelse X X="$D"."$V";echo Sending file $1 to "$V"@"$D" in $F format.; Xfi X Xcase $F in X D*) $L/diskdump -n $LOGNAME $1 | X lp -db -o"-r -v $X -f $LOGNAME";; X N*) $L/netdata -n $LOGNAME -v $V -d $D $1 | X lp -db -o"-r -v $X -f $LOGNAME";; X *) lp -db -o"-v $X -f $LOGNAME" < $1;; Xesac SHAR_EOF if test 840 -ne "`wc -c < 'sendfile'`" then echo shar: error transmitting "'sendfile'" '(should have been 840 characters)' fi fi # end of shell archive exit 0