comparison orpg/networking/mplay_server.py @ 90:d1aff41c031b alpha

Traipse Alpha 'OpenRPG' {090919-00} Traipse is a distribution of OpenRPG that is designed to be easy to setup and go. Traipse also makes it easy for developers to work on code without fear of sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to the code. 'Ornery-Orc''s main goal is to offer more advanced features and enhance the productivity of the user. Update Summary: 00: Adds menu changes to draw attention to important updates, errors, or other events. (image info coming soon) Traipse URL is not included in the repos tab and is set as default. 01: Fixes Copy for Windows and Linux (finally!!) users. Fixes incomplete update to Grid and List nodes. Fixes incomplete update to Chat Commands. 02: Fixes problems with Remote Image Upload. Fixes Drop and Drag of Minis to Map. CherryPy can now use any image in the webfiles/ folder and sub-folders. CherryPy can now Drop and Drag Minis to the Map. 03: Minor changes to Update Manager's GUI. Expert recommendation warning added to Revision Update. Step down compatibility with open_rpg & component added to orpgCore. 19-00: Better backwards compatibility in orpgCore. Using majority of 'Grumpy' network folder to correct server lag.
author sirebral
date Sat, 19 Sep 2009 06:45:21 -0500
parents 449a8900f9ac
children 65c1604e7949 7ed4979cc1cf
comparison
equal deleted inserted replaced
89:b84e0799fed2 90:d1aff41c031b
41 <create_group from='' pwd='' name='' /> 41 <create_group from='' pwd='' name='' />
42 <join_group from='' pwd='' group_id='' /> 42 <join_group from='' pwd='' group_id='' />
43 <role action='set,get,display' player='' group_id='' boot_pwd='' role=''/> 43 <role action='set,get,display' player='' group_id='' boot_pwd='' role=''/>
44 """ 44 """
45 45
46 import re 46 from mplay_client import *
47 from mplay_client import MPLAY_LENSIZE
48 from orpg.dirpath import dir_struct
49 from orpg.tools.validate import validate
47 import gc 50 import gc
48 import cgi 51 import cgi
49 import sys 52 import sys
50 import string 53 import string
51 import time 54 import time
52 import urllib 55 import urllib
53 import traceback
54
55 from mplay_client import *
56 from mplay_client import MPLAY_LENSIZE
57 from orpg.dirpath import dir_struct
58 import orpg.tools.validate
59
60 from orpg.mapper.map_msg import * 56 from orpg.mapper.map_msg import *
61 from threading import Lock, RLock 57 from threading import Lock, RLock
62 from struct import pack, unpack, calcsize 58 from struct import pack, unpack, calcsize
63 from meta_server_lib import * 59 from meta_server_lib import *
60 import traceback
61 import re
64 62
65 # Import the minidom XML module 63 # Import the minidom XML module
66 from xml.dom import minidom 64 from xml.dom import minidom
67 65
68 # Snag the version number 66 # Snag the version number
69 from orpg.orpg_version import VERSION, PROTOCOL_VERSION, CLIENT_STRING, SERVER_MIN_CLIENT_VERSION 67 from orpg.orpg_version import *
70 68
71 #Plugins 69 #Plugins
72 from server_plugins import ServerPlugins 70 from server_plugins import ServerPlugins
73 71
74 def id_compare(a,b): 72 def id_compare(a,b):
110 if self.mapFile is not None and self.persistant == 1 and self.mapFile.find("default_map.xml") == -1: 108 if self.mapFile is not None and self.persistant == 1 and self.mapFile.find("default_map.xml") == -1:
111 f = open(self.mapFile, "w") 109 f = open(self.mapFile, "w")
112 f.write(self.game_map.get_all_xml()) 110 f.write(self.game_map.get_all_xml())
113 f.close() 111 f.close()
114 112
113
115 def add_player(self,id): 114 def add_player(self,id):
116 self.players.append(id) 115 self.players.append(id)
117 116
118 def remove_player(self,id): 117 def remove_player(self,id):
119 if self.voice.has_key(id): 118 if self.voice.has_key(id):
126 125
127 def get_player_ids(self): 126 def get_player_ids(self):
128 tmp = self.players 127 tmp = self.players
129 return tmp 128 return tmp
130 129
130
131 def check_pwd(self,pwd): 131 def check_pwd(self,pwd):
132 return (pwd==self.pwd) 132 return (pwd==self.pwd)
133 133
134 def check_boot_pwd(self,pwd): 134 def check_boot_pwd(self,pwd):
135 return (pwd==self.boot_pwd) 135 return (pwd==self.boot_pwd)
136 136
137 def check_version(self,ver): 137 def check_version(self,ver):
138 if (self.minVersion == ""): return 1 138 if (self.minVersion == ""):
139 return 1
139 minVersion=self.minVersion.split('.') 140 minVersion=self.minVersion.split('.')
140 version=ver.split('.') 141 version=ver.split('.')
141 for i in xrange(min(len(minVersion),len(version))): 142 for i in xrange(min(len(minVersion),len(version))):
142 w=max(len(minVersion[i]),len(version[i])) 143 w=max(len(minVersion[i]),len(version[i]))
143 v1=minVersion[i].rjust(w); 144 v1=minVersion[i].rjust(w);
144 v2=version[i].rjust(w); 145 v2=version[i].rjust(w);
145 if v1<v2: return 1 146 if v1<v2:
146 if v1>v2: return 0 147 return 1
148 if v1>v2:
149 return 0
150
147 if len(minVersion)>len(version): 151 if len(minVersion)>len(version):
148 return 0 152 return 0
149 return 1 153 return 1
150 154
151 #depreciated - see send_group_list() 155 #depreciated - see send_group_list()
155 xml_data += "\" name=\"" + self.name 159 xml_data += "\" name=\"" + self.name
156 xml_data += "\" pwd=\"" + str(self.pwd!="") 160 xml_data += "\" pwd=\"" + str(self.pwd!="")
157 xml_data += "\" players=\"" + str(self.get_num_players()) 161 xml_data += "\" players=\"" + str(self.get_num_players())
158 xml_data += "\" action=\"" + act + "\" />" 162 xml_data += "\" action=\"" + act + "\" />"
159 return xml_data 163 return xml_data
164
160 165
161 166
162 class client_stub(client_base): 167 class client_stub(client_base):
163 def __init__(self,inbox,sock,props,log): 168 def __init__(self,inbox,sock,props,log):
164 client_base.__init__(self) 169 client_base.__init__(self)
182 187
183 def clear_timeout(self): 188 def clear_timeout(self):
184 self.timeout_time = None 189 self.timeout_time = None
185 190
186 def check_time_out(self): 191 def check_time_out(self):
187 if self.timeout_time==None: self.timeout_time = time.time() 192 if self.timeout_time==None:
193 self.timeout_time = time.time()
188 curtime = time.time() 194 curtime = time.time()
189 diff = curtime - self.timeout_time 195 diff = curtime - self.timeout_time
190 if diff > 1800: return 1 196 if diff > 1800:
191 else: return 0 197 return 1
198 else:
199 return 0
192 200
193 def send(self,msg,player,group): 201 def send(self,msg,player,group):
194 if self.get_status() == MPLAY_CONNECTED: 202 if self.get_status() == MPLAY_CONNECTED:
195 self.outbox.put("<msg to='" + player + "' from='0' group_id='" + group + "' />" + msg) 203 self.outbox.put("<msg to='" + player + "' from='0' group_id='" + group + "' />" + msg)
196 204
209 217
210 def take_dom(self,xml_dom): 218 def take_dom(self,xml_dom):
211 self.name = xml_dom.getAttribute("name") 219 self.name = xml_dom.getAttribute("name")
212 self.text_status = xml_dom.getAttribute("status") 220 self.text_status = xml_dom.getAttribute("status")
213 221
214 """ 222
215 ###################################################################### 223 ######################################################################
216 ###################################################################### 224 ######################################################################
217 ## 225 ##
218 ## 226 ##
219 ## MPLAY SERVER 227 ## MPLAY SERVER
220 ## 228 ##
221 ## 229 ##
222 ###################################################################### 230 ######################################################################
223 ###################################################################### 231 ######################################################################
224 """
225 232
226 class mplay_server: 233 class mplay_server:
227 def __init__(self, log_console=None, name=None): 234 def __init__(self, log_console=None, name=None):
228 self.log_to_console = 1 235 self.log_to_console = 1
229 self.log_console = log_console 236 self.log_console = log_console
255 self.maxSendSize = 1024 262 self.maxSendSize = 1024
256 self.server_port = OPENRPG_PORT 263 self.server_port = OPENRPG_PORT
257 self.allowRemoteKill = False 264 self.allowRemoteKill = False
258 self.allowRemoteAdmin = True 265 self.allowRemoteAdmin = True
259 self.sendLobbySound = False 266 self.sendLobbySound = False
260 self.lobbySound = 'http://www.digitalxero.net/music/mus_tavern1.bmu' ##used? 267 self.lobbySound = 'http://www.digitalxero.net/music/mus_tavern1.bmu'
261 268
262 def initServer(self, **kwargs): 269 def initServer(self, **kwargs):
263 for atter, value in kwargs.iteritems(): setattr(self, atter, value) 270 for atter, value in kwargs.iteritems():
271 setattr(self, atter, value)
264 validate.config_file( self.lobbyMapFile, "default_Lobby_map.xml" ) 272 validate.config_file( self.lobbyMapFile, "default_Lobby_map.xml" )
265 validate.config_file( self.lobbyMessageFile, "default_LobbyMessage.html" ) 273 validate.config_file( self.lobbyMessageFile, "default_LobbyMessage.html" )
266 self.server_start_time = time.time() 274 self.server_start_time = time.time()
267 275
268 # Since the server is just starting here, we read in the XML configuration 276 # Since the server is just starting here, we read in the XML configuration
269 # file. Notice the lobby is still created here by default. 277 # file. Notice the lobby is still created here by default.
270 self.groups = { '0': game_group('0','Lobby','', 278 self.groups = { '0': game_group('0','Lobby','','The game lobby', '', '', self.userPath + self.lobbyMapFile, self.userPath + self.lobbyMessageFile, 1)}
271 'The game lobby', '', '', self.userPath + self.lobbyMapFile,
272 self.userPath + self.lobbyMessageFile, 1)}
273 # Make sure the server's name gets set, in case we are being started from 279 # Make sure the server's name gets set, in case we are being started from
274 # elsewhere. Basically, if it's passed in, we'll over ride what we were 280 # elsewhere. Basically, if it's passed in, we'll over ride what we were
275 # prompted for. This should never really happen at any rate. 281 # prompted for. This should never really happen at any rate.
276 282
277 self.initServerConfig() 283 self.initServerConfig()
305 self.addsvrcmd('create_group', self.create_group) 311 self.addsvrcmd('create_group', self.create_group)
306 self.addsvrcmd('moderate', self.moderate_group) 312 self.addsvrcmd('moderate', self.moderate_group)
307 self.addsvrcmd('plugin', self.plugin_msg_handler) 313 self.addsvrcmd('plugin', self.plugin_msg_handler)
308 self.addsvrcmd('sound', self.sound_msg_handler) 314 self.addsvrcmd('sound', self.sound_msg_handler)
309 315
316
310 # This method reads in the server's ban list added by Darren 317 # This method reads in the server's ban list added by Darren
311 def initBanList( self ): 318 def initBanList( self ):
312 self.log_msg("Processing Ban List File...") 319 self.log_msg("Processing Ban List File...")
313 320
314 # make sure the server_ini.xml exists! 321 # make sure the server_ini.xml exists!
373 if not len(self.reg) > 0 or self.reg[0].upper() not in ("Y", "N"): 380 if not len(self.reg) > 0 or self.reg[0].upper() not in ("Y", "N"):
374 opt = raw_input("Do you want to post your server to the OpenRPG Meta Server list? (y,n) ") 381 opt = raw_input("Do you want to post your server to the OpenRPG Meta Server list? (y,n) ")
375 if len(opt) and (opt[0].upper() == 'Y'): self.reg = 'Y' 382 if len(opt) and (opt[0].upper() == 'Y'): self.reg = 'Y'
376 else: self.reg = 'N' 383 else: self.reg = 'N'
377 LobbyName = 'Lobby' 384 LobbyName = 'Lobby'
378
379 if self.configDoc.hasAttribute("lobbyname"): LobbyName = self.configDoc.getAttribute("lobbyname") 385 if self.configDoc.hasAttribute("lobbyname"): LobbyName = self.configDoc.getAttribute("lobbyname")
380 map_node = service_node = self.configDoc.getElementsByTagName("map")[0] 386 map_node = service_node = self.configDoc.getElementsByTagName("map")[0]
381 msg_node = service_node = self.configDoc.getElementsByTagName("message")[0] 387 msg_node = service_node = self.configDoc.getElementsByTagName("message")[0]
382 mapFile = map_node.getAttribute('file') 388 mapFile = map_node.getAttribute('file')
383 msgFile = msg_node.getAttribute('file') 389 msgFile = msg_node.getAttribute('file')
384 if mapFile == '': mapFile = 'Lobby_map.xml' 390 if mapFile == '': mapFile = 'Lobby_map.xml'
385 if msgFile == '': msgFile = 'LobbyMessage.html' 391 if msgFile == '': msgFile = 'LobbyMessage.html'
386 # Update the lobby with the passwords if they've been specified 392 # Update the lobby with the passwords if they've been specified
387
388 if len(self.boot_pwd): 393 if len(self.boot_pwd):
389 self.groups = {'0': game_group( '0', LobbyName, "", 'The game lobby', self.boot_pwd, "", 394 self.groups = {'0': game_group( '0', LobbyName, "", 'The game lobby', self.boot_pwd, "",
390 self.userPath + mapFile.replace("myfiles/", ""), 395 self.userPath + mapFile.replace("myfiles/", ""),
391 self.userPath + msgFile.replace("myfiles/", ""), 1 ) 396 self.userPath + msgFile.replace("myfiles/", ""), 1 )
392 } 397 }
403 self.name = self.configDoc.getAttribute("name") 408 self.name = self.configDoc.getAttribute("name")
404 else: 409 else:
405 if self.reg[0].upper() == "Y": 410 if self.reg[0].upper() == "Y":
406 if self.name == None: self.name = raw_input("Server Name? ") 411 if self.name == None: self.name = raw_input("Server Name? ")
407 self.register() 412 self.register()
408 """ 413
409 # Get the minimum openrpg version from config if available 414 # Get the minimum openrpg version from config if available
410 # if it isn't set min version to internal default. 415 # if it isn't set min version to internal default.
411 # 416 #
412 # server_ini.xml entry for version tag... 417 # server_ini.xml entry for version tag...
413 # <version min="x.x.x"> 418 # <version min="x.x.x">
414 """
415
416 try: 419 try:
417 mver = self.configDoc.getElementsByTagName("version")[0] 420 mver = self.configDoc.getElementsByTagName("version")[0]
418 self.minClientVersion = mver.getAttribute("min") 421 self.minClientVersion = mver.getAttribute("min")
419 except: self.minClientVersion = SERVER_MIN_CLIENT_VERSION #from orpg/orpg_version.py 422 except: self.minClientVersion = SERVER_MIN_CLIENT_VERSION #from orpg/orpg_version.py
420 self.defaultMessageFile = "" 423 self.defaultMessageFile = ""
421 # This try/except bit is to allow older versions of python to continue without a list error. 424 # This try/except bit is to allow older versions of python to continue without a list error.
422 425
423 426
424 """ 427
425 #------------------------[ START <AUTOKICK> TAG PROCESSING ]-------------- 428 #------------------------[ START <AUTOKICK> TAG PROCESSING ]--------------
426 # Auto-kick option defaults for silent booting and 429 # Auto-kick option defaults for silent booting and
427 # setting the default zombie-client delay time --Snowdog 9/05 430 # setting the default zombie-client delay time --Snowdog 9/05
428 # 431 #
429 # server_ini.xml entry for autikick tag... 432 # server_ini.xml entry for autikick tag...
430 # <autokick silent=["no","yes"] delay="(# of seconds)"> 433 # <autokick silent=["no","yes"] delay="(# of seconds)">
431 """
432 434
433 try: 435 try:
434 ak = self.configDoc.getElementsByTagName("autokick")[0] 436 ak = self.configDoc.getElementsByTagName("autokick")[0]
435 if ak.hasAttribute("silent"): 437 if ak.hasAttribute("silent"):
436 if ((ak.getAttribute("silent")).lower() == "yes"): self.silent_auto_kick = 1 438 if ((ak.getAttribute("silent")).lower() == "yes"): self.silent_auto_kick = 1
450 self.log_msg("**WARNING** Error loading autokick settings... using defaults") 452 self.log_msg("**WARNING** Error loading autokick settings... using defaults")
451 453
452 alk = "" 454 alk = ""
453 if (self.silent_auto_kick == 1): alk = "(Silent Mode)" 455 if (self.silent_auto_kick == 1): alk = "(Silent Mode)"
454 self.log_msg("Auto Kick: Delay="+str(self.zombie_time) + " " + alk) 456 self.log_msg("Auto Kick: Delay="+str(self.zombie_time) + " " + alk)
455 """------------------------[ END <AUTOKICK> TAG PROCESSING ]--------------""" 457 #------------------------[ END <AUTOKICK> TAG PROCESSING ]--------------
456 458
457 459
458 """ 460
459 #-------------------------------[ START <ROOM_DEFAULT> TAG PROCESSING ]-------------------- 461 #-------------------------------[ START <ROOM_DEFAULT> TAG PROCESSING ]--------------------
460 # 462 #
461 # New room_defaults configuration option used to set various defaults 463 # New room_defaults configuration option used to set various defaults
462 # for all user created rooms on the server. Incorporates akomans older 464 # for all user created rooms on the server. Incorporates akomans older
463 # default room message code (from above) --Snowdog 11/03 465 # default room message code (from above) --Snowdog 11/03
464 # 466 #
465 # option syntax 467 # option syntax
466 # <room_defaults passwords="yes" map="myfiles/LobbyMap.xml" message="myfiles/LobbyMessage.html" /> 468 # <room_defaults passwords="yes" map="myfiles/LobbyMap.xml" message="myfiles/LobbyMessage.html" />
467 """
468 469
469 #default settings for tag options... 470 #default settings for tag options...
470 roomdefault_msg = str(self.defaultMessageFile) #no message is the default 471 roomdefault_msg = str(self.defaultMessageFile) #no message is the default
471 roomdefault_map = "" #use lobby map as default 472 roomdefault_map = "" #use lobby map as default
472 roomdefault_pass = 1 #allow passwords 473 roomdefault_pass = 1 #allow passwords
489 setting = roomdefaults.getElementsByTagName('map')[0] 490 setting = roomdefaults.getElementsByTagName('map')[0]
490 map = setting.getAttribute('file') 491 map = setting.getAttribute('file')
491 if map != "": 492 if map != "":
492 roomdefault_map = self.userPath + map.replace("myfiles/", "") 493 roomdefault_map = self.userPath + map.replace("myfiles/", "")
493 self.log_msg("Room Defaults: Using " + str(map) + " for room map") 494 self.log_msg("Room Defaults: Using " + str(map) + " for room map")
494 except: self.log_msg("Room Defaults: [Warning] Using Default Map") 495 except:
496 self.log_msg("Room Defaults: [Warning] Using Default Map")
495 497
496 try: 498 try:
497 setting = roomdefaults.getElementsByTagName('message')[0] 499 setting = roomdefaults.getElementsByTagName('message')[0]
498 msg = setting.getAttribute('file') 500 msg = setting.getAttribute('file')
499 if msg != "": 501 if msg != "":
503 except: print ("Room Defaults: [Warning] Using Default Message") 505 except: print ("Room Defaults: [Warning] Using Default Message")
504 except: 506 except:
505 traceback.print_exc() 507 traceback.print_exc()
506 self.log_msg("**WARNING** Error loading default room settings from configuration file. Using internal defaults.") 508 self.log_msg("**WARNING** Error loading default room settings from configuration file. Using internal defaults.")
507 509
510
508 #set the defaults 511 #set the defaults
509 if roomdefault_msg != "" or roomdefault_msg != None: 512 if roomdefault_msg != "" or roomdefault_msg != None:
510 self.defaultMessageFile = roomdefault_msg #<room_defaults> tag superceeds older <newrooms> tag 513 self.defaultMessageFile = roomdefault_msg #<room_defaults> tag superceeds older <newrooms> tag
511 else: self.defaultMessageFile = None 514 else: self.defaultMessageFile = None
515
512 if roomdefault_map != "" or roomdefault_map != None: 516 if roomdefault_map != "" or roomdefault_map != None:
513 self.defaultMapFile = roomdefault_map #<room_defaults> tag superceeds older <newrooms> tag 517 self.defaultMapFile = roomdefault_map #<room_defaults> tag superceeds older <newrooms> tag
514 else: self.defaultMapFile = None 518 else: self.defaultMapFile = None
515 519
516 ##### room default map not handled yet. SETTING IGNORED 520 ##### room default map not handled yet. SETTING IGNORED
517 if roomdefault_pass == 0: self.allow_room_passwords = 0 521 if roomdefault_pass == 0: self.allow_room_passwords = 0
518 else: self.allow_room_passwords = 1 522 else: self.allow_room_passwords = 1
519 """-------------------------------[ END <ROOM_DEFAULT> TAG PROCESSING ]--------------------""" 523
524 #-------------------------------[ END <ROOM_DEFAULT> TAG PROCESSING ]--------------------
525
520 526
521 ###Server Cheat message 527 ###Server Cheat message
522 try: 528 try:
523 cheat_node = self.configDoc.getElementsByTagName("cheat")[0] 529 cheat_node = self.configDoc.getElementsByTagName("cheat")[0]
524 self.cheat_msg = cheat_node.getAttribute("text") 530 self.cheat_msg = cheat_node.getAttribute("text")
525 except: 531 except:
526 self.cheat_msg = "**FAKE ROLL**" 532 self.cheat_msg = "**FAKE ROLL**"
527 self.log_msg("**WARNING** <cheat txt=\"\"> tag missing from server configuration file. Using empty string.") 533 self.log_msg("**WARNING** <cheat txt=\"\"> tag missing from server configuration file. Using empty string.")
528 534
535
536
529 # should validate protocal 537 # should validate protocal
530 validate_protocol_node = self.configDom.getElementsByTagName("validate_protocol ") 538 validate_protocol_node = self.configDom.getElementsByTagName("validate_protocol ")
539
531 self.validate_protocol = 1 540 self.validate_protocol = 1
541
532 if(validate_protocol_node): self.validate_protocol = (validate_protocol_node[0].getAttribute("value") == "True") 542 if(validate_protocol_node): self.validate_protocol = (validate_protocol_node[0].getAttribute("value") == "True")
533 if(self.validate_protocol != 1): self.log_msg("Protocol Validation: OFF") 543 if(self.validate_protocol != 1): self.log_msg("Protocol Validation: OFF")
534 self.makePersistentRooms() 544 self.makePersistentRooms()
545
535 self.log_msg("Server Configuration File: Processing Completed.") 546 self.log_msg("Server Configuration File: Processing Completed.")
547
536 except Exception, e: 548 except Exception, e:
537 traceback.print_exc() 549 traceback.print_exc()
538 self.log_msg("Exception in initServerConfig() " + str(e)) 550 self.log_msg("Exception in initServerConfig() " + str(e))
539 551
552
540 def makePersistentRooms(self): 553 def makePersistentRooms(self):
541 'Creates rooms on the server as defined in the server config file.' 554 'Creates rooms on the server as defined in the server config file.'
555
542 for element in self.configDom.getElementsByTagName('room'): 556 for element in self.configDom.getElementsByTagName('room'):
543 roomName = element.getAttribute('name') 557 roomName = element.getAttribute('name')
544 roomPassword = element.getAttribute('password') 558 roomPassword = element.getAttribute('password')
545 bootPassword = element.getAttribute('boot') 559 bootPassword = element.getAttribute('boot')
546 560
550 564
551 # Extract the map filename attribute from the map node 565 # Extract the map filename attribute from the map node
552 # we only care about the first map element found -- others are ignored 566 # we only care about the first map element found -- others are ignored
553 mapElement = element.getElementsByTagName('map')[0] 567 mapElement = element.getElementsByTagName('map')[0]
554 mapFile = self.userPath + mapElement.getAttribute('file').replace("myfiles/", "") 568 mapFile = self.userPath + mapElement.getAttribute('file').replace("myfiles/", "")
569
555 messageElement = element.getElementsByTagName('message')[0] 570 messageElement = element.getElementsByTagName('message')[0]
556 messageFile = messageElement.getAttribute('file') 571 messageFile = messageElement.getAttribute('file')
572
557 if messageFile[:4] != 'http': messageFile = self.userPath + messageFile.replace("myfiles/", "") 573 if messageFile[:4] != 'http': messageFile = self.userPath + messageFile.replace("myfiles/", "")
558 574
559 # Make sure we have a message to even mess with 575 # Make sure we have a message to even mess with
560 if(len(messageFile) == 0): messageFile = self.defaultMessageFile 576 if(len(messageFile) == 0): messageFile = self.defaultMessageFile
577
561 if(len(mapFile) == 0): mapFile = self.defaultMapFile 578 if(len(mapFile) == 0): mapFile = self.defaultMapFile
579
562 moderated = 0 580 moderated = 0
563 if element.hasAttribute('moderated') and element.getAttribute('moderated').lower() == "true": moderated = 1 581 if element.hasAttribute('moderated') and element.getAttribute('moderated').lower() == "true": moderated = 1
564 582
565 #create the new persistant group 583 #create the new persistant group
566 self.new_group(roomName, roomPassword, 584 self.new_group(roomName, roomPassword, bootPassword, minVersion, mapFile, messageFile, persist = 1, moderated=moderated)
567 bootPassword, minVersion, mapFile, 585
568 messageFile, persist = 1, moderated=moderated) 586
569 587
570 def isPersistentRoom(self, id): 588 def isPersistentRoom(self, id):
571 'Returns True if the id is a persistent room (other than the lobby), otherwise, False.' 589 'Returns True if the id is a persistent room (other than the lobby), otherwise, False.'
572 """ 590
573 # altered persistance tracking from simple room id based to per-group setting 591 # altered persistance tracking from simple room id based to per-group setting
574 # allows arbitrary rooms to be marked as persistant without needing the self.persistRoomThreshold 592 # allows arbitrary rooms to be marked as persistant without needing the self.persistRoomThreshold
575 # -- Snowdog 4/04 593 # -- Snowdog 4/04
576 """
577 try: 594 try:
578 id = str(id) #just in case someone sends an int instead of a str into the function 595 id = str(id) #just in case someone sends an int instead of a str into the function
579 if id not in self.groups: return 0 #invalid room, can't be persistant 596 if id not in self.groups: return 0 #invalid room, can't be persistant
580 pr = (self.groups[id]).persistant 597 pr = (self.groups[id]).persistant
581 return pr 598 return pr
582 except: 599 except:
583 self.log_msg("Exception occured in isPersistentRoom(self,id)") 600 self.log_msg("Exception occured in isPersistentRoom(self,id)")
584 return 0 601 return 0
602
603
585 604
586 #----------------------------------------------------- 605 #-----------------------------------------------------
587 # Toggle Meta Logging -- Added by Snowdog 4/03 606 # Toggle Meta Logging -- Added by Snowdog 4/03
588 #----------------------------------------------------- 607 #-----------------------------------------------------
589 def toggleMetaLogging(self): 608 def toggleMetaLogging(self):
611 else: return 630 else: return
612 #when log mode changes update all connection stubs 631 #when log mode changes update all connection stubs
613 for n in self.players: 632 for n in self.players:
614 try: self.players[n].EnableMessageLogging = mode 633 try: self.players[n].EnableMessageLogging = mode
615 except: self.log_msg("Error changing Message Logging Mode for client #" + str(self.players[n].id)) 634 except: self.log_msg("Error changing Message Logging Mode for client #" + str(self.players[n].id))
616
617 def NetworkLoggingStatus(self): 635 def NetworkLoggingStatus(self):
618 if self.log_network_messages == 0: return "Network Traffic Log: Off" 636 if self.log_network_messages == 0: return "Network Traffic Log: Off"
619 elif self.log_network_messages == 1: return "Network Traffic Log: Logging (composite file)" 637 elif self.log_network_messages == 1: return "Network Traffic Log: Logging (composite file)"
620 elif self.log_network_messages == 2: return "Network Traffic Log: Logging (inbound/outbound files)" 638 elif self.log_network_messages == 2: return "Network Traffic Log: Logging (inbound/outbound files)"
621 else: self.log_msg("Network Traffic Log: [Unknown]") 639 else: self.log_msg("Network Traffic Log: [Unknown]")
640
641
642
622 643
623 def register_callback(instance, xml_dom = None,source=None): 644 def register_callback(instance, xml_dom = None,source=None):
624 if xml_dom: # if we get something 645 if xml_dom: # if we get something
625 if source == getMetaServerBaseURL(): # if the source of this DOM is the authoritative meta 646 if source == getMetaServerBaseURL(): # if the source of this DOM is the authoritative meta
626 try: 647 try:
631 finally: 652 finally:
632 metacache_lock.release() 653 metacache_lock.release()
633 654
634 if newlist != curlist: # If the two lists aren't identical 655 if newlist != curlist: # If the two lists aren't identical
635 # then something has changed. 656 # then something has changed.
636 instance.register() # Call self.register() 657 instance.register() # Call self.register()
637 # which will force a re-read of the meta cache and 658 # which will force a re-read of the meta cache and
638 # redo the registerThreads 659 # redo the registerThreads
639 else: instance.register() 660 else: instance.register()
640 661
641 # Eventually, reset the MetaServerBaseURL here 662 # Eventually, reset the MetaServerBaseURL here
642 663
643 """
644 ## Added to help clean up parser errors in the XML on clients 664 ## Added to help clean up parser errors in the XML on clients
645 ## due to characters that break welformedness of the XML from 665 ## due to characters that break welformedness of the XML from
646 ## the meta server. 666 ## the meta server.
647 ## NOTE: this is a stopgap measure -SD 667 ## NOTE: this is a stopgap measure -SD
648 """
649 def clean_published_servername(self, name): 668 def clean_published_servername(self, name):
650 #clean name of all apostrophes and quotes 669 #clean name of all apostrophes and quotes
651 badchars = "\"\\`><" 670 badchars = "\"\\`><"
652 for c in badchars: name = name.replace(c,"") 671 for c in badchars: name = name.replace(c,"")
653 return name 672 return name
657 id = '0' 676 id = '0'
658 time.sleep(500) 677 time.sleep(500)
659 for rnum in self.groups.keys(): 678 for rnum in self.groups.keys():
660 rooms += urllib.urlencode( {"room_data[rooms][" + str(rnum) + "][name]":self.groups[rnum].name, 679 rooms += urllib.urlencode( {"room_data[rooms][" + str(rnum) + "][name]":self.groups[rnum].name,
661 "room_data[rooms][" + str(rnum) + "][pwd]":str(self.groups[rnum].pwd != "")})+'&' 680 "room_data[rooms][" + str(rnum) + "][pwd]":str(self.groups[rnum].pwd != "")})+'&'
681
662 for pid in self.groups[rnum].players: 682 for pid in self.groups[rnum].players:
663 rooms += urllib.urlencode( {"room_data[rooms][" + str(rnum) + "][players]["+str(pid)+"]":self.players[pid].name,})+'&' 683 rooms += urllib.urlencode( {"room_data[rooms][" + str(rnum) + "][players]["+str(pid)+"]":self.players[pid].name,})+'&'
684
685
664 for meta in self.metas.keys(): 686 for meta in self.metas.keys():
665 while id == '0': 687 while id == '0':
666 id, cookie = self.metas[meta].getIdAndCookie() 688 id, cookie = self.metas[meta].getIdAndCookie()
667 data = urllib.urlencode( {"room_data[server_id]":id, 689 data = urllib.urlencode( {"room_data[server_id]":id,
668 "act":'registerrooms'}) 690 "act":'registerrooms'})
669 get_server_dom(data+'&'+rooms, self.metas[meta].path) 691 get_server_dom(data+'&'+rooms, self.metas[meta].path)
670 692
693
671 def register(self,name_given=None): 694 def register(self,name_given=None):
672 if name_given == None: name = self.name 695 if name_given == None: name = self.name
673 else: self.name = name = name_given 696 else: self.name = name = name_given
697
674 name = self.clean_published_servername(name) 698 name = self.clean_published_servername(name)
675 699
676 # Set up the value for num_users 700 # Set up the value for num_users
677 if self.players: num_players = len(self.players) 701 if self.players: num_players = len(self.players)
678 else: num_players = 0 702 else: num_players = 0
681 metalist = getMetaServers(versions=["2"]) 705 metalist = getMetaServers(versions=["2"])
682 if self.show_meta_messages != 0: 706 if self.show_meta_messages != 0:
683 self.log_msg("Found these valid metas:") 707 self.log_msg("Found these valid metas:")
684 for meta in metalist: self.log_msg("Meta:" + meta) 708 for meta in metalist: self.log_msg("Meta:" + meta)
685 709
686 """
687 # Go through the list and see if there is already a running register 710 # Go through the list and see if there is already a running register
688 # thread for the meta. 711 # thread for the meta.
689 # If so, call it's register() method 712 # If so, call it's register() method
690 # If not, start one, implicitly calling the new thread's register() method 713 # If not, start one, implicitly calling the new thread's register() method
691 714
715
692 # iterate through the currently running metas and prune any 716 # iterate through the currently running metas and prune any
693 # not currently listed in the Meta Server list. 717 # not currently listed in the Meta Server list.
694 """
695
696 if self.show_meta_messages != 0: self.log_msg( "Checking running register threads for outdated metas.") 718 if self.show_meta_messages != 0: self.log_msg( "Checking running register threads for outdated metas.")
697 for meta in self.metas.keys(): 719 for meta in self.metas.keys():
698 if self.show_meta_messages != 0: self.log_msg("meta:" + meta + ": ") 720 if self.show_meta_messages != 0: self.log_msg("meta:" + meta + ": ")
699 if not meta in metalist: # if the meta entry running is not in the list 721 if not meta in metalist: # if the meta entry running is not in the list
700 if self.show_meta_messages != 0: self.log_msg( "Outdated. Unregistering and removing") 722 if self.show_meta_messages != 0: self.log_msg( "Outdated. Unregistering and removing")
704 if self.show_meta_messages != 0: self.log_msg( "Found in current meta list. Leaving intact.") 726 if self.show_meta_messages != 0: self.log_msg( "Found in current meta list. Leaving intact.")
705 727
706 # Now call register() for alive metas or start one if we need one 728 # Now call register() for alive metas or start one if we need one
707 for meta in metalist: 729 for meta in metalist:
708 if self.metas.has_key(meta) and self.metas[meta] and self.metas[meta].isAlive(): 730 if self.metas.has_key(meta) and self.metas[meta] and self.metas[meta].isAlive():
709 self.metas[meta].register(name=name, 731 self.metas[meta].register(name=name, realHostName=self.server_address, num_users=num_players)
710 realHostName=self.server_address,
711 num_users=num_players)
712 else: 732 else:
713 self.metas[meta] = registerThread(name=name, realHostName=self.server_address, 733 self.metas[meta] = registerThread(name=name, realHostName=self.server_address, num_users=num_players, MetaPath=meta, port=self.server_port,register_callback=self.register_callback)
714 num_users=num_players, MetaPath=meta, port=self.server_port,
715 register_callback=self.register_callback)
716 self.metas[meta].start() 734 self.metas[meta].start()
717 735
718 #The register Rooms thread 736 #The register Rooms thread
737
719 self.be_registered = 1 738 self.be_registered = 1
720 thread.start_new_thread(self.registerRooms,(0,)) 739 thread.start_new_thread(self.registerRooms,(0,))
721 740
741
742
722 def unregister(self): 743 def unregister(self):
723 """
724 # loop through all existing meta entries 744 # loop through all existing meta entries
725 # Don't rely on getMetaServers(), as a server may have been 745 # Don't rely on getMetaServers(), as a server may have been
726 # removed since it was started. In that case, then the meta 746 # removed since it was started. In that case, then the meta
727 # would never get unregistered. 747 # would never get unregistered.
728 # 748 #
729 # Instead, loop through all existing meta threads and unregister them 749 # Instead, loop through all existing meta threads and unregister them
730 """
731 750
732 for meta in self.metas.values(): 751 for meta in self.metas.values():
733 if meta and meta.isAlive(): meta.unregister() 752 if meta and meta.isAlive(): meta.unregister()
734 self.be_registered = 0 753 self.be_registered = 0
735 754
736 """
737 # This method runs as it's own thread and does the group_member_check every 755 # This method runs as it's own thread and does the group_member_check every
738 # sixty seconds. This should eliminate zombies that linger when no one is 756 # sixty seconds. This should eliminate zombies that linger when no one is
739 # around to spook them. GC: Frequency has been reduced as I question how valid 757 # around to spook them. GC: Frequency has been reduced as I question how valid
740 # the implementation is as it will only catch a very small segment of lingering 758 # the implementation is as it will only catch a very small segment of lingering
741 # connections. 759 # connections.
742 """
743 def player_reaper_thread_func(self,arg): 760 def player_reaper_thread_func(self,arg):
744 while self.alive: 761 while self.alive:
745 time.sleep(60) 762 time.sleep(60)
763
746 self.p_lock.acquire() 764 self.p_lock.acquire()
747 for group in self.groups.keys(): self.check_group_members(group) 765 for group in self.groups.keys(): self.check_group_members(group)
748 self.p_lock.release() 766 self.p_lock.release()
749 767
750 #This thread runs ever 250 miliseconds, and checks various plugin stuff 768 #This thread runs ever 250 miliseconds, and checks various plugin stuff
751 def PluginThread(self): 769 def PluginThread(self):
752 while self.alive: 770 while self.alive:
753 self.p_lock.acquire() 771 self.p_lock.acquire()
754 players = ServerPlugins.getPlayer() 772 players = ServerPlugins.getPlayer()
773
755 for player in players: 774 for player in players:
756 if player is not None: pass #Do something here so they can show up in the chat room for non web users' 775 if player is not None: pass #Do something here so they can show up in the chat room for non web users'
757 data = ServerPlugins.preParseOutgoing() 776 data = ServerPlugins.preParseOutgoing()
758 for msg in data: 777 for msg in data:
759 try: 778 try:
760 xml_dom = parseXml(msg) 779 xml_dom = parseXml(msg)
761 xml_dom = xml_dom._get_documentElement() 780 xml_dom = xml_dom._get_documentElement()
781
762 if xml_dom.hasAttribute('from') and int(xml_dom.getAttribute('from')) > -1: 782 if xml_dom.hasAttribute('from') and int(xml_dom.getAttribute('from')) > -1:
763 xml_dom.setAttribute('from', '-1') 783 xml_dom.setAttribute('from', '-1')
784
764 xml_dom.setAttribute('to', 'all') 785 xml_dom.setAttribute('to', 'all')
765 self.incoming_msg_handler(xml_dom, msg) 786 self.incoming_msg_handler(xml_dom, msg)
766 xml_dom.unlink() 787 xml_dom.unlink()
767 except: pass 788 except: pass
789
768 self.p_lock.release() 790 self.p_lock.release()
769 time.sleep(0.250) 791 time.sleep(0.250)
792
770 793
771 def sendMsg( self, sock, msg, useCompression=False, cmpType=None): 794 def sendMsg( self, sock, msg, useCompression=False, cmpType=None):
772 """Very simple function that will properly encode and send a message to te 795 """Very simple function that will properly encode and send a message to te
773 remote on the specified socket.""" 796 remote on the specified socket."""
797
774 if useCompression and cmpType != None: 798 if useCompression and cmpType != None:
775 mpacket = cmpType.compress(msg) 799 mpacket = cmpType.compress(msg)
776 lpacket = pack('!i', len(mpacket)) 800 lpacket = pack('!i', len(mpacket))
777 sock.send(lpacket) 801 sock.send(lpacket)
802
778 offset = 0 803 offset = 0
779 while offset < len(mpacket): 804 while offset < len(mpacket):
780 slice = buffer(mpacket, offset, len(mpacket)-offset) 805 slice = buffer(mpacket, offset, len(mpacket)-offset)
781 sent = sock.send(slice) 806 sent = sock.send(slice)
782 offset += sent 807 offset += sent
793 818
794 def recvData( self, sock, readSize ): 819 def recvData( self, sock, readSize ):
795 """Simple socket receive method. This method will only return when the exact 820 """Simple socket receive method. This method will only return when the exact
796 byte count has been read from the connection, if remote terminates our 821 byte count has been read from the connection, if remote terminates our
797 connection or we get some other socket exception.""" 822 connection or we get some other socket exception."""
823
798 data = "" 824 data = ""
799 offset = 0 825 offset = 0
800 try: 826 try:
801 while offset != readSize: 827 while offset != readSize:
802 frag = sock.recv( readSize - offset ) 828 frag = sock.recv( readSize - offset )
805 # Loudly raise an exception because we've been disconnected! 831 # Loudly raise an exception because we've been disconnected!
806 raise IOError, "Remote closed the connection!" 832 raise IOError, "Remote closed the connection!"
807 else: # Continue to build complete message 833 else: # Continue to build complete message
808 offset += rs 834 offset += rs
809 data += frag 835 data += frag
836
810 except socket.error, e: 837 except socket.error, e:
811 self.log_msg("Socket Error: recvData(): " + e ) 838 self.log_msg("Socket Error: recvData(): " + e )
812 data = "" 839 data = ""
813 return data 840 return data
814 841
823 with the OS until we attempt to read the next complete message.""" 850 with the OS until we attempt to read the next complete message."""
824 851
825 msgData = "" 852 msgData = ""
826 try: 853 try:
827 lenData = self.recvData( sock, MPLAY_LENSIZE ) 854 lenData = self.recvData( sock, MPLAY_LENSIZE )
828 (length,) = unpack('!i', lenData) # Now, convert to a usable form 855 # Now, convert to a usable form
829 msgData = self.recvData( sock, length ) # Read exactly the remaining amount of data 856 (length,) = unpack('!i', lenData)
857 # Read exactly the remaining amount of data
858 msgData = self.recvData( sock, length )
830 try: 859 try:
831 if useCompression and cmpType != None: msgData = cmpType.decompress(msgData) 860 if useCompression and cmpType != None: msgData = cmpType.decompress(msgData)
832 except: traceback.print_exc() 861 except: traceback.print_exc()
862
833 except Exception, e: self.log_msg( "Exception: recvMsg(): " + str(e) ) 863 except Exception, e: self.log_msg( "Exception: recvMsg(): " + str(e) )
834 return msgData 864 return msgData
865
835 866
836 def kill_server(self): 867 def kill_server(self):
837 self.alive = 0 868 self.alive = 0
838 self.log_msg("Server stopping...") 869 self.log_msg("Server stopping...")
839 self.unregister() # unregister from the Meta 870 self.unregister() # unregister from the Meta
840 for p in self.players.itervalues(): 871 for p in self.players.itervalues():
841 p.disconnect() 872 p.disconnect()
842 self.incoming.put("<system/>") 873 self.incoming.put("<system/>")
874
843 for g in self.groups.itervalues(): 875 for g in self.groups.itervalues():
844 g.save_map() 876 g.save_map()
877
845 try: 878 try:
846 ip = socket.gethostbyname(socket.gethostname()) 879 ip = socket.gethostbyname(socket.gethostname())
847 kill = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 880 kill = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
848 kill.connect((ip, self.server_port)) 881 kill.connect((ip, self.server_port))
849 882
856 self.listen_sock.close() 889 self.listen_sock.close()
857 self.listen_event.wait(10) 890 self.listen_event.wait(10)
858 self.incoming_event.wait(10) 891 self.incoming_event.wait(10)
859 self.log_msg("Server stopped!") 892 self.log_msg("Server stopped!")
860 893
894
895
861 def log_msg(self,msg): 896 def log_msg(self,msg):
862 if self.log_to_console: 897 if self.log_to_console:
863 if self.log_console: self.log_console(msg) 898 if self.log_console:
864 else: print str(msg) 899 self.log_console(msg)
900 else:
901 print str(msg)
902
865 903
866 def print_help(self): 904 def print_help(self):
867 print 905 print
868 print "Commands: " 906 print "Commands: "
869 print "'kill' or 'quit' - to stop the server" 907 print "'kill' or 'quit' - to stop the server"
896 print "'togglelobbysound' - Will turn on or off the Auto sending of a sound to all players who join the loby" 934 print "'togglelobbysound' - Will turn on or off the Auto sending of a sound to all players who join the loby"
897 print "'lobbysound' - Lets you specify which sound file to send to players joining the lobby" 935 print "'lobbysound' - Lets you specify which sound file to send to players joining the lobby"
898 print "'help' or '?' or 'h' - for this help message" 936 print "'help' or '?' or 'h' - for this help message"
899 print 937 print
900 938
939
901 def broadcast(self,msg): 940 def broadcast(self,msg):
902 self.send_to_all("0","<msg to='all' from='0' group_id='1'><font color='#FF0000'>" + msg + "</font>") 941 self.send_to_all("0","<msg to='all' from='0' group_id='1'><font color='#FF0000'>" + msg + "</font>")
942
903 943
904 def console_log(self): 944 def console_log(self):
905 if self.log_to_console == 1: 945 if self.log_to_console == 1:
906 print "console logging now off" 946 print "console logging now off"
907 self.log_to_console = 0 947 self.log_to_console = 0
908 else: 948 else:
909 print "console logging now on" 949 print "console logging now on"
910 self.log_to_console = 1 950 self.log_to_console = 1
911 951
952
912 def groups_list(self): 953 def groups_list(self):
913 self.p_lock.acquire() 954 self.p_lock.acquire()
914 try: 955 try:
915 keys = self.groups.keys() 956 keys = self.groups.keys()
916 for k in keys: 957 for k in keys:
917 pw = "-" 958 pw = "-"
918 pr = " -" 959 pr = " -"
919 if self.groups[k].pwd != "": pw = "P" 960 if self.groups[k].pwd != "":
920 if self.isPersistentRoom( k ): pr = " S" #using S for static (P for persistant conflicts with password) 961 pw = "P"
962 if self.isPersistentRoom( k ):
963 pr = " S" #using S for static (P for persistant conflicts with password)
921 print "Group: " + k + pr + pw + ' Name: ' + self.groups[k].name 964 print "Group: " + k + pr + pw + ' Name: ' + self.groups[k].name
922 print 965 print
966
923 except Exception, e: 967 except Exception, e:
924 self.log_msg(str(e)) 968 self.log_msg(str(e))
969
925 self.p_lock.release() 970 self.p_lock.release()
926 971
927 """ 972 #----------------------------------------------------------------
928 #---------------------------------------------------------------- 973 # Monitor Function -- Added by snowdog 2/05
929 # Monitor Function -- Added by snowdog 2/05 974 #----------------------------------------------------------------
930 #----------------------------------------------------------------
931 """
932 def monitor(self, pid, mode=1 ): 975 def monitor(self, pid, mode=1 ):
933 "allows monitoring of a specific user(s) network i/o" 976 "allows monitoring of a specific user(s) network i/o"
934 #if mode is not set to 1 then monitor adds toggles the state 977 #if mode is not set to 1 then monitor adds toggles the state
935 #of monitoring on the given user 978 #of monitoring on the given user
979
936 if (mode == 1): 980 if (mode == 1):
937 for p in self.players: 981 for p in self.players:
938 try: p.monitor("off") 982 try: p.monitor("off")
939 except: pass 983 except: pass
940 try: 984 try:
941 r = (self.players[pid]).set_traffic_monitor("toggle") 985 r = (self.players[pid]).set_traffic_monitor("toggle")
942 self.log_msg("Monitor: Mode=" + str(r) + " on Player #" + str(pid)) 986 self.log_msg("Monitor: Mode=" + str(r) + " on Player #" + str(pid))
943 except: 987 except:
944 self.log_msg("Monitor: Invalid Player ID") 988 self.log_msg("Monitor: Invalid Player ID")
945 traceback.print_exc() 989 traceback.print_exc()
990
946 991
947 def search(self,patern): 992 def search(self,patern):
948 keys = self.groups.keys() 993 keys = self.groups.keys()
949 print "Search results:" 994 print "Search results:"
950 for k in keys: 995 for k in keys:
951 ids = self.groups[k].get_player_ids() 996 ids = self.groups[k].get_player_ids()
952 for id in ids: 997 for id in ids:
953 if self.players[id].id.find(patern)>-1: self.print_player_info(self.players[id]) 998 if self.players[id].id.find(patern)>-1:
954 elif self.players[id].name.find(patern)>-1: self.print_player_info(self.players[id]) 999 self.print_player_info(self.players[id])
955 elif self.players[id].ip.find(patern)>-1: self.print_player_info(self.players[id]) 1000
956 elif self.players[id].group_id.find(patern)>-1: self.print_player_info(self.players[id]) 1001 elif self.players[id].name.find(patern)>-1:
957 elif self.players[id].role.find(patern)>-1: self.print_player_info(self.players[id]) 1002 self.print_player_info(self.players[id])
958 elif self.players[id].version.find(patern)>-1: self.print_player_info(self.players[id]) 1003
959 elif self.players[id].protocol_version.find(patern)>-1: self.print_player_info(self.players[id]) 1004 elif self.players[id].ip.find(patern)>-1:
960 elif self.players[id].client_string.find(patern)>-1: self.print_player_info(self.players[id]) 1005 self.print_player_info(self.players[id])
1006
1007 elif self.players[id].group_id.find(patern)>-1:
1008 self.print_player_info(self.players[id])
1009
1010 elif self.players[id].role.find(patern)>-1:
1011 self.print_player_info(self.players[id])
1012
1013 elif self.players[id].version.find(patern)>-1:
1014 self.print_player_info(self.players[id])
1015
1016 elif self.players[id].protocol_version.find(patern)>-1:
1017 self.print_player_info(self.players[id])
1018
1019 elif self.players[id].client_string.find(patern)>-1:
1020 self.print_player_info(self.players[id])
1021
961 1022
962 def print_player_info(self,player): 1023 def print_player_info(self,player):
963 print player.id, player.name, player.ip, player.group_id, player.role, player.version, player.protocol_version, player.client_string 1024 print player.id,player.name,player.ip,player.group_id, player.role,player.version,player.protocol_version,player.client_string
964 1025
965 """
966 #---------------------------------------------------------------- 1026 #----------------------------------------------------------------
967 # Uptime Function -- Added by snowdog 4/03 1027 # Uptime Function -- Added by snowdog 4/03
968 #---------------------------------------------------------------- 1028 #----------------------------------------------------------------
969 """
970 def uptime(self , mode = 0): 1029 def uptime(self , mode = 0):
971 "returns string containing how long server has been in operation" 1030 "returns string containing how long server has been in operation"
972 ut = time.time() - self.server_start_time 1031 ut = time.time() - self.server_start_time
973 d = int(ut/86400) 1032 d = int(ut/86400)
974 h = int( (ut-(86400*d))/3600 ) 1033 h = int( (ut-(86400*d))/3600 )
976 s = int( (ut-(86400*d)-(3600*h)-(60*m)) ) 1035 s = int( (ut-(86400*d)-(3600*h)-(60*m)) )
977 uts = str( "This server has been running for:\n " + str(d) + " days " + str(h) + " hours " + str(m) + " min. " + str(s) + " sec. [" + str(int(ut)) + " seconds]") 1036 uts = str( "This server has been running for:\n " + str(d) + " days " + str(h) + " hours " + str(m) + " min. " + str(s) + " sec. [" + str(int(ut)) + " seconds]")
978 if mode == 0: print uts 1037 if mode == 0: print uts
979 else: return uts 1038 else: return uts
980 1039
981 """
982 #----------------------------------------------------- 1040 #-----------------------------------------------------
983 # Toggle Room Password Allow -- Added by Snowdog 11/03 1041 # Toggle Room Password Allow -- Added by Snowdog 11/03
984 #----------------------------------------------------- 1042 #-----------------------------------------------------
985 """
986 def RoomPasswords(self): 1043 def RoomPasswords(self):
987 if self.allow_room_passwords != 0: 1044 if self.allow_room_passwords != 0:
988 self.allow_room_passwords = 0 1045 self.allow_room_passwords = 0
989 return "Client Created Room Passwords: Disallowed" 1046 return "Client Created Room Passwords: Disallowed"
990 else: 1047 else:
991 self.allow_room_passwords = 1 1048 self.allow_room_passwords = 1
992 return "Client Created Room Passwords: Allowed" 1049 return "Client Created Room Passwords: Allowed"
1050
993 1051
994 def group_dump(self,k): 1052 def group_dump(self,k):
995 self.p_lock.acquire() 1053 self.p_lock.acquire()
996 try: 1054 try:
997 print "Group: " + k 1055 print "Group: " + k
1004 print 1062 print
1005 except Exception, e: 1063 except Exception, e:
1006 self.log_msg(str(e)) 1064 self.log_msg(str(e))
1007 self.p_lock.release() 1065 self.p_lock.release()
1008 1066
1009 """
1010 #---------------------------------------------------------------- 1067 #----------------------------------------------------------------
1011 # Player List -- Added by snowdog 4/03 1068 # Player List -- Added by snowdog 4/03
1012 #---------------------------------------------------------------- 1069 #----------------------------------------------------------------
1013 """
1014 def player_list(self): 1070 def player_list(self):
1015 "display a condensed list of players on the server" 1071 "display a condensed list of players on the server"
1016 self.p_lock.acquire() 1072 self.p_lock.acquire()
1017 try: 1073 try:
1018 print "------------[ PLAYER LIST ]------------" 1074 print "------------[ PLAYER LIST ]------------"
1043 self.p_lock.acquire() 1099 self.p_lock.acquire()
1044 try: 1100 try:
1045 keys = self.groups.keys() 1101 keys = self.groups.keys()
1046 for k in keys: 1102 for k in keys:
1047 print "Group: %s %s (pass: \"%s\")" % (str(k),self.groups[k].name, self.groups[k].pwd) 1103 print "Group: %s %s (pass: \"%s\")" % (str(k),self.groups[k].name, self.groups[k].pwd)
1104
1048 ids = self.groups[k].get_player_ids() 1105 ids = self.groups[k].get_player_ids()
1049 for id in ids: 1106 for id in ids:
1050 if self.players.has_key(id): print str(self.players[id]) 1107 if self.players.has_key(id):
1108 print str(self.players[id])
1051 else: 1109 else:
1052 self.groups[k].remove_player(id) 1110 self.groups[k].remove_player(id)
1053 print "Bad Player Ref (#" + id + ") in group" 1111 print "Bad Player Ref (#" + id + ") in group"
1054 except Exception, e: 1112 except Exception, e:
1055 self.log_msg(str(e)) 1113 self.log_msg(str(e))
1114
1056 self.p_lock.release() 1115 self.p_lock.release()
1116
1057 1117
1058 def update_request(self,newsock,xml_dom): 1118 def update_request(self,newsock,xml_dom):
1059 # handle reconnects 1119 # handle reconnects
1120
1060 self.log_msg( "update_request() has been called." ) 1121 self.log_msg( "update_request() has been called." )
1061 1122
1062 # get player id 1123 # get player id
1063 id = xml_dom.getAttribute("id") 1124 id = xml_dom.getAttribute("id")
1064 group_id = xml_dom.getAttribute("group_id") 1125 group_id = xml_dom.getAttribute("group_id")
1126
1065 self.p_lock.acquire() 1127 self.p_lock.acquire()
1066 if self.players.has_key(id): 1128 if self.players.has_key(id):
1067 self.sendMsg(newsock, self.players[id].toxml("update"), 1129 self.sendMsg( newsock, self.players[id].toxml("update"), self.players[id].useCompression, self.players[id].compressionType )
1068 self.players[id].useCompression,
1069 self.players[id].compressionType )
1070 self.players[id].reset(newsock) 1130 self.players[id].reset(newsock)
1071 self.players[id].clear_timeout() 1131 self.players[id].clear_timeout()
1072 need_new = 0 1132 need_new = 0
1073 else: need_new = 1 1133 else:
1134 need_new = 1
1074 self.p_lock.release() 1135 self.p_lock.release()
1075 if need_new: self.new_request(newsock,xml_dom) 1136
1137 if need_new:
1138 self.new_request(newsock,xml_dom)
1076 else: 1139 else:
1077 msg = self.groups[group_id].game_map.get_all_xml() 1140 msg = self.groups[group_id].game_map.get_all_xml()
1078 self.send(msg,id,group_id) 1141 self.send(msg,id,group_id)
1142
1079 1143
1080 def new_request(self,newsock,xml_dom,LOBBY_ID='0'): 1144 def new_request(self,newsock,xml_dom,LOBBY_ID='0'):
1081 #build client stub 1145 #build client stub
1082 props = {} 1146 props = {}
1083 # Don't trust what the client tells us...trust what they connected as! 1147 # Don't trust what the client tells us...trust what they connected as!
1084 props['ip'] = socket.gethostbyname( newsock.getpeername()[0] ) 1148 props['ip'] = socket.gethostbyname( newsock.getpeername()[0] )
1085 1149
1086 try: props['role'] = xml_dom.getAttribute("role") 1150 try:
1087 except: props['role'] = "GM" 1151 props['role'] = xml_dom.getAttribute("role")
1152 except:
1153 props['role'] = "GM"
1088 1154
1089 props['name'] = xml_dom.getAttribute("name") 1155 props['name'] = xml_dom.getAttribute("name")
1090 props['group_id'] = LOBBY_ID 1156 props['group_id'] = LOBBY_ID
1091 props['id'] = str(self.next_player_id) 1157 props['id'] = str(self.next_player_id)
1092 props['version'] = xml_dom.getAttribute("version") 1158 props['version'] = xml_dom.getAttribute("version")
1093 props['protocol_version'] = xml_dom.getAttribute("protocol_version") 1159 props['protocol_version'] = xml_dom.getAttribute("protocol_version")
1094 props['client_string'] = xml_dom.getAttribute("client_string") 1160 props['client_string'] = xml_dom.getAttribute("client_string")
1095
1096 self.next_player_id += 1 1161 self.next_player_id += 1
1097 new_stub = client_stub(self.incoming,newsock,props,self.log_console) 1162 new_stub = client_stub(self.incoming,newsock,props,self.log_console)
1098 if xml_dom.hasAttribute('useCompression'): 1163 if xml_dom.hasAttribute('useCompression'):
1099 new_stub.useCompression = True 1164 new_stub.useCompression = True
1165
1100 if xml_dom.hasAttribute('cmpType'): 1166 if xml_dom.hasAttribute('cmpType'):
1101 cmpType = xml_dom.getAttribute('cmpType') 1167 cmpType = xml_dom.getAttribute('cmpType')
1102 if cmpBZ2 and cmpType == 'bz2': new_stub.compressionType = bz2 1168 if cmpBZ2 and cmpType == 'bz2':
1103 elif cmpZLIB and cmpType == 'zlib': new_stub.compressionType = zlib 1169 new_stub.compressionType = bz2
1104 else: new_stub.compressionType = None 1170 elif cmpZLIB and cmpType == 'zlib':
1105 else: new_stub.compressionType = bz2 1171 new_stub.compressionType = zlib
1106 else: new_stub.useCompression = False 1172 else:
1173 new_stub.compressionType = None
1174 else:
1175 new_stub.compressionType = bz2
1176
1177 else:
1178 new_stub.useCompression = False
1107 1179
1108 #update newly create client stub with network logging state 1180 #update newly create client stub with network logging state
1109 new_stub.EnableMessageLogging = self.log_network_messages 1181 new_stub.EnableMessageLogging = self.log_network_messages
1182
1110 self.sendMsg(newsock, new_stub.toxml("new"), False, None) 1183 self.sendMsg(newsock, new_stub.toxml("new"), False, None)
1111 1184
1112 # try to remove circular refs 1185 # try to remove circular refs
1113 if xml_dom: 1186 if xml_dom:
1114 xml_dom.unlink() 1187 xml_dom.unlink()
1130 time.sleep(2) 1203 time.sleep(2)
1131 newsock.close() 1204 newsock.close()
1132 print "Error in parse found from " + str(remote_host) + ". Disconnected." 1205 print "Error in parse found from " + str(remote_host) + ". Disconnected."
1133 print " Offending data(" + str(len(data)) + "bytes)=" + data 1206 print " Offending data(" + str(len(data)) + "bytes)=" + data
1134 print "Exception=" + str(e) 1207 print "Exception=" + str(e)
1135 if xml_dom: xml_dom.unlink() 1208
1209 if xml_dom:
1210 xml_dom.unlink()
1136 return 1211 return
1137 1212
1138 #start threads and store player 1213 #start threads and store player
1214
1139 allowed = 1 1215 allowed = 1
1140 version_string = "" 1216 version_string = ""
1141 1217
1142 if ((props['protocol_version'] != PROTOCOL_VERSION) and self.validate_protocol): 1218 if ((props['protocol_version'] != PROTOCOL_VERSION) and self.validate_protocol):
1143 version_string = "Sorry, this server can't handle your client version. (Protocol mismatch)<br />" 1219 version_string = "Sorry, this server can't handle your client version. (Protocol mismatch)<br />"
1144 allowed = 0 1220 allowed = 0
1145 1221
1146 if not self.checkClientVersion(props['version']): 1222 if not self.checkClientVersion(props['version']):
1147 version_string = "Sorry, your client is out of date. <br />" 1223 version_string = "Sorry, your client is out of date. <br />"
1148 version_string += "This server requires your client be version " 1224 version_string += "This server requires your client be version " + self.minClientVersion + " or higher to connect.<br />"
1149 version_string += "" + self.minClientVersion + " or higher to connect.<br />"
1150 allowed = 0 1225 allowed = 0
1151 1226
1152 if not allowed: 1227 if not allowed:
1153 version_string += " Please go to <a href='http://www.assembla.com/traipse'>" 1228 version_string += ' Please go to <a href="http://openrpg.digitalxero.net">http://openrpg.digitalxero.net</a> to find a compatible client.<br />'
1154 version_string += "http://www.assembla.com/traipse</a> to find a compatible client.<br />" 1229 version_string += "If you can't find a compatible client on the website, chances are that the server is running an unreleased development version for testing purposes.<br />"
1155 version_string += "If you can't find a compatible client on the website, "
1156 version_string += "chances are that the server is running an unreleased development "
1157 version_string += "version for testing purposes.<br />"
1158 1230
1159 self.sendMsg( newsock, "<msg to='" + props['id'] + "' from='0' group_id='0' />" + version_string, new_stub.useCompression, new_stub.compressionType) 1231 self.sendMsg( newsock, "<msg to='" + props['id'] + "' from='0' group_id='0' />" + version_string, new_stub.useCompression, new_stub.compressionType)
1160 # Give messages time to flow 1232 # Give messages time to flow
1161 time.sleep(1) 1233 time.sleep(1)
1162 self.log_msg("Connection terminating due to version incompatibility with client (ver: " + props['version'] + " protocol: " + props['protocol_version'] + ")" ) 1234 self.log_msg("Connection terminating due to version incompatibility with client (ver: " + props['version'] + " protocol: " + props['protocol_version'] + ")" )
1169 if self.ban_list.has_key(ip): 1241 if self.ban_list.has_key(ip):
1170 banmsg = "You have been banned from this server.<br />" 1242 banmsg = "You have been banned from this server.<br />"
1171 cmsg = "Banned Client: (" + str(props['id']) + ") " + str(props['name']) + " [" + str(props['ip']) + "]" 1243 cmsg = "Banned Client: (" + str(props['id']) + ") " + str(props['name']) + " [" + str(props['ip']) + "]"
1172 self.log_msg(cmsg) 1244 self.log_msg(cmsg)
1173 allowed = 0 1245 allowed = 0
1246
1174 self.sendMsg( newsock, "<msg to='" + props['id'] + "' from='0' group_id='0' />" + banmsg, new_stub.useCompression, new_stub.compressionType) 1247 self.sendMsg( newsock, "<msg to='" + props['id'] + "' from='0' group_id='0' />" + banmsg, new_stub.useCompression, new_stub.compressionType)
1175 # Give messages time to flow 1248 # Give messages time to flow
1176 time.sleep(1) 1249 time.sleep(1)
1177 newsock.close() 1250 newsock.close()
1178 if xml_dom: 1251 if xml_dom:
1179 xml_dom.unlink() 1252 xml_dom.unlink()
1180 return None 1253 return None
1181 1254
1182 """
1183 #---- Connection order changed by Snowdog 1/05 1255 #---- Connection order changed by Snowdog 1/05
1184 #---- Attempt to register player and send group data 1256 #---- Attempt to register player and send group data
1185 #---- before displaying lobby message 1257 #---- before displaying lobby message
1186 #---- Does not solve the Blackhole bug but under some conditions may 1258 #---- Does not solve the Blackhole bug but under some conditions may
1187 #---- allow for a graceful server response. -SD 1259 #---- allow for a graceful server response. -SD
1189 #---- changed method of sending group names to user 8/05 1261 #---- changed method of sending group names to user 8/05
1190 #---- black hole bug causes the group information to not be sent 1262 #---- black hole bug causes the group information to not be sent
1191 #---- to clients. Not sure why the group messages were being sent to the 1263 #---- to clients. Not sure why the group messages were being sent to the
1192 #---- incomming message queue, when they should be sent directly to user 1264 #---- incomming message queue, when they should be sent directly to user
1193 #---- Does not solve the black hole bug totally -SD 1265 #---- Does not solve the black hole bug totally -SD
1194 """
1195 1266
1196 try: 1267 try:
1197 if xml_dom.getAttribute("id") == props['id']: 1268 if xml_dom.getAttribute("id") == props['id']:
1198 new_stub.initialize_threads() 1269 new_stub.initialize_threads()
1199 self.p_lock.acquire() 1270 self.p_lock.acquire()
1200 self.players[props['id']] = new_stub 1271 self.players[props['id']] = new_stub
1201 self.groups[LOBBY_ID].add_player(props['id']) #always add to lobby on connection. 1272 self.groups[LOBBY_ID].add_player(props['id']) #always add to lobby on connection.
1202 self.send_group_list(props['id']) 1273 self.send_group_list(props['id'])
1203 self.send_player_list(props['id'],LOBBY_ID) 1274 self.send_player_list(props['id'],LOBBY_ID)
1204 self.p_lock.release() 1275 self.p_lock.release()
1276
1205 msg = self.groups[LOBBY_ID].game_map.get_all_xml() 1277 msg = self.groups[LOBBY_ID].game_map.get_all_xml()
1206 self.send(msg,props['id'],LOBBY_ID) 1278 self.send(msg,props['id'],LOBBY_ID)
1207 self.send_to_group(props['id'],LOBBY_ID,self.players[props['id']].toxml('new')) 1279 self.send_to_group(props['id'],LOBBY_ID,self.players[props['id']].toxml('new'))
1208 self.return_room_roles(props['id'],LOBBY_ID) 1280 self.return_room_roles(props['id'],LOBBY_ID)
1209 1281
1210 # Re-initialize the role for this player incase they came from a different server 1282 # Re-initialize the role for this player incase they came from a different server
1211 self.handle_role("set",props['id'], "GM",self.groups[LOBBY_ID].boot_pwd, LOBBY_ID) 1283 self.handle_role("set",props['id'], "GM",self.groups[LOBBY_ID].boot_pwd, LOBBY_ID)
1284
1212 cmsg = "Client Connect: (" + str(props['id']) + ") " + str(props['name']) + " [" + str(props['ip']) + "]" 1285 cmsg = "Client Connect: (" + str(props['id']) + ") " + str(props['name']) + " [" + str(props['ip']) + "]"
1213 self.log_msg(cmsg) 1286 self.log_msg(cmsg)
1214 cmsg = ("connect", props) ################################################# 1287 cmsg = ("connect", props) #################################################
1215 self.log_msg(cmsg) 1288 self.log_msg(cmsg)
1216 1289
1229 err_string += "please contact the servers administrator to correct the issue.</center> " 1302 err_string += "please contact the servers administrator to correct the issue.</center> "
1230 self.sendMsg( newsock, "<msg to='" + props['id'] + "' from='" + props['id'] + "' group_id='0' />" + err_string, new_stub.useCompression, new_stub.compressionType ) 1303 self.sendMsg( newsock, "<msg to='" + props['id'] + "' from='" + props['id'] + "' group_id='0' />" + err_string, new_stub.useCompression, new_stub.compressionType )
1231 time.sleep(2) 1304 time.sleep(2)
1232 newsock.close() 1305 newsock.close()
1233 1306
1307
1234 # Display the lobby message 1308 # Display the lobby message
1235 self.SendLobbyMessage(newsock,props['id']) 1309 self.SendLobbyMessage(newsock,props['id'])
1310
1236 if xml_dom: 1311 if xml_dom:
1237 xml_dom.unlink() 1312 xml_dom.unlink()
1313
1238 1314
1239 def checkClientVersion(self, clientversion): 1315 def checkClientVersion(self, clientversion):
1240 minv = self.minClientVersion.split('.') 1316 minv = self.minClientVersion.split('.')
1241 cver = clientversion.split('.') 1317 cver = clientversion.split('.')
1242 for i in xrange(min(len(minv),len(cver))): 1318 for i in xrange(min(len(minv),len(cver))):
1243 w=max(len(minv[i]),len(cver[i])) 1319 w=max(len(minv[i]),len(cver[i]))
1244 v1=minv[i].rjust(w); 1320 v1=minv[i].rjust(w);
1245 v2=cver[i].rjust(w); 1321 v2=cver[i].rjust(w);
1246 if v1<v2: return 1 1322 if v1<v2:
1247 if v1>v2: return 0 1323 return 1
1248 if len(minv)>len(cver): return 0 1324 if v1>v2:
1325 return 0
1326
1327 if len(minv)>len(cver):
1328 return 0
1249 return 1 1329 return 1
1250 1330
1331
1332
1251 def SendLobbyMessage(self, socket, player_id): 1333 def SendLobbyMessage(self, socket, player_id):
1252 """ 1334 #######################################################################
1253 # Display the lobby message 1335 # Display the lobby message
1254 # prepend this server's version string to the the lobby message 1336 # prepend this server's version string to the the lobby message
1255 """ 1337 try:
1256 try: 1338 lobbyMsg = "You have connected to an <a href=\"http://www.openrpg.com\">OpenRPG</a> server, version '" + VERSION + "'"
1257 lobbyMsg = "You have connected to an <a href=\"http://www.openrpg.com\">OpenRPG</a> "
1258 lobbyMsg += "server, version '" + VERSION + "'"
1259 1339
1260 # See if we have a server name to report! 1340 # See if we have a server name to report!
1341
1261 if len(self.serverName): 1342 if len(self.serverName):
1262 lobbyMsg += ", named '" + self.serverName + "'." 1343 lobbyMsg += ", named '" + self.serverName + "'."
1344
1263 else: 1345 else:
1264 lobbyMsg += "." 1346 lobbyMsg += "."
1265 1347
1266 # Add extra line spacing 1348 # Add extra line spacing
1267 lobbyMsg += "\n\n" 1349 lobbyMsg += "\n\n"
1268 1350
1269 try: validate.config_file("LobbyMessage.html","default_LobbyMessage.html") 1351 try:
1270 except: pass 1352 validate.config_file("LobbyMessage.html","default_LobbyMessage.html")
1353 except:
1354 pass
1271 else: 1355 else:
1272 open_msg = open( self.userPath + "LobbyMessage.html", "r" ) 1356 open_msg = open( self.userPath + "LobbyMessage.html", "r" )
1273 lobbyMsg += open_msg.read() 1357 lobbyMsg += open_msg.read()
1274 open_msg.close() 1358 open_msg.close()
1275 1359
1276 # Send the server's lobby message to the client no matter what 1360 # Send the server's lobby message to the client no matter what
1277 self.sendMsg(socket, "<msg to='" + player_id + "' from='0' group_id='0' />" + lobbyMsg, 1361 self.sendMsg(socket, "<msg to='" + player_id + "' from='0' group_id='0' />" + lobbyMsg, self.players[player_id].useCompression, self.players[player_id].compressionType)
1278 self.players[player_id].useCompression, self.players[player_id].compressionType)
1279 if self.sendLobbySound: 1362 if self.sendLobbySound:
1280 self.sendMsg(socket, '<sound url="' + self.lobbySound + '" group_id="0" from="0" loop="True" />', 1363 self.sendMsg(socket, '<sound url="' + self.lobbySound + '" group_id="0" from="0" loop="True" />', self.players[player_id].useCompression, self.players[player_id].compressionType)
1281 self.players[player_id].useCompression, self.players[player_id].compressionType)
1282 return 1364 return
1283 except: traceback.print_exc() 1365 except:
1284 """ 1366 traceback.print_exc()
1285 # End of lobby message code 1367 # End of lobby message code
1286 """ 1368 #######################################################################
1287 1369
1288 1370
1289 def listenAcceptThread(self,arg): 1371 def listenAcceptThread(self,arg):
1290 # Set up the socket to listen on. 1372 # Set up the socket to listen on.
1291 try: 1373 try:
1292 self.log_msg("\nlisten thread running...") 1374 self.log_msg("\nlisten thread running...")
1293 adder = "" 1375 adder = ""
1294 if self.server_address is not None: adder = self.server_address 1376 if self.server_address is not None:
1377 adder = self.server_address
1295 self.listen_sock.bind(('', self.server_port)) 1378 self.listen_sock.bind(('', self.server_port))
1296 self.listen_sock.listen(5) 1379 self.listen_sock.listen(5)
1297 1380
1298 except Exception, e: 1381 except Exception, e:
1299 self.log_msg(("Error binding request socket!", e)) 1382 self.log_msg(("Error binding request socket!", e))
1300 self.alive = 0 1383 self.alive = 0
1301 1384
1385
1302 while self.alive: 1386 while self.alive:
1387
1303 # Block on the socket waiting for a new connection 1388 # Block on the socket waiting for a new connection
1304 try: 1389 try:
1305 (newsock, addr) = self.listen_sock.accept() 1390 (newsock, addr) = self.listen_sock.accept()
1306 """
1307 ## self.log_msg("New connection from " + str(addr)+ ". Interfacing with server...") 1391 ## self.log_msg("New connection from " + str(addr)+ ". Interfacing with server...")
1308 1392
1309 # Now that we've accepted a new connection, we must immediately spawn a new 1393 # Now that we've accepted a new connection, we must immediately spawn a new
1310 # thread to handle it...otherwise we run the risk of having a DoS shoved into 1394 # thread to handle it...otherwise we run the risk of having a DoS shoved into
1311 # our face! :O After words, this thread is dead ready for another connection 1395 # our face! :O After words, this thread is dead ready for another connection
1312 # accept to come in. 1396 # accept to come in.
1313 """
1314 thread.start_new_thread(self.acceptedNewConnectionThread, ( newsock, addr )) 1397 thread.start_new_thread(self.acceptedNewConnectionThread, ( newsock, addr ))
1315 1398
1316 except: 1399 except:
1317 print "The following exception caught accepting new connection:" 1400 print "The following exception caught accepting new connection:"
1318 traceback.print_exc() 1401 traceback.print_exc()
1319 1402
1320 # At this point, we're done and cleaning up. 1403 # At this point, we're done and cleaning up.
1321 self.log_msg("server socket listening thread exiting...") 1404 self.log_msg("server socket listening thread exiting...")
1322 self.listen_event.set() 1405 self.listen_event.set()
1323 1406
1407
1408
1324 def acceptedNewConnectionThread( self, newsock, addr ): 1409 def acceptedNewConnectionThread( self, newsock, addr ):
1325 """Once a new connection comes in and is accepted, this thread starts up to handle it.""" 1410 """Once a new connection comes in and is accepted, this thread starts up to handle it."""
1411
1326 # Initialize xml_dom 1412 # Initialize xml_dom
1327 xml_dom = None 1413 xml_dom = None
1328 data = None 1414 data = None
1329 1415
1330 # get client info and send othe client info 1416 # get client info and send othe client info
1331 # If this receive fails, this thread should exit without even attempting to process it 1417 # If this receive fails, this thread should exit without even attempting to process it
1332 self.log_msg("Connection from " + str(addr) + " has been accepted. Waiting for data...") 1418 self.log_msg("Connection from " + str(addr) + " has been accepted. Waiting for data...")
1419
1333 data = self.recvMsg( newsock ) 1420 data = self.recvMsg( newsock )
1421
1334 if data=="" or data == None: 1422 if data=="" or data == None:
1335 self.log_msg("Connection from " + str(addr) + " failed. Closing connection.") 1423 self.log_msg("Connection from " + str(addr) + " failed. Closing connection.")
1336 try: newsock.close() 1424 try:
1425 newsock.close()
1337 except Exception, e: 1426 except Exception, e:
1338 self.log_msg( str(e) ) 1427 self.log_msg( str(e) )
1339 print str(e) 1428 print str(e)
1340 return #returning causes connection thread instance to terminate 1429 return #returning causes connection thread instance to terminate
1430
1431
1341 if data == "<system/>": 1432 if data == "<system/>":
1342 try: newsock.close() 1433 try:
1343 except: pass 1434 newsock.close()
1435 except:
1436 pass
1344 return #returning causes connection thread instance to terminate 1437 return #returning causes connection thread instance to terminate
1438
1345 # Clear out the xml_dom in preparation for new stuff, if necessary 1439 # Clear out the xml_dom in preparation for new stuff, if necessary
1346 try: 1440 try:
1347 if xml_dom: xml_dom.unlink() 1441 if xml_dom:
1442 xml_dom.unlink()
1348 1443
1349 except: 1444 except:
1350 self.log_msg( "The following exception caught unlinking xml_dom:") 1445 self.log_msg( "The following exception caught unlinking xml_dom:")
1351 self.log_msg("Continuing") 1446 self.log_msg("Continuing")
1352 try: newsock.close() 1447
1353 except: pass 1448 try:
1449 newsock.close()
1450 except:
1451 pass
1354 return #returning causes connection thread instance to terminate 1452 return #returning causes connection thread instance to terminate
1453
1355 # Parse the XML received from the connecting client 1454 # Parse the XML received from the connecting client
1356 try: 1455 try:
1357 xml_dom = parseXml(data) 1456 xml_dom = parseXml(data)
1358 xml_dom = xml_dom._get_documentElement() 1457 xml_dom = xml_dom._get_documentElement()
1359 1458
1360 except: 1459 except:
1361 try: newsock.close() 1460 try:
1362 except: pass 1461 newsock.close()
1462 except:
1463 pass
1363 self.log_msg( "Error in parse found from " + str(addr) + ". Disconnected.") 1464 self.log_msg( "Error in parse found from " + str(addr) + ". Disconnected.")
1364 self.log_msg(" Offending data(" + str(len(data)) + "bytes)=" + data) 1465 self.log_msg(" Offending data(" + str(len(data)) + "bytes)=" + data)
1365 self.log_msg( "Exception:") 1466 self.log_msg( "Exception:")
1366 traceback.print_exc() 1467 traceback.print_exc()
1367 return #returning causes connection thread instance to terminate 1468 return #returning causes connection thread instance to terminate
1370 try: 1471 try:
1371 # get action 1472 # get action
1372 action = xml_dom.getAttribute("action") 1473 action = xml_dom.getAttribute("action")
1373 1474
1374 # Figure out what type of connection we have going on now 1475 # Figure out what type of connection we have going on now
1375 if action == "new": self.new_request(newsock,xml_dom) 1476 if action == "new":
1376 elif action == "update": self.update_request(newsock,xml_dom) 1477 self.new_request(newsock,xml_dom)
1377 else: self.log_msg("Unknown Join Request!") 1478
1479 elif action == "update":
1480 self.update_request(newsock,xml_dom)
1481
1482 else:
1483 self.log_msg("Unknown Join Request!")
1378 1484
1379 except Exception, e: 1485 except Exception, e:
1380 print "The following message: " + str(data) 1486 print "The following message: " + str(data)
1381 print "from " + str(addr) + " created the following exception: " 1487 print "from " + str(addr) + " created the following exception: "
1382 traceback.print_exc() 1488 traceback.print_exc()
1383 return #returning causes connection thread instance to terminate 1489 return #returning causes connection thread instance to terminate
1384 1490
1385 # Again attempt to clean out DOM stuff 1491 # Again attempt to clean out DOM stuff
1386 try: 1492 try:
1387 if xml_dom: xml_dom.unlink() 1493 if xml_dom:
1494 xml_dom.unlink()
1388 except: 1495 except:
1389 print "The following exception caught unlinking xml_dom:" 1496 print "The following exception caught unlinking xml_dom:"
1390 traceback.print_exc() 1497 traceback.print_exc()
1391 return #returning causes connection thread instance to terminate 1498 return #returning causes connection thread instance to terminate
1392 1499
1393 """ 1500
1501
1394 #======================================================== 1502 #========================================================
1395 # 1503 #
1396 # Message_handler 1504 # Message_handler
1397 # 1505 #
1398 #======================================================== 1506 #========================================================
1399 # 1507 #
1400 # Changed thread organization from one continuous parsing/handling thread 1508 # Changed thread organization from one continuous parsing/handling thread
1401 # to multiple expiring parsing/handling threads to improve server performance 1509 # to multiple expiring parsing/handling threads to improve server performance
1402 # and player load capacity -- Snowdog 3/04 1510 # and player load capacity -- Snowdog 3/04
1403 """
1404 1511
1405 def message_handler(self,arg): 1512 def message_handler(self,arg):
1406 xml_dom = None 1513 xml_dom = None
1407 self.log_msg( "message handler thread running..." ) 1514 self.log_msg( "message handler thread running..." )
1408 while self.alive: 1515 while self.alive:
1409 data = None 1516 data = None
1410 try: data=self.incoming.get(0) 1517 try:
1518 data=self.incoming.get(0)
1411 except Queue.Empty: 1519 except Queue.Empty:
1412 time.sleep(0.5) #sleep 1/2 second 1520 time.sleep(0.5) #sleep 1/2 second
1413 continue 1521 continue
1414 1522
1415 bytes = len(data) 1523 bytes = len(data)
1416 if bytes <= 0: continue 1524 if bytes <= 0:
1525 continue
1417 try: 1526 try:
1418 thread.start_new_thread(self.parse_incoming_dom,(str(data),)) 1527 thread.start_new_thread(self.parse_incoming_dom,(str(data),))
1419 #data has been passed... unlink from the variable references 1528 #data has been passed... unlink from the variable references
1420 #so data in passed objects doesn't change (python passes by reference) 1529 #so data in passed objects doesn't change (python passes by reference)
1421 del data 1530 del data
1439 1548
1440 except Exception, e: 1549 except Exception, e:
1441 print "Error in parse of inbound message. Ignoring message." 1550 print "Error in parse of inbound message. Ignoring message."
1442 print " Offending data(" + str(len(data)) + "bytes)=" + data 1551 print " Offending data(" + str(len(data)) + "bytes)=" + data
1443 print "Exception=" + str(e) 1552 print "Exception=" + str(e)
1553
1444 if xml_dom: xml_dom.unlink() 1554 if xml_dom: xml_dom.unlink()
1555
1445 1556
1446 def message_action(self, xml_dom, data): 1557 def message_action(self, xml_dom, data):
1447 tag_name = xml_dom._get_tagName() 1558 tag_name = xml_dom._get_tagName()
1448 if self.svrcmds.has_key(tag_name): self.svrcmds[tag_name]['function'](xml_dom,data) 1559 if self.svrcmds.has_key(tag_name):
1449 else: raise Exception, "Not a valid header!" 1560 self.svrcmds[tag_name]['function'](xml_dom,data)
1561 else:
1562 raise Exception, "Not a valid header!"
1450 #Message Action thread expires and closes here. 1563 #Message Action thread expires and closes here.
1451 return 1564 return
1565
1452 1566
1453 def do_alter(self, xml_dom, data): 1567 def do_alter(self, xml_dom, data):
1454 target = xml_dom.getAttribute("key") 1568 target = xml_dom.getAttribute("key")
1455 value = xml_dom.getAttribute("val") 1569 value = xml_dom.getAttribute("val")
1456 player = xml_dom.getAttribute("plr") 1570 player = xml_dom.getAttribute("plr")
1457 group_id = xml_dom.getAttribute("gid") 1571 group_id = xml_dom.getAttribute("gid")
1458 boot_pwd = xml_dom.getAttribute("bpw") 1572 boot_pwd = xml_dom.getAttribute("bpw")
1459 actual_boot_pwd = self.groups[group_id].boot_pwd 1573 actual_boot_pwd = self.groups[group_id].boot_pwd
1460 1574
1461 if self.allow_room_passwords == 0: 1575 if self.allow_room_passwords == 0:
1462 msg ="<msg to='" + player + "' from='0' group_id='0' /> " 1576 msg ="<msg to='" + player + "' from='0' group_id='0' /> Room passwords have been disabled by the server administrator."
1463 msg += "Room passwords have been disabled by the server administrator."
1464 self.players[player].outbox.put(msg) 1577 self.players[player].outbox.put(msg)
1465 return 1578 return
1466 elif boot_pwd == actual_boot_pwd: 1579 elif boot_pwd == actual_boot_pwd:
1467 if target == "pwd": 1580 if target == "pwd":
1468 lmessage = "Room password changed to from " + self.groups[group_id].pwd + " to " + value + " by " + player 1581 lmessage = "Room password changed to from \"" + self.groups[group_id].pwd + "\" to \"" + value + "\" by " + player
1469 self.groups[group_id].pwd = value 1582 self.groups[group_id].pwd = value
1470 msg ="<msg to='" + player + "' from='0' group_id='0' /> Room password changed to " + value + "." 1583 msg ="<msg to='" + player + "' from='0' group_id='0' /> Room password changed to \"" + value + "\"."
1471 self.players[player].outbox.put(msg) 1584 self.players[player].outbox.put(msg)
1472 self.log_msg(lmessage) 1585 self.log_msg(lmessage)
1473 self.send_to_all('0',self.groups[group_id].toxml('update')) 1586 self.send_to_all('0',self.groups[group_id].toxml('update'))
1474 elif target == "name": 1587 elif target == "name":
1475 # Check for & in name. We want to allow this because of its common 1588 # Check for & in name. We want to allow this because of its common
1478 msg ="<msg to='" + player + "' from='0' group_id='0' />" + result 1591 msg ="<msg to='" + player + "' from='0' group_id='0' />" + result
1479 self.players[player].outbox.put(msg) 1592 self.players[player].outbox.put(msg)
1480 else: 1593 else:
1481 msg ="<msg to='" + player + "' from='0' group_id='0'>Invalid Administrator Password." 1594 msg ="<msg to='" + player + "' from='0' group_id='0'>Invalid Administrator Password."
1482 self.players[player].outbox.put(msg) 1595 self.players[player].outbox.put(msg)
1596
1483 1597
1484 def do_role(self, xml_dom, data): 1598 def do_role(self, xml_dom, data):
1485 role = "" 1599 role = ""
1486 boot_pwd = "" 1600 boot_pwd = ""
1487 act = xml_dom.getAttribute("action") 1601 act = xml_dom.getAttribute("action")
1498 def do_ping(self, xml_dom, data): 1612 def do_ping(self, xml_dom, data):
1499 player = xml_dom.getAttribute("player") 1613 player = xml_dom.getAttribute("player")
1500 group_id = xml_dom.getAttribute("group_id") 1614 group_id = xml_dom.getAttribute("group_id")
1501 sent_time = "" 1615 sent_time = ""
1502 msg = "" 1616 msg = ""
1503 try: sent_time = xml_dom.getAttribute("time") 1617 try:
1504 except: pass 1618 sent_time = xml_dom.getAttribute("time")
1505 if sent_time != "": msg ="<ping time='" + str(sent_time) + "' />" #because a time was sent return a ping response 1619 except:
1620 pass
1621
1622 if sent_time != "":
1623 #because a time was sent return a ping response
1624 msg ="<ping time='" + str(sent_time) + "' />"
1506 else: 1625 else:
1507 msg ="<msg to='" + player + "' from='" + player + "' group_id='" + group_id + "'>" 1626 msg ="<msg to='" + player + "' from='" + player + "' group_id='" + group_id + "'><font color='#FF0000'>PONG!?!</font>"
1508 msg += "<font color='#FF0000'>PONG!?!</font>" 1627
1509 self.players[player].outbox.put(msg) 1628 self.players[player].outbox.put(msg)
1510 xml_dom.unlink() 1629 xml_dom.unlink()
1511 1630
1512 def do_system(self, xml_dom, data): 1631 def do_system(self, xml_dom, data):
1513 pass 1632 pass
1514 1633
1515 def moderate_group(self,xml_dom,data): 1634 def moderate_group(self,xml_dom,data):
1516 try: 1635 try:
1517 action = xml_dom.getAttribute("action") 1636 action = xml_dom.getAttribute("action")
1518 from_id = xml_dom.getAttribute("from") 1637 from_id = xml_dom.getAttribute("from")
1519 if xml_dom.hasAttribute("pwd"): pwd=xml_dom.getAttribute("pwd") 1638 if xml_dom.hasAttribute("pwd"):
1520 else: pwd="" 1639 pwd=xml_dom.getAttribute("pwd")
1640 else:
1641 pwd=""
1521 group_id=self.players[from_id].group_id 1642 group_id=self.players[from_id].group_id
1643
1522 if action == "list": 1644 if action == "list":
1523 if (self.groups[group_id].moderated): 1645 if (self.groups[group_id].moderated):
1524 msg = "" 1646 msg = ""
1525 for i in self.groups[group_id].voice.keys(): 1647 for i in self.groups[group_id].voice.keys():
1526 if msg != "": msg +=", " 1648 if msg != "":
1527 if self.players.has_key(i): msg += '('+i+') '+self.players[i].name 1649 msg +=", "
1528 else: del self.groups[group_id].voice[i] 1650 if self.players.has_key(i):
1529 if (msg != ""): msg = "The following users may speak in this room: " + msg 1651 msg += '('+i+') '+self.players[i].name
1530 else: msg = "No people are currently in this room with the ability to chat" 1652 else:
1653 del self.groups[group_id].voice[i]
1654 if (msg != ""):
1655 msg = "The following users may speak in this room: " + msg
1656 else:
1657 msg = "No people are currently in this room with the ability to chat"
1531 self.players[from_id].self_message(msg) 1658 self.players[from_id].self_message(msg)
1532 else: self.players[from_id].self_message("This room is currently unmoderated") 1659 else:
1533 elif action == 'enable' or 'disable' or 'addvoice' or 'delvoice': 1660 self.players[from_id].self_message("This room is currently unmoderated")
1534 #condenses password check --TaS 2009 1661 elif action == "enable":
1535 if not self.groups[group_id].check_boot_pwd(pwd): 1662 if not self.groups[group_id].check_boot_pwd(pwd):
1536 self.players[from_id].self_message("Failed - incorrect admin password") 1663 self.players[from_id].self_message("Failed - incorrect admin password")
1537 return 1664 return
1538 if action == 'enable': 1665 self.groups[group_id].moderated = 1
1539 self.groups[group_id].moderated = 1 1666 self.players[from_id].self_message("This channel is now moderated")
1540 self.players[from_id].self_message("This channel is now moderated") 1667 elif action == "disable":
1541 if action == 'disable': 1668 if not self.groups[group_id].check_boot_pwd(pwd):
1542 self.groups[group_id].moderated = 0 1669 self.players[from_id].self_message("Failed - incorrect admin password")
1543 self.players[from_id].self_message("This channel is now unmoderated") 1670 return
1544 if action == 'addvoice': 1671 self.groups[group_id].moderated = 0
1545 users = xml_dom.getAttribute("users").split(',') 1672 self.players[from_id].self_message("This channel is now unmoderated")
1546 for i in users: self.groups[group_id].voice[i.strip()]=1 1673 elif action == "addvoice":
1547 if action == 'delvoice': 1674 if not self.groups[group_id].check_boot_pwd(pwd):
1548 users = xml_dom.getAttribute("users").split(',') 1675 self.players[from_id].self_message("Failed - incorrect admin password")
1549 for i in users: 1676 return
1550 if self.groups[group_id].voice.has_key(i.strip()): del self.groups[group_id].voice[i.strip()] 1677 users = xml_dom.getAttribute("users").split(',')
1678 for i in users:
1679 self.groups[group_id].voice[i.strip()]=1
1680 elif action == "delvoice":
1681 if not self.groups[group_id].check_boot_pwd(pwd):
1682 self.players[from_id].self_message("Failed - incorrect admin password")
1683 return
1684 users = xml_dom.getAttribute("users").split(',')
1685 for i in users:
1686 if self.groups[group_id].voice.has_key(i.strip()):
1687 del self.groups[group_id].voice[i.strip()]
1551 else: 1688 else:
1552 print "Bad input: " + data 1689 print "Bad input: " + data
1690
1553 except Exception,e: 1691 except Exception,e:
1554 self.log_msg(str(e)) 1692 self.log_msg(str(e))
1693
1694
1695
1555 1696
1556 def join_group(self,xml_dom,data): 1697 def join_group(self,xml_dom,data):
1557 try: 1698 try:
1558 from_id = xml_dom.getAttribute("from") 1699 from_id = xml_dom.getAttribute("from")
1559 pwd = xml_dom.getAttribute("pwd") 1700 pwd = xml_dom.getAttribute("pwd")
1569 allowed = 0 1710 allowed = 0
1570 1711
1571 #tell the clients password manager the password failed -- SD 8/03 1712 #tell the clients password manager the password failed -- SD 8/03
1572 pm = "<password signal=\"fail\" type=\"room\" id=\"" + group_id + "\" data=\"\"/>" 1713 pm = "<password signal=\"fail\" type=\"room\" id=\"" + group_id + "\" data=\"\"/>"
1573 self.players[from_id].outbox.put(pm) 1714 self.players[from_id].outbox.put(pm)
1715
1574 msg = 'failed - incorrect room password' 1716 msg = 'failed - incorrect room password'
1575 1717
1576 if not allowed: 1718 if not allowed:
1577 self.players[from_id].self_message(msg) 1719 self.players[from_id].self_message(msg)
1578 #the following line makes sure that their role is reset to normal, 1720 #the following line makes sure that their role is reset to normal,
1582 self.players[from_id].outbox.put(msg) 1724 self.players[from_id].outbox.put(msg)
1583 return 1725 return
1584 1726
1585 #move the player into their new group. 1727 #move the player into their new group.
1586 self.move_player(from_id, group_id) 1728 self.move_player(from_id, group_id)
1729
1587 except Exception, e: 1730 except Exception, e:
1588 self.log_msg(str(e)) 1731 self.log_msg(str(e))
1589 1732
1590 """ 1733
1734
1735
1736 #----------------------------------------------------------------------------
1591 # move_player function -- added by Snowdog 4/03 1737 # move_player function -- added by Snowdog 4/03
1592 # 1738 #
1593 # Split join_group function in half. separating the player validation checks 1739 # Split join_group function in half. separating the player validation checks
1594 # from the actual group changing code. Done primarily to impliment 1740 # from the actual group changing code. Done primarily to impliment
1595 # boot-from-room-to-lobby behavior in the server. 1741 # boot-from-room-to-lobby behavior in the server.
1596 """
1597 1742
1598 def move_player(self, from_id, group_id ): 1743 def move_player(self, from_id, group_id ):
1599 "move a player from one group to another" 1744 "move a player from one group to another"
1600 try: 1745 try:
1601 try: 1746 try:
1610 old_group_id = self.players[from_id].change_group(group_id,self.groups) 1755 old_group_id = self.players[from_id].change_group(group_id,self.groups)
1611 self.send_to_group(from_id,old_group_id,self.players[from_id].toxml('del')) 1756 self.send_to_group(from_id,old_group_id,self.players[from_id].toxml('del'))
1612 self.send_to_group(from_id,group_id,self.players[from_id].toxml('new')) 1757 self.send_to_group(from_id,group_id,self.players[from_id].toxml('new'))
1613 self.check_group(from_id, old_group_id) 1758 self.check_group(from_id, old_group_id)
1614 1759
1615 """
1616 # Here, if we have a group specific lobby message to send, push it on 1760 # Here, if we have a group specific lobby message to send, push it on
1617 # out the door! Make it put the message then announce the player...just 1761 # out the door! Make it put the message then announce the player...just
1618 # like in the lobby during a new connection. 1762 # like in the lobby during a new connection.
1619 # -- only do this check if the room id is within range of known persistent id thresholds 1763 # -- only do this check if the room id is within range of known persistent id thresholds
1620 #also goes ahead if there is a defaultRoomMessage --akoman 1764 #also goes ahead if there is a defaultRoomMessage --akoman
1621 """
1622 1765
1623 if self.isPersistentRoom(group_id) or self.defaultMessageFile != None: 1766 if self.isPersistentRoom(group_id) or self.defaultMessageFile != None:
1624 try: 1767 try:
1625 if self.groups[group_id].messageFile[:4] == 'http': 1768 if self.groups[group_id].messageFile[:4] == 'http':
1626 data = urllib.urlretrieve(self.groups[group_id].messageFile) 1769 data = urllib.urlretrieve(self.groups[group_id].messageFile)
1627 roomMsgFile = open(data[0]) 1770 roomMsgFile = open(data[0])
1628 else: roomMsgFile = open(self.groups[group_id].messageFile, "r") 1771 else:
1772 roomMsgFile = open(self.groups[group_id].messageFile, "r")
1629 roomMsg = roomMsgFile.read() 1773 roomMsg = roomMsgFile.read()
1630 roomMsgFile.close() 1774 roomMsgFile.close()
1631 urllib.urlcleanup() 1775 urllib.urlcleanup()
1632 1776
1633 except Exception, e: 1777 except Exception, e:
1634 roomMsg = "" 1778 roomMsg = ""
1635 self.log_msg(str(e)) 1779 self.log_msg(str(e))
1636 1780
1637 # Spit that darn message out now! 1781 # Spit that darn message out now!
1638 self.players[from_id].outbox.put("<msg to='" + from_id + "' from='0' group_id='" + group_id + "' />" + roomMsg) 1782 self.players[from_id].outbox.put("<msg to='" + from_id + "' from='0' group_id='" + group_id + "' />" + roomMsg)
1783
1639 if self.sendLobbySound and group_id == '0': 1784 if self.sendLobbySound and group_id == '0':
1640 self.players[from_id].outbox.put('<sound url="' + self.lobbySound + '" group_id="0" from="0" loop="True" />') 1785 self.players[from_id].outbox.put('<sound url="' + self.lobbySound + '" group_id="0" from="0" loop="True" />')
1786
1641 # Now, tell everyone that we've arrived 1787 # Now, tell everyone that we've arrived
1642 self.send_to_all('0', self.groups[group_id].toxml('update')) 1788 self.send_to_all('0', self.groups[group_id].toxml('update'))
1789
1643 # this line sends a handle role message to change the players role 1790 # this line sends a handle role message to change the players role
1644 self.send_player_list(from_id,group_id) 1791 self.send_player_list(from_id,group_id)
1792
1645 #notify user about others in the room 1793 #notify user about others in the room
1646 self.return_room_roles(from_id,group_id) 1794 self.return_room_roles(from_id,group_id)
1647 self.log_msg(("join_group", (self.groups[group_id].name, group_id, from_id))) 1795 self.log_msg(("join_group", (self.groups[group_id].name, group_id, from_id)))
1648 self.handle_role("set", from_id, self.players[from_id].role, self.groups[group_id].boot_pwd, group_id) 1796 self.handle_role("set", from_id, self.players[from_id].role, self.groups[group_id].boot_pwd, group_id)
1797
1649 except Exception, e: 1798 except Exception, e:
1650 self.log_msg(str(e)) 1799 self.log_msg(str(e))
1800
1651 thread.start_new_thread(self.registerRooms,(0,)) 1801 thread.start_new_thread(self.registerRooms,(0,))
1652 1802
1653 def return_room_roles(self,from_id,group_id): 1803 def return_room_roles(self,from_id,group_id):
1654 for m in self.players.keys(): 1804 for m in self.players.keys():
1655 if self.players[m].group_id == group_id: 1805 if self.players[m].group_id == group_id:
1656 msg = "<role action=\"update\" id=\"" + self.players[m].id + "\" role=\"" + self.players[m].role + "\" />" 1806 msg = "<role action=\"update\" id=\"" + self.players[m].id + "\" role=\"" + self.players[m].role + "\" />"
1657 self.players[from_id].outbox.put(msg) 1807 self.players[from_id].outbox.put(msg)
1658 1808
1659 """ 1809
1660 # This is pretty much the same thing as the create_group method, however, 1810 # This is pretty much the same thing as the create_group method, however,
1661 # it's much more generic whereas the create_group method is tied to a specific 1811 # it's much more generic whereas the create_group method is tied to a specific
1662 # xml message. Ack! This version simply creates the groups, it does not 1812 # xml message. Ack! This version simply creates the groups, it does not
1663 # send them to players. Also note, both these methods have race 1813 # send them to players. Also note, both these methods have race
1664 # conditions written all over them. Ack! Ack! 1814 # conditions written all over them. Ack! Ack!
1665 """
1666 def new_group( self, name, pwd, boot, minVersion, mapFile, messageFile, persist = 0, moderated=0 ): 1815 def new_group( self, name, pwd, boot, minVersion, mapFile, messageFile, persist = 0, moderated=0 ):
1667 group_id = str( self.next_group_id ) 1816 group_id = str( self.next_group_id )
1668 self.next_group_id += 1 1817 self.next_group_id += 1
1669 self.groups[group_id] = game_group( group_id, name, pwd, "", boot, minVersion, mapFile, messageFile, persist ) 1818 self.groups[group_id] = game_group( group_id, name, pwd, "", boot, minVersion, mapFile, messageFile, persist )
1670 self.groups[group_id].moderated = moderated 1819 self.groups[group_id].moderated = moderated
1672 if persist !=0: ins="Persistant " 1821 if persist !=0: ins="Persistant "
1673 lmsg = "Creating " + ins + "Group... (" + str(group_id) + ") " + str(name) 1822 lmsg = "Creating " + ins + "Group... (" + str(group_id) + ") " + str(name)
1674 self.log_msg( lmsg ) 1823 self.log_msg( lmsg )
1675 self.log_msg(("create_group", (str(name), int(group_id), 0) )) ##-99 works, could be better. 1824 self.log_msg(("create_group", (str(name), int(group_id), 0) )) ##-99 works, could be better.
1676 1825
1826
1677 def change_group_name(self,gid,name,pid): 1827 def change_group_name(self,gid,name,pid):
1678 "Change the name of a group" 1828 "Change the name of a group"
1679 # Check for & in name. We want to allow this because of its common 1829 # Check for & in name. We want to allow this because of its common
1680 # use in d&d games. 1830 # use in d&d games.
1681 try: 1831 try:
1686 if loc > -1: 1836 if loc > -1:
1687 b = name[:loc] 1837 b = name[:loc]
1688 e = name[loc+1:] 1838 e = name[loc+1:]
1689 value = b + "&amp;" + e 1839 value = b + "&amp;" + e
1690 oldloc = loc+1 1840 oldloc = loc+1
1841
1691 loc = name.find("'") 1842 loc = name.find("'")
1692 oldloc = 0 1843 oldloc = 0
1693 while loc > -1: 1844 while loc > -1:
1694 loc = name.find("'",oldloc) 1845 loc = name.find("'",oldloc)
1695 if loc > -1: 1846 if loc > -1:
1696 b = name[:loc] 1847 b = name[:loc]
1697 e = name[loc+1:] 1848 e = name[loc+1:]
1698 name = b + "&#39;" + e 1849 name = b + "&#39;" + e
1699 oldloc = loc+1 1850 oldloc = loc+1
1851
1700 loc = name.find('"') 1852 loc = name.find('"')
1701 oldloc = 0 1853 oldloc = 0
1702 while loc > -1: 1854 while loc > -1:
1703 loc = name.find('"',oldloc) 1855 loc = name.find('"',oldloc)
1704 if loc > -1: 1856 if loc > -1:
1705 b = name[:loc] 1857 b = name[:loc]
1706 e = name[loc+1:] 1858 e = name[loc+1:]
1707 name = b + "&quot;" + e 1859 name = b + "&quot;" + e
1708 oldloc = loc+1 1860 oldloc = loc+1
1861
1709 oldroomname = self.groups[gid].name 1862 oldroomname = self.groups[gid].name
1710 self.groups[gid].name = str(name) 1863 self.groups[gid].name = str(name)
1711 lmessage = "Room name changed to from \"" + oldroomname + "\" to \"" + name + "\"" 1864 lmessage = "Room name changed to from \"" + oldroomname + "\" to \"" + name + "\""
1712 self.log_msg(lmessage + " by " + str(pid) ) 1865 self.log_msg(lmessage + " by " + str(pid) )
1713 self.send_to_all('0',self.groups[gid].toxml('update')) 1866 self.send_to_all('0',self.groups[gid].toxml('update'))
1714 return lmessage 1867 return lmessage
1715 except: return "An error occured during rename of room!" 1868 except:
1869 return "An error occured during rename of room!"
1870
1716 thread.start_new_thread(self.registerRooms,(0,)) 1871 thread.start_new_thread(self.registerRooms,(0,))
1872
1873
1717 1874
1718 def create_group(self,xml_dom,data): 1875 def create_group(self,xml_dom,data):
1719 try: 1876 try:
1720 from_id = xml_dom.getAttribute("from") 1877 from_id = xml_dom.getAttribute("from")
1721 pwd = xml_dom.getAttribute("pwd") 1878 pwd = xml_dom.getAttribute("pwd")
1726 messageFile = self.defaultMessageFile 1883 messageFile = self.defaultMessageFile
1727 1884
1728 # see if passwords are allowed on this server and null password if not 1885 # see if passwords are allowed on this server and null password if not
1729 if self.allow_room_passwords != 1: pwd = "" 1886 if self.allow_room_passwords != 1: pwd = ""
1730 1887
1888
1889 #
1731 # Check for & in name. We want to allow this because of its common 1890 # Check for & in name. We want to allow this because of its common
1732 # use in d&d games. 1891 # use in d&d games.
1733 1892
1734 loc = name.find("&") 1893 loc = name.find("&")
1735 oldloc = 0 1894 oldloc = 0
1738 if loc > -1: 1897 if loc > -1:
1739 b = name[:loc] 1898 b = name[:loc]
1740 e = name[loc+1:] 1899 e = name[loc+1:]
1741 name = b + "&amp;" + e 1900 name = b + "&amp;" + e
1742 oldloc = loc+1 1901 oldloc = loc+1
1902
1743 loc = name.find("'") 1903 loc = name.find("'")
1744 oldloc = 0 1904 oldloc = 0
1745 while loc > -1: 1905 while loc > -1:
1746 loc = name.find("'",oldloc) 1906 loc = name.find("'",oldloc)
1747 if loc > -1: 1907 if loc > -1:
1748 b = name[:loc] 1908 b = name[:loc]
1749 e = name[loc+1:] 1909 e = name[loc+1:]
1750 name = b + "&#39;" + e 1910 name = b + "&#39;" + e
1751 oldloc = loc+1 1911 oldloc = loc+1
1912
1752 loc = name.find('"') 1913 loc = name.find('"')
1753 oldloc = 0 1914 oldloc = 0
1754 while loc > -1: 1915 while loc > -1:
1755 loc = name.find('"',oldloc) 1916 loc = name.find('"',oldloc)
1756 if loc > -1: 1917 if loc > -1:
1757 b = name[:loc] 1918 b = name[:loc]
1758 e = name[loc+1:] 1919 e = name[loc+1:]
1759 name = b + "&quot;" + e 1920 name = b + "&quot;" + e
1760 oldloc = loc+1 1921 oldloc = loc+1
1922
1923
1761 group_id = str(self.next_group_id) 1924 group_id = str(self.next_group_id)
1762 self.next_group_id += 1 1925 self.next_group_id += 1
1763 self.groups[group_id] = game_group(group_id,name,pwd,"",boot_pwd, minVersion, None, messageFile ) 1926 self.groups[group_id] = game_group(group_id,name,pwd,"",boot_pwd, minVersion, None, messageFile )
1764 self.groups[group_id].voice[from_id]=1 1927 self.groups[group_id].voice[from_id]=1
1765 self.players[from_id].outbox.put(self.groups[group_id].toxml('new')) 1928 self.players[from_id].outbox.put(self.groups[group_id].toxml('new'))
1779 if self.defaultMessageFile != None: 1942 if self.defaultMessageFile != None:
1780 if self.defaultMessageFile[:4] == 'http': 1943 if self.defaultMessageFile[:4] == 'http':
1781 data = urllib.urlretrieve(self.defaultMessageFile) 1944 data = urllib.urlretrieve(self.defaultMessageFile)
1782 open_msg = open(data[0]) 1945 open_msg = open(data[0])
1783 urllib.urlcleanup() 1946 urllib.urlcleanup()
1784 else: open_msg = open( self.defaultMessageFile, "r" ) 1947 else:
1948 open_msg = open( self.defaultMessageFile, "r" )
1949
1785 roomMsg = open_msg.read() 1950 roomMsg = open_msg.read()
1786 open_msg.close() 1951 open_msg.close()
1787 # Send the rooms message to the client no matter what 1952 # Send the rooms message to the client no matter what
1788 self.players[from_id].outbox.put( "<msg to='" + from_id + "' from='0' group_id='" + group_id + "' />" + roomMsg ) 1953 self.players[from_id].outbox.put( "<msg to='" + from_id + "' from='0' group_id='" + group_id + "' />" + roomMsg )
1789 except Exception, e: self.log_msg( "Exception: create_group(): " + str(e)) 1954
1955 except Exception, e:
1956 self.log_msg( "Exception: create_group(): " + str(e))
1957
1790 thread.start_new_thread(self.registerRooms,(0,)) 1958 thread.start_new_thread(self.registerRooms,(0,))
1959
1791 1960
1792 def check_group(self, from_id, group_id): 1961 def check_group(self, from_id, group_id):
1793 try: 1962 try:
1794 if group_id not in self.groups: return 1963 if group_id not in self.groups: return
1795 if group_id == '0': 1964 if group_id == '0':
1797 return #never remove lobby *sanity check* 1966 return #never remove lobby *sanity check*
1798 if not self.isPersistentRoom(group_id) and self.groups[group_id].get_num_players() == 0: 1967 if not self.isPersistentRoom(group_id) and self.groups[group_id].get_num_players() == 0:
1799 self.send_to_all("0",self.groups[group_id].toxml('del')) 1968 self.send_to_all("0",self.groups[group_id].toxml('del'))
1800 del self.groups[group_id] 1969 del self.groups[group_id]
1801 self.log_msg(("delete_group", (group_id, from_id))) 1970 self.log_msg(("delete_group", (group_id, from_id)))
1802 else: self.send_to_all("0",self.groups[group_id].toxml('update')) 1971
1972 else:
1973 self.send_to_all("0",self.groups[group_id].toxml('update'))
1803 1974
1804 #The register Rooms thread 1975 #The register Rooms thread
1805 thread.start_new_thread(self.registerRooms,(0,)) 1976 thread.start_new_thread(self.registerRooms,(0,))
1806 1977
1807 except Exception, e: self.log_msg(str(e)) 1978 except Exception, e:
1979 self.log_msg(str(e))
1808 1980
1809 def del_player(self,id,group_id): 1981 def del_player(self,id,group_id):
1810 try: 1982 try:
1811 dmsg = "Client Disconnect: (" + str(id) + ") " + str(self.players[id].name) 1983 dmsg = "Client Disconnect: (" + str(id) + ") " + str(self.players[id].name)
1812 self.players[id].disconnect() 1984 self.players[id].disconnect()
1813 self.groups[group_id].remove_player(id) 1985 self.groups[group_id].remove_player(id)
1814 del self.players[id] 1986 del self.players[id]
1815 self.log_msg(dmsg) 1987 self.log_msg(dmsg)
1816 self.log_msg(("disconnect",id)) 1988 self.log_msg(("disconnect",id))
1817 """ 1989
1990
1818 # If already registered then re-register, thereby updating the Meta 1991 # If already registered then re-register, thereby updating the Meta
1819 # on the number of players 1992 # on the number of players
1820 # Note: Upon server shutdown, the server is first unregistered, so 1993 # Note: Upon server shutdown, the server is first unregistered, so
1821 # this code won't be repeated for each player being deleted. 1994 # this code won't be repeated for each player being deleted.
1822 """
1823 if self.be_registered: 1995 if self.be_registered:
1824 self.register() 1996 self.register()
1825 except Exception, e: self.log_msg(str(e)) 1997
1998
1999 except Exception, e:
2000 self.log_msg(str(e))
2001
1826 self.log_msg("Explicit garbage collection shows %s undeletable items." % str(gc.collect())) 2002 self.log_msg("Explicit garbage collection shows %s undeletable items." % str(gc.collect()))
2003
2004
1827 2005
1828 def incoming_player_handler(self,xml_dom,data): 2006 def incoming_player_handler(self,xml_dom,data):
1829 id = xml_dom.getAttribute("id") 2007 id = xml_dom.getAttribute("id")
1830 act = xml_dom.getAttribute("action") 2008 act = xml_dom.getAttribute("action")
1831 #group_id = xml_dom.getAttribute("group_id") 2009 #group_id = xml_dom.getAttribute("group_id")
1832 group_id = self.players[id].group_id 2010 group_id = self.players[id].group_id
1833 ip = self.players[id].ip 2011 ip = self.players[id].ip
1834 self.log_msg("Player with IP: " + str(ip) + " joined.") 2012 self.log_msg("Player with IP: " + str(ip) + " joined.")
2013
1835 ServerPlugins.setPlayer(self.players[id]) 2014 ServerPlugins.setPlayer(self.players[id])
2015
1836 self.send_to_group(id,group_id,data) 2016 self.send_to_group(id,group_id,data)
1837 if act=="new": 2017 if act=="new":
1838 try: 2018 try:
1839 self.send_player_list(id,group_id) 2019 self.send_player_list(id,group_id)
1840 self.send_group_list(id) 2020 self.send_group_list(id)
1841 except Exception, e: traceback.print_exc() 2021 except Exception, e:
2022 traceback.print_exc()
1842 elif act=="del": 2023 elif act=="del":
1843 #print "del player" 2024 #print "del player"
1844 self.del_player(id,group_id) 2025 self.del_player(id,group_id)
1845 self.check_group(id, group_id) 2026 self.check_group(id, group_id)
1846 elif act=="update": 2027 elif act=="update":
1855 "boot": xml_dom.getAttribute("rm_boot"), 2036 "boot": xml_dom.getAttribute("rm_boot"),
1856 "version": xml_dom.getAttribute("version"), 2037 "version": xml_dom.getAttribute("version"),
1857 "ping": xml_dom.getAttribute("time") \ 2038 "ping": xml_dom.getAttribute("time") \
1858 })) 2039 }))
1859 2040
2041
1860 def strip_cheat_roll(self, string): 2042 def strip_cheat_roll(self, string):
1861 try: 2043 try:
1862 cheat_regex = re.compile('&amp;#91;(.*?)&amp;#93;') 2044 cheat_regex = re.compile('&amp;#91;(.*?)&amp;#93;')
1863 string = cheat_regex.sub( r'[ ' + self.cheat_msg + " \\1 " + self.cheat_msg + ' ]', string) 2045 string = cheat_regex.sub( r'[ ' + self.cheat_msg + " \\1 " + self.cheat_msg + ' ]', string)
1864 except: pass 2046 except:
2047 pass
1865 return string 2048 return string
1866 2049
1867 def strip_body_tags(self, string): 2050 def strip_body_tags(self, string):
1868 try: 2051 try:
1869 bodytag_regex = re.compile('&lt;\/?body(.*?)&gt;') 2052 bodytag_regex = re.compile('&lt;\/?body(.*?)&gt;')
1870 string = bodytag_regex.sub('', string) 2053 string = bodytag_regex.sub('', string)
1871 except: pass 2054 except:
2055 pass
1872 return string 2056 return string
1873 2057
1874 def msgTooLong(self, length): 2058 def msgTooLong(self, length):
1875 if length > self.maxSendSize and not self.maxSendSize == 0: return True 2059 if length > self.maxSendSize and not self.maxSendSize == 0:
2060 return True
1876 return False 2061 return False
1877 2062
1878 def incoming_msg_handler(self,xml_dom,data): 2063 def incoming_msg_handler(self,xml_dom,data):
1879 xml_dom, data = ServerPlugins.preParseIncoming(xml_dom, data) 2064 xml_dom, data = ServerPlugins.preParseIncoming(xml_dom, data)
2065
1880 to_id = xml_dom.getAttribute("to") 2066 to_id = xml_dom.getAttribute("to")
1881 from_id = xml_dom.getAttribute("from") 2067 from_id = xml_dom.getAttribute("from")
1882 group_id = xml_dom.getAttribute("group_id") 2068 group_id = xml_dom.getAttribute("group_id")
1883 end = data.find(">") 2069 end = data.find(">")
1884 msg = data[end+1:] 2070 msg = data[end+1:]
1885 2071
1886 if from_id == "0" or len(from_id) == 0: 2072 if from_id == "0" or len(from_id) == 0:
1887 print "WARNING!! Message received with an invalid from_id. Message dropped." 2073 print "WARNING!! Message received with an invalid from_id. Message dropped."
1888 return None 2074 return None
1889 2075
1890 """ check for < body to prevent someone from changing the background""" 2076 #
2077 # check for < body to prevent someone from changing the background
2078 #
2079
1891 data = self.strip_body_tags(data) 2080 data = self.strip_body_tags(data)
1892 2081
1893 """check for &#91 and &#93 codes which are often used to cheat with dice.""" 2082 #
2083 # check for &#91 and &#93 codes which are often used to cheat with dice.
2084 #
1894 if self.players[from_id].role != "GM": 2085 if self.players[from_id].role != "GM":
1895 data = self.strip_cheat_roll(data) 2086 data = self.strip_cheat_roll(data)
1896 2087
1897 if group_id == '0' and self.msgTooLong(len(msg) and msg[:5] == '<chat'): 2088 if group_id == '0' and self.msgTooLong(len(msg) and msg[:5] == '<chat'):
1898 self.send("Your message was too long, break it up into smaller parts please", from_id, group_id) 2089 self.send("Your message was too long, break it up into smaller parts please", from_id, group_id)
1916 2107
1917 else: 2108 else:
1918 if to_id == 'all': 2109 if to_id == 'all':
1919 if self.groups[group_id].moderated and not self.groups[group_id].voice.has_key(from_id): 2110 if self.groups[group_id].moderated and not self.groups[group_id].voice.has_key(from_id):
1920 self.players[from_id].self_message('This room is moderated - message not sent to others') 2111 self.players[from_id].self_message('This room is moderated - message not sent to others')
1921 else: self.send_to_group(from_id,group_id,data) 2112 else:
1922 else: self.players[to_id].outbox.put(data) 2113 self.send_to_group(from_id,group_id,data)
2114 else:
2115 self.players[to_id].outbox.put(data)
2116
1923 self.check_group_members(group_id) 2117 self.check_group_members(group_id)
1924 return 2118 return
1925 2119
1926 def sound_msg_handler(self, xml_dom, data): 2120 def sound_msg_handler(self, xml_dom, data):
1927 from_id = xml_dom.getAttribute("from") 2121 from_id = xml_dom.getAttribute("from")
1928 group_id = xml_dom.getAttribute("group_id") 2122 group_id = xml_dom.getAttribute("group_id")
1929 if group_id != 0: self.send_to_group(from_id, group_id, data) 2123 if group_id != 0:
2124 self.send_to_group(from_id, group_id, data)
1930 2125
1931 def plugin_msg_handler(self,xml_dom,data): 2126 def plugin_msg_handler(self,xml_dom,data):
1932 to_id = xml_dom.getAttribute("to") 2127 to_id = xml_dom.getAttribute("to")
1933 from_id = xml_dom.getAttribute("from") 2128 from_id = xml_dom.getAttribute("from")
1934 group_id = xml_dom.getAttribute("group_id") 2129 group_id = xml_dom.getAttribute("group_id")
1936 msg = data[end+1:] 2131 msg = data[end+1:]
1937 2132
1938 if from_id == "0" or len(from_id) == 0: 2133 if from_id == "0" or len(from_id) == 0:
1939 print "WARNING!! Message received with an invalid from_id. Message dropped." 2134 print "WARNING!! Message received with an invalid from_id. Message dropped."
1940 return None 2135 return None
2136
2137
1941 if to_id == 'all': 2138 if to_id == 'all':
1942 if self.groups[group_id].moderated and not self.groups[group_id].voice.has_key(from_id): 2139 if self.groups[group_id].moderated and not self.groups[group_id].voice.has_key(from_id):
1943 self.players[from_id].self_message('This room is moderated - message not sent to others') 2140 self.players[from_id].self_message('This room is moderated - message not sent to others')
1944 else: self.send_to_group(from_id, group_id, msg) 2141 else:
1945 else: self.players[to_id].outbox.put(msg) 2142 self.send_to_group(from_id, group_id, msg)
2143 else:
2144 self.players[to_id].outbox.put(msg)
2145
1946 self.check_group_members(group_id) 2146 self.check_group_members(group_id)
1947 return 2147 return
1948 2148
1949 def handle_role(self, act, player, role, given_boot_pwd, group_id): 2149 def handle_role(self, act, player, role, given_boot_pwd, group_id):
1950 if act == "display": 2150 if act == "display":
1951 msg = "<msg to=\"" + player + "\" from=\"0\" group_id=\"" + group_id + "\" />" 2151 msg = "<msg to=\"" + player + "\" from=\"0\" group_id=\"" + group_id + "\" />"
1952 msg += "Displaying Roles<br /><br /><u>Role</u>&nbsp&nbsp&nbsp<u>Player</u><br />" 2152 msg += "Displaying Roles<br /><br /><u>Role</u>&nbsp&nbsp&nbsp<u>Player</u><br />"
1953 keys = self.players.keys() 2153 keys = self.players.keys()
1954 for m in keys: 2154 for m in keys:
1955 if self.players[m].group_id == group_id: msg += self.players[m].role + " " + self.players[m].name + "<br />" 2155 if self.players[m].group_id == group_id:
2156 msg += self.players[m].role + " " + self.players[m].name + "<br />"
1956 self.send(msg,player,group_id) 2157 self.send(msg,player,group_id)
1957 elif act == "set": 2158 elif act == "set":
1958 try: 2159 try:
1959 actual_boot_pwd = self.groups[group_id].boot_pwd 2160 actual_boot_pwd = self.groups[group_id].boot_pwd
1960 if self.players[player].group_id == group_id: 2161 if self.players[player].group_id == group_id:
1963 2164
1964 # Send update role event to all 2165 # Send update role event to all
1965 msg = "<role action=\"update\" id=\"" + player + "\" role=\"" + role + "\" />" 2166 msg = "<role action=\"update\" id=\"" + player + "\" role=\"" + role + "\" />"
1966 self.send_to_group("0", group_id, msg) 2167 self.send_to_group("0", group_id, msg)
1967 self.players[player].role = role 2168 self.players[player].role = role
1968 if (role.lower() == "gm" or role.lower() == "player"): self.groups[group_id].voice[player]=1 2169 if (role.lower() == "gm" or role.lower() == "player"):
2170 self.groups[group_id].voice[player]=1
1969 else: 2171 else:
1970 #tell the clients password manager the password failed -- SD 8/03 2172 #tell the clients password manager the password failed -- SD 8/03
1971 pm = "<password signal=\"fail\" type=\"admin\" id=\"" + group_id + "\" data=\"\"/>" 2173 pm = "<password signal=\"fail\" type=\"admin\" id=\"" + group_id + "\" data=\"\"/>"
1972 self.players[player].outbox.put(pm) 2174 self.players[player].outbox.put(pm)
1973 self.log_msg( "Administrator passwords did not match") 2175 self.log_msg( "Administrator passwords did not match")
1993 traceback.print_exc() 2195 traceback.print_exc()
1994 2196
1995 try: 2197 try:
1996 actual_boot_pwd = self.groups[group_id].boot_pwd 2198 actual_boot_pwd = self.groups[group_id].boot_pwd
1997 server_admin_pwd = self.groups["0"].boot_pwd 2199 server_admin_pwd = self.groups["0"].boot_pwd
2200
1998 self.log_msg("Actual boot pwd = " + actual_boot_pwd) 2201 self.log_msg("Actual boot pwd = " + actual_boot_pwd)
1999 self.log_msg("Given boot pwd = " + given_boot_pwd) 2202 self.log_msg("Given boot pwd = " + given_boot_pwd)
2000 2203
2001 if self.players[to_id].group_id == group_id: 2204 if self.players[to_id].group_id == group_id:
2002 """ 2205
2003 ### ---CHANGES BY SNOWDOG 4/03 --- 2206 ### ---CHANGES BY SNOWDOG 4/03 ---
2004 ### added boot to lobby code. 2207 ### added boot to lobby code.
2005 ### if boot comes from lobby dump player from the server 2208 ### if boot comes from lobby dump player from the server
2006 ### any user in-room boot will dump to lobby instead 2209 ### any user in-room boot will dump to lobby instead
2007 """
2008 if given_boot_pwd == server_admin_pwd: 2210 if given_boot_pwd == server_admin_pwd:
2009 # Send a message to everyone in the room, letting them know someone has been booted 2211 # Send a message to everyone in the room, letting them know someone has been booted
2010 boot_msg = "<msg to='all' from='%s' group_id='%s'/><font color='#FF0000'>Booting '(%s) %s' from server...</font>" % (from_id, group_id, to_id, self.players[to_id].name) 2212 boot_msg = "<msg to='all' from='%s' group_id='%s'/><font color='#FF0000'>Booting '(%s) %s' from server...</font>" % (from_id, group_id, to_id, self.players[to_id].name)
2213
2011 self.log_msg("boot_msg:" + boot_msg) 2214 self.log_msg("boot_msg:" + boot_msg)
2215
2012 self.send_to_group( "0", group_id, boot_msg ) 2216 self.send_to_group( "0", group_id, boot_msg )
2013 time.sleep( 1 ) 2217 time.sleep( 1 )
2218
2014 self.log_msg("Booting player " + str(to_id) + " from server.") 2219 self.log_msg("Booting player " + str(to_id) + " from server.")
2015 2220
2016 # Send delete player event to all 2221 # Send delete player event to all
2017 self.send_to_group("0",group_id,self.players[to_id].toxml("del")) 2222 self.send_to_group("0",group_id,self.players[to_id].toxml("del"))
2018 2223
2023 self.check_group(to_id, group_id) 2228 self.check_group(to_id, group_id)
2024 2229
2025 elif actual_boot_pwd == given_boot_pwd: 2230 elif actual_boot_pwd == given_boot_pwd:
2026 # Send a message to everyone in the room, letting them know someone has been booted 2231 # Send a message to everyone in the room, letting them know someone has been booted
2027 boot_msg = "<msg to='all' from='%s' group_id='%s'/><font color='#FF0000'>Booting '(%s) %s' from room...</font>" % (from_id, group_id, to_id, self.players[to_id].name) 2232 boot_msg = "<msg to='all' from='%s' group_id='%s'/><font color='#FF0000'>Booting '(%s) %s' from room...</font>" % (from_id, group_id, to_id, self.players[to_id].name)
2233
2028 self.log_msg("boot_msg:" + boot_msg) 2234 self.log_msg("boot_msg:" + boot_msg)
2235
2029 self.send_to_group( "0", group_id, boot_msg ) 2236 self.send_to_group( "0", group_id, boot_msg )
2030 time.sleep( 1 ) 2237 time.sleep( 1 )
2031 2238
2032 #dump player into the lobby 2239 #dump player into the lobby
2033 self.move_player(to_id,"0") 2240 self.move_player(to_id,"0")
2044 traceback.print_exc() 2251 traceback.print_exc()
2045 self.log_msg('Exception in handle_boot() ' + str(e)) 2252 self.log_msg('Exception in handle_boot() ' + str(e))
2046 2253
2047 finally: 2254 finally:
2048 try: 2255 try:
2049 if xml_dom: xml_dom.unlink() 2256 if xml_dom:
2257 xml_dom.unlink()
2050 except Exception, e: 2258 except Exception, e:
2051 traceback.print_exc() 2259 traceback.print_exc()
2052 self.log_msg('Exception in xml_dom.unlink() ' + str(e)) 2260 self.log_msg('Exception in xml_dom.unlink() ' + str(e))
2053 2261
2054 """ 2262
2263 #---------------------------------------------------------------
2055 # admin_kick function -- by Snowdog 4/03 2264 # admin_kick function -- by Snowdog 4/03
2056 # 9/17/05 updated to allow stealth boots (no client chat announce) -SD 2265 # 9/17/05 updated to allow stealth boots (no client chat announce) -SD
2057 """ 2266 #---------------------------------------------------------------
2058 def admin_kick(self, id, message="", silent = 0 ): 2267 def admin_kick(self, id, message="", silent = 0 ):
2059 "Kick a player from a server from the console" 2268 "Kick a player from a server from the console"
2060 2269
2061 try: 2270 try:
2062 group_id = self.players[id].group_id 2271 group_id = self.players[id].group_id
2063 # Send a message to everyone in the victim's room, letting them know someone has been booted 2272 # Send a message to everyone in the victim's room, letting them know someone has been booted
2064 boot_msg = "<msg to='all' from='0' group_id='%s'/><font color='#FF0000'>Kicking '(%s) %s' from server... %s</font>" % ( group_id, id, self.players[id].name, str(message)) 2273 boot_msg = "<msg to='all' from='0' group_id='%s'/><font color='#FF0000'>Kicking '(%s) %s' from server... %s</font>" % ( group_id, id, self.players[id].name, str(message))
2065 self.log_msg("boot_msg:" + boot_msg) 2274 self.log_msg("boot_msg:" + boot_msg)
2066 if (silent == 0): self.send_to_group( "0", group_id, boot_msg ) 2275 if (silent == 0):
2276 self.send_to_group( "0", group_id, boot_msg )
2067 time.sleep( 1 ) 2277 time.sleep( 1 )
2068 2278
2069 self.log_msg("kicking player " + str(id) + " from server.") 2279 self.log_msg("kicking player " + str(id) + " from server.")
2070 # Send delete player event to all 2280 # Send delete player event to all
2071 self.send_to_group("0",group_id,self.players[id].toxml("del")) 2281 self.send_to_group("0",group_id,self.players[id].toxml("del"))
2077 self.check_group(id, group_id) 2287 self.check_group(id, group_id)
2078 2288
2079 except Exception, e: 2289 except Exception, e:
2080 traceback.print_exc() 2290 traceback.print_exc()
2081 self.log_msg('Exception in admin_kick() ' + str(e)) 2291 self.log_msg('Exception in admin_kick() ' + str(e))
2292
2082 2293
2083 def admin_banip(self, ip, name="", silent = 0): 2294 def admin_banip(self, ip, name="", silent = 0):
2084 "Ban a player from a server from the console" 2295 "Ban a player from a server from the console"
2085 try: 2296 try:
2086 self.ban_list[ip] = {} 2297 self.ban_list[ip] = {}
2124 traceback.print_exc() 2335 traceback.print_exc()
2125 self.log_msg('Exception in admin_ban() ' + str(e)) 2336 self.log_msg('Exception in admin_ban() ' + str(e))
2126 2337
2127 def admin_unban(self, ip): 2338 def admin_unban(self, ip):
2128 try: 2339 try:
2129 if self.ban_list.has_key(ip): del self.ban_list[ip] 2340 if self.ban_list.has_key(ip):
2341 del self.ban_list[ip]
2342
2130 self.saveBanList() 2343 self.saveBanList()
2131 2344
2132 except Exception, e: 2345 except Exception, e:
2133 traceback.print_exc() 2346 traceback.print_exc()
2134 self.log_msg('Exception in admin_unban() ' + str(e)) 2347 self.log_msg('Exception in admin_unban() ' + str(e))
2141 msg.append(self.ban_list[ip]['name']) 2354 msg.append(self.ban_list[ip]['name'])
2142 msg.append("</td><td>") 2355 msg.append("</td><td>")
2143 msg.append(self.ban_list[ip]['ip']) 2356 msg.append(self.ban_list[ip]['ip'])
2144 msg.append("</td></tr>") 2357 msg.append("</td></tr>")
2145 msg.append("</table>") 2358 msg.append("</table>")
2359
2146 return "".join(msg) 2360 return "".join(msg)
2147 2361
2148 def admin_toggleSound(self): 2362 def admin_toggleSound(self):
2149 if self.sendLobbySound: self.sendLobbySound = False 2363 if self.sendLobbySound:
2150 else: self.sendLobbySound = True 2364 self.sendLobbySound = False
2365 else:
2366 self.sendLobbySound = True
2367
2151 return self.sendLobbySound 2368 return self.sendLobbySound
2152 2369
2153 def admin_soundFile(self, file): 2370 def admin_soundFile(self, file):
2154 self.lobbySound = file 2371 self.lobbySound = file
2155 2372
2164 return "Invalid Room Id. Ignoring remove request." 2381 return "Invalid Room Id. Ignoring remove request."
2165 2382
2166 self.groups[group].persistant = 0 2383 self.groups[group].persistant = 0
2167 try: 2384 try:
2168 keys = self.groups[group].get_player_ids() 2385 keys = self.groups[group].get_player_ids()
2169 for k in keys: self.del_player(k, str(group)) 2386 for k in keys:
2387 self.del_player(k, str(group))
2170 self.check_group("0", str(group)) 2388 self.check_group("0", str(group))
2171 except: pass 2389 except:
2390 pass
2172 2391
2173 def send(self,msg,player,group): 2392 def send(self,msg,player,group):
2174 self.players[player].send(msg,player,group) 2393 self.players[player].send(msg,player,group)
2394
2175 2395
2176 def send_to_all(self,from_id,data): 2396 def send_to_all(self,from_id,data):
2177 try: 2397 try:
2178 print data 2398 print data
2179 self.p_lock.acquire() 2399 self.p_lock.acquire()
2180 keys = self.players.keys() 2400 keys = self.players.keys()
2181 self.p_lock.release() 2401 self.p_lock.release()
2182 for k in keys: 2402 for k in keys:
2183 if k != from_id: self.players[k].outbox.put(data) 2403 if k != from_id:
2404 self.players[k].outbox.put(data)
2184 except Exception, e: 2405 except Exception, e:
2185 traceback.print_exc() 2406 traceback.print_exc()
2186 self.log_msg("Exception: send_to_all(): " + str(e)) 2407 self.log_msg("Exception: send_to_all(): " + str(e))
2187 2408
2188 def send_to_group(self, from_id, group_id, data): 2409 def send_to_group(self, from_id, group_id, data):
2191 try: 2412 try:
2192 self.p_lock.acquire() 2413 self.p_lock.acquire()
2193 keys = self.groups[group_id].get_player_ids() 2414 keys = self.groups[group_id].get_player_ids()
2194 self.p_lock.release() 2415 self.p_lock.release()
2195 for k in keys: 2416 for k in keys:
2196 if k != from_id: self.players[k].outbox.put(data) 2417 if k != from_id:
2418 self.players[k].outbox.put(data)
2197 except Exception, e: 2419 except Exception, e:
2198 traceback.print_exc() 2420 traceback.print_exc()
2199 self.log_msg("Exception: send_to_group(): " + str(e)) 2421 self.log_msg("Exception: send_to_group(): " + str(e))
2200 2422
2201 def send_player_list(self,to_id,group_id): 2423 def send_player_list(self,to_id,group_id):
2216 self.players[to_id].outbox.put(xml) 2438 self.players[to_id].outbox.put(xml)
2217 except Exception, e: 2439 except Exception, e:
2218 self.log_msg("Exception: send_group_list(): (client #"+to_id+") : " + str(e)) 2440 self.log_msg("Exception: send_group_list(): (client #"+to_id+") : " + str(e))
2219 traceback.print_exc() 2441 traceback.print_exc()
2220 2442
2221 """ 2443 #--------------------------------------------------------------------------
2222 # KICK_ALL_CLIENTS() 2444 # KICK_ALL_CLIENTS()
2223 # 2445 #
2224 # Convience method for booting all clients off the server at once. 2446 # Convience method for booting all clients off the server at once.
2225 # used while troubleshooting mysterious "black hole" server bug 2447 # used while troubleshooting mysterious "black hole" server bug
2226 # Added by Snowdog 11-19-04 2448 # Added by Snowdog 11-19-04
2227 """
2228 def kick_all_clients(self): 2449 def kick_all_clients(self):
2229 try: 2450 try:
2230 keys = self.groups.keys() 2451 keys = self.groups.keys()
2231 for k in keys: 2452 for k in keys:
2232 pl = self.groups[k].get_player_ids() 2453 pl = self.groups[k].get_player_ids()
2233 for p in pl: self.admin_kick(p,"Purged from server") 2454 for p in pl:
2455 self.admin_kick(p,"Purged from server")
2234 except Exception, e: 2456 except Exception, e:
2235 traceback.print_exc() 2457 traceback.print_exc()
2236 self.log_msg("Exception: kick_all_clients(): " + str(e)) 2458 self.log_msg("Exception: kick_all_clients(): " + str(e))
2237 2459
2238 """ 2460
2239 # This really has little value as it will only catch people that are hung 2461 # This really has little value as it will only catch people that are hung
2240 # on a disconnect which didn't complete. Other idle connections which are 2462 # on a disconnect which didn't complete. Other idle connections which are
2241 # really dead go undeterred. 2463 # really dead go undeterred.
2242 # 2464 #
2243 # UPDATED 11-29-04: Changed remove XML send to forced admin_kick for 'dead clients' 2465 # UPDATED 11-29-04: Changed remove XML send to forced admin_kick for 'dead clients'
2244 # Dead clients now removed more effeciently as soon as they are detected 2466 # Dead clients now removed more effeciently as soon as they are detected
2245 # --Snowdog 2467 # --Snowdog
2246 """
2247 def check_group_members(self, group_id): 2468 def check_group_members(self, group_id):
2248 try: 2469 try:
2249 keys = self.groups[group_id].get_player_ids() 2470 keys = self.groups[group_id].get_player_ids()
2250 for k in keys: 2471 for k in keys:
2251 #drop any clients that are idle for more than 8 hours 2472 #drop any clients that are idle for more than 8 hours
2252 #as these are likely dead clients 2473 #as these are likely dead clients
2253 idlemins = self.players[k].idle_time() 2474 idlemins = self.players[k].idle_time()
2254 idlemins = idlemins/60 2475 idlemins = idlemins/60
2255 if (idlemins > self.zombie_time): self.admin_kick(k,"Removing zombie client", self.silent_auto_kick) 2476 if (idlemins > self.zombie_time):
2477 self.admin_kick(k,"Removing zombie client", self.silent_auto_kick)
2256 elif self.players[k].get_status() != MPLAY_CONNECTED: 2478 elif self.players[k].get_status() != MPLAY_CONNECTED:
2257 if self.players[k].check_time_out(): 2479 if self.players[k].check_time_out():
2258 self.log_msg("Player #" + k + " Lost connection!") 2480 self.log_msg("Player #" + k + " Lost connection!")
2259 self.admin_kick(k,"Removing dead client", self.silent_auto_kick) 2481 self.admin_kick(k,"Removing dead client", self.silent_auto_kick)
2260 except Exception, e: 2482 except Exception, e:
2261 self.log_msg("Exception: check_group_members(): " + str(e)) 2483 self.log_msg("Exception: check_group_members(): " + str(e))
2262 2484
2263 2485
2264 def remote_admin_handler(self,xml_dom,data): 2486 def remote_admin_handler(self,xml_dom,data):
2265 """
2266 # handle incoming remove server admin messages 2487 # handle incoming remove server admin messages
2267 # (allows basic administration of server from a remote client) 2488 # (allows basic administration of server from a remote client)
2268 # base message format: <admin id="" pwd="" cmd="" [data for command]> 2489 # base message format: <admin id="" pwd="" cmd="" [data for command]>
2269 """ 2490
2270 if not self.allowRemoteAdmin: return 2491 if not self.allowRemoteAdmin:
2492 return
2493
2271 try: 2494 try:
2272 pid = xml_dom.getAttribute("id") 2495 pid = xml_dom.getAttribute("id")
2273 gid = "" 2496 gid = ""
2274 given_pwd = xml_dom.getAttribute("pwd") 2497 given_pwd = xml_dom.getAttribute("pwd")
2275 cmd = xml_dom.getAttribute("cmd") 2498 cmd = xml_dom.getAttribute("cmd")
2276 server_admin_pwd = self.groups["0"].boot_pwd 2499 server_admin_pwd = self.groups["0"].boot_pwd
2277 p_id = "" 2500 p_id = ""
2278 p_name= "" 2501 p_name= ""
2279 p_ip = "" 2502 p_ip = ""
2503
2280 2504
2281 #verify that the message came from the proper ID/Socket and get IP address for logging 2505 #verify that the message came from the proper ID/Socket and get IP address for logging
2282 if self.players.has_key(pid): 2506 if self.players.has_key(pid):
2283 p_name=(self.players[pid]).name 2507 p_name=(self.players[pid]).name
2284 p_ip=(self.players[pid]).ip 2508 p_ip=(self.players[pid]).ip
2297 #dump and log any attempts to control server remotely with invalid password 2521 #dump and log any attempts to control server remotely with invalid password
2298 if server_admin_pwd != given_pwd: 2522 if server_admin_pwd != given_pwd:
2299 #tell the clients password manager the password failed -- SD 8/03 2523 #tell the clients password manager the password failed -- SD 8/03
2300 pm = "<password signal=\"fail\" type=\"server\" id=\"" + str(self.players[pid].group_id) + "\" data=\"\"/>" 2524 pm = "<password signal=\"fail\" type=\"server\" id=\"" + str(self.players[pid].group_id) + "\" data=\"\"/>"
2301 self.players[pid].outbox.put(pm) 2525 self.players[pid].outbox.put(pm)
2302 m = "Invalid Remote Server Control Message (bad password) from " 2526 m = "Invalid Remote Server Control Message (bad password) from #" + str(pid) + " (" + str(p_name) + ") " + str(p_ip)
2303 m += "#" + str(pid) + " (" + str(p_name) + ") " + str(p_ip)
2304 self.log_msg( m ) 2527 self.log_msg( m )
2305 return 2528 return
2306 2529
2307 #message now deemed 'authentic' 2530 #message now deemed 'authentic'
2308 #determine action to take based on command (cmd) 2531 #determine action to take based on command (cmd)
2532
2309 if cmd == "list": 2533 if cmd == "list":
2310 #return player list to this user. 2534 #return player list to this user.
2311 msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'>" + self.player_list_remote() 2535 msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'>" + self.player_list_remote()
2312 self.players[pid].outbox.put(msg) 2536 self.players[pid].outbox.put(msg)
2537
2313 elif cmd == "banip": 2538 elif cmd == "banip":
2314 ip = xml_dom.getAttribute("bip") 2539 ip = xml_dom.getAttribute("bip")
2315 name = xml_dom.getAttribute("bname") 2540 name = xml_dom.getAttribute("bname")
2316 msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'> Banned: " + str(ip) 2541 msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'> Banned: " + str(ip)
2317 self.admin_banip(ip, name) 2542 self.admin_banip(ip, name)
2543
2318 elif cmd == "ban": 2544 elif cmd == "ban":
2319 id = xml_dom.getAttribute("bid") 2545 id = xml_dom.getAttribute("bid")
2320 msg = "<msg to='" + id + "' from='0' group_id='" + gid + "'> Banned!" 2546 msg = "<msg to='" + id + "' from='0' group_id='" + gid + "'> Banned!"
2321 self.players[pid].outbox.put(msg) 2547 self.players[pid].outbox.put(msg)
2322 self.admin_ban(id, "") 2548 self.admin_ban(id, "")
2549
2323 elif cmd == "unban": 2550 elif cmd == "unban":
2324 ip = xml_dom.getAttribute("ip") 2551 ip = xml_dom.getAttribute("ip")
2325 self.admin_unban(ip) 2552 self.admin_unban(ip)
2326 msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'> Unbaned: " + str(ip) 2553 msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'> Unbaned: " + str(ip)
2327 self.players[pid].outbox.put(msg) 2554 self.players[pid].outbox.put(msg)
2555
2328 elif cmd == "banlist": 2556 elif cmd == "banlist":
2329 msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'>" + self.admin_banlist() 2557 msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'>" + self.admin_banlist()
2330 self.players[pid].outbox.put(msg) 2558 self.players[pid].outbox.put(msg)
2559
2331 elif cmd == "killgroup": 2560 elif cmd == "killgroup":
2332 ugid = xml_dom.getAttribute("gid") 2561 ugid = xml_dom.getAttribute("gid")
2333 if ugid == "0": 2562 if ugid == "0":
2334 m = "<msg to='" + pid + "' from='0' group_id='" + gid + "'>" 2563 m = "<msg to='" + pid + "' from='0' group_id='" + gid + "'>Cannot Remove Lobby! Remote administrator request denied!"
2335 m += "Cannot Remove Lobby! Remote administrator request denied!"
2336 self.players[pid].outbox.put(m) 2564 self.players[pid].outbox.put(m)
2337 else: 2565 else:
2338 result = self.prune_room(ugid) 2566 result = self.prune_room(ugid)
2339 msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'>" + str(result) 2567 msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'>" + str(result)
2340 self.players[pid].outbox.put(msg) 2568 self.players[pid].outbox.put(msg)
2345 pmsg = "<msg to='" + tuid + "' from='0' group_id='" + self.players[tuid].group_id + "' >" + msg 2573 pmsg = "<msg to='" + tuid + "' from='0' group_id='" + self.players[tuid].group_id + "' >" + msg
2346 try: self.players[tuid].outbox.put(pmsg) 2574 try: self.players[tuid].outbox.put(pmsg)
2347 except: 2575 except:
2348 msg = "<msg to='" + pid + "' from='0' group_id='" + gid + ">Unknown Player ID: No message sent." 2576 msg = "<msg to='" + pid + "' from='0' group_id='" + gid + ">Unknown Player ID: No message sent."
2349 self.players[pid].outbox.put(msg) 2577 self.players[pid].outbox.put(msg)
2578
2350 elif cmd == "broadcast": 2579 elif cmd == "broadcast":
2351 bmsg = xml_dom.getAttribute("msg") 2580 bmsg = xml_dom.getAttribute("msg")
2352 self.broadcast(bmsg) 2581 self.broadcast(bmsg)
2582
2353 elif cmd == "killserver" and self.allowRemoteKill: 2583 elif cmd == "killserver" and self.allowRemoteKill:
2354 #dangerous command..once server stopped it must be restarted manually 2584 #dangerous command..once server stopped it must be restarted manually
2355 self.kill_server() 2585 self.kill_server()
2586
2356 elif cmd == "uptime": 2587 elif cmd == "uptime":
2357 msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'>" + self.uptime(1) 2588 msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'>" + self.uptime(1)
2358 self.players[pid].outbox.put(msg) 2589 self.players[pid].outbox.put(msg)
2590
2359 elif cmd == "help": 2591 elif cmd == "help":
2360 msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'>" 2592 msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'>"
2361 msg += self.AdminHelpMessage() 2593 msg += self.AdminHelpMessage()
2362 self.players[pid].outbox.put( msg) 2594 self.players[pid].outbox.put( msg)
2595
2363 elif cmd == "roompasswords": 2596 elif cmd == "roompasswords":
2364 # Toggle if room passwords are allowed on this server 2597 # Toggle if room passwords are allowed on this server
2365 msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'>" 2598 msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'>"
2366 msg += self.RoomPasswords() 2599 msg += self.RoomPasswords()
2367 self.players[pid].outbox.put( msg) 2600 self.players[pid].outbox.put( msg)
2601
2368 elif cmd == "createroom": 2602 elif cmd == "createroom":
2369 rm_name = xml_dom.getAttribute("name") 2603 rm_name = xml_dom.getAttribute("name")
2370 rm_pass = xml_dom.getAttribute("pass") 2604 rm_pass = xml_dom.getAttribute("pass")
2371 rm_boot = xml_dom.getAttribute("boot") 2605 rm_boot = xml_dom.getAttribute("boot")
2372 result = self.create_temporary_persistant_room(rm_name, rm_boot, rm_pass) 2606 result = self.create_temporary_persistant_room(rm_name, rm_boot, rm_pass)
2373 msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'>" + result 2607 msg = "<msg to='" + pid + "' from='0' group_id='" + gid + "'>" + result
2374 self.players[pid].outbox.put(msg) 2608 self.players[pid].outbox.put(msg)
2609
2375 elif cmd == "nameroom": 2610 elif cmd == "nameroom":
2376 rm_id = xml_dom.getAttribute("rmid") 2611 rm_id = xml_dom.getAttribute("rmid")
2377 rm_name = xml_dom.getAttribute("name") 2612 rm_name = xml_dom.getAttribute("name")
2378 result = self.change_group_name(rm_id,rm_name,pid) 2613 result = self.change_group_name(rm_id,rm_name,pid)
2379 msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'/>" + result 2614 msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'/>" + result
2380 self.players[pid].outbox.put(msg) 2615 self.players[pid].outbox.put(msg)
2616
2381 elif cmd == "passwd": 2617 elif cmd == "passwd":
2382 tgid = xml_dom.getAttribute("gid") 2618 tgid = xml_dom.getAttribute("gid")
2383 npwd = xml_dom.getAttribute("pass") 2619 npwd = xml_dom.getAttribute("pass")
2384 if tgid == "0": 2620 if tgid == "0":
2385 msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'>" 2621 msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'>Server password may not be changed remotely!"
2386 msg += "Server password may not be changed remotely!"
2387 self.players[pid].outbox.put(msg) 2622 self.players[pid].outbox.put(msg)
2388 else: 2623 else:
2389 try: 2624 try:
2390 self.groups[tgid].boot_pwd = npwd 2625 self.groups[tgid].boot_pwd = npwd
2391 msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'>Password changed for room " + tgid 2626 msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'>Password changed for room " + tgid
2392 self.players[pid].outbox.put(msg) 2627 self.players[pid].outbox.put(msg)
2393 except: pass 2628 except: pass
2629
2394 elif cmd == "savemaps": 2630 elif cmd == "savemaps":
2395 for g in self.groups.itervalues(): 2631 for g in self.groups.itervalues():
2396 g.save_map() 2632 g.save_map()
2633
2397 msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'>Persistent room maps saved" 2634 msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'>Persistent room maps saved"
2398 self.players[pid].outbox.put(msg) 2635 self.players[pid].outbox.put(msg)
2636
2637
2399 else: 2638 else:
2400 msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'><i>[Unknown Remote Administration Command]</i>" 2639 msg ="<msg to='" + pid + "' from='0' group_id='" + gid + "'><i>[Unknown Remote Administration Command]</i>"
2401 self.players[pid].outbox.put(msg) 2640 self.players[pid].outbox.put(msg)
2641
2642
2402 except Exception, e: 2643 except Exception, e:
2403 self.log_msg("Exception: Remote Admin Handler Error: " + str(e)) 2644 self.log_msg("Exception: Remote Admin Handler Error: " + str(e))
2404 traceback.print_exc() 2645 traceback.print_exc()
2405 2646
2647
2406 def toggleRemoteKill(self): 2648 def toggleRemoteKill(self):
2407 if self.allowRemoteKill: self.allowRemoteKill = False 2649 if self.allowRemoteKill:
2408 else: self.allowRemoteKill = True 2650 self.allowRemoteKill = False
2651 else:
2652 self.allowRemoteKill = True
2653
2409 return self.allowRemoteKill 2654 return self.allowRemoteKill
2410 2655
2411 def toggleRemoteAdmin(self): 2656 def toggleRemoteAdmin(self):
2412 if self.allowRemoteAdmin: self.allowRemoteAdmin = False 2657 if self.allowRemoteAdmin:
2413 else: self.allowRemoteAdmin = True 2658 self.allowRemoteAdmin = False
2659 else:
2660 self.allowRemoteAdmin = True
2661
2414 return self.allowRemoteAdmin 2662 return self.allowRemoteAdmin
2415 2663
2416 """ 2664 #-----------------------------------------------------------------
2417 # Remote Administrator Help (returns from server not client) 2665 # Remote Administrator Help (returns from server not client)
2418 """ 2666 #-----------------------------------------------------------------
2419 def AdminHelpMessage(self): 2667 def AdminHelpMessage(self):
2420 "returns a string to be sent as a message to a remote admin" 2668 "returns a string to be sent as a message to a remote admin"
2669
2421 #define the help command list information 2670 #define the help command list information
2422 info = [] 2671 info = []
2423 info.append( ['list', '/admin list', 'Displays information about rooms and players on the server'] ) 2672 info.append( ['list', '/admin list', 'Displays information about rooms and players on the server'] )
2424 info.append( ['uptime', '/admin uptime', 'Information on how long server has been running'] ) 2673 info.append( ['uptime', '/admin uptime', 'Information on how long server has been running'] )
2425 info.append( ['help', '/admin help', 'This help message']) 2674 info.append( ['help', '/admin help', 'This help message'])
2426 info.append( ['passwd', '/admin passwd &lt;group id&gt; &lt;new password&gt;', 2675 info.append( ['passwd', '/admin passwd &lt;group id&gt; &lt;new password&gt;', 'Changes a rooms bootpassword. Server(lobby) password may not be changed'])
2427 'Changes a rooms bootpassword. Server(lobby) password may not be changed'])
2428 info.append( ['roompasswords', '/admin roompasswords', 'Allow/Disallow Room Passwords on the server (toggles)']) 2676 info.append( ['roompasswords', '/admin roompasswords', 'Allow/Disallow Room Passwords on the server (toggles)'])
2429 info.append( ['message', '/admin message &lt;user id&gt; &lt;message&gt;', 2677 info.append( ['message', '/admin message &lt;user id&gt; &lt;message&gt;', 'Send a message to a specific user on the server'])
2430 'Send a message to a specific user on the server'])
2431 info.append( ['broadcast', '/admin broadcast &lt;message&gt;', 'Broadcast message to all players on server']) 2678 info.append( ['broadcast', '/admin broadcast &lt;message&gt;', 'Broadcast message to all players on server'])
2432 info.append( ['createroom', '/admin createroom &lt;room name&gt; &lt;boot password&gt; [password]', 2679 info.append( ['createroom', '/admin createroom &lt;room name&gt; &lt;boot password&gt; [password]', 'Creates a temporary persistant room if possible.<i>Rooms created this way are lost on server restarts'])
2433 'Creates a temporary persistant room if possible.<i>Rooms created this way are lost on server restarts'])
2434 info.append( ['nameroom', '/admin nameroom &lt;group id&gt; &lt;new name&gt;', 'Rename a room']) 2680 info.append( ['nameroom', '/admin nameroom &lt;group id&gt; &lt;new name&gt;', 'Rename a room'])
2435 info.append( ['killgroup', '/admin killgroup &lt;room id&gt;', 2681 info.append( ['killgroup', '/admin killgroup &lt;room id&gt;', 'Remove a room from the server and kick everyone in it.'])
2436 'Remove a room from the server and kick everyone in it.'])
2437 if self.allowRemoteKill: 2682 if self.allowRemoteKill:
2438 info.append( ['killserver', '/admin killserver', 2683 info.append( ['killserver', '/admin killserver', 'Shuts down the server. <b>WARNING: Server cannot be restarted remotely via OpenRPG</b>'])
2439 'Shuts down the server. <b>WARNING: Server cannot be restarted remotely via OpenRPG</b>'])
2440 info.append( ['ban', '/admin ban {playerId}', 'Ban a player from the server.']) 2684 info.append( ['ban', '/admin ban {playerId}', 'Ban a player from the server.'])
2441 info.append( ['unban', '/admin unban {bannedIP}', 'UnBan a player from the server.']) 2685 info.append( ['unban', '/admin unban {bannedIP}', 'UnBan a player from the server.'])
2442 info.append( ['banlist', '/admin banlist', 'List Banned IPs and the Names associated with them']) 2686 info.append( ['banlist', '/admin banlist', 'List Banned IPs and the Names associated with them'])
2443 info.append( ['savemaps', '/admin savemaps', 2687 info.append( ['savemaps', '/admin savemaps', 'Save all persistent room maps that are not using the default map file.'])
2444 'Save all persistent room maps that are not using the default map file.']) 2688
2445 2689
2446 #define the HTML for the help display 2690 #define the HTML for the help display
2447 FS = "<font size='-1'>" 2691 FS = "<font size='-1'>"
2448 FE = "<font>" 2692 FE = "<font>"
2693
2449 help = "<hr><B>REMOTE ADMINISTRATOR COMMANDS SUPPORTED</b><br /><br />" 2694 help = "<hr><B>REMOTE ADMINISTRATOR COMMANDS SUPPORTED</b><br /><br />"
2450 help += "<table border='1' cellpadding='2'>" 2695 help += "<table border='1' cellpadding='2'>"
2451 help += "<tr><td width='15%'><b>Command</b></td><td width='25%'><b>Format</b>" 2696 help += "<tr><td width='15%'><b>Command</b></td><td width='25%'><b>Format</b></td><td width='60%'><b>Description</b></td></tr>"
2452 help += "</td><td width='60%'><b>Description</b></td></tr>"
2453 for n in info: 2697 for n in info:
2454 help += "<tr><td>" + FS + n[0] + FE + "</td><td><nobr>" + FS + n[1] + FE + "</nobr>" 2698 help += "<tr><td>" + FS + n[0] + FE + "</td><td><nobr>" + FS + n[1] + FE + "</nobr></td><td>" + FS + n[2] + FE + "</td></tr>"
2455 help += "</td><td>" + FS + n[2] + FE + "</td></tr>"
2456 help += "</table>" 2699 help += "</table>"
2457 return help 2700 return help
2458 2701
2459 """ 2702
2703 #----------------------------------------------------------------
2460 # Create Persistant Group -- Added by Snowdog 6/03 2704 # Create Persistant Group -- Added by Snowdog 6/03
2461 # 2705 #
2462 # Allows persistant groups to be created on the fly. 2706 # Allows persistant groups to be created on the fly.
2463 # These persistant groups are not added to the server.ini file 2707 # These persistant groups are not added to the server.ini file
2464 # however and are lost on server restarts 2708 # however and are lost on server restarts
2465 # 2709 #
2466 # Updated function code to use per-group based persistance and 2710 # Updated function code to use per-group based persistance and
2467 # removed references to outdated persistRoomIdThreshold 2711 # removed references to outdated persistRoomIdThreshold
2468 """ 2712 #----------------------------------------------------------------
2469 2713
2470 def create_temporary_persistant_room(self, roomname, bootpass, password=""): 2714 def create_temporary_persistant_room(self, roomname, bootpass, password=""):
2471 # if the room id just above the persistant room limit is available (not in use) 2715 # if the room id just above the persistant room limit is available (not in use)
2472 # then it will be assigned as a persistant room on the server 2716 # then it will be assigned as a persistant room on the server
2473 "create a temporary persistant room" 2717 "create a temporary persistant room"
2474 2718
2475 group_id = str(self.next_group_id) 2719 group_id = str(self.next_group_id)
2476 self.next_group_id += 1 2720 self.next_group_id += 1
2477 self.groups[group_id] = game_group( group_id, roomname, password, "", bootpass, persist = 1 ) 2721 self.groups[group_id] = game_group( group_id, roomname, password, "", bootpass, persist = 1 )
2479 self.log_msg( cgmsg ) 2723 self.log_msg( cgmsg )
2480 self.send_to_all('0',self.groups[group_id].toxml('new')) 2724 self.send_to_all('0',self.groups[group_id].toxml('new'))
2481 self.send_to_all('0',self.groups[group_id].toxml('update')) 2725 self.send_to_all('0',self.groups[group_id].toxml('update'))
2482 return str("Persistant room created (group " + group_id + ").") 2726 return str("Persistant room created (group " + group_id + ").")
2483 2727
2484 """ 2728 #----------------------------------------------------------------
2485 # Prune Room -- Added by Snowdog 6/03 2729 # Prune Room -- Added by Snowdog 6/03
2486 # 2730 #
2487 # similar to remove_room() except rooms are removed regardless 2731 # similar to remove_room() except rooms are removed regardless
2488 # of them being persistant or not 2732 # of them being persistant or not
2489 # 2733 #
2490 # Added some error checking and updated room removal for per-room 2734 # Added some error checking and updated room removal for per-room
2491 # based persistance -- Snowdog 4/04 2735 # based persistance -- Snowdog 4/04
2492 """ 2736 #----------------------------------------------------------------
2493 2737
2494 def prune_room(self,group): 2738 def prune_room(self,group):
2495 #don't allow lobby to be removed 2739 #don't allow lobby to be removed
2496 if group == '0': return "Lobby is required to exist and cannot be removed." 2740 if group == '0': return "Lobby is required to exist and cannot be removed."
2497 2741
2498 #check that group id exists 2742 #check that group id exists
2499 if group not in self.groups: return "Invalid Room Id. Ignoring remove request." 2743 if group not in self.groups:
2744 return "Invalid Room Id. Ignoring remove request."
2500 2745
2501 try: 2746 try:
2502 keys = self.groups[group].get_player_ids() 2747 keys = self.groups[group].get_player_ids()
2503 for k in keys: self.move_player(k,'0') 2748 for k in keys:
2749 self.move_player(k,'0')
2750
2504 ins = "Room" 2751 ins = "Room"
2505 if self.isPersistentRoom(group) : ins="Persistant room" 2752 if self.isPersistentRoom(group) : ins="Persistant room"
2506 self.send_to_all("0",self.groups[group].toxml('del')) 2753 self.send_to_all("0",self.groups[group].toxml('del'))
2507 del self.groups[group] 2754 del self.groups[group]
2508 self.log_msg(("delete_group", ('0',group))) 2755 self.log_msg(("delete_group", ('0',group)))
2509 return ins + " removed." 2756 return ins + " removed."
2757
2510 except: 2758 except:
2511 traceback.print_exc() 2759 traceback.print_exc()
2512 return "An Error occured on the server during room removal!" 2760 return "An Error occured on the server during room removal!"
2513 2761
2514 """ 2762
2515 # Remote Player List -- Added by snowdog 6/03 2763 #----------------------------------------------------------------
2516 # 2764 # Remote Player List -- Added by snowdog 6/03
2517 # Similar to console listing except formated for web display 2765 #
2518 # in chat window on remote client 2766 # Similar to console listing except formated for web display
2519 """ 2767 # in chat window on remote client
2768 #----------------------------------------------------------------
2520 def player_list_remote(self): 2769 def player_list_remote(self):
2521 COLOR1 = "\"#004080\"" #header/footer background color 2770 COLOR1 = "\"#004080\"" #header/footer background color
2522 COLOR2 = "\"#DDDDDD\"" #group line background color 2771 COLOR2 = "\"#DDDDDD\"" #group line background color
2523 COLOR3 = "\"#FFFFFF\"" #player line background color 2772 COLOR3 = "\"#FFFFFF\"" #player line background color
2524 COLOR4 = "\"#FFFFFF\"" #header/footer text color 2773 COLOR4 = "\"#FFFFFF\"" #header/footer text color
2526 LCOLOR = "\"#404040\"" #Lurker text color 2775 LCOLOR = "\"#404040\"" #Lurker text color
2527 GCOLOR = "\"#FF0000\"" #GM text color 2776 GCOLOR = "\"#FF0000\"" #GM text color
2528 SIZE = "size=\"-1\"" #player info text size 2777 SIZE = "size=\"-1\"" #player info text size
2529 FG = PCOLOR 2778 FG = PCOLOR
2530 2779
2780
2531 "display a condensed list of players on the server" 2781 "display a condensed list of players on the server"
2532 self.p_lock.acquire() 2782 self.p_lock.acquire()
2533 pl = "<br /><table border=\"0\" cellpadding=\"1\" cellspacing=\"2\">" 2783 pl = "<br /><table border=\"0\" cellpadding=\"1\" cellspacing=\"2\">"
2534 pl += "<tr><td colspan='4' bgcolor=" + COLOR1 + "><font color=" + COLOR4 + ">" 2784 pl += "<tr><td colspan='4' bgcolor=" + COLOR1 + "><font color=" + COLOR4 + "><b>GROUP &amp; PLAYER LIST</b></font></td></tr>"
2535 pl += "<b>GROUP &amp; PLAYER LIST</b></font></td></tr>" 2785 try:
2536 try: 2786
2537 keys = self.groups.keys() 2787 keys = self.groups.keys()
2538 keys.sort(id_compare) 2788 keys.sort(id_compare)
2539 for k in keys: 2789 for k in keys:
2540 groupstring = "<tr><td bgcolor=" + COLOR2 + " colspan='2'>" 2790 groupstring = "<tr><td bgcolor=" + COLOR2 + " colspan='2'><b>Group " + str(k) + ": " + self.groups[k].name + "</b>"
2541 groutstring += "<b>Group " + str(k) + ": " + self.groups[k].name + "</b>" 2791 groupstring += "</td><td bgcolor=" + COLOR2 + " > <i>Password: \"" + self.groups[k].pwd + "\"</td><td bgcolor=" + COLOR2 + " > Boot: \"" + self.groups[k].boot_pwd + "\"</i></td></tr>"
2542 groupstring += "</td><td bgcolor=" + COLOR2 + " > <i>Password: \"" + self.groups[k].pwd + "\"</td>"
2543 groupstring += "<td bgcolor=" + COLOR2 + " > Boot: \"" + self.groups[k].boot_pwd + "\"</i></td></tr>"
2544 pl += groupstring 2792 pl += groupstring
2545 ids = self.groups[k].get_player_ids() 2793 ids = self.groups[k].get_player_ids()
2546 ids.sort(id_compare) 2794 ids.sort(id_compare)
2547 for id in ids: 2795 for id in ids:
2548 if self.players.has_key(id): 2796 if self.players.has_key(id):
2552 else: FG = LCOLOR 2800 else: FG = LCOLOR
2553 else: FG = PCOLOR 2801 else: FG = PCOLOR
2554 pl += "<tr><td bgcolor=" + COLOR3 + ">" 2802 pl += "<tr><td bgcolor=" + COLOR3 + ">"
2555 pl += "<font color=" + FG + " " + SIZE + ">&nbsp;&nbsp;(" + (self.players[id]).id + ") " 2803 pl += "<font color=" + FG + " " + SIZE + ">&nbsp;&nbsp;(" + (self.players[id]).id + ") "
2556 pl += (self.players[id]).name 2804 pl += (self.players[id]).name
2557 pl += "</font></td><td bgcolor=" + COLOR3 + " >" 2805 pl += "</font></td><td bgcolor=" + COLOR3 + " ><font color=" + FG + " " + SIZE + ">[IP: " + (self.players[id]).ip + "]</font></td><td bgcolor=" + COLOR3 + " ><font color=" + FG + " " + SIZE + "> "
2558 pl += "<font color=" + FG + " " + SIZE + ">[IP: " + (self.players[id]).ip + "]</font>"
2559 pl += "</td><td bgcolor=" + COLOR3 + " ><font color=" + FG + " " + SIZE + "> "
2560 pl += (self.players[id]).idle_status() 2806 pl += (self.players[id]).idle_status()
2561 pl += "</font></td><td><font color=" + FG + " " + SIZE + ">" 2807 pl += "</font></td><td><font color=" + FG + " " + SIZE + ">"
2562 pl += (self.players[id]).connected_time_string() 2808 pl += (self.players[id]).connected_time_string()
2563 pl += "</font>" 2809 pl += "</font>"
2810
2564 else: 2811 else:
2565 self.groups[k].remove_player(id) 2812 self.groups[k].remove_player(id)
2566 pl +="<tr><td colspan='4' bgcolor=" + COLOR3 + " >Bad Player Ref (#" + id + ") in group" 2813 pl +="<tr><td colspan='4' bgcolor=" + COLOR3 + " >Bad Player Ref (#" + id + ") in group"
2567 pl+="</td></tr>" 2814 pl+="</td></tr>"
2568 pl += "<tr><td colspan='4' bgcolor=" + COLOR1 + ">" 2815 pl += "<tr><td colspan='4' bgcolor=" + COLOR1 + "><font color=" + COLOR4 + "><b><i>Statistics: groups: " + str(len(self.groups)) + " players: " + str(len(self.players)) + "</i></b></font></td></tr></table>"
2569 pl += "<font color=" + COLOR4 + "><b><i>Statistics: groups: " + str(len(self.groups)) + " " 2816 except Exception, e:
2570 pl += "players: " + str(len(self.players)) + "</i></b></font></td></tr></table>" 2817 self.log_msg(str(e))
2571 except Exception, e: self.log_msg(str(e))
2572 self.p_lock.release() 2818 self.p_lock.release()
2573 return pl 2819 return pl