Class: Muby::Connection
- Inherits:
-
Object
- Object
- Muby::Connection
- Includes:
- Configurable, Displayer, Logger
- Defined in:
- lib/muby/connection.rb
Overview
The class that encapsulates the actual Connection
Constant Summary collapse
- TELNET_COMMANDS =
{ 240 => :end_of_sub_negotiation, 241 => :noop, 242 => :data_mark, 243 => :break, 249 => :go_ahead, 250 => :sub_negotiation, 251 => :will, 252 => :wont, 253 => :do, 254 => :dont, 255 => :iac }
Instance Method Summary collapse
- #append_buffers(c) ⇒ Object
- #close ⇒ Object
- #colorize(s) ⇒ Object
-
#connect! ⇒ Object
Almost ripped from the documentation: www.ruby-doc.org/core/classes/Socket.src/M002114.html.
- #display_buffer ⇒ Object
- #feed(s) ⇒ Object
-
#gag(matchBuffer) ⇒ Object
Check if we want to gag the current matchBuffer and debug about it.
- #getc ⇒ Object
- #homemade_split(s, r) ⇒ Object
-
#initialize(inputWindow, outputWindow, host, port) ⇒ Connection
constructor
Set it up with windows, handle and host info.
-
#listen ⇒ Object
Keep listening to the remote socket and react accordingly.
-
#nongag(matchBuffer) ⇒ Object
Check if we should definitely NOT gag the current matchBuffer, and debug about it.
- #process(c) ⇒ Object
- #run_remote_triggers ⇒ Object
-
#send(s) ⇒ Object
Just plain send the string we got.
-
#single_shot_gag(matchBuffer) ⇒ Object
Check if we want to gag the current matchBuffer with the single shot gags and debug about it.
-
#status(message) ⇒ Object
Display a status message in the outputwindow if wanted (conf.connection_status).
- #substitute(buffer, hash) ⇒ Object
-
#trigger(matchBuffer, hash, skip_used = true) ⇒ Object
Check if we should trigger a Proc on the current matchBuffer, and debug about it.
Methods included from Displayer
debug, error, exception, info, trace, warn
Methods included from Configurable
Methods included from Logger
Constructor Details
#initialize(inputWindow, outputWindow, host, port) ⇒ Connection
Set it up with windows, handle and host info.
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/muby/connection.rb', line 16 def initialize(inputWindow, outputWindow, host, port) @inputWindow = inputWindow @outputWindow = outputWindow status("Connecting to " + host.inspect + ":" + port.inspect) @host = host @port = port connect! conf.connect_triggers.each do |command| @inputWindow.execute(command, @inputWindow, @outputWindow) end status("Connected to " + host.inspect + ":" + port.inspect) @matchBuffer = "" @showBuffer = [] @used_triggers = {} @listener = Thread.new do begin status("Listening thread started") listen status("Listening thread finished") rescue Exception => e exception(e) ensure close end end if @socket end |
Instance Method Details
#append_buffers(c) ⇒ Object
312 313 314 315 316 317 318 319 |
# File 'lib/muby/connection.rb', line 312 def append_buffers(c) if String === @showBuffer.last @showBuffer.last << c.chr else @showBuffer << c.chr end @matchBuffer = @matchBuffer + c.chr end |
#close ⇒ Object
354 355 356 357 358 359 360 361 362 363 364 365 366 |
# File 'lib/muby/connection.rb', line 354 def close if Thread.current != @listener && @listener && @listener.alive? status("Killing listening thread") @listener.kill end if @socket && !@socket.closed? status("Disconnecting our end") conf.disconnect_triggers.each do |command| @inputWindow.execute(command, @inputWindow, @outputWindow) end @socket.close if @socket end end |
#colorize(s) ⇒ Object
408 409 410 411 412 413 |
# File 'lib/muby/connection.rb', line 408 def colorize(s) conf.colors.each do |reg, colors| return colors if s.match(reg) end return ["", ""] end |
#connect! ⇒ Object
Almost ripped from the documentation: www.ruby-doc.org/core/classes/Socket.src/M002114.html
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/muby/connection.rb', line 46 def connect! @socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) addr = Socket.sockaddr_in(@port, @host) begin @socket.connect_nonblock(addr) rescue Errno::EINPROGRESS IO.select(nil, [@socket], nil, conf.connect_timeout) begin @socket.connect_nonblock(addr) rescue Errno::EISCONN rescue Errno::EALREADY raise "Connection timed out" end end end |
#display_buffer ⇒ Object
415 416 417 418 419 420 421 422 423 424 425 426 427 |
# File 'lib/muby/connection.rb', line 415 def display_buffer unless @showBuffer.empty? if !gag(@matchBuffer) || nongag(@matchBuffer) @showBuffer = substitute(@showBuffer, conf.remote_substitutions) Muby::Completer.get_instance.store(@matchBuffer) if conf.feed_completer_with_input pre, post = colorize(@matchBuffer) @showBuffer.unshift pre @showBuffer.push post @outputWindow.print(*@showBuffer) end @showBuffer = [] end end |
#feed(s) ⇒ Object
167 168 169 170 171 172 |
# File 'lib/muby/connection.rb', line 167 def feed(s) s.unpack("C*").each do |c| handle(c) end nil end |
#gag(matchBuffer) ⇒ Object
Check if we want to gag the current matchBuffer and debug about it.
Remove the gag regexp if it is broken.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/muby/connection.rb', line 76 def gag(matchBuffer) returnValue = false conf.gags.each do |gag| begin if matchBuffer.match(gag) trace(matchBuffer + " matches " + gag.inspect + ": gag active") returnValue = true end rescue RegexpError => error conf.gags.delete(key) exception(e) end end returnValue = true if single_shot_gag(matchBuffer) returnValue end |
#getc ⇒ Object
190 191 192 193 194 |
# File 'lib/muby/connection.rb', line 190 def getc c = @socket.getc log_input(c.chr) if c c end |
#homemade_split(s, r) ⇒ Object
373 374 375 376 377 378 379 380 381 382 |
# File 'lib/muby/connection.rb', line 373 def homemade_split(s, r) rval = [] rest = s while match = rest.match(/(.*?)#{r.source}(.*)/) rval << match[1] rest = match[2] end rval << rest rval end |
#listen ⇒ Object
Keep listening to the remote socket and react accordingly.
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 |
# File 'lib/muby/connection.rb', line 324 def listen c = true # While we get characters while c # While we have something to read within one second while select([@socket],nil,nil,1) && c = getc # If it is a regular character if regular_char = process(c) # Append it to our match and show buffers append_buffers(regular_char) # Trigger all remote character triggers on it trigger(@matchBuffer, conf.remote_character_triggers, true) # If it is a newline if regular_char == 10 # Trigger all normal remote triggers on it run_remote_triggers display_buffer @matchBuffer = "" end end end trigger(@matchBuffer, conf.remote_character_triggers, true) run_remote_triggers display_buffer if conf.flush @matchBuffer = "" end status("Connection closed by remote end") @inputWindow.disconnect end |
#nongag(matchBuffer) ⇒ Object
Check if we should definitely NOT gag the current matchBuffer, and debug about it.
Remove the nongag regexp if it is broken.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/muby/connection.rb', line 122 def nongag(matchBuffer) returnValue = false conf.anti_gags.each do |nongag| begin if matchBuffer.match(nongag) trace(matchBuffer + " matches " + nongag.inspect + ": nongag active") returnValue = true end rescue RegexpError => error conf.anti_gags.delete(key) exception(e) end end returnValue end |
#process(c) ⇒ Object
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 |
# File 'lib/muby/connection.rb', line 196 def process(c) # # The telnet support (just so we dont explode or something) # # We are just plain ignoring most of it atm. # if TELNET_COMMANDS[c] == :iac # this is an "interpret as command" c = getc if (next_command = TELNET_COMMANDS[c]) == :iac # if the next one as well is an iac, we actually want to display a 255 handle_regular_character(c) else case next_command when :do # ignore the option negotiation c = getc when :dont # ignore the option negotiation c = getc when :will # ignore the option negotiation c = getc when :wont # ignore the option negotiation c = getc when :noop # waf? # do nothing when :data_mark warn("Got a data_mark (TELNET protocol) which I don't know how to handle. Expect strange behaviour...") when :break warn("Got a break (TELNET protocol) which I don't know how to handle. Expect strange behaviour...") when :go_ahead display_buffer # on a go ahead the server obviously wants us to display the @displayBuffer regardless of our conf.flush setting when :sub_negotiation # we just skip ahead to the end of the sub negotiation while TELNET_COMMANDS[c] != :end_of_sub_negotiation c = getc end else warn("Got an unknown TELNET command (#{c.chr}) which I don't know how to handle. Expect strange behaviour...") end end return nil elsif c == 27 # escape char! this is probably some ANSI color or shite c = getc if c.chr == "[" # this is an ansi-something that is more than one char long ansiString = "" while !"cnRhl()HABCfsurhgKJipm".include?((c = getc).chr) ansiString << c.chr end if c.chr == "m" && Ncurses.has_colors? # ah, text property! i understand this! properties = ansiString.split(";") attributes = 0 bgcolor = false fgcolor = false reset = properties.index("0") if reset properties.delete("0") end properties.each do |property| case property.to_i when 1 attributes = attributes | Ncurses.const_get("A_BOLD") when 2 attributes = attributes | Ncurses.const_get("A_DIM") when 4 attributes = attributes | Ncurses.const_get("A_UNDERLINE") when 5 attributes = attributes | Ncurses.const_get("A_BLINK") unless conf.disable_blink when 7 attributes = attributes | Ncurses.const_get("A_REVERSE") when 8 attributes = attributes | Ncurses.const_get("A_INVIS") when 30 fgcolor = Ncurses.const_get("COLOR_BLACK") when 31 fgcolor = Ncurses.const_get("COLOR_RED") when 32 fgcolor = Ncurses.const_get("COLOR_GREEN") when 33 fgcolor = Ncurses.const_get("COLOR_YELLOW") when 34 fgcolor = Ncurses.const_get("COLOR_BLUE") when 35 fgcolor = Ncurses.const_get("COLOR_MAGENTA") when 36 fgcolor = Ncurses.const_get("COLOR_CYAN") when 37 fgcolor = Ncurses.const_get("COLOR_WHITE") when 40 bgcolor = Ncurses.const_get("COLOR_BLACK") when 41 bgcolor = Ncurses.const_get("COLOR_RED") when 42 bgcolor = Ncurses.const_get("COLOR_GREEN") when 43 bgcolor = Ncurses.const_get("COLOR_YELLOW") when 44 bgcolor = Ncurses.const_get("COLOR_BLUE") when 45 bgcolor = Ncurses.const_get("COLOR_MAGENTA") when 46 bgcolor = Ncurses.const_get("COLOR_CYAN") when 47 bgcolor = Ncurses.const_get("COLOR_WHITE") end end style = nil if reset style = Muby::Style.new(attributes, fgcolor, bgcolor, false) else style = Muby::Style.new(attributes, fgcolor, bgcolor, true) end @showBuffer.push(style) end end return nil elsif !conf.broken_keycodes.include?(c) return c end end |
#run_remote_triggers ⇒ Object
368 369 370 371 |
# File 'lib/muby/connection.rb', line 368 def run_remote_triggers @showBuffer = [] unless trigger(@matchBuffer, conf.remote_triggers, false) @used_triggers = {} end |
#send(s) ⇒ Object
Just plain send the string we got.
432 433 434 435 436 437 438 439 440 |
# File 'lib/muby/connection.rb', line 432 def send(s) log_output(s) conf.local_substitutions.each do |key, value| # It might be useful to allow colour codes for highlighting local substitutions.. but only when echo is on. # No, cause this only gets sent to the server, it never shows up to the user. s.gsub!(key, value) end @socket.print(s) if @socket end |
#single_shot_gag(matchBuffer) ⇒ Object
Check if we want to gag the current matchBuffer with the single shot gags and debug about it. Remove all matching gags, and all gags producing regexp errors.
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/muby/connection.rb', line 97 def single_shot_gag(matchBuffer) returnValue = false new_gags = [] conf.single_shot_gags.each do |gag| this_gag_matched = false begin if matchBuffer.match(gag) trace(matchBuffer + " matches " + gag.inspect + ": gag active (but only once)") returnValue = true this_gag_matched = true end rescue RegexpError => error exception(e) end new_gags << gag unless this_gag_matched end conf.single_shot_gags = new_gags returnValue end |
#status(message) ⇒ Object
Display a status message in the outputwindow if wanted (conf.connection_status)
65 66 67 68 69 |
# File 'lib/muby/connection.rb', line 65 def status() if conf.connection_status @outputWindow.print_on_newline(*[ + "\n"]) end end |
#substitute(buffer, hash) ⇒ Object
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 |
# File 'lib/muby/connection.rb', line 384 def substitute(buffer, hash) return_value = [] buffer.each do |part| if String === part part_to_append = [part] hash.each do |regexp, substitution| case substitution when String part_to_append = [part.gsub(regexp, substitution)] when Array if part.match(regexp) split_part = homemade_split(part, regexp) part_to_append = split_part.zip([substitution] * (split_part.size - 1)).flatten.compact end end end return_value += part_to_append else return_value << part end end return_value end |
#trigger(matchBuffer, hash, skip_used = true) ⇒ Object
Check if we should trigger a Proc on the current matchBuffer, and debug about it.
Remove the trigger regexp if it is broken.
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/muby/connection.rb', line 143 def trigger(matchBuffer, hash, skip_used = true) rval = true hash.each do |key, value| if skip_used && @used_triggers.include?(key) trace("#{key.inspect} has already been matched on this line, skipping it") else trace("checking if " + matchBuffer + " matches " + key.inspect) begin if match = matchBuffer.match(key) trace(matchBuffer + " matches " + key.inspect + ": .call'ing Proc") # Run the procedure associated with that trigger: rval &&= @inputWindow.execute(value, @inputWindow, @outputWindow, match) @used_triggers[key] = true if skip_used end # If we received an error with the regular expression: rescue RegexpError => error hash.delete(key) exception(error) end end end return rval end |