diff --git a/terminator b/terminator index f1864adc..03687ada 100755 --- a/terminator +++ b/terminator @@ -79,8 +79,8 @@ if __name__ == '__main__': parser = OptionParser (usage) parser.add_option ("-v", "--version", action="store_true", dest="version", help="Display program version") - parser.add_option ("-d", "--debug", action="store_true", dest="debug", - help="Enable debugging information") + parser.add_option ("-d", "--debug", action="count", dest="debug", + help="Enable debugging information (twice for debug server)") parser.add_option ("-m", "--maximise", action="store_true", dest="maximise", help="Open the %s window maximised" % APP_NAME.capitalize()) parser.add_option ("-f", "--fullscreen", action="store_true", dest="fullscreen", @@ -143,20 +143,16 @@ See the following bug report for more details: except IOError: pass - import terminatorlib.debugserver as debugserver - import threading - - gtk.gdk.threads_init() - dbg ('profile_cb: settled on profile: "%s"' % options.profile) term = Terminator (options.profile, command, options.fullscreen, options.maximise, options.borderless, options.no_gconf) - (serverthread, server) = debugserver.spawn(locals()) + if options.debug > 1: + import terminatorlib.debugserver as debugserver + import threading + + gtk.gdk.threads_init() + debugserver.spawn(locals()) + gtk.main() -# guithread = threading.Thread(target=gtk.main, name="Main GUI thread") -# guithread.start() -# guithread.join() - server.socket.close() - diff --git a/terminatorlib/debugserver.py b/terminatorlib/debugserver.py index 38387372..ee685c4c 100644 --- a/terminatorlib/debugserver.py +++ b/terminatorlib/debugserver.py @@ -17,40 +17,69 @@ import readline import rlcompleter import re +def ddbg(msg): + return + ddbg(msg) + class PythonConsoleServer(SocketServer.BaseRequestHandler): env = None def setup(self): - dbg('debugserver: connect from %s' % str(self.client_address)) - dbg('debugserver: env=%s' % repr(PythonConsoleServer.env)) + ddbg('debugserver: connect from %s' % str(self.client_address)) + ddbg('debugserver: env=%s' % repr(PythonConsoleServer.env)) self.console = TerminatorConsole(PythonConsoleServer.env) def handle(self): - dbg("debugserver: handling") + ddbg("debugserver: handling") try: self.socketio = self.request.makefile() sys.stdout = self.socketio sys.stdin = self.socketio -# sys.stderr = self.socketio + sys.stderr = self.socketio self.console.run(self) finally: sys.stdout = sys.__stdout__ sys.stdin = sys.__stdin__ -# sys.stderr = sys.__stderr__ + sys.stderr = sys.__stderr__ self.socketio.close() - dbg("debugserver: done handling") + ddbg("debugserver: done handling") def verify_request(self, request, client_address): return True def finish(self): - dbg('debugserver: disconnect from %s' % str(self.client_address)) + ddbg('debugserver: disconnect from %s' % str(self.client_address)) -BareLF = re.compile('([^\015])\015') -DoDont = re.compile('(^|[^\377])\377[\375\376](.)') -WillWont = re.compile('(^|[^\377])\377[\373\374](.)') -AreYouThere = re.compile('(^|[^\377])\377\366') -IpTelnet = re.compile('(^|[^\377])\377\364') -OtherTelnet = re.compile('(^|[^\377])\377[^\377]') +# rfc1116/rfc1184 +LINEMODE = chr(34) # Linemode negotiation + +NULL = chr(0) +ECHO = chr(1) +CR = chr(13) +LF = chr(10) +SE = chr(240) # End subnegotiation +NOP = chr(241) +DM = chr(242) # Data Mark +BRK = chr(243) # Break +IP = chr(244) # Interrupt Process +AO = chr(245) # Abort Output +AYT = chr(246) # Are You There +EC = chr(247) # Erase Character +EL = chr(248) # Erase Line +GA = chr(249) # Go Ahead +SB = chr(250) # Subnegotiation follows +WILL = chr(251) # Subnegotiation commands +WONT = chr(252) +DO = chr(253) +DONT = chr(254) +IAC = chr(255) # Interpret As Command + +UIAC = '(^|[^' + IAC + '])' + IAC # Unescaped IAC +BareLF = re.compile('([^' + CR + '])' + CR) +DoDont = re.compile(UIAC +'[' + DO + DONT + '](.)') +WillWont = re.compile(UIAC + '[' + WILL + WONT + '](.)') +AreYouThere = re.compile(UIAC + AYT) +IpTelnet = re.compile(UIAC + IP) +OtherTelnet = re.compile(UIAC + '[^' + IAC + ']') # See http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/205335 for telnet bits # Python doesn't make this an especially neat conversion :( @@ -58,59 +87,57 @@ class TerminatorConsole(code.InteractiveConsole): def parse_telnet(self, data): odata = data data = re.sub(BareLF, '\\1', data) - data = data.replace('\015\000', '') - data = data.replace('\000', '') + data = data.replace(CR + NULL, '') + data = data.replace(NULL, '') bits = re.findall(DoDont, data) - dbg("bits = %s" % repr(bits)) + ddbg("bits = %s" % repr(bits)) if bits: data = re.sub(DoDont, '\\1', data) - dbg("telnet: DO/DON'T answer") + ddbg("telnet: DO/DON'T answer") # answer DO and DON'T with WON'T for bit in bits: - self.write("\377\374" + bit[1]) + self.write(IAC + WONT + bit[1]) bits = re.findall(WillWont, data) if bits: data = re.sub(WillWont, '\\1', data) - dbg("telnet: WILL/WON'T answer") + ddbg("telnet: WILL/WON'T answer") for bit in bits: # answer WILLs and WON'T with DON'Ts - self.write("\377\376" + bit[1]) + self.write(IAC + DONT + bit[1]) bits = re.findall(AreYouThere, data) if bits: - dbg("telnet: am I there answer") + ddbg("telnet: am I there answer") data = re.sub(AreYouThere, '\\1', data) for bit in bits: self.write("Yes, I'm still here, I think.\n") - bits = re.findall(IpTelnet, data) # IP (Interrupt Process) - for bit in bits: - dbg("debugserver: Ctrl-C detected") + (data, interrupts) = re.subn(IpTelnet, '\\1', data) + if interrupts: + ddbg("debugserver: Ctrl-C detected") raise KeyboardInterrupt - data = re.sub(IpTelnet, '\\1', data) # ignore IP Telnet codes data = re.sub(OtherTelnet, '\\1', data) # and any other Telnet codes - data = data.replace('\377\377', '\377') # and handle escapes + data = data.replace(IAC + IAC, IAC) # and handle escapes if data != odata: - dbg("debugserver: Replaced %s with %s" % (repr(odata), repr(data))) + ddbg("debugserver: Replaced %s with %s" % (repr(odata), repr(data))) return data - def raw_input(self, prompt = None): - dbg("debugserver: raw_input prompt = %s" % repr(prompt)) + ddbg("debugserver: raw_input prompt = %s" % repr(prompt)) if prompt: self.write(prompt) buf = '' compstate = 0 while True: - data = self.server.socketio.read(1) # should get the client sending unbuffered for tab complete? - dbg('raw_input: char=%s' % repr(data)) - if data == '\n' or data == '\006': + data = self.server.socketio.read(1) + ddbg('raw_input: char=%s' % repr(data)) + if data == LF or data == '\006': buf = self.parse_telnet(buf + data).lstrip() if buf != '': return buf @@ -120,7 +147,7 @@ class TerminatorConsole(code.InteractiveConsole): buf += data def write(self, data): - dbg("debugserver: write %s" % repr(data)) + ddbg("debugserver: write %s" % repr(data)) self.server.socketio.write(data) self.server.socketio.flush() @@ -135,22 +162,12 @@ class TerminatorConsole(code.InteractiveConsole): pass -def server(): - tcpserver = SocketServer.TCPServer(('127.0.0.1', 0), PythonConsoleServer) - print "Serving on %s" % str(tcpserver.server_address) - tcpserver.serve_forever() - def spawn(env): -# server() PythonConsoleServer.env = env - # tcpserver = SocketServer.ThreadingTCPServer(('', 0), PythonConsoleServer) - tcpserver = SocketServer.TCPServer(('', 0), PythonConsoleServer) - print("debugserver: listening on %s" % str(tcpserver.server_address)) - dbg("debugserver: about to spawn thread") + tcpserver = SocketServer.TCPServer(('127.0.0.1', 0), PythonConsoleServer) + dbg("debugserver: listening on %s" % str(tcpserver.server_address)) debugserver = threading.Thread(target=tcpserver.serve_forever, name="DebugServer") debugserver.setDaemon(True) - dbg("debugserver: about to start thread") debugserver.start() - dbg("debugserver: started thread") return(debugserver, tcpserver)