PageRenderTime 90ms CodeModel.GetById 2ms app.highlight 80ms RepoModel.GetById 1ms app.codeStats 0ms

/laddermanager.py

https://github.com/renemilk/SpringLadder
Python | 824 lines | 808 code | 13 blank | 3 comment | 50 complexity | 5fa551f75e2e84c905fee2a6e1cbb162 MD5 | raw file
  1# -*- coding: utf-8 -*-
  2from customlog import *
  3from ParseConfig import *
  4import commands, thread, os, sys, signal, traceback, subprocess, platform
  5from db_entities import *
  6from ladderdb import *
  7if platform.system() == "Windows":
  8	import win32api
  9
 10import helpstrings
 11helpstring_ladder_admin = helpstrings.helpstring_ladder_admin_manager
 12helpstring_global_admin = helpstrings.helpstring_global_admin_manager
 13helpstring_user = helpstrings.helpstring_user_manager
 14
 15def mError( msg ):
 16	Log.Error( msg, '[LadderManager]' )
 17
 18def mInfo( msg ):
 19	Log.Info( msg, '[LadderManager]' )
 20
 21def pm(s,p,m):
 22	try:
 23		for line in m.split('\n'):
 24			mInfo( "PM To:%s, Message: %s" %(p,line))
 25			s.send("SAYPRIVATE %s %s\n" %(p,line))
 26	except:
 27		pass
 28
 29def saychannel( socket, channel, message ):
 30		for line in message.split('\n'):
 31			mInfo( "Channel :%s, Message: %s" %(channel,line) )
 32			socket.send("SAY %s %s\n" %(channel,line) )
 33
 34class Main:
 35	botpid = dict() # slot -> bot pid
 36	botstatus = [] # slot -> bot already spawned
 37	battleswithbots = [] # battle id -> bot already in
 38	ladderlist = dict() # id -> ladder name
 39	ladderoptions = dict() # id -> ladder options
 40
 41	def botthread(self,slot,battleid,battlepassword,fromwho,ladderid):
 42		nick = self.app.config["nick"]+str(slot)
 43		try:
 44			d = dict()
 45			d.update([("serveraddr",self.app.config["serveraddr"])])
 46			d.update([("serverport",self.app.config["serverport"])])
 47			d.update([("admins",self.app.config["admins"])])
 48			d.update([("nick",nick)])
 49			d.update([("password",self.app.config["password"])])
 50			d.update([("plugins","ladderslave")])
 51			d.update( [ ( "bans", self.app.config["bans"] ) ] )
 52			d.update([("battleid",str(battleid))])
 53			d.update([("battlepassword",str(battlepassword))])
 54			d.update([("ladderid",str(ladderid))])
 55			d.update([("fromwho",fromwho)])
 56			d.update([("alchemy-uri",self.app.config["alchemy-uri"])])
 57			d.update([("alchemy-verbose",self.app.config["alchemy-verbose"])])
 58			d.update([("springdedclientpath",self.app.config["springdedclientpath"])])
 59			if "springdatapath" in self.app.config:
 60				d.update([("springdatapath",self.app.config["springdatapath"])])
 61			writeconfigfile(nick+".cfg",d)
 62			p = subprocess.Popen(("python","Main.py","-c", "%s" % (nick+".cfg")),stdout=sys.stdout)
 63			self.botpid[slot] = p.pid
 64			p.wait()
 65		except:
 66			mError(traceback.print_exc(file=sys.stdout))
 67
 68	def onload(self,tasc):
 69		self.tsc = tasc
 70		self.bans = []
 71		self.app = tasc.main
 72		self.channels = parselist(self.app.config["channelautojoinlist"],",")
 73		self.admins = parselist(self.app.config["admins"],",")
 74		self.db = LadderDB( parselist(self.app.config["alchemy-uri"],",")[0], self.admins, parselist(self.app.config["alchemy-verbose"],",")[0] )
 75		self.closewhenempty = False
 76		self.enabled = True
 77
 78	def notifyuser( self, socket, fromwho, fromwhere, ispm, message ):
 79		if fromwhere == "main" or fromwhere == "newbies":
 80			ispm = True
 81		if not ispm:
 82			saychannel( socket, fromwhere, message )
 83		else:
 84			pm( socket, fromwho, message )
 85
 86	def sayPermissionDenied(self, socket, command, username,fromwhere, ispm  ):
 87		msg = 'You do not have sufficient access right to execute %s on this bot\n' %( command )
 88		self.notifyuser( socket, username, fromwhere, ispm, msg )
 89
 90	def spawnbot( self,  socket, battleid, password, fromwho, ladderid ):
 91		slot = 0
 92		busyslot = slot in self.botstatus
 93		while busyslot:
 94			slot = slot+1
 95			busyslot = slot in self.botstatus
 96		notice("spawning " + self.app.config["nick"]+str(slot) + " to join battle " + str(battleid) + " with ladder " + str(ladderid))
 97		self.threads.append(thread.start_new_thread(self.botthread,(slot,battleid,password,fromwho,ladderid)))
 98
 99	def oncommandfromuser(self,fromwho,fromwhere,ispm,command,args,socket):
100		try:
101			if fromwho == self.app.config["nick"]:
102				return
103			if len(command) > 0 and command[0] == "!":
104				if not self.db.AccessCheck( -1, fromwho, Roles.User ):
105					self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
106					#log
107					return
108			else:
109				return
110
111			# !TODO refactor to use function dict
112			if command == "!ladder":
113				if not self.enabled and not self.db.AccessCheck( -1, fromwho, Roles.GlobalAdmin ):
114					self.notifyuser( socket, fromwho, fromwhere, ispm, "Ladder functionality is temporarily disabled." )
115					return
116				ladderid = -1
117				battleid = -2
118				password = ""
119				if len(args) > 0:
120					if args[0].isdigit():
121						ladderid = int(args[0])
122						if len(args) > 1:
123							password = " ".join(args[1:])
124					else:
125						password = " ".join(args[0:])
126				try:
127					battleid = self.tsc.users[fromwho].battleid
128				except:
129					bad("User " + fromwho + " not found")
130				if ( battleid < 0 ):
131					self.notifyuser( socket, fromwho, fromwhere, ispm, "You are not in a battle." )
132				else:
133					if not self.db.AccessCheck( ladderid, fromwho, Roles.User ):
134						self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
135						#log
136						return
137					if ( battleid in self.battleswithbots ):
138						self.notifyuser( socket, fromwho, fromwhere, ispm, "A ladder bot is already present in your battle." )
139					else:
140						if ( ladderid == -1 or self.db.LadderExists( ladderid ) ):
141							self.spawnbot( socket, battleid, password, fromwho, ladderid )
142						else:
143							self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid ladder ID." )
144			if command == "!ladderjoinchannel":
145				if not self.db.AccessCheck( -1, fromwho, Roles.GlobalAdmin ):
146					self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
147					#log
148					return
149				if len(args) < 1:
150					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
151				else:
152					channel = " ".join(args[0:])
153					socket.send("JOIN " + channel + "\n")
154					if not channel in self.channels:
155						self.channels.append(channel)
156						self.app.config["channelautojoinlist"] = ','.join(self.channels)
157						self.app.SaveConfig()
158			if command == "!ladderleavechannel":
159				if not self.db.AccessCheck( -1, fromwho, Roles.GlobalAdmin ):
160					self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
161					#log
162					return
163				if len(args) != 1:
164					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
165				else:
166					channel = args[0]
167					if channel in self.channels:
168						socket.send("LEAVE " + channel + "\n")
169						self.channels.remove(channel)
170						self.app.config["channelautojoinlist"] = ','.join(self.channels)
171						self.app.SaveConfig()
172			if command == "!ladderlist":
173				self.notifyuser( socket, fromwho, fromwhere, ispm, "Available ladders, format name: ID:" )
174				for l in self.db.GetLadderList(Ladder.name):
175					self.notifyuser( socket, fromwho, fromwhere, ispm, "%s: %d" %(l.name, l.id ) )
176			if command == "!ladderadd":
177				if not self.db.AccessCheck( -1, fromwho, Roles.GlobalAdmin ):
178					self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
179					#log
180					return
181				if len(args) < 1:
182					self.notifyuser( socket, fromwho, fromwhere, ispm, "Ladder name can't be empty." )
183				else:
184					try:
185						laddername = " ".join(args[0:])
186						ladderid = self.db.AddLadder( laddername )
187						self.notifyuser( socket, fromwho, fromwhere, ispm, "New ladder created, ID: " + str(ladderid) )
188					except ElementExistsException, e:
189						error(e)
190			if command == "!ladderremove":
191				if not self.db.AccessCheck( -1, fromwho, Roles.GlobalAdmin ):
192					self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
193					#log
194					return
195				if len(args) != 1 or not args[0].isdigit():
196					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
197				else:
198					ladderid = int(args[0])
199					try:
200						self.db.RemoveLadder( args[0] )
201						self.notifyuser( socket, fromwho, fromwhere, ispm, "Ladder removed." )
202					except ElementNotFoundException, e:
203						self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid ladder ID." )
204			if command == "!ladderchangeaicount":
205				if len(args) > 3 or not args[0].isdigit() or not args[1].isdigit():
206					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
207				else:
208					ladderid = int(args[0])
209					try:
210						ladder = self.db.GetLadder( ladderid )
211						if not self.db.AccessCheck( ladderid, fromwho, Roles.LadderAdmin ):
212							self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
213							#log
214							return
215						ladder.min_ai_count = int(args[1])
216						if len(args) == 2: # min = max
217							ladder.max_ai_count = int(args[1])
218						elif len(args) == 3: # separate min & max
219							if args[2] < args[1]:
220								self.notifyuser( socket, fromwho, fromwhere, ispm, "max ai count < min! not changed." )
221								return
222							ladder.max_ai_count = int(args[2])
223						self.db.SetLadder( ladder )
224						self.notifyuser( socket, fromwho, fromwhere, ispm, "Ladder ai count changed." )
225					except ElementNotFoundException, e:
226						self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid ladder ID." )
227			if command == "!ladderchangecontrolteamsize":
228				if len(args) > 3 or not args[0].isdigit() or not args[1].isdigit():
229					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
230				else:
231					ladderid = int(args[0])
232					try:
233						ladder = self.db.GetLadder( ladderid )
234						if not self.db.AccessCheck( ladderid, fromwho, Roles.LadderAdmin ):
235							self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
236							#log
237							return
238						ladder.min_team_size = int(args[1])
239						if len(args) == 2: # min = max
240							ladder.max_team_size = int(args[1])
241						elif len(args) == 3: # separate min & max
242							if args[2] < args[1]:
243								self.notifyuser( socket, fromwho, fromwhere, ispm, "max control team size < min! not changed." )
244								return
245							ladder.max_team_size = int(args[2])
246						self.db.SetLadder( ladder )
247						self.notifyuser( socket, fromwho, fromwhere, ispm, "Ladder control team size changed." )
248					except ElementNotFoundException, e:
249						self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid ladder ID." )
250			if command == "!ladderchangeallysize":
251				if len(args) > 3 or not args[0].isdigit() or not args[1].isdigit():
252					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
253				else:
254					ladderid = int(args[0])
255					try:
256						ladder = self.db.GetLadder( ladderid )
257						if not self.db.AccessCheck( ladderid, fromwho, Roles.LadderAdmin ):
258							self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
259							#log
260							return
261						ladder.min_ally_size = int(args[1])
262						if len(args) == 2: # min = max
263							ladder.max_ally_size = int(args[1])
264						elif len(args) == 3: # separate min & max
265							if args[2] < args[1]:
266								self.notifyuser( socket, fromwho, fromwhere, ispm, "max ally size < min! not changed." )
267								return
268							ladder.max_ally_size = int(args[2])
269						self.db.SetLadder( ladder )
270						self.notifyuser( socket, fromwho, fromwhere, ispm, "Ladder ally size changed." )
271					except ElementNotFoundException, e:
272						self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid ladder ID." )
273			if command == "!ladderchangecontrolteamcount":
274				if len(args) > 3 or not args[0].isdigit() or not args[1].isdigit():
275					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
276				else:
277					ladderid = int(args[0])
278					try:
279						ladder = self.db.GetLadder( ladderid )
280						if not self.db.AccessCheck( ladderid, fromwho, Roles.LadderAdmin ):
281							self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
282							#log
283							return
284						ladder.min_team_count = int(args[1])
285						if len(args) == 2: # min = max
286							ladder.max_team_count = int(args[1])
287						elif len(args) == 3: # separate min & max
288							if args[2] < args[1]:
289								self.notifyuser( socket, fromwho, fromwhere, ispm, "max control team count < min! not changed." )
290								return
291							ladder.max_team_count = int(args[2])
292						self.db.SetLadder( ladder )
293						self.notifyuser( socket, fromwho, fromwhere, ispm, "Ladder control team count changed." )
294					except ElementNotFoundException, e:
295						self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid ladder ID." )
296			if command == "!ladderchangeallycount":
297				if len(args) > 3 or not args[0].isdigit() or not args[1].isdigit():
298					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
299				else:
300					ladderid = int(args[0])
301					try:
302						ladder = self.db.GetLadder( ladderid )
303						if not self.db.AccessCheck( ladderid, fromwho, Roles.LadderAdmin ):
304							self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
305							#log
306							return
307						ladder.min_ally_count = int(args[1])
308						if len(args) == 2: # min = max
309							ladder.max_ally_count = int(args[1])
310						elif len(args) == 3: # separate min & max
311							if args[2] < args[1]:
312								self.notifyuser( socket, fromwho, fromwhere, ispm, "max ally count < min! not changed." )
313								return
314							ladder.max_ally_count = int(args[2])
315						self.db.SetLadder( ladder )
316						self.notifyuser( socket, fromwho, fromwhere, ispm, "Ladder ally count changed." )
317					except ElementNotFoundException, e:
318						self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid ladder ID." )
319			if command == "!ladderaddoption":
320				if len(args) < 4 or not args[0].isdigit() or not args[1].isdigit():
321					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
322				else:
323					ladderid = int(args[0])
324					if self.db.LadderExists( ladderid ):
325						if not self.db.AccessCheck( ladderid, fromwho, Roles.LadderAdmin ):
326							self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
327							#log
328							return
329						whitelist = int(args[1]) != 0
330						keyname = args[2]
331						value = " ".join(args[3:])
332						if self.db.GetOptionKeyExists(ladderid, not whitelist, keyname ):
333							self.notifyuser( socket, fromwho, fromwhere, ispm, "You cannot use blacklist and whitelist at the same time for the same option key." )
334						else:
335							try:
336								self.db.AddOption( ladderid, whitelist, keyname, value )
337								message = "blacklist"
338								if whitelist:
339									message = "whitelist"
340								self.notifyuser( socket, fromwho, fromwhere, ispm, "Option added to the " + message + "." )
341							except ElementExistsException, e:
342								self.notifyuser( socket, fromwho, fromwhere, ispm, "Option already in db" )
343					else:
344						self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid ladder ID." )
345			if command == "!ladderremoveoption":
346				if len(args) < 3 or not args[0].isdigit():
347					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
348				else:
349					ladderid = int(args[0])
350					if self.db.LadderExists( ladderid ):
351						if not self.db.AccessCheck( ladderid, fromwho, Roles.LadderAdmin ):
352							self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
353							#log
354							return
355						keyname = args[1]
356						value = " ".join(args[2:])
357						indisabledoptions = self.db.GetOptionKeyExists(ladderid, False, keyname )
358						inenabledoptions = self.db.GetOptionKeyExists(ladderid, True, keyname )
359						if not indisabledoptions and not inenabledoptions:
360							self.notifyuser( socket, fromwho, fromwhere, ispm, "Key doesn't exist in either whitelist and blackist." )
361						else:
362							if not self.db.GetOptionKeyValueExists( ladderid, inenabledoptions, keyname, value ):
363								message = "blacklisted"
364								if inenabledoptions:
365									message = "whitelisted"
366								self.notifyuser( socket, fromwho, fromwhere, ispm, "Value doesn't exist in " + message + " options" )
367							else:
368								self.db.DeleteOption( ladderid, inenabledoptions, keyname, value )
369								message = "blacklist"
370								if inenabledoptions:
371									message = "whitelist"
372								self.notifyuser( socket, fromwho, fromwhere, ispm, "Option removed from the " + message + "." )
373					else:
374						self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid ladder ID." )
375			if command == "!ladderlistoptions":
376				if len(args) != 1 or not args[0].isdigit():
377					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
378				else:
379					ladderid = int(args[0])
380					if self.db.LadderExists( ladderid ):
381						self.notifyuser( socket, fromwho, fromwhere, ispm, "Ladder: " + self.db.GetLadderName(ladderid) )
382						self.notifyuser( socket, fromwho, fromwhere, ispm, "Min AIs in a Match ( how many AIs ): " + str(self.db.GetLadderOption( ladderid, "min_ai_count" )) )
383						self.notifyuser( socket, fromwho, fromwhere, ispm, "Max Ais in a Match ( how many AIs ): " + str(self.db.GetLadderOption( ladderid, "max_ai_count" )) )
384						self.notifyuser( socket, fromwho, fromwhere, ispm, "Min Players in a Team ( sharing control ): " + str(self.db.GetLadderOption( ladderid, "min_team_size" )) )
385						self.notifyuser( socket, fromwho, fromwhere, ispm, "Max Players in a Team ( sharing control ): " + str(self.db.GetLadderOption( ladderid, "max_team_size" )) )
386						self.notifyuser( socket, fromwho, fromwhere, ispm, "Min Teams in an Ally ( being allied ): " + str(self.db.GetLadderOption( ladderid, "min_ally_size" )) )
387						self.notifyuser( socket, fromwho, fromwhere, ispm, "Max Teams in an Ally ( being allied ): " + str(self.db.GetLadderOption( ladderid, "max_ally_size" )) )
388						self.notifyuser( socket, fromwho, fromwhere, ispm, "Min Teams in a Match ( how many Teams ): " + str(self.db.GetLadderOption( ladderid, "min_team_count" )) )
389						self.notifyuser( socket, fromwho, fromwhere, ispm, "Max Teams in a Match ( how many Teams ): " + str(self.db.GetLadderOption( ladderid, "max_team_count" )) )
390						self.notifyuser( socket, fromwho, fromwhere, ispm, "Min Alliances in a Match ( how many Allys ): " + str(self.db.GetLadderOption( ladderid, "min_ally_count" )) )
391						self.notifyuser( socket, fromwho, fromwhere, ispm, "Max Alliances in a Match ( how many Allys ): " + str(self.db.GetLadderOption( ladderid, "max_ally_count" )) )
392						self.notifyuser( socket, fromwho, fromwhere, ispm, "Whitelisted options ( if a key is present, no other value except for those listed will be allowed for such key ):" )
393						for opt in self.db.GetFilteredOptions( ladderid, True ):
394							self.notifyuser( socket, fromwho, fromwhere, ispm, opt.key + ": " + opt.value )
395						self.notifyuser( socket, fromwho, fromwhere, ispm, "Blacklisted options ( if a value is present for a key, such value won't be allowed ):" )
396						for opt in self.db.GetFilteredOptions( ladderid, False ):
397							self.notifyuser( socket, fromwho, fromwhere, ispm, opt.key + ": " + opt.value )
398					else:
399						self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid ladder ID." )
400			if command == "!score":
401				if not self.db.AccessCheck( -1, fromwho, Roles.User ):
402					self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
403					#log
404					return
405				if len(args) > 2:
406					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
407				else:
408					ladderid = -1
409					playername = ""
410					rep = ''
411					if len(args) == 1:
412						if args[0].isdigit():
413							ladderid = int(args[0])
414							rep = GlobalRankingAlgoSelector.GetPrintableRepresentation( self.db.GetRanks( ladderid ), self.db )
415						else:
416							playername = args[0]
417							rep = GlobalRankingAlgoSelector.GetPrintableRepresentationPlayer( self.db.GetPlayerRanks( playername ), self.db )
418						self.notifyuser( socket, fromwho, fromwhere, ispm, rep )
419
420					elif len(args) == 2:
421						if not args[0].isdigit():
422							self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
423						else:
424							ladderid = int(args[0])
425							playername = args[1]
426							rep = GlobalRankingAlgoSelector.GetPrintableRepresentation( self.db.GetRanks( ladderid, playername ), self.db )
427							self.notifyuser( socket, fromwho, fromwhere, ispm, rep )
428			if command == "!ladderhelp":
429				self.notifyuser( socket, fromwho, fromwhere, ispm, "Hello, I am a bot to manage and keep stats of ladder games.\nYou can use the following commands:")
430				if self.db.AccessCheck( -1, fromwho, Roles.GlobalAdmin ):
431					self.notifyuser( socket, fromwho, fromwhere, ispm, helpstring_global_admin )
432				if self.db.AccessCheck( -1, fromwho, Roles.LadderAdmin ):
433					self.notifyuser( socket, fromwho, fromwhere, ispm, helpstring_ladder_admin )
434				self.notifyuser( socket, fromwho, fromwhere, ispm, helpstring_user )
435			if command == "!help":
436				ispm = True
437				self.notifyuser( socket, fromwho, fromwhere, ispm, "Hello, I am a bot to manage and keep stats of ladder games.\nYou can use the following commands:")
438				if self.db.AccessCheck( -1, fromwho, Roles.GlobalAdmin ):
439					self.notifyuser( socket, fromwho, fromwhere, ispm, helpstring_global_admin )
440				if self.db.AccessCheck( -1, fromwho, Roles.LadderAdmin ):
441					self.notifyuser( socket, fromwho, fromwhere, ispm, helpstring_ladder_admin )
442				self.notifyuser( socket, fromwho, fromwhere, ispm, helpstring_user )
443			if command == "!laddercopy":
444				if not self.db.AccessCheck( -1, fromwho, Roles.GlobalAdmin ):
445					self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
446					#log
447					return
448				if len(args) < 2:
449					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
450				else:
451					source_id = args[0]
452					target_name = " ".join(args[1:])
453					try:
454						self.db.CopyLadder( source_id, target_name )
455					except:
456						self.notifyuser( socket, fromwho, fromwhere, ispm, "Couldn't copy ladder" )
457			if command == "!ladderaddglobaladmin":
458				if not self.db.AccessCheck( -1, fromwho, Roles.Owner ):
459					self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
460					#log
461					return
462				if len(args) < 1:
463					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
464				else:
465					username = args[0]
466					try:
467						self.db.AddGlobalAdmin( username )
468					except:
469						self.notifyuser( socket, fromwho, fromwhere, ispm, "Couldn't add global admin" )
470			if command == "!ladderaddladderadmin":
471				if not self.db.AccessCheck( -1, fromwho, Roles.GlobalAdmin ):
472					self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
473					#log
474					return
475				if len(args) < 2:
476					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
477				else:
478					ladderid = args[0]
479					username = args[1]
480					try:
481						self.db.AddLadderAdmin( ladderid, username )
482					except ElementNotFoundException, e:
483						self.notifyuser( socket, fromwho, fromwhere, ispm, "Couldn't add ladder admin: " + str(e) )
484			if command == "!ladderdeleteglobaladmin":
485				if not self.db.AccessCheck( -1, fromwho, Roles.Owner ):
486					self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
487					#log
488					return
489				if len(args) < 1:
490					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
491				else:
492					username = args[0]
493					try:
494						self.db.DeleteGlobalAdmin( username )
495					except:
496						self.notifyuser( socket, fromwho, fromwhere, ispm, "Couldn't delete global admin" )
497			if command == "!ladderdeleteladderadmin":
498				if not self.db.AccessCheck( -1, fromwho, Roles.GlobalAdmin ):
499					self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
500					#log
501					return
502				if len(args) < 2:
503					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
504				else:
505					ladderid = args[0]
506					username = args[1]
507					try:
508						self.db.DeleteLadderAdmin( ladderid, username )
509					except:
510						self.notifyuser( socket, fromwho, fromwhere, ispm, "Couldn't delete ladder admin" )
511			if command == "!ladderlistrankingalgos":
512				if len(args) > 0:
513					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
514				else:
515					self.notifyuser( socket, fromwho, fromwhere, ispm, GlobalRankingAlgoSelector.ListRegisteredAlgos() )
516			if command == "!laddersetrankingalgo":
517				if len(args) < 2:
518					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
519				else:
520					ladderid = args[0]
521					algoname = args[1]
522					try:
523						GlobalRankingAlgoSelector.GetInstance( algoname ) # algo unknonw -> excpetion raised
524						self.db.SetLadderRankingAlgo( ladderid, algoname )
525					except ElementNotFoundException, e:
526						self.notifyuser( socket, fromwho, fromwhere, ispm, "Couldn't set ranking algo: " + str(e) )
527			if command == "!ladderlistmatches":
528				if len(args) != 1:
529					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
530				else:
531					ladderid = args[0]
532					try:
533						matches = self.db.GetMatches( ladderid )
534						res = ''
535						for m in matches:
536							res += 'Match no. %d (%s)\n'%(m.id,m.date)
537						self.notifyuser( socket, fromwho, fromwhere, ispm, res )
538					except ElementNotFoundException, e:
539						self.notifyuser( socket, fromwho, fromwhere, ispm, "Error: " + str(e) )
540			if command == "!ladderdeletematch":
541				if len(args) != 2:
542					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
543				else:
544					ladderid = int(args[0])
545					match_id = int(args[1])
546					if not self.db.AccessCheck( ladderid, fromwho, Roles.LadderAdmin ):
547							self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
548								#log
549							return
550
551					try:
552						self.db.DeleteMatch( ladderid, match_id )
553					except ElementNotFoundException, e:
554						self.notifyuser( socket, fromwho, fromwhere, ispm, "Error: " + str(e) )
555			if command == "!ladderbanuserglobal":
556				if len(args) < 1:
557					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
558				else:
559					username = args[0]
560					if len(args) == 2:
561						t_fields = args[1].split(':')
562						if len( t_fields ) > 1:
563							days  = float(t_fields[0])
564							hours = float(t_fields[1])
565						else:
566							days = 0
567							hours = float(t_fields[0])
568						t_delta = timedelta( days=days, hours=hours )
569					else:
570						t_delta = timedelta.max
571					if not self.db.AccessCheck( -1, fromwho, Roles.GlobalAdmin ):
572							self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
573								#log
574							return
575					try:
576						self.db.BanPlayer( -1, username, t_delta )
577					except ElementNotFoundException, e:
578						self.notifyuser( socket, fromwho, fromwhere, ispm, "Error: " + str(e) )
579			if command == "!ladderunbanuserglobal":
580				if len(args) != 1:
581					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
582				else:
583					username = args[0]
584					if not self.db.AccessCheck( -1, fromwho, Roles.GlobalAdmin ):
585						self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
586							#log
587						return
588					try:
589						self.db.UnbanPlayer( username )
590					except ElementNotFoundException, e:
591						self.notifyuser( socket, fromwho, fromwhere, ispm, "Error: " + str(e) )
592			if command == "!ladderbanuser":
593				if len(args) < 2:
594					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
595				else:
596					ladderid = args[0]
597					username = args[1]
598					if len(args) == 3:
599						t_fields = args[2].split(':')
600						if len( t_fields ) > 1:
601							days  = float(t_fields[0])
602							hours = float(t_fields[1])
603						else:
604							days = 0
605							hours = float(t_fields[0])
606						t_delta = timedelta( days=days, hours=hours )
607					else:
608						t_delta = timedelta.max
609					if not self.db.AccessCheck( ladderid, fromwho, Roles.LadderAdmin ):
610							self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
611								#log
612							return
613					try:
614						self.db.BanPlayer( ladderid, username, t_delta )
615					except ElementNotFoundException, e:
616						self.notifyuser( socket, fromwho, fromwhere, ispm, "Error: " + str(e) )
617			if command == "!ladderunbanuser":
618				if len(args) < 2:
619					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
620				else:
621					ladderid = args[0]
622					username = args[1]
623					if not self.db.AccessCheck( ladderid, fromwho, Roles.LadderAdmin ):
624							self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
625								#log
626							return
627					try:
628						self.db.UnbanPlayer( username, ladderid )
629					except ElementNotFoundException, e:
630						self.notifyuser( socket, fromwho, fromwhere, ispm, "Error: " + str(e) )
631			if command == "!ladderlistbans":
632				if len(args) < 1:
633					ladderid = -1
634				else:
635					ladderid = args[0]
636				if not self.db.AccessCheck( ladderid, fromwho, Roles.LadderAdmin ):
637						self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
638							#log
639						return
640				try:
641					bans = self.db.GetBansPerLadder( ladderid )
642					msg = ''
643					s = self.db.sessionmaker() #not nice, but needed for lazy load?!?
644					s.add_all( bans )
645					for b in bans:
646						msg += str(b) + '\n'
647					self.notifyuser( socket, fromwho, fromwhere, ispm, msg )
648					s.close()
649				except ElementNotFoundException, e:
650					self.notifyuser( socket, fromwho, fromwhere, ispm, "Error: " + str(e) )
651					s.close()
652			if command == "!ladderclosewhenempty":
653				if not self.db.AccessCheck( -1, fromwho, Roles.GlobalAdmin ):
654					self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
655					#log
656					return
657				self.closewhenempty = True
658				if len(self.botstatus) == 0:
659					self.KillBot()
660			if command == "!ladderdisable":
661				if not self.db.AccessCheck( -1, fromwho, Roles.GlobalAdmin ):
662					self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
663					#log
664					return
665				self.enabled = False
666				self.updatestatus( socket )
667				self.notifyuser( socket, fromwho, fromwhere, ispm, "Ladder bot spawning is now disabled." )
668			if command == "!ladderenable":
669				if not self.db.AccessCheck( -1, fromwho, Roles.GlobalAdmin ):
670					self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
671					#log
672					return
673				self.enabled = True
674				self.updatestatus( socket )
675				self.notifyuser( socket, fromwho, fromwhere, ispm, "Ladder bot spawning is now enabled." )
676			if command == "!ladderrecalculateranks":
677				if len(args) != 1:
678					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
679				ladderid = int(args[0])
680				if not self.db.AccessCheck( ladderid, fromwho, Roles.LadderAdmin ):
681					self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
682					#log
683					return
684				else:
685					self.notifyuser( socket, fromwho, fromwhere, ispm, "Beginning to recalculate rankings." )
686					self.db.RecalcRankings(ladderid)
687					self.notifyuser( socket, fromwho, fromwhere, ispm, "Done recalculating the ranks." )
688			if command == "!laddermergeaccounts":
689				if len(args) < 2 or len(args) > 3:
690					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
691					return
692				if not self.db.AccessCheck( -1, fromwho, Roles.GlobalAdmin ):
693					self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
694					#log
695					return
696				else:
697					self.notifyuser( socket, fromwho, fromwhere, ispm, "Beginning to merge the accounts." )
698					if len(args) == 2:
699						answer = self.db.MergeAccounts( args[0], args[1] )
700					else:
701						answer = self.db.MergeAccounts( args[0], args[1], bool(args[2]) )
702					self.notifyuser( socket, fromwho, fromwhere, ispm, answer )
703
704			if command == "!ladderauth":
705				if len(args) < 1 or len(args) > 2:
706					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
707					return
708				else:
709					nick = fromwho
710					if len(args) == 2:
711						if not self.db.AccessCheck( -1, fromwho, Roles.GlobalAdmin ):
712							self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
713							#log
714							return
715						nick = args[1]
716					ok = self.db.SetPassword( nick, args[0] )
717					if ok:
718						self.notifyuser( socket, fromwho, fromwhere, ispm, "Password sucessfully set" )
719					else:
720						self.notifyuser( socket, fromwho, fromwhere, ispm, "Password setting failed" )
721				
722			if command == "!ladderopponent":
723				if len(args) != 1:
724					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid command syntax, check !ladderhelp for usage." )
725					return
726				ladderid = int(args[0])
727				if not self.db.AccessCheck( ladderid, fromwho, Roles.User ):
728					self.sayPermissionDenied( socket, command, fromwho, fromwhere, ispm )
729					#log
730					return
731				if not self.db.LadderExists( ladderid ):
732					self.notifyuser( socket, fromwho, fromwhere, ispm, "Invalid ladderID." )
733					return
734				userlist, ranks = GlobalRankingAlgoSelector.GetCandidateOpponents( fromwho, ladderid, self.db )
735				opponent_found = False
736				for user in userlist:
737					try:
738						userstatus = self.tsc.users[user]
739					except: # skip offline
740						continue
741					if userstatus.ingame:
742						continue
743					if userstatus.afk:
744						continue
745					opponent_found = True
746					self.notifyuser( socket, fromwho, fromwhere, ispm, ranks[user] )
747				if not opponent_found:
748					self.notifyuser( socket, fromwho, fromwhere, ispm, "No suitable candidates as opponent are available currently, try again later." )
749
750		except DbConnectionLostException, e:
751			self.notifyuser( socket, fromwho, fromwhere, ispm, "Database temporarily lost in processing your command, please try again" )
752			err = 'DbConnectionLostException: %s\nargs: %s\ncmd" %s\nwho: %s\nwhere" \n'%(e.getTrace(), args, command, fromwho,fromwhere )
753			self.mError( err )
754			self.saychannel( socket, 'ladder', err )
755
756	def oncommandfromserver(self,command,args,socket):
757		if command == "SAID" and len(args) > 2 and args[2].startswith("!"):
758			self.oncommandfromuser(args[1],args[0],False,args[2],args[3:],socket)
759		if command == "SAIDPRIVATE" and len(args) > 1 and args[1].startswith("!"):
760			self.oncommandfromuser(args[0],"PM",True,args[1],args[2:],socket)
761		if command == "FORCELEAVECHANNEL" and len(args) > 1:
762			if args[0] in self.channels:
763				self.channels.remove(args[0])
764				self.app.config["channelautojoinlist"] = ','.join(self.channels)
765				self.app.SaveConfig()
766		if command == "ADDUSER" and len(args) > 0:
767			name = args[0]
768			basebotname = self.app.config["nick"]
769			if name.startswith(basebotname):
770				name = name[len(basebotname):] # truncate prefix
771				if name.isdigit():
772					self.botstatus.append(int(name))
773			if len(args) > 2:
774				serveraccountid = int(args[3])
775				try: # if a player is already in the db, but lacks server_id, add it
776					self.db.AssignServerID( name, serveraccountid )
777				except ElementNotFoundException:
778					pass
779				try: # if player in the db with same server_id exists, rename it to the new nick
780					self.db.RenamePlayer( serveraccountid, name )
781				except ElementNotFoundException:
782					pass
783		if command == "REMOVEUSER" and len(args) > 0:
784			name = args[0]
785			basebotname = self.app.config["nick"]
786			if name.startswith(basebotname):
787				name = name[len(basebotname):] # truncate prefix
788				if name.isdigit():
789					self.botstatus.remove(int(name))
790					if self.closewhenempty:
791						if len(self.botstatus) == 0:
792							self.KillBot()
793		if command == "JOINEDBATTLE" and len(args) > 1:
794			name = args[1]
795			battleid = int(args[0])
796			basebotname = self.app.config["nick"]
797			if name.startswith(basebotname):
798				name = name[len(basebotname):] # truncate prefix
799				if name.isdigit():
800					number = int(name)
801					if number in self.botstatus:
802						if not battleid in self.battleswithbots:
803							self.battleswithbots.append(battleid)
804		if command == "LEFTBATTLE" and len(args) > 1:
805			name = args[1]
806			battleid = int(args[0])
807			basebotname = self.app.config["nick"]
808			if name.startswith(basebotname):
809				name = name[len(basebotname):] # truncate prefix
810				if name.isdigit():
811					number = int(name)
812					if number in self.botstatus:
813						if battleid in self.battleswithbots:
814							self.battleswithbots.remove(battleid)
815	def updatestatus(self,socket):
816		socket.send("MYSTATUS %i\n" % int(int(0)+int(not self.enabled)*2))
817	def onloggedin(self,socket):
818		self.updatestatus(socket)
819	def KillBot(self):
820		if platform.system() == "Windows":
821			handle = win32api.OpenProcess(1, 0, os.getpid())
822			win32api.TerminateProcess(handle, 0)
823		else:
824			os.kill(os.getpid(),signal.SIGKILL)