{"id":4828,"date":"2014-12-17T11:47:42","date_gmt":"2014-12-17T09:47:42","guid":{"rendered":"http:\/\/www.limilabs.com\/blog\/?p=4828"},"modified":"2015-01-02T10:57:54","modified_gmt":"2015-01-02T08:57:54","slug":"using-limilabs-ftp-dll-with-zos-mainframes","status":"publish","type":"post","link":"https:\/\/www.limilabs.com\/blog\/using-limilabs-ftp-dll-with-zos-mainframes","title":{"rendered":"Using Limilabs\u2019 Ftp.dll with zOS Mainframes"},"content":{"rendered":"<p>I purchased the Limilabs FTP product for FTP because I needed to send data to and from an IBM mainframe from my VB.NET program running in Windows. In particular I needed to be able to submit jobs, and receive the job output. These notes show how it&#8217;s done.<\/p>\n<h2>Introduction<\/h2>\n<p>FTP to\/from IBM computers is pretty much like any other FTP except for two things.<br \/>\n1. IBM Mainframe and Midrange computers mostly use EBCDIC encoding rather than ASCII.  With the FTP defaults your data can be garbled and useless when it arrives at the other end.<br \/>\n2. The SITE command is used to submit jobs to the mainframe, and get the results back.<\/p>\n<h2>Getting Started<\/h2>\n<p>I created a class called &#8220;JazzFTP&#8221; to wrap the Limilabs&#8217; code.  This was going to contain the functions that I wanted for my project, and so I started by defining the common elements that all methods would use. In my situation every FTP would be authenticated, and would be exchanging text data (not binary) with the remote computer.<\/p>\n<p>Here is the initial class definition:<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\nImports Limilabs.FTP.Client\r\n\r\nPublic Class JazzFTP\r\n    '   This class wraps the FTP library from Limilabs (\/ftp)\r\n    '   All methods\r\n    '   1   Connect and logon using information from MySettings:  Sub LoginFTP\r\n    '   2   Perform their action based on their parameters\r\n    '   3   Close the connection\r\n    Dim ftp As New Ftp()\r\n    Dim response As FtpResponse\r\n    Private Sub LoginFTP()\r\n        ftp.Connect(My.Settings.SubmitIP)\r\n        ftp.Login(My.Settings.Userid, My.Settings.Password)\r\n    End Sub\r\n    '   My functions will be written here\r\nEnd Class\r\n<\/pre>\n<h2>Basic FTP<\/h2>\n<p>Here is my first method, a basic function to upload a text file: &#8211;<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n    Function Upload(DestinationFile As String, Uploadfile As String) As String \r\n        LoginFTP()\r\n        ftp.TransfersDataType = FtpDataType.Ascii\r\n        response = ftp.Upload(DestinationFile, Uploadfile)\r\n        ftp.Close()\r\n        Return response.message\r\n    End Function\r\n<\/pre>\n<p>FTP\u2019s default is Binary, which is correct if you are transmitting a .JPG or other binary object, and it probably doesn&#8217;t matter if you are transmitting text to\/from another Windows computer or a Unix computer. However if you are transmitting to\/from an IBM mainframe or midrange computer it probably needs EBCDIC rather than ASCII characters.  You must tell it that the file is Ascii text, not binary, otherwise it won&#8217;t be converted and it will be gibberish when you examine it on the mainframe. <\/p>\n<p>Although this code above works, it is very fragile: the FTP server has to be up and running, you have to get the connection details exactly right, the source and destination files must exist, and so on. Since I couldn&#8217;t guarantee all of these details, I enclosed the code in Try\/Catch to deal with any errors.  For the time being I&#8217;ve simply used MsgBox to display the error message.<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n    Function Upload(DestinationFile As String, Uploadfile As String) As String\r\n        Try\r\n            LoginFTP()\r\n            ftp.TransfersDataType = FtpDataType.Ascii\r\n            response = ftp.Upload(DestinationFile, Uploadfile)\r\n            ftp.Close()\r\n            Return response.EndLine\r\n        Catch ex As Exception\r\n            MsgBox(ex.Message)\r\n            Return ex.Message\r\n        End Try\r\n    End Function\r\n<\/pre>\n<p>Download, which is not illustrated, is similar except that you&#8217;d use ftp.Download. Again, you specify:<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n            ftp.TransfersDataType = FtpDataType.Ascii\r\n<\/pre>\n<h2>Submitting Jobs and Receiving Job Output<\/h2>\n<p>Submitting a job is essentially an upload with a twist.  Instead of uploading the file containing the job to a named file on the mainframe, you upload it to the JES (Job Entry System) input queue.  Here is the basic code:<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n            response = ftp.Site(&quot;FILETYPE=JES&quot;)\r\n            ftp.TransfersDataType = FtpDataType.Ascii\r\n            response = ftp.Upload(&quot;JES&quot;, JCLFile)\r\n<\/pre>\n<p>The first line uses \u201cftp.Site\u201d.  Site means that this is a site-specific command, something that the FTP system at the other end will presumably know about. For an IBM mainframe &#8220;FILETYPE=JES&#8221; means that the data is going to and from JES.<\/p>\n<p>The third line uploads the file in which we have prepared our job: in this case JCLFile is a file containing something like this: &#8211;<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n\/\/IBMUSERH JOB  ,CLASS=A,MSGCLASS=H,NOTIFY=&amp;SYSUID,COND=(8,LT) \r\n\/\/*** COPY SOURCE INTO SOURCE LIBRARY\r\n\/\/COPY EXEC PGM=IEBGENER\r\n\/\/SYSPRINT DD SYSOUT=*\r\n\/\/SYSIN DD DUMMY\r\n\/\/SYSUT2 DD DSN=IBMUSER.MANAJAZZ.SRCLIB(CRDTA1),DISP=SHR\r\n\/\/SYSUT1 DD *\r\n<\/pre>\n<p>Like any upload the FTP client syntax requires a destination file name, but because of the preceding FILETYPE=JES this will be ignored. I have written \u201cJES\u201d purely for documentation.<\/p>\n<p>This will submit the job and it will run, appearing in the output like this: <\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"\/blog\/wp-content\/uploads\/2014\/09\/tasks.png\" alt=\"tasks\" width=\"811\" height=\"240\" class=\"aligncenter size-full wp-image-4830\" srcset=\"https:\/\/www.limilabs.com\/blog\/wp-content\/uploads\/2014\/09\/tasks.png 811w, https:\/\/www.limilabs.com\/blog\/wp-content\/uploads\/2014\/09\/tasks-300x88.png 300w\" sizes=\"(max-width: 811px) 100vw, 811px\" \/><\/p>\n<p>Of course we can view the job output on the mainframe, but we may want to return it to Windows.  We do this by downloading the file by naming the JobID \u2013 JOB00594 in this case \u2013 and again using the Site command. The essential code is: &#8211;<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n        response = ftp.Site(&quot;FILETYPE=JES&quot;)\r\n        ftp.TransfersDataType = FtpDataType.Ascii\r\n        ftp.Download(Jobname, LocalPath)\r\n<\/pre>\n<p>But how do we get the Jobname?  JES returns a message with this information when the job is submitted.  We need to add code to  the Job Submission logic to extract this from the message.  In function JobSub<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n       response = ftp.Upload(&quot;JES&quot;, JCLFile)\r\n<\/pre>\n<p>upload the job and (if all goes well) returns a message like<br \/>\n&#8220;It is known to JES as JOB00594&#8243;<br \/>\nThis code extracts JOB00594&#8221; and puts it into variable JobName<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n       Dim TestString As String = &quot;It is known to JES as&quot;\r\n       If Mid(response.Message, 1, Len(TestString)) = TestString Then  'Should be true\r\n           Jobname = Trim(Mid(response.Message, Len(TestString) + 1))\r\n       End If\r\n<\/pre>\n<p>Now, since it is logical that if we submit a job we&#8217;ll want to get it back, I coded this in the JobSub function: &#8211;<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n    Function JobSub(JCLFile As String, ByRef Jobname As String) As FtpResponse\r\n        '   JCLFile is path to a .JCL file (format .txt) containing the job to be submitted\r\n        '   If successful submission, the job name is returned in JobName\r\n        Dim Tstring As String = &quot;&quot;\r\n        Try\r\n            Jobname = &quot;Unknown&quot;\r\n            LoginFTP()\r\n            response = ftp.Site(&quot;FILETYPE=JES&quot;)\r\n            ftp.TransfersDataType = FtpDataType.Ascii\r\n            response = ftp.Upload(&quot;JES&quot;, JCLFile)\r\n            Dim TestString As String = &quot;It is known to JES as&quot;\r\n            If Mid(response.Message, 1, Len(TestString)) = TestString Then  'Should be true\r\n                Jobname = Trim(Mid(response.Message, Len(TestString) + 1))\r\n            End If\r\n            JobGet(Jobname, False)\r\n            ftp.Close()\r\n        Catch ex As Exception\r\n            MsgBox(ex.Message, MsgBoxStyle.OkOnly, &quot;Jazz FTP&quot;)\r\n            Return response\r\n        End Try\r\n        Return response\r\n    End Function\r\n<\/pre>\n<p>and I coded JobGet to accept these parameters: &#8211;<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n    Function JobGet(Jobname As String, Optional Login As Boolean = True) As FtpResponse\r\n        '   Get job output, save as Jobname.txt in Jazz Program Library.  \r\n        If Login Then\r\n            LoginFTP()\r\n        End If\r\n        response = ftp.Site(&quot;FILETYPE=JES&quot;)\r\n        ftp.TransfersDataType = FtpDataType.Ascii\r\n        Dim LocalPath As String = My.Settings.UserCommonPath &amp; &quot;\\&quot; &amp; My.Settings.Programs &amp; &quot;\\&quot; &amp; Jobname &amp; &quot;.txt&quot;\r\n        Jazzworkbench.ShowBtnResults(Jobname, Jazzworkbench.ResultsStatus.Pending)\r\n        ftp.Download(Jobname, LocalPath)\r\n        ftp.DeleteFile(Jobname)\r\n        Jazzworkbench.ShowBtnResults(Jobname, Jazzworkbench.ResultsStatus.JobReturned)\r\n        ftp.Close()\r\n        Return response\r\n    End Function\r\n<\/pre>\n<p>Once the job output has been downloaded I didn&#8217;t want to leave it cluttering up my Held Job Output Queue, so after the Download <\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n        ftp.DeleteFile(Jobname)\r\n<\/pre>\n<p>gets rid of it.<\/p>\n<p>This all works for my test jobs (which are very quick) and provided that mainframe FTP server is available. <\/p>\n<p>If you want to know any more about my project to revolutionize mainframe programming, then have a look at www.jazzsoftware.co.nz <\/p>\n<p>Best wishes with your programming,<br \/>\nRobert Barnes.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I purchased the Limilabs FTP product for FTP because I needed to send data to and from an IBM mainframe from my VB.NET program running in Windows. In particular I needed to be able to submit jobs, and receive the job output. These notes show how it&#8217;s done. Introduction FTP to\/from IBM computers is pretty [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[23],"tags":[22,80,57,109],"class_list":["post-4828","post","type-post","status-publish","format-standard","hentry","category-ftp-dll","tag-ftp","tag-ftp-component","tag-vb-net","tag-zos"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/posts\/4828"}],"collection":[{"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/comments?post=4828"}],"version-history":[{"count":6,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/posts\/4828\/revisions"}],"predecessor-version":[{"id":4882,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/posts\/4828\/revisions\/4882"}],"wp:attachment":[{"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/media?parent=4828"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/categories?post=4828"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/tags?post=4828"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}