#! /usr/bin/python2.3

# Minimal interface to the Internet telnet protocol.
#
# It refuses all telnet options and does not recognize any of the other
# telnet commands, but can still be used to connect in line-by-line mode.
# It's also useful to play with a number of other services,
# like time, finger, smtp and even ftp.
#
# Usage: telnet host [port]
#
# The port may be a service name or a decimal port number;
# it defaults to 'telnet'.

import string
import sys, posix
#from socket import *
import socket
#import syslog

BUFSIZE = 1024

# Telnet protocol characters

IAC  = chr(255)	# Interpret as command
DONT = chr(254)
DO   = chr(253)
WONT = chr(252)
WILL = chr(251)

def kill_off(s):
	sys.stdout.write("Killing client off due to inactivity of more than 15 minutes...")
	s.send('t\r\n')
	s.send('y\r\n')
#	os.kill(pid,SIGTERM)
	sys.exit(0)

def test_connected(callsign):
  # fetch the connections from the /proc/net/ax25 file
  stillconnected = False
  connections = open('/proc/net/ax25')
  #syslog.syslog("connection callsign is:"+callsign + " proc says:" + repr(connections))
  for connect in connections:
    testconnection = connect.split(" ")[3]
    if callsign == testconnection:
      #syslog.syslog("connection callsign is:"+callsign + " proc says:" + repr(testconnection))
      #sys.stdout.write(testconnection)
      #sys.stdout.write(callsign)
      stillconnected = True
    if stillconnected:
      #syslog.syslog("think I am still connected...")
      pass
    else:
      #syslog.syslog("Not connected anymore going to die...")
      kill_off(s)
      connections.close()

def main():
        # make sure the node program has arguments correct order
        # should be like this
        # ExtCmd          CItadel 1       root    /usr/bin/python python /root/telnet-hack.py 127.0.0.1 23 %S
	callsign = sys.argv[3]
	host = sys.argv[1]
	try:
		hostaddr = socket.gethostbyname(host)
	except error:
		sys.stderr.write(sys.argv[1] + ': bad host name\n')
		sys.exit(2)
	#
	if len(sys.argv) > 2:
		servname = sys.argv[2]
	else:
		servname = 'telnet'
	#
	if '0' <= servname[:1] <= '9':
		port = eval(servname)
	else:
		try:
			port = socket.getservbyname(servname, 'tcp')
		except error:
			sys.stderr.write(servname + ': bad tcp service name\n')
			sys.exit(2)
	#
	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	#
	try:
		s.connect((host, port))
	except error, msg:
		sys.stderr.write('connect failed: ' + `msg` + '\n')
		sys.exit(1)
	#
	pid = posix.fork()
	#
	if pid == 0:
          # child -- read stdin, write socket
          while 1:
            line = sys.stdin.readline()
            s.send(line)
            # aha! test for connected inside the parent!  Disconnect kills the child!
            test_connected(callsign)
          test_connected(callsign)
	else:
                # parent -- read socket, write stdout
		iac = 0		# Interpret next char as command
		opt = ''	# Interpret next char as option
		while 1:
			data = s.recv(BUFSIZE)
			if not data:
				# EOF; kill child and exit
				sys.stderr.write( '(Closed by remote host)\n')
				posix.kill(pid, 9)
				sys.exit(1)
			cleandata = ''
			for c in data:
				if opt:
					#print ord(c)
					s.send(opt + c)
					opt = ''
				elif iac:
					iac = 0
					if c == IAC:
						cleandata = cleandata + c
					elif c in (DO, DONT):
						if c == DO:
							pass
							#print '(DO)',
						else: 
							pass
							#print '(DONT)',
						opt = IAC + WONT
					elif c in (WILL, WONT):
						if c == WILL:
							pass
							#print '(WILL)',
						else:
							pass
							#print '(WONT)',
						opt = IAC + DONT
					else:
						pass
						#print '(command)', ord(c)
				elif c == IAC:
					iac = 1
					#print '(IAC)',
				else:
					cleandata = cleandata + c
                        cleandata = cleandata.replace('\r\n','\r')
			# replace strange return null return thingie
			cleandata = cleandata.replace('\r' + chr(0) + '\r', '')
			# replace remaining nulls
                        cleandata = cleandata.replace(chr(0),'')
			
			# debug the weird chars in xmission...
			#print "first 10 chars --"
			#for charpart in cleandata[0:10]:
			#	print ord(charpart),
			#print "last 10 chars --"
			#for charpart in cleandata[-10:]:
			#	print ord(charpart),	
			if len(cleandata) > 0:
				# strip off the silly return at the start of the string...
				if cleandata[0] == '\r':
					# take 1 to the end slice
					cleandata = cleandata[1:]
				# also check for so many spaces it makes your head spin...
				# need to ensure it is just spaces followed by the prompt (not any other data!)
				# this needs serious work or we need to fix the client (citadel) chat output!
				# first ensure that it is a string of only spaces followed by the prompt
				skipclean = 1
				for nugget in cleandata:
					# don't care about spaces or prompt...
					if ord(nugget) == 32 or ord(nugget) == 62:
						pass
					else:
						skipclean = 0
				# now make sure we have 2 chars (at least, space and prompt!)
				# ok 10, as many spaces exist in the keep-alive for chat....
				if len(cleandata) > 10:
					if ord(cleandata[0]) == 32 and ord(cleandata[-2]) == 62 and skipclean:
						cleandatabuild = ""
						for nugget in cleandata:
							if ord(nugget) == 32:
								pass
							else:
								cleandatabuild = cleandatabuild  + nugget
						# millions of spaces cleaned off for your sanitation!
						cleandata = cleandatabuild
			# check for 2 chars space /backspace combo keep-alive thingie
			if len(cleandata) == 2:
				# old space backspace keepalive that kills packet!
				if ord(cleandata[0]) == 32 and ord(cleandata[1]) == 8:
					# just do nothing, ax25 link is keepalive!
					pass
			#if nothing to say, why say anything :-) (same as it ever was...)
			elif len(cleandata) == 0:
				pass
			# if only len 1 and only a prompt, why bother (also it is keepalive in chat!)
			elif len(cleandata) == 1 and ord(cleandata) == 62:
				pass
			# good data (hopefully remains)
			else:
				# emit the ords of the chars (like to say that ha ha).
				#for charpart in cleandata:
				#	print ord(charpart),
				# reset the current timer
                                # remove the extra spaces (hope this does not change meaning, but need to do for chat stuff)
				sys.stdout.write(cleandata.strip())
				sys.stdout.flush()

try:
	main()
except KeyboardInterrupt:
	pass
