Published 2024-04-10.
Time to read: 7 minutes.
mainframe
collection.
I was tasked with working with a code example from the book entitled Designing & Programming with CICS Applications. The book includes a CD-ROM, archived here in a zip file.
The files in the CDROM/cicsadp/Cobol Application/TSO/
directory are intended to be loaded and used on a mainframe.
The load module of interest is CDROM/cicsadp/Cobol Application/TSO/loadlib/cicsadp.loa
.
My task is to load the module (provided in the zip file linked above), then run ABMLIST so the CSECTs that are defined and referenced from and by this load module are displayed. My task had three major steps:
- Transfer the files to my LPAR on the Maintec mainframe.
- Receive (convert) the files into appropriate data sets according to their purpose.
- Run ABMLIST.
- Run ASMDASM.
- Retrieve the results.
This article discusses the first two steps above. Listing CSECTs using ABMLIST discusses the third step. Disassembling mainframe COBOL with ASMDASM discusses the fourth step. Running JCL from a PC discusses the last step.
XMIT Files
These files to be transferred are provided in TSO Transmit (XMIT
) format.
XMIT files contain fixed-length records in EBCDIC format.
They must be transmitted to the mainframes in binary mode via FTP, SFTP or TELNET.
The Hercules documentation
provides the best explanation of the compressed XMIT
file format
and the two principal TSO commands for handling them: TRANSMIT
and RECEIVE
.
The TRANSMIT command packages sequential (
DSORG=PS
) or partitioned (DSORG=PO
) datasets
into a format that may be sent as a stream of 80 character records.
Partitioned datasets are first unloaded using the IEBCOPY
utility before being packaged into the 80 character format.
On the other end of the process, the
RECEIVE
command reverses the process reproduce the copy of the original datasets.
Xmit Manager XmitManager is a Windows-based tool that allows for the manipulation of IBM Mainframe created Xmit format files.
Old Modules
The book is devoted to discussing a program that was written, compiled and linked in July 2000, 24 years ago. The program runs in 31-bit mode and is not 64-bit compatible. IBM extended OS/390 to include 64-bit support in December 2001, 16 months after the book was published.
Step 1: Upload To My LPAR
The book says all the files need to be transferred and shows instructions on page 349. The instructions fail to mention the subdirectories that the source files reside in. It seemed likely to me that the destination files should be sent to the same directory, and in retrospect, this was correct.
Options I considered for transferring the file to the mainframe were:
Vista TN3270 Transfer
I tested by only transferring one file:
-
I did not change the default Vista TN3270 settings (menu item Options / Options / Misc):
-
Menu item Transfer / Send to Host:
-
The details for the transfer were:
- Selected the desired file to transfer (
cicsadp.loa
) - Set the Data mode to Binary
- Set the Host to TSO
- Type in the name of the file on the host
- Selected the desired file to transfer (
-
Looks like it worked! (The failed transfers were from a previous session.)
I note with interest that the Vista TN3270 Windows Help contains this page:
Here is the text of the section of interest:
IND$FILE transfer has various options, which are described in the list below. But please remember that the list was obtained by peeking at the IND$FILE load module, not from IBM documentation, and is a best guess. Most should probably be issued as name(parameter).
I found this procedure to be tedious and error-prone. The available tools are showing their age and do not work well; one reason is that IBM's documentation is inadequate.
Uploading Files Via FTP
This was the upload mechanism that I adopted. Not only can FTP upload files, it can also submit JCL files for execution and retrieve the results.
It took a fair while for me to discover that the files would not be receive
d unless they had a block size of 80.
The ftp
subcommand bin fixed 80
was insufficient for this purpose;
the mainframe’s ftp site
command needed to be used,
and for that the client’s tnftp quote
subcommand is required.
I discuss the details of using ftp
with a mainframe in
Running JCL from a PC.
Uploading One File
I wrote this bash script to simplify the transfer of an arbitrary file to a mainframe:
#!/bin/bash if [ -z "$1" ]; then echo "Error: a file name must be specified to transfer to the mainframe." exit 1 fi if [ ! -f "$1" ]; then echo "Error: '$1' does not exist" exit 1 fi ftp ftp://MIKES01:$MAINTEC_PWD@maintec <<EOF bin fixed 80 quote site lrecl=80 blksize=80 recfm=f put $1 $1 bye EOF
Here is an FTP session using the above script:
Uploading All Files
Following is a bash script to upload all the files with the proper settings, and store the files into the user default directory.
It uses an environment variable that I defined called loadlib
, which holds the directory path of the files to transfer.
#!/bin/bash cd "$loadlib" ftp ftp://MIKES01:$MAINTEC_PWD@maintec <<EOF binary fixed 80 quote site lrecl=80 blksize=80 recfm=f put copybook/cicsadp.cpy cicsadp.cpyseq put csddefs/cicsadp.csd cicsadp.csdseq put loadlib/cicsadp.loa cicsadp.loaseq put loadlib/cicsadp.cor cicsadp.corseq put source/cicsadp.src cicsadp.srcseq put source/cicsadp.mac cicsadp.macseq put vsam_jcl/cicsadp.jcl cicsadp.jclseq put vsam_data/cicsadp.txt cicsadp.txtseq bye EOF
The output from running the above was:
Connected to maintec. 220-FTPD1 IBM FTP CS V2R4 at MTI1, 17:07:50 on 2024-04-04. 220 Connection will close if idle for more than 5 minutes. 331 Send password please. 230 MIKES01 is logged on. Working directory is "MIKES01.". Remote system type is MVS. 200 Representation type is Image 200 Representation type is Image local: copybook/cicsadp.cpy remote: cicsadp.cpyseq 229 Entering Extended Passive Mode (|||12647|) 125 Storing data set MIKES01.CICSADP.CPYSEQ 100% |***************************************************************************| 95920 1.11 MiB/s 00:00 ETA 250 Transfer completed successfully. 95920 bytes sent in 00:00 (575.37 KiB/s) local: csddefs/cicsadp.csd remote: cicsadp.csdseq 229 Entering Extended Passive Mode (|||12648|) 125 Storing data set MIKES01.CICSADP.CSDSEQ 100% |***************************************************************************| 10000 27.09 MiB/s 00:00 ETA 250 Transfer completed successfully. 10000 bytes sent in 00:00 (202.39 KiB/s) local: loadlib/cicsadp.loa remote: cicsadp.loaseq 229 Entering Extended Passive Mode (|||12649|) 125 Storing data set MIKES01.CICSADP.LOASEQ 100% |***************************************************************************| 67680 851.45 KiB/s 00:00 ETA 250 Transfer completed successfully. 67680 bytes sent in 00:00 (545.79 KiB/s) local: loadlib/cicsadp.cor remote: cicsadp.corseq 229 Entering Extended Passive Mode (|||12650|) 125 Storing data set MIKES01.CICSADP.CORSEQ 100% |***************************************************************************| 2782 8.03 MiB/s 00:00 ETA 250 Transfer completed successfully. 2782 bytes sent in 00:00 (56.39 KiB/s) local: source/cicsadp.src remote: cicsadp.srcseq 229 Entering Extended Passive Mode (|||12651|) 125 Storing data set MIKES01.CICSADP.SRCSEQ 100% |***************************************************************************| 446 KiB 1.47 MiB/s 00:00 ETA 250 Transfer completed successfully. 457600 bytes sent in 00:00 (1.25 MiB/s) local: source/cicsadp.mac remote: cicsadp.macseq 229 Entering Extended Passive Mode (|||12652|) 125 Storing data set MIKES01.CICSADP.MACSEQ 100% |***************************************************************************| 19200 43.70 MiB/s 00:00 ETA 250 Transfer completed successfully. 19200 bytes sent in 00:00 (183.11 KiB/s) local: vsam_jcl/cicsadp.jcl remote: cicsadp.jclseq 229 Entering Extended Passive Mode (|||12653|) 125 Storing data set MIKES01.CICSADP.JCLSEQ 100% |***************************************************************************| 10161 29.81 MiB/s 00:00 ETA 250 Transfer completed successfully. 10161 bytes sent in 00:00 (156.34 KiB/s) local: vsam_data/cicsadp.txt remote: cicsadp.txtseq 229 Entering Extended Passive Mode (|||12654|) 125 Storing data set MIKES01.CICSADP.TXTSEQ 100% |***************************************************************************| 10720 28.39 MiB/s 00:00 ETA 250 Transfer completed successfully. 10720 bytes sent in 00:00 (225.22 KiB/s) 221 Quit command received. Goodbye.
A listing of the transferred files shows the record length and block size of all files are set to 80 characters.
ftp> ls cicsadp.* 229 Entering Extended Passive Mode (|||13075|) 125 List started OK Volume Unit Referred Ext Used Recfm Lrecl BlkSz Dsorg Dsname USER12 3390 2024/04/05 1 1 F 80 80 PS CICSADP.CORSEQ USER10 3390 2024/04/05 16 16 F 80 80 PS CICSADP.CPYSEQ USER01 3390 2024/04/05 2 2 F 80 80 PS CICSADP.CSDSEQ USER13 3390 2024/04/05 2 2 F 80 80 PS CICSADP.JCLSEQ USER03 3390 2024/04/05 11 11 F 80 80 PS CICSADP.LOASEQ USER11 3390 2024/04/05 4 4 F 80 80 PS CICSADP.MACSEQ USER11 3390 2024/04/05 16 16 F 80 80 PS CICSADP.SRCSEQ USER10 3390 2024/04/05 2 2 F 80 80 PS CICSADP.TXTSEQ 250 List completed successfully.
Uploading Required Files
I only need to upload 2 of the files for later analysis by AMBLIST
.
This script would suffice:
#!/bin/bash cd "$loadlib" ftp ftp://MIKES01:$MAINTEC_PWD@maintec <<EOF binary fixed 80 quote site lrecl=80 blksize=80 recfm=f put loadlib/cicsadp.loa cicsadp.loaseq put loadlib/cicsadp.cor cicsadp.corseq bye EOF
Step 2: Receiving Files
Once the files have been sent to the mainframe, they need to be unpacked and converted into partitioned datasets.
The TSO receive
command does this.
TSO Receive Commands
The TSO receive
command is documented
here.
The INDSNAME
and NONAMES
parameters are documented as:
INDSNAME(dsname) | INDATASET(dsname)
specifies the use of a sequential data set as the input data set to receive the transmitted data. Define the data set with RECFM=F, FB, V, VB, or U. For F and FB, LRECL=80. The remaining DCB attributes are installation dependent.
If you specify INDATASET or INDSNAME with RECEIVE, the transmitted data is not logged and no acknowledgment is sent to the originator. If you do not specify INDATASET, the transmitted data is logged into the log entry and an acknowledgment is sent to the originator.
Use INDSNAME and INDATASET in combination with OUTDSNAME and OUTDATASET operands of the TRANSMIT command.
INDSNAME and INDATASET are primarily intended for system programmer use.
NAMES | NONAMES
NAMES
specifies that RECEIVE search and resolve the NAMES data set for a matching node and user ID of the user who
transmitted the data or message.
If the nickname and name of the user are found, RECEIVE places the nickname, name, user ID, and node into the log data set.
If the nickname and name are not found, RECEIVE places only the user ID and node into the log data set.
All other NAMES data set processing remains the same.
For more information about the NAMES data set, see NAMES data set function under the TRANSMIT command.
NAMES is the default.
NONAMES
specifies that the nickname and name of the user who transmitted the data or message are not to be resolved.
RECEIVE places only the node and user ID in the log data set.
All other NAMES data set processing remain the same.
For more information about the NAMES data set, see NAMES data set function under the TRANSMIT command.
If you specify NONAMES with LOGDATASET or LOGDSNAME, the system does not process the NAMES data set.
Receiving All Files
The book says that the sequential files that were uploaded to the mainframe should be unloaded into TSO partitioned data sets.
After logging on to the mainframe, ISPF must be exited by typing X and then pressing Enter.
Now the receive
commands can be entered.
The I/O dialog for the receive
command is unusual;
it consists of an initial command, followed by an interactive question/response.
I am unaware of how to specify both parts in one command, so a script cannot be written for this task.
The complete set of commands to receive the files follows.
I inserted comments that begin with #; however, these should not be provided to TSO;
they are merely for the reader's benefit.
Note that my user id (MIKES01
) on the system was used;
if you attempt to replicate these steps, you will need to specify your user id instead.
# copy to a partitioned data set (PDS) receive indsname(cicsadp.cpyseq) NONAMES dsn('MIKES01.CICSADP.COBCOPY') # copy to a partitioned data set (PDS) receive indsname(cicsadp.csdseq) NONAMES dsn('CICSADP.CSDDEFS') # copy to a partitioned data set (PDS) receive indsname(cicsadp.loaseq) NONAMES dsn('MIKES01.CICSADP.LOADLIB') # copy to a partitioned data set extended (PDSE) receive indsname(cicsadp.corseq) NONAMES dsn('MIKES01.CICSADP.CORLIB') # copy to a partitioned data set (PDS) receive indsname(cicsadp.srcseq) NONAMES dsn('MIKES01.CICSADP.COBSRCE') # copy to a partitioned data set (PDS) receive indsname(cicsadp.macseq) NONAMES dsn('MIKES01.CICSADP.COBSRCE') # copy to a partitioned data set (PDS) receive indsname(cicsadp.jclseq) NONAMES dsn('MIKES01.CICSADP.JCL') # copy to a sequential data set (SDS) receive indsname(cicsadp.txtseq) NONAMES dsn('MIKES01.CICSADP.VSAMDATA')
Note that cicsadp.macseq
and cicsadp.srcseq
are received into the same dataset.
Executing the above commands resulted in the following, which has been broken out into separate chunks for readability. Some files were not properly received; they are highlighted.
cicsadp.cpyseq
receive indsname(cicsadp.cpyseq) NONAMES INMR901I Dataset CTS.V130.CICSJC.COPYLIB from JCOUSIN on WINMVS28 INMR906A Enter restore parameters or 'DELETE' or 'END' + dsn('MIKES01.CICSADP.COBCOPY') IEBCOPY MESSAGES AND CONTROL STATEMENTS PAGE 1 IEB1135I IEBCOPY FMID HDZ2240 SERVICE LEVEL UJ00519 DATED 20190816 DFSMS 02. 04.00 z/OS 02.04.00 HBB77C0 CPU 2828 IEB1035I MIKES01 ISPFPROC ISPFPROC 12:44:22 FRI 05 APR 2024 PARM='WORK=4M,SIZE=1M' COPY INDD=((SYS00143,R)),OUTDD=SYS00141 IEB1013I COPYING FROM PDSU INDD=SYS00143 VOL=USER08 DSN=SYS24096.T124422.RA000 .MIKES01.R0134071 IEB1014I TO PDS OUTDD=SYS00141 VOL=USER01 DSN=MIKES01.CICSADP.COBCOPY IEB167I FOLLOWING MEMBER(S) LOADED FROM INPUT DATA SET REFERENCED BY SYS00143 IEB154I NACCBRWS HAS BEEN SUCCESSFULLY LOADED IEB154I NACCCRUD HAS BEEN SUCCESSFULLY LOADED IEB154I NACCERRH HAS BEEN SUCCESSFULLY LOADED IEB154I NACCTREC HAS BEEN SUCCESSFULLY LOADED IEB154I NACTSET HAS BEEN SUCCESSFULLY LOADED IEB154I NACWBRWS HAS BEEN SUCCESSFULLY LOADED IEB154I NACWCRUD HAS BEEN SUCCESSFULLY LOADED IEB154I NACWERRH HAS BEEN SUCCESSFULLY LOADED IEB154I NACWLITS HAS BEEN SUCCESSFULLY LOADED IEB154I NACWLOCK HAS BEEN SUCCESSFULLY LOADED IEB154I NACWTREC HAS BEEN SUCCESSFULLY LOADED IEB1098I 11 OF 11 MEMBERS LOADED FROM INPUT DATA SET REFERENCED BY SYS00143 IEB144I THERE ARE 0 UNUSED TRACKS IN OUTPUT DATA SET REFERENCED BY SYS00141 IEB149I THERE ARE 5 UNUSED DIRECTORY BLOCKS IN OUTPUT DIRECTORY IEB147I END OF JOB - 0 WAS HIGHEST SEVERITY CODE INMR001I Restore successful to dataset 'MIKES01.CICSADP.COBCOPY'
cicsadp.csdseq
receive indsname(cicsadp.csdseq) NONAMES INMR901I Dataset CTS.V130.CICSJC.CSDDEFS from JCOUSIN on WINMVS28 INMR906A Enter restore parameters or 'DELETE' or 'END' + dsn('MIKES01.CICSADP.CSDDEFS') IEBCOPY MESSAGES AND CONTROL STATEMENTS PAGE 1 IEB1135I IEBCOPY FMID HDZ2240 SERVICE LEVEL UJ00519 DATED 20190816 DFSMS 02.04.00 z/OS 02.04.00 HBB77C0 CPU 2828 IEB1035I MIKES01 ISPFPROC ISPFPROC 13:45:18 FRI 05 APR 2024 PARM='WORK=4M,SIZE=1M' COPY INDD=((SYS00159,R)),OUTDD=SYS00158 IEB1013I COPYING FROM PDSU INDD=SYS00159 VOL=USER12 DSN=SYS24096.T134518.RA000.MIKES01.R0134091 IEB1014I TO PDS OUTDD=SYS00158 VOL=USER10 DSN=MIKES01.CICSADP.CSDDEFS IEB167I FOLLOWING MEMBER(S) LOADED FROM INPUT DATA SET REFERENCED BY SYS00159 IEB154I CICSJADP HAS BEEN SUCCESSFULLY LOADED IEB154I CICS0ADP HAS BEEN SUCCESSFULLY LOADED IEB1098I 2 OF 2 MEMBERS LOADED FROM INPUT DATA SET REFERENCED BY SYS00159 IEB144I THERE ARE 1 UNUSED TRACKS IN OUTPUT DATA SET REFERENCED BY SYS00158 IEB149I THERE ARE 5 UNUSED DIRECTORY BLOCKS IN OUTPUT DIRECTORY IEB147I END OF JOB - 0 WAS HIGHEST SEVERITY CODE INMR001I Restore successful to dataset 'MIKES01.CICSADP.CSDDEFS'
cicsadp.loaseq
receive indsname(cicsadp.loaseq) NONAMES INMR901I Dataset CTS.V130.CICSJC.COPYLIB from JCOUSIN on WINMVS28 INMR906A Enter restore parameters or 'DELETE' or 'END' + dsn('MIKES01.CICSADP.COBCOPY') IEBCOPY MESSAGES AND CONTROL STATEMENTS PAGE 1 IEB1135I IEBCOPY FMID HDZ2240 SERVICE LEVEL UJ00519 DATED 20190816 DFSMS 02.04.00 z/OS 02.04.00 HBB77C0 CPU 2828 IEB1035I MIKES01 ISPFPROC ISPFPROC 14:10:14 FRI 05 APR 2024 PARM='WORK=4M,SIZE=1M' COPY INDD=((SYS00192,R)),OUTDD=SYS00191 IEB1013I COPYING FROM PDSU INDD=SYS00192 VOL=USER13 DSN=SYS24096.T141014.RA000.MIKES01.R0134126 IEB1014I TO PDS OUTDD=SYS00191 VOL=USER10 DSN=MIKES01.CICSADP.LOADLIB IEB167I FOLLOWING MEMBER(S) LOADED FROM INPUT DATA SET REFERENCED BY SYS00192 IEB154I NACTSET HAS BEEN SUCCESSFULLY LOADED IEB154I NACT01 HAS BEEN SUCCESSFULLY LOADED IEB154I NACT02 HAS BEEN SUCCESSFULLY LOADED IEB154I NACT03 HAS BEEN SUCCESSFULLY LOADED IEB154I NACT04 HAS BEEN SUCCESSFULLY LOADED IEB154I NACT05 HAS BEEN SUCCESSFULLY LOADED IEB1098I 6 OF 6 MEMBERS LOADED FROM INPUT DATA SET REFERENCED BY SYS00192 IEB144I THERE ARE 12 UNUSED TRACKS IN OUTPUT DATA SET REFERENCED BY SYS00191 IEB149I THERE ARE 5 UNUSED DIRECTORY BLOCKS IN OUTPUT DIRECTORY IEB147I END OF JOB - 0 WAS HIGHEST SEVERITY CODE INMR001I Restore successful to dataset 'MIKES01.CICSADP.LOADLIB' %}
The above receive
command loaded the following modules defined by the book’s program:
NACCBRWS
, NACCCRUD
, NACCERRH
, NACCTREC
, NACTSET
,
NACWBRWS
, NACWCRUD
, NACWERRH
, NACWLITS
, NACWLOCK
and NACWTREC
.
cicsadp.corseq
ëñ+Bd
INMR901I Dataset X.RECEIVE.INVALID.FILE from ? on ?
INMR907A Enter copy parameters or 'DELETE' or 'END' +
cicsadp.srcseq
receive indsname(cicsadp.srcseq) NONAMES INMR901I Dataset CTS.V130.CICSJC.SRC from JCOUSIN on WINMVS28 INMR906A Enter restore parameters or 'DELETE' or 'END' + dsn('MIKES01.CICSADP.COBSRCE') INMR108I RECEIVE command terminated. Trailer record missing
cicsadp.macseq
receive indsname(cicsadp.macseq) NONAMES INMR901I Dataset CTS.V130.CICSJC.MAP from JCOUSIN on WINMVS28 INMR906A Enter restore parameters or 'DELETE' or 'END' + dsn('MIKES01.CICSADP.COBSRCE') IEBCOPY MESSAGES AND CONTROL STATEMENTS PAGE 1 IEB1135I IEBCOPY FMID HDZ2240 SERVICE LEVEL UJ00519 DATED 20190816 DFSMS 02.04.00 z/OS 02.04.00 HBB77C0 CPU 2828 IEB1035I MIKES01 ISPFPROC ISPFPROC 13:57:04 FRI 05 APR 2024 PARM='WORK=4M,SIZE=1M' COPY INDD=((SYS00179,R)),OUTDD=SYS00177 IEB1013I COPYING FROM PDSU INDD=SYS00179 VOL=USER04 DSN=SYS24096.T135704.RA000.MIKES01.R0134105 IEB1014I TO PDS OUTDD=SYS00177 VOL=USER15 DSN=MIKES01.CICSADP.COBSRCE IEB167I FOLLOWING MEMBER(S) LOADED FROM INPUT DATA SET REFERENCED BY SYS00179 IEB154I NACTSET HAS BEEN SUCCESSFULLY LOADED IEB1098I 1 OF 1 MEMBERS LOADED FROM INPUT DATA SET REFERENCED BY SYS00179 IEB144I THERE ARE 12 UNUSED TRACKS IN OUTPUT DATA SET REFERENCED BY SYS00177 IEB149I THERE ARE 5 UNUSED DIRECTORY BLOCKS IN OUTPUT DIRECTORY IEB147I END OF JOB - 0 WAS HIGHEST SEVERITY CODE INMR001I Restore successful to dataset 'MIKES01.CICSADP.COBSRCE'
cicsadp.jclseq
receive indsname(cicsadp.corseq) NONAMES
"¢ä|íëñ+ Bpïñ+(îë ä "¢ä|í
ëñ+Bd
INMR901I Dataset X.RECEIVE.INVALID.FILE from ? on ?
INMR907A Enter copy parameters or 'DELETE' or 'END' +
cicsadp.txtseq
receive indsname(cicsadp.txtseq) NONAMES INMR901I Dataset CTS.V130.CICSJC.TXT from JCOUSIN on WINMVS28 INMR906A Enter restore parameters or 'DELETE' or 'END' + dsn('MIKES01.CICSADP.VSAMDATA') INMR001I Restore successful to dataset 'MIKES01.CICSADP.VSAMDATA'
Receiving Minimal Files
The only two files of interest for AMBLIST to examine are:
CICSADP.LOADLIB
(received fromcicsadp.loaseq
)CICSADP.CORLIB
(received fromcicsadp.corseq
)
Thus, the TSO session above could be reduced to:
receive indsname(cicsadp.loaseq) NONAMES dsn('MIKES01.CICSADP.LOADLIB') receive indsname(cicsadp.corseq) NONAMES dsn('MIKES01.CICSADP.CORLIB')
Master’s Thesis
I was curious to know what the interwebs might reveal to me about the modules defined in the book’s program. Google brought me to a CS Master’s thesis submitted to the University of Leipzig: Generation of a standalone CICS business application accessed by the 3270 Interface and by MQSeries & Securing CICS with RACF.
The thesis explains in detail how the author worked through the book “Designing and Programming CICS Applications” and acknowledges the support he got while stationed at IBM Leipzig. Chapter 4.3, “The NACT COBOL programs and their commands”, describes the CICSADP program quite well. Page 62 of the thesis shows the CICS commands used by the various components of the program:
Appendix A (page 229) of the thesis discusses how to upload the files from the book provided on CD-ROM to the mainframe.
The author describes how he used ISPF to set the parameters for each transferred file, which seems excessively painful.
The author mentions that section 4.2 on page 48 of the book suggests using the quote site
ftp subcommand;
however, the author does not mention that the book fails to mention the import block size parameter.