In the middle months of 2000, a colleague came to me with a question. He wanted to know if there was any way that we could have our mainframe host systems email their reports to selected email addresses. After some investigation, I had to tell him that, with existing, approved tools, there was no way that we could arrange to have a mainframe application send email. "However," I said, "there is a way to do this through the back door." I explained that the mainframe supports various modes of printing, and that with suitable arrangement, it could be persuaded to direct print output to a Unix system that could then email the data as it saw fit.
Although this back-door approach was not acceptable to the situation that he was investigating at the time, the idea stayed with me. A year later, the question came up again, but this time the situation was not as critical and I was given some latitude to investigate the possibilities. My co-workers (Rob Corr and Phil Robson) and I crafted two "proof-of-concept" implementations, one using tools that, while they weren't approved for our use, were built to provide mainframe application access to email, and the other being the 'back-door' approach that I had suggested the previous year. This paper describes how we implemented our 'back-door' proof-of-concept mainframe "print-to-email" using a spare Linux box, some simple tools, and a bit of knowledge.
Our goal was to be able to have host output, generated from an IMS transaction, a CICS transaction, or a batch job, routed to an arbitrary, application selected email address. As there was no direct route from the host online systems to our email service, we decided to try an indirect route through a spare Linux box on our LAN. This proof-of-concept was not meant to be a production-ready facility, but instead was intended simply to assist in determining what problems would have to be resolved, and how a production-ready facility would have to be built.
At our disposal were:
In theory, it should have been possible to "print to email" using these existing MVS/JES and Unix facilities. The process would be:
In general, the flow of print data from sending application to receiving client looks like this diagram.
Our Linux system was a minimal installation of Slackware 7.0 on a spare Pentium 90 processor. We had used this system for a number of proof-of-concept tests and it was sitting idle and available for our print-to-email trial. We configured the system to accept lpd spool requests from the host (indirectly, from the NT "protocol converter" system), process the print into emailable text, and email the text according to the requirements embedded in the print data's JES2 flash page
In order to permit the Windows NT protocol converter access to the Linux lpd resources, we had to add the NT system to the lpd security files. Since the NT system was assigned a DHCP IP address but no dynamic DNS (dDNS) hostname, we included it's IP address to the /etc/hosts file along with a fake hostname, and added the fake hostname to the /etc/hosts.lpd
Next, the lpd printer 'jesprt' was defined in the /etc/printcap file. This definition includes details on the spool directory (/var/spool/lpd/jesprt) and spool filter program (/var/spool/lpd/jesprt.filter) to be used to process print to email.
Finally, the print filter (/var/spool/lpd/jesprt.filter) and it's support programs were written. jesprt.filter respooled the print data to a temporary file, then extracted the destination email address and other details from the spooled data. Once all the particulars had been established, the temporary file was emailed to the destination and the local copy was deleted.
I wrote four support modules for this filter:
/usr/local/bin/collapse took the print data prepared by the NT "protocol converter" program and reformatted it into text lines. This was necessary because the protocol conversion generated large print files where each print line consisted of many lines overprinting each other. As the print filter extracted information from the print data, this overprinting had to be 'collapsed' into single print lines. Additionally, the protocol conversion performed a unique form of overprinting, where each pair of blocks of overprint were positioned 1 character to the right of the previous pair., which, if not accommodated, would lead to errors in the resulting print data.
/var/spool/lpd/tools/jesprt.mailto.awk looked through the leading flashpage, and extracted a destination email address from the data. It checked in three places for the target email address:
The "USERID:" username was fixed at MVS/JES2 job submission time. However, the "EMAIL:" email addresses were dynamically assigned through one of four ADDRESS parameters passed to the JES2 print spooling system. The two possibilities accounted for in the awk script accommodated the placement of the email address in the first or the second and subsequent ADDRESS parameters. If the email address text was passed through the first ADDRESS parameter, then that text would be found in the flash page as part of the first line of the "ADDRESS:" line, and prefixed with a "EMAIL:" sentinel text. However, if the email address text was passed through a subsequent ADDRESS parameter, then the email address would be found in the flash page as a stand-alone line and prefixed with a "EMAIL:" sentinel text.
Finally, no email address text were passed in any of the ADDRESS parameters, then the email address would default to the MVS LOGONID for the job, which was found as the username that follows the "USERID:" sentinel text in the flashpage.
/var/spool/lpd/tools/jesprt.subject.awk looked through the leading flashpage, and extracted an email subject line from the data. It obtained this information from the text that follows the "TITLE:" sentinel text in the flash page. Any text populated to the TITLE parameter was placed here by JES2. For example, if the host program set the TITLE to the text string "email subject goes here", JES2 would populate it to the flashpage, and /var/spool/lpd/tools/jesprt.subject.awk would extract the text "email subject line goes here"from the flashpage. This text was then be used to prepare the email subject line. If no text was found, the email subject line would just indicate the source jobname, jobnumber, and system, as found on the flashpage.
/var/spool/lpd/tools/jesprt.notice.text carried a notice text that is appended to the end of every report respooled by this print filter. This allows us to add a "message of the day" to each print report indicating the processing performed on it, if we desire.
The VPS print spool package on the host communicated using SNA LU1 to a package running on a Microsoft Windows NT system . This package reprocessed the print data using Window NT printer drivers to communicate with the LAN-attached printers. We arranged for the owners of this system to setup the connection between JES2 remote PTE01 and our Linux jesprt lpd printer. On the Windows NT side, this printer was configured as a "Generic" / "Generic/Text Only" print driver using a local "Microsoft LPR" port connected to printer jesprt on the Linux server.
The Windows NT protocol converter was configured so as not to suppress the JES2 flashpages (suppression is the default setting), so that the Linux side could retrieve the email subject and address metadata from the JES2 flash page text. Host applications would be expected to generate their output and direct it to a JES2 "SYSOUT". JES2 "SYSOUT"s act like pipes into the print spooling system.
On the MVS/JES2 side, applications can use one of three different methods of spooling print output, depending on their environmental requirements: BATCH print spooling, IMS "Spool API" print spooling, and CICS "Spool API" print spooling.
MVS/JES2 supports a background processing system that uses JCL (or "Job Control Language") instructions to control the execution of programs and the distribution of their print data. In this environment, print data is referred to as "SYSOUT", which stands for "System Output".
Any SYSOUT directed to (in our case) printer DEST=PTE01 would be respooled (by JES2) to VPS, and on to the lpd support on our Linux system. The JES2 OUTPUT JCL statement was used to set the email subject line and target email address for the report.
The format and use of the JCL OUTPUT statement is documented in Chapter 22 of the OS/390 V2R10 MVS JCL Reference, while the format and use of the DD SYSOUT is documented in Chapter 12 of the same manual.
For our IMS transaction to print to the JES2 spool (and thus onwards to email), it had to perform DLI CHNG and ISRT calls to a modifiable alternate non-express PCB.
First, the transaction's application code prepared specific WORKING-STORAGE variables and performed a CHNG call to redirect the alternate modifiable non-express PCB (in this case PCB APM00001) to the IMS Spool interface.
Then, the application performed one or more ISRT calls to send print data to the PCB. The print data was placed in a structure which was passed through the IMS ISRT call to the JES2 print queue.
This ISRT was repeated for each line of the text to be emailed. The email would be released to the spool at the end of the Unit of Work (at COMMIT or at the next GU on the IOPCB), or when the next CHNG call to the modifiable alternate non-express PCB was executed.
Appendix A of the "IMS Version 7 Application Programming: Design Guide" provides a technical overview of the IMS SPOOL API and it's use in a JES2 environment. Sections 1.3.2 and 1.3.7 from the "IMS Version 7 Application Programming: Transaction Manager" manual provides details on the specific IMS DLI calls necessary to spool output to MVS, and section 1.56 of the TSO/E V2R5 Command Reference manual provides the format and values of the spool control parameters.
For a CICS transaction to print to the JES2 spool (and onward to email), it must use the CICS SPOOL API. The documentation here in the "CICS Application Programming Reference" describes the SPOOLOPEN/SPOOLWRITE/SPOOLCLOSE verbs that must be used to create a JES2-spooled report.
First, the application must SPOOLOPEN the printer. This is a bit tricky because the SPOOLOPEN verb requires the print options parameter to be an indirect pointer to the print options list. To enable this, the program must execute logic to GETMAIN some storage, manipulate the returned pointer to the GETMAINed memory to conform with CICS requirements, move the print options list into the GETMAINed memory, use the GETMAINed area in the SPOOLOPEN verb, and FREEMAIN the print options storage once the SPOOLOPEN is complete.
Once this is done, the program can repeatedly load a print buffer with text data and EXECutes the SPOOLWRITE function to write each line of report data to the spool.
When all the print data has been spooled, the program then EXECutes the SPOOLCLOSE function to close the spool and send the spooled output onward to the printer.
Section 5.6 of the CICS TS for OS/390 V1R3 Application Programming Guide provides an overview of the CICS SPOOL API and examples of it's use, while Sections 1.227 through 1.231 of the CICS TS for OS/390 V1R3 Application Programming Reference provides details on the specifics of the various EXEC SPOOLxxxx calls necessary to spool output to MVS, while section 1.56 of the TSO/E V2R5 Command Reference manual provides the format and values of the spool control parameters used in the EXEC SPOOLOPEN call.
From this exercise, we not only established that a "print-to-email" facility could be built without intrusion into the realm of MVS system programming, we also established that it was easy to build such a system. Even if we shelve this project, the techniques we learned (IMS and CICS SPOOLING APIs, JES2 printer setup, Linux and BSD LPD print spooler setup, etc.) can easily be applied to other projects in our domain.
For what it's worth, we learned a lot. We stood on the shoulders of giants and saw further than we could have on our own. Perhaps we too have now given our successors a footing from which to climb to greater heights.
So, do you feel like doing a bit of climbing?
This article has several supplemental files which are linked extensively in the text. For convenience, here's a listing of all the files: