Re: Driving TN5250 non-interactively

Holger Schurig <[email protected]>
Newsgroups gmane.comp.emulators.tn5250
Message-ID <[email protected]>
> I've been tasked with writing an interface between an application that 
> runs on a remote iSeries host, accessible with TN5250 over a private 
> network, and our application that would query the iSeries in real time 
> without human interaction. My application will run on a Linux or AIX 
> box, and act like a broker between the local application and the remote 
> iSeries host application that contains the database we are querying.

Hi Richard !

For my employer I wrote a terminal program (in Qt, this it runs on Linux and
Windows) for fork-lift terminals. This program uses lib5250 for it's 5250
emulation.

I also wrote a layer where you can screen-scrape the text contents via the Lua
programming language and send code. For example, here is a Lua program that
automatically deletes all dynamic defined QPA-Devices. Sorry for the german 
comments.

If you want something like this, please contact me off-list.


---------------------------------------------------------------------
--  Demo-Script, welches alle QPA-Devices in der AS/400 abhängt
--  und, wenn es schon abgehängt war, anschließend löscht
---------------------------------------------------------------------
--  Ähnlich wie:
--  WRKCFGSTS CFGTYPE(*DEV) CFGD(QPA*)
--  VRYCFG CFGOBJ(QPA*) CFGTYPE(*DEV) STATUS(*OFF)
--  DLTDEVD DEVD(QPA*)
--  Und wenn man schon mal beim Aufräumen ist:
--  WRKSPLF SELECT(*ALL)

--
-- Login with necessary rights
--
local username = "SCHURIG"
local password = "XXX"


--
-- Welche QPA-Devices interessierung uns?  (andere, wie z.B. QCONSOLE,
-- ETHTCCP bleiben erhalten). Wir speichern das in einem assoziativen Array,
-- a.k.a. "hash" in Python und Perl. Später kann man das testen, indem man
-- einfach darauf zugreif:
--
--    interestingQPAs["QPA"]    gibt 1 zurück
--    interestingQPAs["FUNK"]   gibt nil zurück
--
local interestingQPAs = {
  ["ABC"] = 1,
  ["DUMMY"] = 1,
  ["MDE"] = 1,
  ["MNCI"] = 1,
  ["QPA"] = 1,
}


---------------------------------------------------------------------
-- Ab hier sollten keine Anpassungen mehr nötig sein
---------------------------------------------------------------------



--
-- Hiermit meldet man sich an der AS/400 an.
--
-- Sollte bereits eine -- alte, "geparkte" Sitzung existieren, wird diese
-- beendet.
--
-- Sollte eine andere Session mit demselben Namen existieren, wird der
-- entsprechende Warnhinweis übergangen
--
local function login()
	pause(200)

	local i = 0

        -- "~=" ist ungleich, in anderen Sprachen "!=" oder "<>" geschrieben
	while i ~= 1 do
		send(username)
		sendkey(0x1001)	-- TAB
		send(password)
		sendkey(0x1004) -- RETURN

		i = waitfor("Auswahl oder Befehl",
		            "90. Vorherigen interaktiven Job",
		            "ist anderem Job zugeordnet")
		if i == 2 then
			send("90\r")
			waitfor("Ende")
			send("\r")
			waitfor("COPYRIGHT IBM CORP")
		elseif i == 3 then
			send("\r")
		end
	end
end



--
-- Löscht ein QPA-Device
--
-- Ist das Device noch angehängt oder mit der Anmeldeanzeige versehen,
-- wird es zunächst abgehängt
--
-- Ist das Device abgehängt, dann wird wird es sowie seine Beschreibung
-- gelöscht
--
local function deleteQPA(qpa, y)
	-- getscreen(x,y,len) liefert exakt "len" Zeichen von der angegeben
	-- Bildschirmposition. Links oben ist übrigens 1,1 (nicht 0,0).
	-- Wenn Leerzeichen enthalten sind, sind die dann Teil des zurück-
	-- gelieferten Strings.
	--
	-- Mit string.gsub(quelle, was, wonach) kann werden diese entfernt.
	-- Der zweite Parameter von string.gsub() ist eine reguläre
	-- Expression. "%s" wird in anderen Sprachen als "\s" geschrieben
	-- und steht für ein "Space", also Tab oder Leerzeichen.--"+"
	-- dahinter bestimmt, daß es ein- oder mehrmals vorkommen muß.--Das
	-- "$" sorgt dafür, daß es am Zeilenende sein muß.
	local status = string.gsub(getscreen(26, y, 21), "%s+$", "")
	if status == "ANHÄNGEN ANSTEHEND" or status == "ANMELDEANZEIGE" then
		send("2\r")
		waitfor("beendet")
		status = "ABGEHÄNGT"
	end
	if status == "ABGEHÄNGT" then
		send("8\r") -- Mit Beschreibung arbeiten
		waitfor("Parameter oder Befehl")
		send("4\r") -- Löschen
		waitfor("Ende")
		send("\r")  -- Bestätigen
		waitfor("Parameter oder Befehl")
		sendkey(0x1032) -- F3
		waitfor("Parameter oder Befehl")
	end

	-- print("qpa: '", qpa, "', status: '", status, "'")
end


--
-- Stellt fest, ob ein von der AS/400 ausgegebener Fehler kritisch ist.
-- Bei einigen Fehlermeldungen in der Statuszeile wissen wir, daß sie
-- keine Fehler sind, dort geben wir 0 zurück. Bei anderen Fehlern geben
-- wir eine 1 zurück.
--

local function checkError()
	local error = string.gsub(getscreen(2, 24, 50), "%s+$", "")
	local l = string.len(error)
	if error == "" then
		return 0
	elseif string.sub(error, 1, 20) == "Abhängen von Einheit" then
		return 0
	elseif string.sub(error, l-21, l) == ", Art *DEVD, gelöscht." then
		return 0
	end
	-- print("Error: ", error)
	return 1
end


--
-- Ruft die Workstation-Konfiguration der Devices auf
--
-- Mit TAB gehen wir von Eintrag zu Eintrag und prüfen, ob das
-- entsprechende Device zu den "interessanten" gehört, wir es also
-- löschen dürfen.
--
-- Wenn wir nach einem TAB auf einmal eine höhere Position haben (der
-- Cursor als "um den Bildschirm herum" gesprungen ist), dann holen wir
-- mit PAGEDOWN eine weitere Seite ab.
--
-- Bei unbekannten Fehlermeldungen beenden wir das Löschen
--

local function wrkcfgsts()
	send("WRKCFGSTS CFGTYPE(*DEV)\r")
	waitfor("Parameter oder Befehl")

	while 1 do
		pause(50)

		-- get status of item at cursor position
		local x,y = getcursor()
		local qpa = string.gsub(getscreen(8, y, 16),  "%s+$", "")

		-- process all QPA devices
		if qpa ~= "" then
			for dev in pairs(interestingQPAs) do
				--print(dev, ", ", string.sub(qpa, 1, string.len(dev)))
				if dev == string.sub(qpa, 1, string.len(dev)) then
					deleteQPA(qpa, y)
					break
				end
			end
		end

		if checkError()==1 then break end

		local lasty = y
		sendkey(0x1001)	-- TAB
		x, y = getcursor()
		if y < lasty then
			sendkey(0x1001)	-- TAB
			sendkey(0x1017)	-- PGDOWN
			if checkError()==1 then break end
		end
	end
end


--
-- Hiermit schließlich loggen wir uns aus
--
-- Die Funktion ist nicht sonderlich robust, sie testet noch nicht
-- mal, ob irgendwo "90. Abmelden" steht ...
--

local function logout()
	pause(1000)
	sendkey(0x1032) -- F3
	i = waitfor("Auswahl oder Befehl")
	send("90\r")
end


login()
wrkcfgsts()
logout()


-- 
Homepage: http://www.holgerschurig.de
-- 
This is the Linux 5250 Development Project (LINUX5250) mailing list
To post a message email: LINUX5250-Zwy7GipZuJhWk0Htik3J/[email protected]
To subscribe, unsubscribe, or change list options,
visit: http://lists.midrange.com/mailman/listinfo/linux5250
or email: LINUX5250-request-Zwy7GipZuJhWk0Htik3J/[email protected]
Before posting, please take a moment to review the archives
at http://archive.midrange.com/linux5250.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.