GithubHelp home page GithubHelp logo

mstiri / p3270 Goto Github PK

View Code? Open in Web Editor NEW
41.0 7.0 18.0 145 KB

A python library to take control of remote IBM hosts

License: GNU General Public License v3.0

Python 100.00%
python-library ibm-hosts ibm communication tn3270 cics mainframe

p3270's Introduction

A Python library to access IBM hosts

build status coverage

Description

A Python library that provides an interface to communicate with IBM hosts: send commands and text, receive output (screens). The library provides the means to do what a human can do using a 3270 emulator.

The library is highly customizable and is built with simplicity in mind. It is written in Python 3, runs on Linux and Unix-like Operating Systems, and relies on the s3270 utility. So it is required to have the s3270 installed on your system and available on your PATH.

The library allows you to open a telnet connection to an IBM host, and execute a set of instructions as you specified them in your python program.

Installation

A simple pip command brings the library to your environment:

pip install p3270

NB: Make sure that you're using the python3 version of the pip command.

Usage

Import the client class from the library:

from p3270 import P3270Client

Create a client object specifying a configuration file:

my_client = P3270Client(configFile='my-config.cfg')

It is also possible to create a client object with the config options stated in the code.

my_client = P3270Client(hostName='192.168.100.25', path='c:\\wc3270\\', codePage='cp277')

If the s3270 program is downloaded as a .zip file or otherwise fails to be added to the path when installed, it is possible to state the path when creating the P3270Client.

Connect the client, and you're good to go:

if not my_client.connect():
    print('Connection failed !')
    exit(1)

# Start sending your commands to the host ...

Configuration file:

The configuration file is used to set a bunch of parameters about the client and host interaction. The file has the following format:

<parameter> = <value>

Lines starting with a '#' are considered as comments and therefore ignored. For now the parameters are:

  • hostname: The name or IP address of the host to connect to. Default is localhost.
  • port: The port (on the host) to which the client should connect. Default is 23.
  • model: Terminal model name. The possible values are: 3278-n and 3279-n (n is the model number and can take the value: 2, 3, 4 or 5). The base model 3278 is a green on black 3270 display, whereas 3279 base model is a color 3270 display. Model numbers are used to specify the screen definition (rows and columns) as follows:
Model number Columns Rows
2 80 24
3 80 32
4 80 43
5 132 27
Default is 3279-2.
  • traceFile: The file to which communication traces will be directed. If not set traces will not be generated.
  • LUName: LU name to use for connection to the host. If it is not set, connection is done with no LU name.
  • enableTLS: Enable or not TLS connection to remote hosts(yes or np). Default is no.
  • verifyCert: Verify or not the certificate of the remote host (yes or no). Default is yes.
  • codePage: The EBCDIC character set to use for communication with the host. Supported code pages depens on your s3270 version. The list can be obtained by running the following command on your shell:
# s3270 -v

Default is cp037.

An example of configuration file would be:

# Target hostname 
hostname = 192.168.100.25
# Port
port = 10023
# Model Name: Default 3279-2
model = 3279-2
# TraceFile
traceFile = client.trace
# LU name to use
#LUName = LUPY0001
# EBCDIC character set to use for the host
codePage = cp037
# The file where all the screens should be saved
screensDir = /home/me/projects/python/mainframe/screens/

One configuration file can be shared by multiple clients.

Library methods:

Once the client object (P3270Client class) is created, the following methods can be used to interact with the host.

  • connect():
    • Description: Connect the client to the host
    • Arguments: none
  • disconnect()
    • Description: Disconenct the client from the host
    • Arguments: none
  • endSession()
    • Description: End the client session
    • Arguments: none
  • sendEnter()
    • Description: Send the Enter key to host
    • Arguments: none
  • sendPF(n)
    • Description: Send a PF (Program Function AID) key
    • Arguments:
      n (int): PF key number.
      The number should be in the range 1..24
  • sendPA(n)
    • Description: Send a PA (Program Attention AID) key
    • Arguments: n (int): PA key number.
      The number should be in the range 1..3
  • sendBackSpace()
    • Description: Send Back space to the host ()
    • Arguments: none
  • sendBackTab()
    • Description: Send back Tab to the host (go to start of previous input field)
    • Arguments: none
  • sendHome()
    • Description: Send Home key to the host
    • Arguments: none
  • sendTab()
    • Description: Send Tab key to the host
    • Arguments: none
  • sendKeys(keys)
    • Description: Emulates pressing keys to the host
      • Arguments:
        keys (string): The keys to emulate to the host
  • clearScreen()
    • Description: Clear the screen
    • Arguments: none
  • delChar()
    • Description: Delete character next to the cursor (ASCII DEL)
    • Arguments: none
  • delField()
    • Description: Delete the whole field
    • Arguments: none
  • delWord()
    • Description: Delete word under cursor
    • Arguments: none
  • eraseChar()
    • Description: Erase character previous character (ASCII BS)
    • Arguments: none
  • moveCursorDown()
    • Description: Move cursor down
    • Arguments: none
  • moveCursorUp()
    • Description: Move cursor up
    • Arguments: none
  • moveCursorLeft()
    • Description: Move cursor left
    • Arguments: none
  • moveCursorRight()
    • Description: Move cursor right
    • Arguments: none
  • moveTo(row, col)
    • Description: Move cursor to a specific position
    • Arguments:
      row (int): Row position to which the cursor should be moved.
      col (int): Column position to which the cursor should be moved.
  • moveToFirstInputField()
    • Description: Move cursor to the first input field on the current screen
    • Arguments: none
  • sendText(text)
    • Description: Send text to the host
    • Arguments:
      text (string): The string to send to the host
  • saveScreen(fileName, dataType)
    • Description: Save the current screen to a file
    • Arguments:
      fileName (string): File name to which the screen will be saved.
      If the file does not exist it is created, otherwise it is appended.
      Files are saved under the specified name in the directory specified in the parameter screensDir of the configuration file. Default: screen
      dataType (string): The data type of the captured screen. Supported data types are html, or rtf. Default: html
  • getScreen()
    • Description: Get the actual screen as raw text
    • Arguments: none
  • printScreen()
    • Description: Print the current screen to the standard output
    • Arguments: none
  • isConnected()
    • Description: Get the connection status of the client
    • Arguments: none
  • readTextAtPosition(row, col, length)
    • Description: Reads text at a row,col position and returns it
    • Arguments:
      row (int): Row position on where to read.
      col (int): Column position on where to read.
      length (int): How many chars to read
  • readTextArea(row, col, rows, cols)
    • Description: Reads text area at a row,col position and returns it
    • Arguments:
      row (int): Row position on where to read.
      col (int): Column position on where to read.
      rows (int): Number of rows to read down from the starting row.
      cols (int): Number of columns to read, right from the starting column.
  • readTextAtPosition(row, col, expected_text)
    • Description: Will check at the given coordinates if the text appear or not. Returns true if the text was found, false if not.
    • Arguments:
      row (int): Row position on where to read.
      col (int): Column position on where to read.
      expected_text (string): The text to look for
  • waitForField()
    • Description: Will wait for the field to be ready where the cursor is standing
    • Arguments: none
  • trySendTextToField(text, row, col)
    • Description: Will try and write the given text at the given position. Once the text is written, it will check if the text is now shown at the screen at that position. Returns true if succeeded, false if not.
    • Arguments:
      row (int): Row position on where to read.
      col (int): Column position on where to read.
      text (string): Text to write

All of the above methods return True if they succeed, and False otherwise. The only exceptions:

  • endSession(), it terminates the emulation session and returns True in all cases.
  • readTextAtPosition, readTextArea, getScreen all return the text they read.

Example:

from p3270 import P3270Client

# Connect and test if connection succeeded or not
if not my_client.connect():
    print('Connection failed !')
    exit(1)

# Save the home screen to a file called 'home.html'. HTML format is the default.
my_client.saveScreen(fileName='home.html')

# Send user name to the current field (user ID)
my_client.sendText('user1')

# Send TAB key to go to the next field
my_client.sendTab()

# Send the user password to the password field.
my_client.sendText('password1')

# Send Enter key to submit the current screen with field contents
my_client.sendEnter()

# Clear the screen 
my_client.clearScreen()

# Send the CICS command 'CEMT INQ TASK' to get running tasks
my_client.sendText('CEMT INQ TASK')

# Submit 
my_client.sendEnter()

# Capture the screen
my_client.saveScreen(fileName='tasks.html')

# Go back : PF3 key
my_client.sendPF(3)

# Go back again
my_client.sendPF(3)

# Disconnect from the host 
my_client.disconnect()

# End the emulation session
my_client.endSession()

Screens should go to the directory specified in the parameter screensDir specified in the configuration file. The library generates some log messages on the file p3270.log. You can adjust th elog level by modifying it directly on the library.

Contributing

  • Fork the project and create a new branch.
  • Do some work.
  • Commit and push.
  • Open a Pull Request.

License

GPLv3. See the LICENSE file.

p3270's People

Contributors

danilotorol avatar gemiusz avatar mike-pt avatar mstiri avatar simonfaltum avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

p3270's Issues

Not really an issue

Hi, trying to start 'my_client = P3270Client(configFile='p3270.cfg')' with a .cfg file I created and placed in the directory. When running is stating the following error:

FileNotFoundError: [WinError 2] The system cannot find the file specified

this is the config file:

Target hostname

hostname = 'myhost'

Port

port = 992

Model Name: Default 3279-2

model = 3279-2

TraceFile

traceFile = client.trace

LU name to use

#LUName = LUPY0001

EBCDIC character set to use for the host

codePage = cp037

The file where all the screens should be saved

#screensDir =

Missing enableTLS parameter

In line

hostPort=self.hostPort, luName=self.luName, modelName=self.modelName, codePage=codePage)

is missing enableTLS parameter.
Solution proposal :
hostPort=self.hostPort, luName=self.luName, modelName=self.modelName, codePage=codePage, enableTLS = self.enableTLS)

Sending PF key wont register

Hello, I was trying to send a PF 8 to my terminal but it is not working, it is not returning errors but it seems that the terminal is not receiving the command. Interestingly, it receives PF 2, for example. Not sure of what could be wrong since I used the s3270 from the command line and the PF keys worked fine (Yeah, lots of String() and Ascii() to get to the right screen).

Any help would be appreciated

Unable to Stablish a SSL connection

Problem Determination

  1. I'm able to access the system using x3270
    x3270 -noverifycert L:X.X.X.X:XX
  2. I try by modifying the p3270.py:
    def connect(self):
        """ Connect to the host
        """
        if self.conf.luName:
            logger.info("Connect to host [{}] with LUName: [{}]".format(self.conf.hostName, self.conf.luName))
            **return self.s3270.do('Connect(L:{}@{})'.format(self.conf.luName,self.conf.hostName))**
        else:
            logger.info("Connect to host [{}] with no LUName".format(self.conf.hostName))
            return self.s3270.do('Connect(L:{})'.format(self.conf.hostName))

And I got the following error which was expected (I face this issue while trying to connect using x3270):

20200109.195907.698 SSL: SSLHandshake: invalid certificate chain
20200109.195907.698 Output for Macro[2]: 'data: SSL: SSLHandshake: invalid certificate chain'

3.- I tried to connect using s3270 on the command line:

From the command Line I'm able to establish connection


s3270 -noverifycert L:X.X.X.X:XX 


U F U C(X.X.X.X) I 4 43 80 38 15 0x0 -
ok
U F U C(X.X.X.X) I 4 43 80 38 15 0x0 -
ok

From here I tried to add the following "-noverifycert" to this part of the code:

def connect(self):
        """ Connect to the host
        """
        if self.conf.luName:
            logger.info("Connect to host [{}] with LUName: [{}]".format(self.conf.hostName, self.conf.luName))
            **return self.s3270.do('Connect({},L:{}@{})'.format(self.conf.cert,self.conf.luName,self.conf.hostName))**
        else:
            logger.info("Connect to host [{}] with no LUName".format(self.conf.hostName))
            return self.s3270.do('Connect(L:{})'.format(self.conf.hostName))

And I'm getting the following error:

20200109.194957.267 PeerScript[1]: 'Connect(-noverifycert,L:B:[email protected])'
20200109.194957.267 Disabling input for PeerScript[1]
20200109.194957.267 Macro[2] running
20200109.194957.267 Macro[2]: 'Connect(-noverifycert,L:B:[email protected])'
20200109.194957.267 Script -> Connect("-noverifycert", "L:B:[email protected]")
20200109.194957.267 Connect requires 1 argument
20200109.194957.267 Output for Macro[2]: 'data: Connect requires 1 argument'
20200109.194957.267 Macro[2] error
20200109.194957.267 Macro[2] complete
20200109.194957.267 PeerScript[1] continuing
20200109.194957.267 Output for PeerScript[1]: 'L U U N N 2 24 80 0 0 0x0 -'
20200109.194957.267 Output for PeerScript[1]: 'error'
20200109.194957.267 Enabling input for PeerScript[1]
20200109.194957.267 Waiting for events
20200109.194957.267 Got 0 events
20200109.194957.268 Waiting for events
20200109.194957.280 Got 1 event
20200109.194957.280 Input for PeerScript[1] IDLE reading fd 0
20200109.194957.280 Input for PeerScript[1] IDLE complete, nr=0

Do you have any idea or hint of how to include the option -noverifycert into the command?

S3270 -devname option

I'm using p3270 to access a server which validates the Workstation ID when I login so I need to specify my Workstation ID.
I already tried adding " devname = ****" to the config file but it didn't work.
Would it be possible for you to add that option to your code?

Thank you for your time

Servname not supported for ai_socktype

hi,
I'm trying to use this library tool on Linux el7 but getting "Servname not supported for ai_socktype" error when trying to connect. Below is the trace and cfg file. Am I missing something?

$ python3.6 test.py
Connection failed !

Version: s3270 v3.3.12ga12 Mon Jan 27 16:40:31 EST 2014 mockbuild
Build options: --enable-ansi --enable-apl --enable-dbcs --enable-ft --enable-local-process --enable-tn3270e --enable-trace --with-ssl
Command: s3270 s3270 -model 3279-2 -port 23 -trace -tracefile client.trace
Model 3279-2-E, 24 rows x 80 cols, extended data stream, color emulation, bracket charset
Locale codeset: UTF-8
Host codepage: 37
Data stream:
20190812.154242.449 Enabling input for PeerScript[1]
20190812.154242.449 Waiting for events
20190812.154242.449 Got 1 event
20190812.154242.449 Input for PeerScript[1] IDLE reading fd 0
20190812.154242.449 Input for PeerScript[1] IDLE complete nr=24
20190812.154242.449 PeerScript[1] running
20190812.154242.449 PeerScript[1]: 'Connect(B:166.37.160.2)'
20190812.154242.449 Script -> Connect("B:166.37.160.2")
20190812.154242.460 B/166.37.160.2: Servname not supported for ai_socktype
20190812.154242.461 Keyboard unlock(kybd_connect) -NOT_CONNECTED
20190812.154242.461 Keyboard lock(kybd_connect) +NOT_CONNECTED
20190812.154242.461 Waiting for events
20190812.154242.469 Got 1 event
20190812.154242.469 Input for PeerScript[1] IDLE reading fd 0
20190812.154242.470 Input for PeerScript[1] IDLE complete nr=0
20190812.154242.470 EOF PeerScript[1]
20190812.154242.470 PeerScript[1] complete
20190812.154242.470 Trace stopped

Target hostname

hostname = 166.37.160.2

Port

port = 23

Model Name: Default 3279-2

model = 3279-2

TraceFile

traceFile = client.trace

LU name to use

#LUName = CIADCSC5

EBCDIC character set to use for the host

#codePage = cp037

The file where all the screens should be saved

screensDir = /vzwhome/chikone/p3270/

verifyCert='no' is not respected, it seems to default to yes regardless

Using this

from p3270 import P3270Client

my_client = P3270Client(luName='#LU01', hostName='170.1.2.3', hostPort='1234',
                        modelName='3278-4', verifyCert='no', timeoutInSec=5)

I found that verifyCert would still default to yes, and so this arg is never appended:

            if self.conf.verifyCert == "no":
                self.args.append('-noverifycert')

I'm not quite sure why though didn't really see anything that seemed wrong at first glance, and the other args are not behaving like this

I had to manually edit the code :

    def __init__(self, cfgFile=None, hostName='localhost', hostPort='23',
                 modelName='3279-2', traceFile=None,
                 luName=None, codePage='cp037', screensDir=None, verifyCert='no', enableTLS='no'):

This works

Getting error while connecting

Tried on Python 3.6 with

conf file:

hostname = 10.195.252.10
port = 992
model = 3279-2
traceFile = client.trace
LUName = LUPY0001
codePage = cp037
screensDir = C:\Users\asioh\PycharmProjects\Testproj\


Code:
from p3270 import P3270Client

my_client = P3270Client(configFile='config.cfg')
if not my_client.connect():
print('Connection failed !')
exit(1)
print("connected")


Error
File "C:/Users/asioh/PycharmProjects/Testproj/rest.py", line 10, in
my_client = P3270Client(configFile='config.cfg')
File "C:\Users\asioh\AppData\Local\Python\Python36-32\lib\site-packages\p3270\p3270.py", line 97, in init
self.s3270 = S3270(self.args)
File "C:\Users\asioh\AppData\Local\Python\Python36-32\lib\site-packages\p3270\p3270.py", line 27, in init
stderr=subprocess.PIPE)
File "C:\Users\asioh\AppData\Local\Python\Python36-32\lib\subprocess.py", line 707, in init
restore_signals, start_new_session)
File "C:\Users\asioh\AppData\Local\Python\Python36-32\lib\subprocess.py", line 992, in _execute_child
startupinfo)
FileNotFoundError: [WinError 2] The system cannot find the file specified


Can you please help

dataType

if dataType == 'html' or dataType == 'rtf':

I think this is a problem in s3270 program too but in documentation are example of how to do it and this is diffrent way than in code.

Information from documentation of s3270 program:
PrintText()_action

Examples below:
Capture a plain text screen snapshot in a file.
PrintText(file,/tmp/snapshot.txt)

Capture an HTML screen snapshot in a file.
PrintText(file,/tmp/snapshot.html)

TLS connection issue. Works with config file but does not work with parameters.

My issue is with TLS connection. Basically when I'am using a configuration file it works fine but when I'am using parameters on the p3270Client method then it doesn't work and the connection just fail. You will find below a trace with the 2 scenarios.

My python application to use directly the x3270 application that you have created and I have some issues with TLS connections. Basically, when I'am using a config file it works fine as what the debug output below shows:

Python instruction: client = p3270.P3270Client(configFile=cfgfile)

cfgfile =

hostname = x.x.x.x
port = 992
model = 3279-2
codePage = cp037
enableTLS = yes
verifyCert = yes

Debug output:

--- Logging error ---
Traceback (most recent call last):
File "C:\Users\my_user\AppData\Local\Programs\Python\Python311\Lib\logging__init__.py", line 1110, in emit
msg = self.format(record)
^^^^^^^^^^^^^^^^^^^
File "C:\Users\my_user\AppData\Local\Programs\Python\Python311\Lib\logging__init__.py", line 953, in format
return fmt.format(record)
^^^^^^^^^^^^^^^^^^
File "C:\Users\my_user\AppData\Local\Programs\Python\Python311\Lib\logging__init__.py", line 687, in format
record.message = record.getMessage()
^^^^^^^^^^^^^^^^^^^
File "C:\Users\my_user\AppData\Local\Programs\Python\Python311\Lib\logging__init__.py", line 377, in getMessage
msg = msg % self.args
~~~~^~~~~~~~~~~
TypeError: not all arguments converted during string formatting
Call stack:
File "C:\Users\my_user\Documents\git\Check1\RBO-TLS.py", line 175, in <module>
main()
File "C:\Users\my_user\Documents\git\Check1\RBO-TLS.py", line 98, in main
client = p3270.P3270Client(configFile=cfgfile)
File "C:\Users\my_user\AppData\Local\Programs\Python\Python311\Lib\site-packages\p3270\p3270.py", line 108, in init
self.s3270 = S3270(self.args, self.conf.encoding)
File "C:\Users\my_user\AppData\Local\Programs\Python\Python311\Lib\site-packages\p3270\p3270.py", line 27, in init
logger.debug('Calling s3270 with the following args: ', self.args)
Message: 'Calling s3270 with the following args: '
Arguments: (['s3270', '-model', '3279-2', '-port', '992', '-charset', 'cp037', '-noverifycert'],)</module>

When it does not work I have this from the command line:

Python instruction: client = p3270.P3270Client(hostName='x.x.x.x', hostPort='992',configFile=None, verifyCert='no', enableTLS='yes', codePage='cp037', path=None, timeoutInSec=20)

Debug error:

--- Logging error ---
Traceback (most recent call last):
File "C:\Users\my_user\AppData\Local\Programs\Python\Python311\Lib\logging__init__.py", line 1110, in emit
msg = self.format(record)
^^^^^^^^^^^^^^^^^^^
File "C:\Users\my_user\AppData\Local\Programs\Python\Python311\Lib\logging__init__.py", line 953, in format
return fmt.format(record)
^^^^^^^^^^^^^^^^^^
File "C:\Users\my_user\AppData\Local\Programs\Python\Python311\Lib\logging__init__.py", line 687, in format
record.message = record.getMessage()
^^^^^^^^^^^^^^^^^^^
File "C:\Users\my_user\AppData\Local\Programs\Python\Python311\Lib\logging__init__.py", line 377, in getMessage
msg = msg % self.args
~~~~^~~~~~~~~~~
TypeError: not all arguments converted during string formatting
Call stack:
File "C:\Users\my_user\Documents\git\Check1\RBO-TLS.py", line 176, in <module>
main()
File "C:\Users\my_user\Documents\git\Check1\RBO-TLS.py", line 99, in main
client = p3270.P3270Client(hostName='10.137.18.18', hostPort='992', verifyCert='no', enableTLS='yes', path='wc3270\')
File "C:\Users\my_user\AppData\Local\Programs\Python\Python311\Lib\site-packages\p3270\p3270.py", line 108, in init
self.s3270 = S3270(self.args, self.conf.encoding)
File "C:\Users\my_user\AppData\Local\Programs\Python\Python311\Lib\site-packages\p3270\p3270.py", line 27, in init
logger.debug('Calling s3270 with the following args: ', self.args)
Message: 'Calling s3270 with the following args: '
Arguments: (['wc3270\s3270', '-model', '3279-2', '-port', '992', '-charset', 'cp037'],)
**Connection failed !</module>**

As you can see above there is a difference in the parameter that are passed. The '-noverifycert' is not passed to the module. So, I believe this is why it does not work. I would rather pass the parameter through the class/method call rather using a configuration file as this make things a bit more complex.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.