#	pubtcp.py			8/05/96 JJS##	This module defines an Actor which connects to the#	game via TCP/IP -- in effect, turning PUB into MUD.##	Use this module with:  import pubtcp##----------------------------------------------------------------------# standard modulesimport whrandomimport stringimport typesimport regeximport copyfrom socket import *# PUB modulesimport pubfrom pubcore import *import pubverbsfrom pubobjs import Actor#----------------------------------------------------------------------# global (module) vars#HOST = ''		# null string means local host (this machine)PORT = 4000		# port to useMAXCONS = 3		# maximum connections to allowendl = "\r\n"		# string to end lines (for standard Telnet)connlist = []		# list of connected playersrunning = 0		# 0=starting up, 1=running, -1=shutting downsock = None		# socket used to receive connectionsNPlist = []		# list of all NetPlayersLoginList = []		# list of people trying to log in#----------------------------------------------------------------------# function to start the server#def StartServer():	global HOST, PORT, running, sock	sock = socket(AF_INET, SOCK_STREAM)	sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)	sock.bind(HOST, PORT)	sock.setblocking(0)		sock.listen(1)	print "Server open on port",PORT	running = 1#----------------------------------------------------------------------# function to disconnect a NetPlayer#def Disconnect(player, msg=''):	global endl,connlist	if player.conn:		if msg: player.send( msg+endl );		player.conn.close()	player.conn = None	player.connected = 0	if player in connlist: connlist.remove(player)#----------------------------------------------------------------------# function to shut the server down#def ShutDown():	global connlist, running, endl, sock	if running < -1: return	print "Shutting server down."	for p in connlist: Disconnect(p, "Server shutting down.")	sock.close()	running = -2#----------------------------------------------------------------------# handle a new connection#def NewConn( conn, addr ):	global connlist, MAXCONS, endl	print "Got connection from",addr	if running < 1:		conn.send("Server is not running.")		conn.close()	if len(connlist)+len(LoginList) >= MAXCONS:		conn.send("Sorry, only " + str(MAXCONS) + \			" connections are allowed.  Please try again later." \			+ endl )		conn.close()		return	# looks good -- log 'em in...	conn.setblocking(0)	LoginConn(conn)#----------------------------------------------------------------------# network update -- call this function periodically#def NetUpdate():	global connlist, running, sock	if not running: return StartServer()	if running < 0: return ShutDown()		# check for incoming connections	try:		conn, addr = sock.accept()		NewConn( conn, addr )	except: pass	# handle incoming messages	for u in connlist + LoginList:		u.Act()		try:			data = u.conn.recv(1024)		except: data = None		if data:			data = filter(lambda x: x>=' ' and x<='z', data)			data = string.strip(data)			if data:#				print "From",u.name,':', data				u.HandleMsg(data)				if data == "shutdown": running=-1#----------------------------------------------------------------------## class of the network player -- i.e., the Actor interfaced to a socket#class NetPlayer(Actor):	def __init__(self,pNames):		global NPlist		Actor.__init__(self,pNames)		self.linebreak = 80		self.connected = 0		self.conn = None		self.inbuf = []		self.password = ''		NPlist.append(self)			def send(self, pWhat):		if not self.conn: return		try: self.conn.send(pWhat)		except: pass	def Tell(self, pWhat):		if not self.connected or not self.conn:			return               		pWhat = string.join(string.split(pWhat,'\n'),endl)		if self.linebreak:			# break lines every <linebreak> characters:			while len(pWhat) >= self.linebreak:				pos = string.rfind(pWhat[:self.linebreak],' ')				pos2 = string.rfind(pWhat[:self.linebreak],'\n')				if pos2 < pos and pos2 > -1: pos = pos2				self.send( pWhat[:pos] + endl )				pWhat = pWhat[pos+1:]		self.send( pWhat + endl )	def Act(self):		if pub.scheduler.HasEventFor( self ): 			return		# no scheduled events, so check for a command in the buffer		if len(self.inbuf):			cmdstr = self.inbuf[0]			self.inbuf = self.inbuf[1:]#			print self.name,"doing command:",cmdstr			if cmdstr=='quit': self.Quit()			else: self.DoCommandString(cmdstr)		else: pub.scheduler.AddEvent( 1, Event(self, 'object.Act()') )	def HandleMsg(self,msg):		# place the message in the inbuf, for later use		self.inbuf.append(msg)	def Quit(self):		# leave the game (without killing th server!)		Disconnect(self,"Goodbye!")# end of class NetPlayer#----------------------------------------------------------------------#----------------------------------------------------------------------## class LoginConn -- a connection still in the process of logging in#class LoginConn(NetPlayer):	def __init__(self,conn,pNames='<login>'):		global LoginList, NPlist		NetPlayer.__init__(self,pNames)		self.conn = conn		conn.send('Name: ')		NPlist.remove(self)		LoginList.append(self)	def HandleMsg(self,msg):		global NPlist, endl		if self.name == '<login>':	# first msg should be name			if len(msg)<2: return			self.name = msg			if msg == 'guest':				self.password = 'guest'			else:				self.send('Password: ')			return		elif self.password == '':			self.password = msg			# check to see if this matches some player			mtch = filter(self.Matches, NPlist)			if not mtch:				return self.Abort('Invalid login.');			mtch = mtch[0]	# shouldn't be more than one!			if mtch.connected:				return self.Abort('Already logged in!');			# looks good -- let 'em in			self.EnterGame(mtch)			return		else:		    print "Unexpected message after login:",msg	def Act(self):		return		# no actions to take yet	def Abort(self,msg='You are kicked off:'):		global endl, LoginList		if msg: self.send(msg+endl)		self.conn.close()		if self in LoginList: LoginList.remove(self)	def Matches(self,player):	# return 1 if matches this NetPlayer		return (self.password == player.password and \			self.name == player.name)	def EnterGame(self,match):		global LoginList, connlist, endl		match.conn = self.conn		match.connected = 1		LoginList.remove(self)		self.send('Welcome, '+match.name+'!'+endl)		match.inbuf = ["look"]		connlist.append(match)