1---
2-- TN3270 Emulator Library
3--
4-- Summary
5-- * This library implements an RFC 1576 and 2355 (somewhat) compliant TN3270 emulator.
6--
7-- The library consists of one class <code>Telnet</code> consisting of multiple
8-- functions required for initiating a TN3270 connection.
9--
10-- The following sample code illustrates how scripts can use this class
11-- to interface with a mainframe:
12--
13-- <code>
14-- mainframe = Telnet:new()
15-- status, err = mainframe:initiate(host, port)
16-- status, err = mainframe:send_cursor("LOGON APPLID(TSO)")
17-- mainframe:get_data()
18-- curr_screen = mainframe:get_screen()
19-- status, err = mainframe:disconnect()
20-- </code>
21--
22-- The implementation is based on packet dumps, x3270, the excellent decoding
23-- provided by Wireshark and the Data Stream Programmers Reference (Dec 88)
24
25local stdnse    = require "stdnse"
26local drda      = require "drda" -- We only need this to decode EBCDIC
27local comm      = require "comm"
28local math = require "math"
29local nmap = require "nmap"
30local string = require "string"
31local table = require "table"
32
33_ENV = stdnse.module("tn3270", stdnse.seeall)
34
35Telnet = {
36  --__index = Telnet,
37
38  commands = {
39    SE   = "\240", -- End of subnegotiation parameters
40    SB   = "\250", -- Sub-option to follow
41    WILL = "\251", -- Will; request or confirm option begin
42    WONT = "\252", -- Wont; deny option request
43    DO   = "\253", -- Do = Request or confirm remote option
44    DONT = "\254", -- Don't = Demand or confirm option halt
45    IAC  = "\255", -- Interpret as Command
46    SEND = "\001", -- Sub-process negotiation SEND command
47    IS   = "\000", -- Sub-process negotiation IS command
48    EOR  = "\239"
49  },
50  tncommands = {
51    ASSOCIATE  = "\000",
52    CONNECT    = "\001",
53    DEVICETYPE = "\002",
54    FUNCTIONS  = "\003",
55    IS         = "\004",
56    REASON     = "\005",
57    REJECT     = "\006",
58    REQUEST    = "\007",
59    RESPONSES  = "\002",
60    SEND       = "\008",
61    EOR        = "\239"
62  },
63
64    -- Thesse are the options we accept for telnet
65  options = {
66    BINARY   = "\000",
67    EOR      = "\025",
68    TTYPE    = "\024",
69    TN3270   = "\028",
70    TN3270E  = "\040"
71  },
72
73  command = {
74    EAU   = "\015",
75    EW    = "\005",
76    EWA   = "\013",
77    RB    = "\002",
78    RM    = "\006",
79    RMA   = "",
80    W     = "\001",
81    WSF   = "\017",
82    NOP   = "\003",
83    SNS   = "\004",
84    SNSID = "\228"
85  },
86  sna_command ={
87    RMA   = "\110",
88    EAU   = "\111",
89    EWA   = "\126",
90    W     = "\241",
91    RB    = "\242",
92    WSF   = "\243",
93    EW    = "\245",
94    NOP   = "\003",
95    RM    = "\246"
96  },
97
98  orders = {
99    SF  = "\029",
100    SFE = "\041",
101    SBA = "\017",
102    SA  = "\040",
103    MF  = "\044",
104    IC  = "\019",
105    PT  = "\005",
106    RA  = "\060",
107    EUA = "\018",
108    GE  = "\008"
109  },
110
111  fcorders = {
112    NUL = "\000",
113    SUB = "\063",
114    DUP = "\028",
115    FM  = "\030",
116    FF  = "\012",
117    CR  = "\013",
118    NL  = "\021",
119    EM  = "\025",
120    EO  = "\255"
121  },
122
123  aids = {
124    NO      = 0x60, -- no aid
125    QREPLY  = 0x61, -- reply
126    ENTER   = 0x7d, -- enter
127    PF1     = 0xf1,
128    PF2     = 0xf2,
129    PF3     = 0xf3,
130    PF4     = 0xf4,
131    PF5     = 0xf5,
132    PF6     = 0xf6,
133    PF7     = 0xf7,
134    PF8     = 0xf8,
135    PF9     = 0xf9,
136    PF10    = 0x7a,
137    PF11    = 0x7b,
138    PF12    = 0x7c,
139    PF13    = 0xc1,
140    PF14    = 0xc2,
141    PF15    = 0xc3,
142    PF16    = 0xc4,
143    PF17    = 0xc5,
144    PF18    = 0xc6,
145    PF19    = 0xc7,
146    PF20    = 0xc8,
147    PF21    = 0xc9,
148    PF22    = 0x4a,
149    PF23    = 0x4b,
150    PF24    = 0x4c,
151    OICR    = 0xe6,
152    MSR_MHS = 0xe7,
153    SELECT  = 0x7e,
154    PA1     = 0x6c,
155    PA2     = 0x6e,
156    PA3     = 0x6b,
157    CLEAR   = 0x6d,
158    SYSREQ  = 0xf0
159  },
160
161  -- used to translate buffer addresses
162  code_table = {
163    0x40, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
164    0xC8, 0xC9, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
165    0x50, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
166    0xD8, 0xD9, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
167    0x60, 0x61, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
168    0xE8, 0xE9, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
169    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
170    0xF8, 0xF9, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F
171  },
172
173  -- Variables used for Telnet Negotiation and data buffers
174  word_state = { "Negotiating", "Connected", "TN3270 mode", "TN3270E mode"},
175  NEGOTIATING    = 1,
176  CONNECTED      = 2,
177  TN3270_DATA    = 3,
178  TN3270E_DATA   = 4,
179  device_type    = "IBM-3278-2",
180
181  -- TN3270E Header variables
182  tn3270_header = {
183    data_type     = '',
184    request_flag  = '',
185    response_flag = '',
186    seq_number    = ''
187  },
188
189  -- TN3270 Datatream Processing flags
190  NO_OUTPUT      = 0,
191  OUTPUT         = 1,
192  BAD_COMMAND    = 2,
193  BAD_ADDRESS    = 3,
194  NO_AID         = 0x60,
195  aid            = 0x60,  -- initial Attention Identifier is No AID
196
197  -- Header response flags.
198  NO_RESPONSE       = 0x00,
199  ERROR_RESPONSE    = 0x01,
200  ALWAYS_RESPONSE   = 0x02,
201  POSITIVE_RESPONSE = 0x00,
202  NEGATIVE_RESPONSE = 0x01,
203
204  -- Header data type names.
205  DT_3270_DATA    = 0x00,
206  DT_SCS_DATA     = 0x01,
207  DT_RESPONSE     = 0x02,
208  DT_BIND_IMAGE   = 0x03,
209  DT_UNBIND       = 0x04,
210  DT_NVT_DATA     = 0x05,
211  DT_REQUEST      = 0x06,
212  DT_SSCP_LU_DATA = 0x07,
213  DT_PRINT_EOJ    = 0x08,
214
215  -- Header response data.
216  POS_DEVICE_END             = 0x00,
217  NEG_COMMAND_REJECT         = 0x00,
218  NEG_INTERVENTION_REQUIRED  = 0x01,
219  NEG_OPERATION_CHECK        = 0x02,
220  NEG_COMPONENT_DISCONNECTED = 0x03,
221
222  -- TN3270E Negotiation Options
223  TN3270E_ASSOCIATE   = 0x00,
224  TN3270E_CONNECT     = 0x01,
225  TN3270E_DEVICE_TYPE = 0x02,
226  TN3270E_FUNCTIONS   = 0x03,
227  TN3270E_IS          = 0x04,
228  TN3270E_REASON      = 0x05,
229  TN3270E_REJECT      = 0x06,
230  TN3270E_REQUEST     = 0x07,
231  TN3270E_SEND        = 0x08,
232
233  -- SFE Attributes
234  SFE_3270 = "192",
235  order_max = "\063", -- tn3270 orders can't be greater than 0x3F
236  COLS = 80, -- hardcoded width.
237  ROWS = 24, -- hardcoded rows. We only support 3270 model 2 which was 24x80.
238  buffer_addr = 1,
239  cursor_addr = 1,
240  isSSL = true,
241
242  --- Creates a new TN3270 Client object
243
244  new = function(self, socket)
245    local o = {
246      socket = socket or nmap.new_socket(),
247      -- TN3270 Buffers
248      buffer         = {},
249      fa_buffer      = {},
250      output_buffer  = {},
251      overwrite_buf  = {},
252      telnet_state   = 0, -- same as TNS_DATA to begin with
253      server_options = {},
254      client_options = {},
255      unsupported_opts = {},
256      sb_options     = '',
257      connected_lu   = '',
258      connected_dtype= '',
259      telnet_data    = '',
260      tn_buffer      = '',
261      negotiated     = false,
262      first_screen   = false,
263      state          = 0,
264      buffer_address = 1,
265      formatted      = false,
266    }
267    setmetatable(o, self)
268    self.__index = self
269    return o
270  end,
271
272  --- Connects to a tn3270 servers
273  connect = function ( self, host, port )
274
275    local TN_PROTOCOLS = { "ssl", "tcp" }
276    local status, err
277    if not self.isSSL then
278      status, err = self.socket:connect(host, port, 'tcp')
279      local proto = 'tcp'
280      if status then
281        TN_PROTOCOLS = {proto}
282        return true
283      end
284    else
285
286      for _, proto in pairs(TN_PROTOCOLS) do
287        status, err = self.socket:connect(host, port, proto)
288        if status then
289          TN_PROTOCOLS = {proto}
290          return true
291        end
292        stdnse.debug(3,"Can't connect using %s: %s", proto, err)
293      end
294    end
295    self.socket:close()
296    return false, err
297  end,
298
299  disconnect = function ( self )
300    stdnse.debug(2,"Disconnecting")
301    return self.socket:close()
302  end,
303
304  recv_data = function ( self )
305    return self.socket:receive()
306  end,
307
308  close = function ( self )
309    return self.socket:close()
310  end,
311
312  send_data = function ( self, data )
313    stdnse.debug(2, "Sending data: 0x%s", stdnse.tohex(data))
314    return self.socket:send( data )
315  end,
316
317  ------------- End networking functions
318
319
320  -- TN3270 Helper functions
321  -----------
322  --- Decode Buffer Address
323  --
324  -- Buffer addresses can come in 14 or 12 (this terminal doesn't support 16 bit)
325  -- this function takes two bytes (buffer addresses are two bytes long) and returns
326  -- the decoded buffer address.
327  -- @param1 unsigned char, first byte of buffer address.
328  -- @param2 unsigned char, second byte of buffer address.
329  -- @return integer of buffer address
330  DECODE_BADDR = function ( byte1, byte2 )
331    if (byte1 & 0xC0) == 0 then
332      -- (byte1 & 0x3F) << 8 | byte2
333      return (((byte1 & 0x3F) << 8) | byte2)
334    else
335      -- (byte1 & 0x3F) << 6 | (byte2 & 0x3F)
336      return (((byte1 & 0x3F) << 6) | (byte2 & 0x3F))
337    end
338  end,
339
340  --- Encode Buffer Address
341  --
342  -- @param integer buffer address
343  -- @return TN3270 encoded buffer address (12 bit) as string
344  ENCODE_BADDR = function ( self, address )
345    stdnse.debug(3, "Encoding Address: " .. address)
346    return string.pack("BB",
347      -- (address >> 8) & 0x3F
348      -- we need the +1 because LUA tables start at 1 (yay!)
349      self.code_table[((address >> 6) & 0x3F)+1],
350      -- address & 0x3F
351      self.code_table[(address & 0x3F)+1]
352      )
353  end,
354
355  BA_TO_ROW = function ( self, addr )
356    return math.ceil((addr / self.COLS) + 0.5)
357  end,
358
359  BA_TO_COL = function ( self, addr )
360    return addr % self.COLS
361  end,
362
363  INC_BUF_ADDR = function ( self, addr )
364    return ((addr + 1) % (self.COLS * self.ROWS))
365  end,
366
367  DEC_BUF_ADDR = function ( self, addr )
368    return ((addr + 1) % (self.COLS * self.ROWS))
369  end,
370
371  --- Initiates tn3270 connection
372  initiate = function ( self, host, port )
373    local status = true
374    --local status, err = self:connect(host , port)
375    local opts = {recv_before = true}
376    self.socket, self.telnet_data = comm.tryssl(host, port, '', opts)
377
378    if ( not(self.socket) ) then
379      return false, self.telnet_data
380    end
381    -- clear out options buffers
382    self.client_options = {}
383    self.server_options = {}
384    self.state = self.NEGOTIATING
385    self.first_screen = false
386
387    self:process_packets() -- process the first batch of information
388    -- then loop through until we're done negotiating telnet/tn3270 options
389    while not self.first_screen and status do
390      status, self.telnet_data = self:recv_data()
391      self:process_packets()
392    end
393    return status
394  end,
395
396  --- rebuilds tn3270 screen based on information sent
397  -- Closes the socket if the mainframe has closed the socket on us
398  -- Is done reading when it encounters EOR
399  get_data = function ( self )
400    local status = true
401    self.first_screen = false
402    while not self.first_screen and status do
403      status, self.telnet_data = self:recv_data()
404      self:process_packets()
405    end
406    if not status then
407      self:disconnect()
408    end
409    return status
410  end,
411
412  get_all_data = function ( self, timeout )
413    if timeout == nil then
414      timeout = 200
415    end
416    local status = true
417    self.first_screen = false
418    self.socket:set_timeout(timeout)
419    while status do
420      status, self.telnet_data = self:recv_data()
421      if self.telnet_data ~= "TIMEOUT" then
422        self:process_packets()
423      end
424    end
425    self.socket:set_timeout(3000)
426    return status
427  end,
428
429  process_packets = function ( self )
430    for i = 1,#self.telnet_data,1 do
431      self:ts_processor(self.telnet_data:sub(i,i))
432    end
433    -- once all the data has been processed we clear out the buffer
434    self.telnet_data = ''
435  end,
436
437  --- Disable SSL
438  -- by default the tn3270 object uses SSL first. This disables SSL
439  disableSSL = function (self)
440    stdnse.debug(2,"Disabling SSL connections")
441    self.isSSL = false
442  end,
443
444  --- Telnet State processor
445  --
446  -- @return true if success false if encoutered any issues
447
448  ts_processor = function ( self, data )
449    local TNS_DATA   = 0
450    local TNS_IAC    = 1
451    local TNS_WILL   = 2
452    local TNS_WONT   = 3
453    local TNS_DO     = 4
454    local TNS_DONT   = 5
455    local TNS_SB     = 6
456    local TNS_SB_IAC = 7
457    local supported  = false
458    local DO_reply   = self.commands.IAC .. self.commands.DO
459    local DONT_reply = self.commands.IAC .. self.commands.DONT
460    local WILL_reply = self.commands.IAC .. self.commands.WILL
461    local WONT_reply = self.commands.IAC .. self.commands.WONT
462
463    --nsedebug.print_hex(data)
464    --stdnse.debug(3,"current state:" .. self.telnet_state)
465
466    if self.telnet_state == TNS_DATA then
467      if data == self.commands.IAC then
468        -- got an IAC
469        self.telnet_state = TNS_IAC
470        return true
471      end
472      -- stdnse.debug("Adding 0x%s to Data Buffer", stdnse.tohex(data))
473      self:store3270(data)
474    elseif self.telnet_state == TNS_IAC then
475      if data == self.commands.IAC then
476        -- insert this 0xFF in to the buffer
477        self:store3270(data)
478        self.telnet_state = TNS_DATA
479      elseif data == self.commands.EOR then
480        -- we're at the end of the TN3270 data
481        -- let's process it and see what we've got
482        -- but only if we're in 3270 mode
483        if self.state == self.TN3270_DATA or self.state == self.TN3270E_DATA then
484          self:process_data()
485        end
486        self.telnet_state = TNS_DATA
487      elseif data == self.commands.WILL then self.telnet_state = TNS_WILL
488      elseif data == self.commands.WONT then self.telnet_state = TNS_WONT
489      elseif data == self.commands.DO   then self.telnet_state = TNS_DO
490      elseif data == self.commands.DONT then self.telnet_state = TNS_DONT
491      elseif data == self.commands.SB   then self.telnet_state = TNS_SB
492      end
493    elseif self.telnet_state == TNS_WILL then
494      stdnse.debug(3, "[TELNET] IAC WILL 0x%s?", stdnse.tohex(data))
495      for _,v in pairs(self.options) do -- check to see if we support this sub option (SB)
496        if v == data then
497          stdnse.debug(3, "[TELNET] IAC DO 0x%s", stdnse.tohex(data))
498          supported = true
499          break
500        end
501      end -- end of checking options
502      for _,v in pairs(self.unsupported_opts) do
503        if v == data then
504          stdnse.debug(3, "[TELNET] IAC DONT 0x%s (disabled)", stdnse.tohex(data))
505          supported = false
506        end
507      end
508      if supported then
509        if not self.server_options[data] then -- if we haven't already replied to this, let's reply
510          self.server_options[data] = true
511          self:send_data(DO_reply..data)
512          stdnse.debug(3, "[TELNET] Sent Will Reply: 0x%s", stdnse.tohex(data))
513          self:in3270()
514        end
515      else
516        self:send_data(DONT_reply..data)
517        stdnse.debug(3, "[TELNET] Sent Don't Reply: 0x%s", stdnse.tohex(data))
518      end
519      self.telnet_state = TNS_DATA
520    elseif self.telnet_state == TNS_WONT then
521      if self.server_options[data] then
522        self.server_options[data] = false
523        self:send_data(DONT_reply..data)
524        stdnse.debug(3, "[TELNET] Sent Don't Reply: 0x%s", stdnse.tohex(data))
525        self:in3270()
526      end
527      self.telnet_state = TNS_DATA
528    elseif self.telnet_state == TNS_DO then
529      stdnse.debug(3, "[TELNET] IAC DO 0x%s?", stdnse.tohex(data))
530      for _,v in pairs(self.options) do -- check to see if we support this sub option (SB)
531        if v == data then
532          stdnse.debug(3, "[TELNET] IAC WILL 0x%s", stdnse.tohex(data))
533          supported = true
534          break
535        end
536      end -- end of checking options
537      for _,v in pairs(self.unsupported_opts) do
538        if v == data then
539          stdnse.debug(3, "[TELNET] IAC WONT 0x%s (disabled)", stdnse.tohex(data))
540          supported = false
541        end
542      end
543      if supported then
544        if not self.client_options[data] then
545          self.client_options[data] = true
546          self:send_data(WILL_reply..data)
547          stdnse.debug(3, "[TELNET] Sent Do Reply: 0x%s" , stdnse.tohex(data))
548          self:in3270()
549        end
550      else
551        self:send_data(WONT_reply..data)
552        stdnse.debug(3, "[TELNET] Got unsupported Do. Sent Won't Reply: " .. data .. " " .. self.telnet_data)
553      end
554      self.telnet_state = TNS_DATA
555    elseif self.telnet_state == TNS_DONT then
556      if self.client_options[data] then
557        self.client_options[data] = false
558        self:send_data(WONT_reply .. data)
559        stdnse.debug(3, "[TELNET] Sent Wont Reply: 0x%s", stdnse.tohex(data))
560        self:in3270()
561      end
562      self.telnet_state = TNS_DATA
563    elseif self.telnet_state == TNS_SB then
564      if data == self.commands.IAC then
565        self.telnet_state = TNS_SB_IAC
566      else
567        self.sb_options = self.sb_options .. data
568      end
569    elseif self.telnet_state == TNS_SB_IAC then
570      stdnse.debug(3, "[TELNET] Processing SB options")
571--      self.sb_options = self.sb_options .. data -- looks like this is a bug? Why append F0 to the end?
572      if data == self.commands.SE then
573        self.telnet_state = TNS_DATA
574        if self.sb_options:sub(1,1) == self.options.TTYPE and
575          self.sb_options:sub(2,2) == self.commands.SEND then
576          self:send_data(self.commands.IAC  ..
577            self.commands.SB   ..
578            self.options.TTYPE ..
579            self.commands.IS   ..
580            self.device_type   ..
581            self.commands.IAC  ..
582            self.commands.SE   )
583        elseif (self.client_options[self.options.TN3270] or self.client_options[self.options.TN3270E]) and
584               (self.sb_options:sub(1,1) == self.options.TN3270 or
585                self.sb_options:sub(1,1) == self.options.TN3270E) then
586          if not self:negotiate_tn3270() then
587            return false
588          end
589          stdnse.debug(3, "[TELNET] Done Negotiating Options")
590        else
591          self.telnet_state = TNS_DATA
592        end
593        self.sb_options = ''
594      end
595      --self.sb_options = ''
596    end -- end of makeshift switch/case
597    return true
598  end,
599
600  --- Stores a character on a buffer to be processed
601  --
602  store3270 = function ( self, char )
603    self.tn_buffer = self.tn_buffer .. char
604  end,
605
606  --- Function to negotiate TN3270 sub options
607
608  negotiate_tn3270 = function ( self )
609    stdnse.debug(3, "[TN3270] Processing tn data subnegotiation options ")
610    local option = self.sb_options:sub(2,2)
611   -- stdnse.debug("[TN3270E] We got this: 0x%s", stdnse.tohex(option))
612
613    if option == self.tncommands.SEND then
614      if self.sb_options:sub(3,3) == self.tncommands.DEVICETYPE then
615        if self.connected_lu == '' then
616          self:send_data(self.commands.IAC          ..
617          self.commands.SB           ..
618          self.options.TN3270E        ..
619          self.tncommands.DEVICETYPE ..
620          self.tncommands.REQUEST    ..
621          self.device_type           ..
622          self.commands.IAC          ..
623          self.commands.SE           )
624        else
625          stdnse.debug(3,"[TN3270] Sending LU: %s", self.connected_lu)
626          self:send_data(self.commands.IAC          ..
627          self.commands.SB           ..
628          self.options.TN3270E       ..
629          self.tncommands.DEVICETYPE ..
630          self.tncommands.REQUEST    ..
631          self.device_type           ..
632          self.tncommands.CONNECT    ..
633          self.connected_lu          ..
634          self.commands.IAC          ..
635          self.commands.SE           )
636        end
637      else
638        stdnse.debug(3,"[TN3270] Received TN3270 Send but not device type. Weird.")
639        return false
640      end
641    elseif option == self.tncommands.DEVICETYPE then -- Mainframe is confirming device type. Good!
642      if self.sb_options:sub(3,3) == self.tncommands.REJECT then
643        -- Welp our LU request failed, shut it down
644        stdnse.debug(3,"[TN3270] Received TN3270 REJECT.")
645        return false
646      elseif self.sb_options:sub(3,3) == self.tncommands.IS then
647        local tn_loc = 1
648        while self.sb_options:sub(4+tn_loc,4+tn_loc) ~= self.commands.SE and
649        self.sb_options:sub(4+tn_loc,4+tn_loc) ~= self.tncommands.CONNECT do
650          tn_loc = tn_loc + 1
651        end
652        --XXX Unused variable??? Should this be tn_loc?
653        -- local sn_loc = 1
654        if self.sb_options:sub(4+tn_loc,4+tn_loc) == self.tncommands.CONNECT then
655          self.connected_lu = self.sb_options:sub(5+tn_loc, #self.sb_options)
656          self.connected_dtype = self.sb_options:sub(4,3+tn_loc)
657          stdnse.debug(3,"[TN3270] Current LU: %s", self.connected_lu)
658        end
659        -- since We've connected lets send our options
660        self:send_data(self.commands.IAC          ..
661          self.commands.SB           ..
662          self.options.TN3270E       ..
663          self.tncommands.FUNCTIONS  ..
664          self.tncommands.REQUEST    ..
665          --self.tncommands.RESPONSES  .. -- we'll only support basic 3270E mode
666          self.commands.IAC          ..
667          self.commands.SE           )
668      end
669    elseif option == self.tncommands.FUNCTIONS then
670      if self.sb_options:sub(3,3) == self.tncommands.IS then
671        -- they accepted the function request, lets move on
672        self.negotiated = true
673        stdnse.debug(3,"[TN3270] Option Negotiation Done!")
674        self:in3270()
675      elseif self.sb_options:sub(3,3) == self.tncommands.REQUEST then
676        -- dummy functions for now. Our client doesn't have any
677        -- functions really but we'll agree to whatever they want
678        self:send_data(self.commands.IAC         ..
679          self.commands.SB          ..
680          self.options.TN3270E      ..
681          self.tncommands.FUNCTIONS ..
682          self.tncommands.IS        ..
683          self.sb_options:sub(4,4)  ..
684          self.commands.IAC         ..
685          self.commands.SE          )
686        self.negotiated = true
687        self:in3270()
688      end
689    end
690    return true
691  end,
692
693  --- Check to see if we're in TN3270
694  in3270 = function ( self )
695    if self.client_options[self.options.TN3270E] then
696    stdnse.debug(3,"[in3270] In TN3270E mode")
697      if self.negotiated then
698        stdnse.debug(3,"[in3270] TN3270E negotiated")
699        self.state = self.TN3270E_DATA
700      end
701    elseif self.client_options[self.options.EOR] and
702      self.client_options[self.options.BINARY] and
703      self.client_options[self.options.EOR] and
704      self.client_options[self.options.BINARY] and
705      self.client_options[self.options.TTYPE] then
706      stdnse.debug(3,"[in3270] In TN3270 mode")
707      self.state = self.TN3270_DATA
708    end
709
710    if self.state == self.TN3270_DATA or self.state == self.TN3270E_DATA then
711      -- since we're in TN3270 mode, let's create an empty buffer
712      stdnse.debug(3, "[in3270] Creating Empty IBM-3278-2 Buffer")
713      for i=0, 1920 do
714        self.buffer[i] = "\0"
715        self.fa_buffer[i] = "\0"
716        self.overwrite_buf[i] = "\0"
717      end
718      stdnse.debug(3, "[in3270] Empty Buffer Created. Length: " .. #self.buffer)
719    end
720    stdnse.debug(3,"[in3270] Current State: "..self.word_state[self.state])
721  end,
722
723  --- Also known as process_eor
724  process_data = function ( self )
725    local reply = 0
726    stdnse.debug(3,"Processing TN3270 Data")
727    if self.state == self.TN3270E_DATA then
728      stdnse.debug(3,"[TN3270E] Processing TN3270 Data header: %s", stdnse.tohex(self.tn_buffer:sub(1,5)))
729      self.tn3270_header.data_type     = self.tn_buffer:sub(1,1)
730      self.tn3270_header.request_flag  = self.tn_buffer:sub(2,2)
731      self.tn3270_header.response_flag = self.tn_buffer:sub(3,3)
732      self.tn3270_header.seq_number    = self.tn_buffer:sub(4,5)
733      if self.tn3270_header.data_type == "\000" then
734        reply = self:process_3270(self.tn_buffer:sub(6))
735        stdnse.debug(3,"[TN3270E] Reply: %s", reply)
736      end
737      if reply < 0  and self.tn3270_header.request_flag ~= self.TN3270E_RSF_NO_RESPONSE then
738        self:tn3270e_nak(reply)
739      elseif reply == self.NO_OUTPUT and
740        self.tn3270_header.request_flag == self.ALWAYS_RESPONSE then
741        self:tn3270e_ack()
742      end
743    else
744      self:process_3270(self.tn_buffer)
745    end
746    -- nsedebug.print_hex(self.tn_buffer)
747
748    self.tn_buffer = ''
749    return  true
750  end,
751
752  tn3270e_nak = function ( self, reply )
753    local neg = ""
754    if reply == self.BAD_COMMAND then
755      neg = self.NEG_COMMAND_REJECT
756    elseif reply == self.BAD_ADDRESS then
757      neg = self.NEG_OPERATION_CHECK
758    end
759
760    -- build the TN3270E nak reply header
761    local reply_buf = string.pack("BBB c2",
762      self.DT_RESPONSE, -- type
763      0, -- request
764      self.NEGATIVE_RESPONSE, -- response
765      -- because this is telnet we gotta double up 0xFF chars
766      self.tn3270_header.seq_number:sub(1,2):gsub(self.commands.IAC, self.commands.IAC:rep(2))
767      ) .. neg .. self.commands.IAC .. self.commands.EOR
768
769    -- now send the whole thing
770    self:send_data(reply_buf)
771  end,
772
773  tn3270e_ack = function ( self )
774    -- build the TN3270E ack reply header
775    local reply_buf = string.pack("BBB c2",
776      self.DT_RESPONSE, -- type
777      0, -- request
778      self.POSITIVE_RESPONSE, -- response
779      -- because this is telnet we gotta double up 0xFF chars
780      self.tn3270_header.seq_number:sub(1,2):gsub(self.commands.IAC, self.commands.IAC:rep(2))
781      ) .. self.POS_DEVICE_END .. self.commands.IAC .. self.commands.EOR
782    -- now send the whole package
783    self:send_data(reply_buf)
784  end,
785
786  clear_screen = function ( self )
787    self.buffer_address = 1
788    for i=1,1920,1 do
789      self.buffer[i] = "\0"
790      self.fa_buffer[i] = "\0"
791    end
792  end,
793
794  clear_unprotected = function ( self )
795    -- we don't support protect vs unprotected (yet)
796    -- this function is a stub for now
797  end,
798
799  process_3270 = function ( self, data )
800    -- the first byte will be the command we have to follow
801    local com = data:sub(1,1)
802    stdnse.debug(3, "[PROCESS 3270] Value Received: 0x%s", stdnse.tohex(com))
803    if com == self.command.EAU then
804      stdnse.debug(3,"TN3270 Command: Erase All Unprotected")
805      self:clear_unprotected()
806      return self.NO_OUTPUT
807    elseif com == self.command.EWA or com == self.sna_command.EWA or
808      com == self.command.EW  or com == self.sna_command.EW  then
809      stdnse.debug(3,"TN3270 Command: Erase Write (Alternate)")
810      self:clear_screen()
811      self:process_write(data) -- so far should only return No Output
812      return self.NO_OUTPUT
813    elseif com == self.command.W   or com == self.sna_command.W then
814      stdnse.debug(3,"TN3270 Command: Write")
815      self:process_write(data)
816    elseif com == self.command.RB  or com == self.sna_command.RB then
817      stdnse.debug(3,"TN3270 Command: Read Buffer")
818      self:process_read()
819      return self.OUTPUT
820    elseif com == self.command.RM  or com == self.sna_command.RM or
821      com == self.command.RMA or com == self.sna_command.RMA then
822      stdnse.debug(3,"TN3270 Command: Read Modified (All)")
823      --XXX What is read_modified? What is aid?
824      --self:read_modified(aid)
825      --return self.OUTPUT
826      stdnse.debug1("UNIMPLEMENTED TN3270 Command: Read Modified (All)")
827      return self.BAD_COMMAND
828    elseif com == self.command.WSF or com == self.sna_command.WSF then
829      stdnse.debug(3,"TN3270 Command: Write Structured Field")
830      return self:w_structured_field(data)
831    elseif com == self.command.NOP or com == self.sna_command.NOP then
832      stdnse.debug(3,"TN3270 Command: No OP (NOP)")
833      return self.NO_OUTPUT
834    else
835      stdnse.debug(3,"Unknown 3270 Data Stream command: 0x"..stdnse.tohex(com))
836      return self.BAD_COMMAND
837
838    end
839    return 1 -- we may sometimes enter a state where we have nothing which is fine
840
841  end,
842
843  --- WCC / tn3270 data stream processor
844  --
845  -- @param tn3270 data stream
846  -- @return status true on success, false on failure
847  -- @return changes self.buffer to match requested changes
848  process_write = function ( self, data )
849    stdnse.debug(3, "Processing TN3270 Write Command")
850    local prev = ''
851    local cp = ''
852    local num_attr = 0
853    local last_cmd = false
854    local i = 2 -- skip SF to get WCC
855
856    if (data:byte(i) & 0x40) == 0x40 then
857      stdnse.debug(3,"[WCC] Reset")
858    end
859
860    if (data:byte(i) & 0x02) == 0x02 then
861      stdnse.debug(3,"[WCC] Restore")
862    end
863
864    i = 3 -- skip the SF and the WCC.
865    while i <= #data do
866      cp = data:sub(i,i)
867      stdnse.debug(4,"Current Position: ".. i .. " of " .. #data)
868      stdnse.debug(4,"Current Item: ".. stdnse.tohex(cp))
869      -- yay! lua has no switch statement
870      if cp == self.orders.SF then
871        stdnse.debug(4,"Start Field")
872        prev = 'ORDER'
873
874        last_cmd = true
875        i = i + 1 -- skip SF
876        stdnse.debug(4,"Writting Zero to buffer at address: " .. self.buffer_address)
877        stdnse.debug(4,"Attribute Type: 0x".. stdnse.tohex(data:sub(i,i)))
878        self:write_field_attribute(data:sub(i,i))
879        self:write_char("\00")
880        self.buffer_address = self:INC_BUF_ADDR(self.buffer_address)
881        -- set the current position one ahead (after SF)
882        i = i + 1
883
884      elseif cp == self.orders.SFE then
885        stdnse.debug(4,"Start Field Extended")
886        i = i + 1 -- skip SFE
887        num_attr = data:byte(i)
888        stdnse.debug(4,"Number of Attributes: ".. num_attr)
889        for j = 1,num_attr do
890          i = i + 1
891          if data:byte(i) == 0xc0 then
892            stdnse.debug(4,"Writting Zero to buffer at address: " .. self.buffer_address)
893            stdnse.debug(4,"Attribute Type: 0x".. stdnse.tohex(data:sub(i,i)))
894            self:write_char("\00")
895            self:write_field_attribute(data:sub(i,i))
896          end
897
898          i = i + 1
899        end
900        i = i + 1
901        self.buffer_address = self:INC_BUF_ADDR(self.buffer_address)
902      elseif cp == self.orders.SBA then
903        stdnse.debug(4,"Set Buffer Address (SBA) 0x11")
904        self.buffer_address = self.DECODE_BADDR(data:byte(i+1), data:byte(i+2))
905        stdnse.debug(4,"Buffer Address: " .. self.buffer_address)
906        stdnse.debug(4,"Row: " .. self:BA_TO_ROW(self.buffer_address))
907        stdnse.debug(4,"Col: " .. self:BA_TO_COL(self.buffer_address))
908        last_cmd = true
909        prev = 'SBA'
910        -- the current position is SBA, the next two bytes are the lengths
911        i = i + 3
912        stdnse.debug(4,"Next Command: ".. stdnse.tohex(data:sub(i,i)))
913      elseif cp == self.orders.IC then -- Insert Cursor
914        stdnse.debug(4,"Insert Cursor (IC) 0x13")
915        stdnse.debug(4,"Current Cursor Address: " .. self.cursor_addr)
916        stdnse.debug(4,"Buffer Address: " .. self.buffer_address)
917        stdnse.debug(4,"Row: " .. self:BA_TO_ROW(self.buffer_address))
918        stdnse.debug(4,"Col: " .. self:BA_TO_COL(self.buffer_address))
919        prev = 'ORDER'
920        self.cursor_addr = self.buffer_address
921        last_cmd = true
922        i = i + 1
923      elseif cp == self.orders.RA then
924        -- Repeat address repeats whatever the next char is after the two byte buffer address
925        -- There's all kinds of weird GE stuff we could do, but not now. Maybe in future vers
926        stdnse.debug(4,"Repeat to Address (RA) 0x3C")
927        local ra_baddr = self.DECODE_BADDR(data:byte(i+1), data:byte(i+2))
928        stdnse.debug(4,"Repeat Character: " .. stdnse.tohex(data:sub(i+1,i+2)))
929
930        stdnse.debug(4,"Repeat to this Address: " .. ra_baddr)
931        stdnse.debug(4,"Currrent Address: " .. self.buffer_address)
932        prev = 'ORDER'
933        --char_code = data:sub(i+3,i+3)
934        i = i + 3
935        local char_to_repeat = data:sub(i,i)
936        stdnse.debug(4,"Repeat Character: " .. stdnse.tohex(char_to_repeat))
937        while (self.buffer_address ~= ra_baddr) do
938          self:write_char(char_to_repeat)
939          self.buffer_address = self:INC_BUF_ADDR(self.buffer_address)
940        end
941      elseif cp == self.orders.EUA then
942        stdnse.debug(4,"Erase Unprotected All (EAU) 0x12")
943        local eua_baddr = self.DECODE_BADDR(data:byte(i+1), data:byte(i+2))
944        i = i + 3
945        stdnse.debug(4,"EAU to this Address: " .. eua_baddr)
946        stdnse.debug(4,"Currrent Address: " .. self.buffer_address)
947        while (self.buffer_address ~= eua_baddr) do
948          -- do nothing for now. this feature isn't supported/required at the moment
949          self.buffer_address = self:INC_BUF_ADDR(self.buffer_address)
950          --stdnse.debug(3,"Currrent Address: " .. self.buffer_address)
951          --stdnse.debug(3,"EAU to this Address: " .. eua_baddr)
952        end
953      elseif cp == self.orders.GE then
954        stdnse.debug(4,"Graphical Escape (GE) 0x08")
955        prev = 'ORDER'
956        i = i + 1 -- move to next byte
957        local ge_char = data:sub(i,i)
958        self:write_char(self, ge_char)
959        self.buffer_address = self:INC_BUF_ADDR(self.buffer_address)
960      elseif cp == self.orders.MF then
961        -- MotherFucker, lol!
962        -- or mainframe maybe
963        -- we don't actually have 'fields' at this point
964        -- so there's nothing to be modified
965        stdnse.debug(4,"Modify Field (MF) 0x2C")
966        prev = 'ORDER'
967        i = i + 1
968        local num_attr = tonumber(data:sub(i,i))
969        for j = 1, num_attr, 1 do
970          -- placeholder in case we need to do something here
971          stdnse.debug(4,"Set Attribute (MF) 0x2C")
972          i = i + 1
973        end
974        self.buffer_address = self:INC_BUF_ADDR(self.buffer_address)
975      elseif cp == self.orders.SA then
976        -- We'll add alerting here to identify hidden field
977        -- but for now we're doing NOTHING
978        i = i + 1
979
980      elseif cp == self.fcorders.NUL or
981        cp == self.fcorders.SUB or
982        cp == self.fcorders.DUP or
983        cp == self.fcorders.FM or
984        cp == self.fcorders.FF or
985        cp == self.fcorders.CR or
986        cp == self.fcorders.NL or
987        cp == self.fcorders.EM or
988        cp == self.fcorders.EO then
989        stdnse.debug(4,"Format Control Order received")
990        prev = 'ORDER'
991        self:write_char("\064")
992        self.buffer_address = self:INC_BUF_ADDR(self.buffer_address)
993        i = i + 1
994      else -- whoa we made it.
995        local ascii_char = drda.StringUtil.toASCII(cp)
996        stdnse.debug(4,"Inserting 0x"..stdnse.tohex(cp).." (".. ascii_char ..") at the following location:")
997        stdnse.debug(4,"Row: " .. self:BA_TO_ROW(self.buffer_address))
998        stdnse.debug(4,"Col: " .. self:BA_TO_COL(self.buffer_address))
999        stdnse.debug(4,"Buffer Address: " .. self.buffer_address)
1000        self:write_char(data:sub(i,i))
1001        self.buffer_address = self:INC_BUF_ADDR(self.buffer_address)
1002        self.first_screen = true
1003        i = i + 1
1004      end -- end of massive if/else
1005    end -- end of while loop
1006    self.formatted = true
1007  end,
1008
1009  write_char = function ( self, char )
1010    if self.buffer[self.buffer_address] == "\0" then
1011      self.buffer[self.buffer_address] = char
1012    else
1013      self.overwrite_buf[self.buffer_address] = self.buffer[self.buffer_address]
1014      self.buffer[self.buffer_address] = char
1015    end
1016  end,
1017
1018  write_field_attribute = function ( self, attr )
1019    self.fa_buffer[self.buffer_address] = attr
1020  end,
1021
1022  process_read = function ( self )
1023    local output_addr = 0
1024    self.output_buffer = {}
1025    stdnse.debug(3,"Generating Read Buffer")
1026    self.output_buffer[output_addr] = string.pack("B",self.aid)
1027    output_addr = output_addr + 1
1028    stdnse.debug(3,"Output Address: ".. output_addr)
1029    self.output_buffer[output_addr] = self:ENCODE_BADDR(self.cursor_addr)
1030    return self:send_tn3270(self.output_buffer)
1031
1032    -- need to add while loop
1033
1034  end,
1035
1036  w_structured_field = function ( self, wsf_data )
1037    -- this is the ugliest hack ever
1038    -- but it works and it doesn't matter what we support anyway
1039    stdnse.debug(3, "Processing TN3270 Write Structured Field Command")
1040    -- all our options, one liner style
1041    local query_options =
1042    "\x88\x00\x16\x81\x86\x00\x08\x00\xf4\xf1\x00\xf2\x00\xf3\x00\xf4\z
1043     \x00\xf5\x00\xf6\x00\xf7\x00\x00\x0d\x81\x87\x04\x00\xf0\xf1\xf1\z
1044     \xf2\xf2\xf4\xf4\x00\x22\x81\x85\x82\x00\x07\x10\x00\x00\x00\x00\z
1045     \x07\x00\x00\x00\x00\x65\x00\x25\x00\x00\x00\x02\xb9\x00\x25\x01\z
1046     \x00\xf1\x03\xc3\x01\x36\x00\x2e\x81\x81\x03\x00\x00\x50\x00\x18\z
1047     \x00\x00\x01\x00\x48\x00\x01\x00\x48\x07\x10\x00\x00\x00\x00\x00\z
1048     \x00\x13\x02\x00\x01\x00\x50\x00\x18\x00\x00\x01\x00\x48\x00\x01\z
1049     \x00\x48\x07\x10\x00\x1c\x81\xa6\x00\x00\x0b\x01\x00\x00\x50\x00\z
1050     \x18\x00\x50\x00\x18\x0b\x02\x00\x00\x07\x00\x10\x00\x07\x00\x10\z
1051     \x00\x07\x81\x88\x00\x01\x02\x00\x16\x81\x80\x80\x81\x84\x85\x86\z
1052     \x87\x88\xa1\xa6\xa8\x96\x99\xb0\xb1\xb2\xb3\xb4\xb6\x00\x08\x81\z
1053     \x84\x00\x0a\x00\x04\x00\x06\x81\x99\x00\x00\xff\xef"
1054    stdnse.debug(3, "Current WSF : %s", stdnse.tohex(wsf_data:sub(4,4)) )
1055
1056    if self.state == self.TN3270E_DATA then
1057      -- We need to add the header here since we're in TN3270E mode
1058      query_options = "\x00\x00\x00\x00\x00" .. query_options
1059    end
1060    self:send_data(query_options)
1061    return 1
1062  end,
1063
1064
1065  --- Sends TN3270 Packet
1066  --
1067  -- Expands IAC to IAC IAC and finally appends IAC EOR
1068  -- @param data: table containing buffer array
1069  send_tn3270 = function ( self, data )
1070    local packet = ''
1071    if self.state == self.TN3270E_DATA then
1072      packet = "\x00\x00\x00\x00\x00"
1073      -- we need to create the tn3270E (the E is important) header
1074      -- which, in basic 3270E is 5 bytes of 0x00
1075      --packet = string.pack("BBB >I2",
1076      --  self.DT_3270_DATA, -- type
1077      --  0, -- request
1078      --  0, -- response
1079      --  0
1080       -- )
1081      --self.tn3270_header.seq_number
1082    end
1083    -- create send buffer and double up IACs
1084
1085    for i=0,#data do
1086      stdnse.debug(3,"Adding 0x" .. stdnse.tohex(data[i]) .. " to the read buffer")
1087      packet = packet .. data[i]
1088      if data[i] == self.commands.IAC then
1089        packet = packet .. self.commands.IAC
1090      end
1091    end
1092    packet = packet .. self.commands.IAC .. self.commands.EOR
1093    return self:send_data(packet) -- send the output buffer
1094  end,
1095
1096  get_screen = function ( self )
1097    stdnse.debug(3,"Returning the current TN3270 buffer")
1098    local buff = '\n'
1099    for i = 0,#self.buffer do
1100      if self.buffer[i] == "\00" then
1101        buff = buff .. " "
1102      else
1103        buff = buff .. drda.StringUtil.toASCII(self.buffer[i])
1104      end
1105      if (i+1) % 80 == 0 then
1106        buff = buff .. "\n"
1107      end
1108    end
1109    return buff
1110  end,
1111
1112  get_screen_debug = function ( self, lvl )
1113    lvl = lvl or 1
1114    stdnse.debug(lvl,"---------------------- Printing the current TN3270 buffer ----------------------")
1115    local buff = ''
1116    for i = 0,#self.buffer do
1117      if self.buffer[i] == "\00" then
1118        buff = buff .. " "
1119      else
1120        buff = buff .. drda.StringUtil.toASCII(self.buffer[i])
1121      end
1122      if (i+1) % 80 == 0 then
1123        stdnse.debug(lvl, buff)
1124        buff = ''
1125      end
1126    end
1127    stdnse.debug(lvl,"----------------------- End of the current TN3270 buffer ---------------------")
1128
1129    return buff
1130  end,
1131
1132  get_screen_raw = function ( self )
1133    local buff = ''
1134    for i = 0,#self.buffer do
1135      buff = buff .. drda.StringUtil.toASCII(self.buffer[i])
1136    end
1137    return buff
1138  end,
1139
1140
1141  --- Sends data at the current cursor location. Ignores field attributes.
1142  --
1143  -- It only uses enter key (AID = 0x7d) to send this data
1144  -- for more complicated items use send_location
1145  -- @param string you wish to send.
1146  send_cursor = function ( self, data )
1147    local ebcdic_letter = ''
1148    self.output_buffer = {} -- empty the output buffer
1149    self.output_buffer[0] = string.pack("B",self.aids.ENTER) -- what follows is an ENTER
1150    stdnse.debug(3,"Cursor Location ("..self.cursor_addr.."): Row: %s, Column: %s ",
1151      self:BA_TO_ROW(self.cursor_addr),
1152      self:BA_TO_COL(self.cursor_addr) )
1153    table.insert(self.output_buffer, self:ENCODE_BADDR(self.cursor_addr + #data)) -- location of cursor
1154    table.insert(self.output_buffer, self.orders.SBA) -- set the buffer address to the following location
1155    table.insert(self.output_buffer, self:ENCODE_BADDR(self.cursor_addr)) -- location of buffer address
1156    for i = 1, #data do
1157      stdnse.debug(3,"Inserting %s to the send buffer", data:sub(i,i))
1158      ebcdic_letter = drda.StringUtil.toEBCDIC( data:sub(i,i) )
1159      table.insert(self.output_buffer, ebcdic_letter ) -- insert the ebcdic character on the array
1160    end
1161    return self:send_tn3270(self.output_buffer)
1162  end,
1163
1164  --- Sends the data to the location specified
1165  --
1166  -- Using a location on the screen sends the data
1167  -- @param location: a location on the screen (between 0 and 1920)
1168  -- @param data: ascii data to send to that location
1169  send_location = function( self, location, data )
1170    local cursor_location = location + #data
1171    local ebcdic_letter = ''
1172    self.output_buffer = {}
1173    self.output_buffer[0] = string.pack("B",self.aids.ENTER)
1174    table.insert(self.output_buffer, self:ENCODE_BADDR(cursor_location))
1175    stdnse.debug(3,"Cursor Location ("..cursor_location.."): Row: %s, Column: %s ",
1176      self:BA_TO_ROW(cursor_location),
1177      self:BA_TO_COL(cursor_location) )
1178    stdnse.debug(3,"Inserting %s at location %d", data, location )
1179    table.insert(self.output_buffer, self.orders.SBA)
1180    cursor_location = location
1181    table.insert(self.output_buffer, self:ENCODE_BADDR(cursor_location))
1182    for j = 1, #data do
1183      ebcdic_letter = drda.StringUtil.toEBCDIC( data:sub(j,j) )
1184      table.insert(self.output_buffer, ebcdic_letter )
1185    end
1186
1187    return self:send_tn3270(self.output_buffer)
1188  end,
1189
1190  --- Sends the data to multiple locations on the screen
1191  --
1192  -- Using a supplied tuple of location and data generates tn3270 data to
1193  -- fill out the screen
1194  -- @param location_tuple: and array of tuples with location and data. For
1195  --                        example: send_locations([{579:"dade"},{630:"secret"}])
1196  send_locations = function( self, location_tuple )
1197    local cursor_location = location_tuple[#location_tuple][1] + #location_tuple[#location_tuple][2]
1198    local ebcdic_letter = ''
1199    self.output_buffer = {}
1200    self.output_buffer[0] = string.pack("B",self.aids.ENTER)
1201    table.insert(self.output_buffer, self:ENCODE_BADDR(cursor_location))
1202    stdnse.debug(3,"Cursor Location ("..cursor_location.."): Row: %s, Column: %s ",
1203      self:BA_TO_ROW(cursor_location),
1204      self:BA_TO_COL(cursor_location) )
1205    for i = 1, #location_tuple do
1206      stdnse.debug(3,"Inserting %s at location %d", location_tuple[i][2], location_tuple[i][1] )
1207      table.insert(self.output_buffer, self.orders.SBA)
1208      cursor_location = location_tuple[i][1]
1209      table.insert(self.output_buffer, self:ENCODE_BADDR(cursor_location))
1210      for j = 1, #location_tuple[i][2] do
1211        ebcdic_letter = drda.StringUtil.toEBCDIC( location_tuple[i][2]:sub(j,j) )
1212        table.insert(self.output_buffer, ebcdic_letter )
1213      end
1214    end
1215    return self:send_tn3270(self.output_buffer)
1216  end,
1217
1218  send_enter = function ( self )
1219    local ebcdic_letter = ''
1220    self.output_buffer = {}
1221    self.output_buffer[0] = string.pack("B",self.aids.ENTER)
1222    table.insert(self.output_buffer, self:ENCODE_BADDR(self.cursor_addr))
1223    table.insert(self.output_buffer, self.orders.SBA)
1224    table.insert(self.output_buffer, self:ENCODE_BADDR(self.cursor_addr))
1225    return self:send_tn3270(self.output_buffer)
1226  end,
1227
1228  send_clear = function ( self )
1229    return self:send_data( string.pack("B",self.aids.CLEAR) .. self.commands.IAC .. self.commands.EOR )
1230  end,
1231
1232  send_pf = function ( self, pf )
1233    if pf > 24 or pf < 0 then
1234      return false, "PF Value must be between 1 and 24"
1235    end
1236    self.output_buffer = {}
1237    self.output_buffer[0] = string.pack("B", self.aids["PF"..pf] )
1238    stdnse.debug(3,"Cursor Location ("..self.cursor_addr.."): Row: %s, Column: %s ",
1239      self:BA_TO_ROW(self.cursor_addr),
1240      self:BA_TO_COL(self.cursor_addr) )
1241    self.output_buffer[1] = self:ENCODE_BADDR(self.cursor_addr)
1242    return self:send_tn3270(self.output_buffer)
1243  end,
1244
1245  writeable = function (self)
1246    -- Returns a list with all writeable fields as {location, length} tuples
1247    local writeable_list = {}
1248    for i = 0,#self.fa_buffer do
1249      if ( self.fa_buffer[i] ~= "\00" ) and (self.fa_buffer[i]:byte(1) & 0x20) ~= 0x20 then
1250        -- found writeable flag
1251        for j = i,#self.fa_buffer do
1252          -- find end of field
1253          if (self.fa_buffer[j]:byte(1) & 0x20) == 0x20 then
1254            stdnse.debug(3,"[WRITEABLE] Area: %d Row: %d Col: %d Length: %d", i + 1, self:BA_TO_ROW(i + 1), self:BA_TO_COL(i + 2), j-i-1)
1255            table.insert(writeable_list, {i + 1, j-i-1})
1256            break
1257          end
1258        end
1259      end
1260    end
1261    return writeable_list
1262  end,
1263
1264  find = function ( self, str )
1265    local buff = ''
1266    for i = 0,#self.buffer do
1267      if self.buffer[i] == "\00" then
1268        buff = buff .. " "
1269      else
1270        buff = buff .. drda.StringUtil.toASCII(self.buffer[i])
1271      end
1272    end
1273    --local buff = self:get_screen()
1274    stdnse.debug(3, "[FIND] Looking for: %s", tostring(str))
1275    local i, j = string.find(buff, str)
1276    if i == nil then
1277      stdnse.debug(3, "[FIND] Couldn't find: %s", tostring(str))
1278      return false
1279    else
1280      stdnse.debug(3, "[FIND] Found String: %s", tostring(str))
1281      return i , j
1282    end
1283  end,
1284
1285  isClear = function ( self )
1286    local buff = ''
1287    for i = 0,#self.buffer do
1288      if self.buffer[i] == "\00" then
1289        buff = buff .. " "
1290      else
1291        buff = buff .. drda.StringUtil.toASCII(self.buffer[i])
1292      end
1293    end
1294    local i, j = string.find(buff, '%w')
1295    if i ~= nil then
1296      stdnse.debug(3, "[CLEAR] Screen has text")
1297      return false
1298    else
1299      stdnse.debug(3, "[CLEAR] Screen is Empty")
1300      return true
1301    end
1302  end,
1303
1304  --- Any Hidden Fields
1305  --
1306  -- @returns true if there are any hidden fields in the buffer
1307  any_hidden = function ( self )
1308    local hidden_attrib = 0x0c -- 00001100 is hidden
1309    for i = 0,#self.fa_buffer do
1310      if (self.fa_buffer[i]:byte(1) & hidden_attrib) == hidden_attrib then
1311        return true
1312      end
1313    end
1314  end,
1315
1316  --- Hidden Fields
1317  --
1318  -- @returns the locations of hidden fields in a table with each pair being the start and stop of the hidden field
1319  hidden_fields_location = function ( self )
1320    local hidden_attrib = 0x0c -- 00001100 is hidden
1321    local hidden_location = {}
1322    local i = 1
1323    if not self:any_hidden() then
1324      return hidden_location
1325    end
1326    while i <= #self.fa_buffer do
1327      if (self.fa_buffer[i]:byte(1) & hidden_attrib) == hidden_attrib then
1328        stdnse.debug(3, "Found hidden field at buffer location: " .. i)
1329        table.insert(hidden_location, i)
1330        i = i + 1
1331        while self.fa_buffer[i] == "\0" do
1332          i = i + 1
1333        end
1334        table.insert(hidden_location, i)
1335      end
1336      i = i + 1
1337    end
1338    return hidden_location
1339  end,
1340
1341  hidden_fields = function ( self )
1342    local locations = self:hidden_fields_location()
1343    local fields = {}
1344    local i, j = 1,1
1345    local start, stop = 0
1346    while i <= #locations do
1347      start = locations[i] + 1
1348      stop  = locations[i+1] - 1
1349      stdnse.debug(3, "Start Location: %i Stop Location %i", start, stop)
1350      fields[j] = ''
1351      for k = start,stop do
1352        -- stdnse.debug(3, "k = %i Inserting 0x%s", k, stdnse.tohex(self.buffer[k]))
1353        fields[j] = fields[j] .. drda.StringUtil.toASCII(self.buffer[k])
1354      end
1355      j = j + 1
1356      i = i + 2
1357    end
1358    return fields
1359  end,
1360
1361  any_overwritten = function ( self )
1362    for i = 1, #self.overwrite_buf do
1363      if self.overwrite_buf[i] ~= "\0" then
1364        return true
1365      end
1366    end
1367    return false
1368  end,
1369
1370  set_lu = function (self, LU)
1371    -- Sets an LU
1372    self.connected_lu = LU
1373  end,
1374
1375  get_lu = function ( self )
1376     return self.connected_lu
1377  end,
1378  disable_tn3270e = function ( self )
1379    stdnse.debug(3,"Disabling TN3270E")
1380    table.insert(self.unsupported_opts,self.options.TN3270E)
1381  end,
1382  overwrite_data = function ( self )
1383    if not self:any_overwritten() then
1384      return false
1385    end
1386    stdnse.debug(3,"Printing the overwritten TN3270 buffer")
1387    local buff = '\n'
1388    for i = 0,#self.overwrite_buf do
1389      if self.overwrite_buf[i] == "\0" then
1390        buff = buff .. " "
1391      else
1392        buff = buff .. drda.StringUtil.toASCII(self.buffer[i])
1393      end
1394      if i % 80 == 0 then
1395        buff = buff .. "\n"
1396      end
1397    end
1398    return buff
1399  end
1400}
1401
1402return _ENV
1403