view orpg/networking/mplay_server_gui.py @ 98:95b5281e8d34 alpha

Traipse Alpha 'OpenRPG' {090925-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: Update forwards to the 090909-02 Server code that now works. New default Lobby Map, designed for Traipse. Feel free to change it. Updates to Server GUI: * Admin can Ban from Backend. * Prework to modify Ban List in back end. * Server GUI finds your Lobby Name * New users default as Lurker unless a Role is set New Addition to Chat Die Roll commands. Math Ordering. Ex. [(X+Y)dZ]. Currently does pairs only, no nesting either. Cleaner TraipseSuiteAttention portability and clean up in Main (Beta!) 01: Die Roll Commands addition removed in favor of Core code {090925-00}: Updates to Server GUI: *Admin can Modify Ban List and Un Ban users. New About Dialog. A more uniform About Dialog.
author sirebral
date Fri, 25 Sep 2009 06:16:37 -0500
parents 65c1604e7949
children 9314d63c0941
line wrap: on
line source

#!/usr/bin/env python
#
#   OpenRPG Server Graphical Interface
#        GNU General Public License
#

__appname__=' OpenRPG GUI Server v0.7 '
__version__='$Revision: 1.26 $'[11:-2]
__cvsinfo__='$Id: mplay_server_gui.py,v 1.26 2007/11/06 00:32:39 digitalxero Exp $'[5:-2]
__doc__="""OpenRPG Server Graphical Interface"""

import os
import sys
import time
import types
from orpg.dirpath import dir_struct
#import orpg.systempath looks old
from orpg.tools.validate import validate
from orpg.orpg_wx import *
import webbrowser
from threading import Thread
from meta_server_lib import post_server_data, remove_server
from mplay_server import mplay_server, server
from xml.dom import minidom
from orpg.orpgCore import component

# Constants ######################################
SERVER_RUNNING = 1
SERVER_STOPPED = 0
MENU_START_SERVER = wx.NewId()
MENU_STOP_SERVER = wx.NewId()
MENU_EXIT = wx.NewId()
MENU_REGISTER_SERVER = wx.NewId()
MENU_UNREGISTER_SERVER = wx.NewId()
MENU_START_PING_PLAYERS = wx.NewId()
MENU_STOP_PING_PLAYERS = wx.NewId()
MENU_PING_INTERVAL = wx.NewId()
### Alpha ###
MENU_MODIFY_BANLIST = wx.NewId()
#############

# Add our menu id's for our right click popup
MENU_PLAYER_BOOT = wx.NewId()
### Alpha ###
MENU_ADMIN_BAN = wx.NewId()
MENU_BAN_LIST = wx.NewId()
MENU_ADMIN_UNBAN = wx.NewId()
#############
MENU_PLAYER_CREATE_ROOM = wx.NewId()
MENU_PLAYER_SEND_MESSAGE = wx.NewId()
MENU_PLAYER_SEND_ROOM_MESSAGE = wx.NewId()
MENU_PLAYER_SEND_SERVER_MESSAGE = wx.NewId()

# Our new event type that gets posted from one
# thread to another
wxEVT_LOG_MESSAGE = wx.NewEventType()
wxEVT_FUNCTION_MESSAGE = wx.NewEventType()

# Our event connector -- wxEVT_LOG_MESSAGE
EVT_LOG_MESSAGE = wx.PyEventBinder(wxEVT_LOG_MESSAGE, 1)

# Our event connector -- wxEVT_FUNCTION_MESSAGE
EVT_FUNCTION_MESSAGE = wx.PyEventBinder(wxEVT_FUNCTION_MESSAGE, 1)

# Utils ##########################################
def format_bytes(b):
    f = ['b', 'Kb', 'Mb', 'Gb']
    i = 0
    while i < 3:
        if b < 1024: return str(b) + f[i]
        else: b = b/1024
        i += 1
    return str(b) + f[3]

# wxEVT_LOG_MESSAGE
# MessageLogEvent ###############################
class MessageLogEvent(wx.PyEvent):
    def __init__( self, message ):
        wx.PyEvent.__init__( self )
        self.SetEventType(wxEVT_LOG_MESSAGE)
        self.message = message

# wxEVT_TUPLE_MESSAGE
# MessageLogEvent ###############################
class MessageFunctionEvent(wx.PyEvent):
    def __init__( self, func, message ):
        wx.PyEvent.__init__( self )
        self.SetEventType(wxEVT_FUNCTION_MESSAGE)
        self.func = func
        self.message = message

# ServerConfig Object ############################
class ServerConfig:
    """ This class contains configuration
        setting used to control the server."""

    def __init__(self, owner ): 
        """ Loads default configuration settings."""
        validate.config_file("server_ini.xml", "default_server_ini.xml" ) 
        configDom = minidom.parse(dir_struct["user"] + 'server_ini.xml') 
        port = configDom.childNodes[0].childNodes[1].getAttribute('port')
        OPENRPG_PORT = 6774 if port == '' else int(port) #Pretty ugly, but I couldn't find the tag any other way.
        self.owner = owner

    def load_xml(self, xml):
        """ Load configuration from XML data.
            xml (xml) -- xml string to parse """
        pass

    def save_xml(self):
        """ Returns XML file representing
            the active configuration. """
        pass

# Server Monitor #################################

class ServerMonitor(Thread):
    """ Monitor thread for GameServer. """
    def __init__(self, cb, conf, name, pwd):
        """ Setup the server. """
        Thread.__init__(self)
        self.cb = cb
        self.conf = conf
        self.serverName = name
        self.bootPwd = pwd

    def log(self, mesg):
        if type(mesg) == types.TupleType:
            func, msg = mesg
            event = MessageFunctionEvent( func, msg )
        else: event = MessageLogEvent( mesg )
        wx.PostEvent( self.conf.owner, event )
        del event

    def run(self):
        """ Start the server. """
        self.server = mplay_server(self.log, self.serverName )
        self.server.initServer(bootPassword=self.bootPwd, reg="No")
        self.alive = 1
        while self.alive: time.sleep(3)

    def stop(self):
        """ Stop the server. """
        self.server.kill_server()
        self.alive = 0

# GUI Server #####################################
# Parent = notebook
# Main = GUI
class Connections(wx.ListCtrl):
    def __init__( self, parent, main ):
        wx.ListCtrl.__init__( self, parent, -1, wx.DefaultPosition, 
                            wx.DefaultSize, wx.LC_REPORT|wx.SUNKEN_BORDER|wx.EXPAND|wx.LC_HRULES )
        self.main = main

        ### Alpha ### Get Lobby Name
        validate.config_file("server_ini.xml", "default_server_ini.xml" ) 
        configDom = minidom.parse(dir_struct["user"] + 'server_ini.xml') 
        lobbyname = configDom.childNodes[0].getAttribute('lobbyname')
        #############

        self.roomList = { 0 : lobbyname }
        self._imageList = wx.ImageList( 16, 16, False )
        img = wx.Image(dir_struct["icon"]+"player.gif", wx.BITMAP_TYPE_GIF).ConvertToBitmap()
        self._imageList.Add( img )
        img = wx.Image(dir_struct["icon"]+"player-whisper.gif", wx.BITMAP_TYPE_GIF).ConvertToBitmap()
        self._imageList.Add( img )
        self.SetImageList( self._imageList, wx.IMAGE_LIST_SMALL )

        # Set The columns
        self.InsertColumn(0, "ID")
        self.InsertColumn(1, "Player")
        self.InsertColumn(2, "Status")
        self.InsertColumn(3, "Room")
        self.InsertColumn(4, "Version")
        self.InsertColumn(5, "Role")
        self.InsertColumn(6, "IP")
        self.InsertColumn(7, "Ping")

        # Set the column widths
        self.AutoAjust()

        # Build our pop up menu to do cool things with the players in the list
        self.menu = wx.Menu()
        self.menu.SetTitle( "Player Menu" )
        self.menu.Append( MENU_PLAYER_BOOT, "Boot Player" )
        self.menu.Append( MENU_ADMIN_BAN, 'Ban Player' )
        self.menu.AppendSeparator()
        self.menu.Append( MENU_PLAYER_SEND_MESSAGE, "Send Player Message" )
        self.menu.Append( MENU_PLAYER_SEND_ROOM_MESSAGE, "Send Room Message" ) 
        self.menu.Append( MENU_PLAYER_SEND_SERVER_MESSAGE, "Broadcast Server Message" )

        # Associate our events
        self.Bind(wx.EVT_RIGHT_DOWN, self.OnPopupMenu)
        self.Bind(wx.EVT_MENU, self.OnPopupMenuItem, id=MENU_PLAYER_BOOT)
        self.Bind(wx.EVT_MENU, self.OnPopupMenuItem, id=MENU_ADMIN_BAN)
        self.Bind(wx.EVT_MENU, self.OnPopupMenuItem, id=MENU_PLAYER_SEND_MESSAGE)
        self.Bind(wx.EVT_MENU, self.OnPopupMenuItem, id=MENU_PLAYER_SEND_ROOM_MESSAGE)
        self.Bind(wx.EVT_MENU, self.OnPopupMenuItem, id=MENU_PLAYER_SEND_SERVER_MESSAGE)

    def add(self, player):
        i = self.InsertImageStringItem( 0, player["id"], 0 )
        self.SetStringItem( i, 1, self.stripHtml( player["name"] ) )
        self.SetStringItem( i, 2, "NEW" )
        self.SetStringItem( i, 3, self.roomList[0] )
        self.SetStringItem( i, 4, self.stripHtml( player["version"] ) )
        self.SetStringItem( i, 5, 'Lurker' if self.stripHtml( player["role"] ) == '' else self.stripHtml( player["role"] ))
        self.SetStringItem( i, 6, self.stripHtml( player["ip"] ) )
        self.SetStringItem (i, 7, "PING" )
        self.SetItemData( i, int(player["id"]) )
        self.AutoAjust()

    def remove(self, id):
        i = self.FindItemData( -1, int(id) )
        self.DeleteItem( i )
        self.AutoAjust()

    def AutoAjust(self):
        self.SetColumnWidth(0, -1)
        self.SetColumnWidth(1, -1)
        self.SetColumnWidth(2, -1)
        self.SetColumnWidth(3, -1)
        self.SetColumnWidth(4, -1)
        self.SetColumnWidth(5, -1)
        self.SetColumnWidth(6, -1)
        self.SetColumnWidth(7, -1)
        self.Refresh()

    def update(self, player):
        i = self.FindItemData( -1, int(player["id"]) )
        if i > -1:
            self.SetStringItem(i, 1, self.stripHtml(player["name"]))
            self.SetStringItem(i, 2, self.stripHtml(player["status"]))
            self.SetStringItem(i, 5, 'Lurker' if self.stripHtml(player["role"]) == '' else self.stripHtml(player["role"]))
            self.AutoAjust()
        else: self.add(player)

    def updateRoom( self, data ):
        (room, room_id, player) = data
        i = self.FindItemData( -1, int(player) )
        if player > 0: self.SetStringItem( i, 3, room )
        self.AutoAjust()

    def setPlayerRole( self, id, role ):
        i = self.FindItemData( -1, int(id) )
        self.SetStringItem( i, 5, role )
        self.AutoAjust

    def stripHtml( self, name ):
        ret_string = ""
        x = 0
        in_tag = 0
        for x in range( len(name) ):
            if name[x] == "<" or name[x] == ">" or in_tag == 1 :
                if name[x] == "<": in_tag = 1
                elif name[x] == ">": in_tag = 0
                else: pass
            else: ret_string = ret_string + name[x]
        return ret_string

    # When we right click, cause our popup menu to appear
    def OnPopupMenu( self, event ):
        pos = wx.Point( event.GetX(), event.GetY() )
        (item, flag) = self.HitTest( pos )
        if item > -1:
            self.selectedItem = item
            self.PopupMenu( self.menu, pos )

    # Process the events associated with our popup menu
    def OnPopupMenuItem( self, event ):
        # if we are not running, the player list is empty anyways
        if self.main.STATUS == SERVER_RUNNING:
            menuItem = event.GetId()
            playerID = str( self.GetItemData( self.selectedItem ) )
            room = str(self.GetItem((int(playerID)-1), 3).GetText())
            idList = self.main.server.server.groups
            for r in self.roomList:
                if room == self.roomList[r]: groupID = r
                else: groupID = 0
            if menuItem == MENU_PLAYER_BOOT:
                print "booting player: ", playerID
                self.main.server.server.del_player( playerID, groupID )
                self.main.server.server.check_group( playerID, groupID )
                self.remove( playerID )
            ### Alpha ###
            elif menuItem == MENU_ADMIN_BAN:
                message = 'Banishment'
                BanMsg = wx.TextEntryDialog( self, "Enter A Message To Send:",
                                                 "Ban Message", message, wx.OK|wx.CANCEL|wx.CENTRE )
                if BanMsg.ShowModal() == wx.ID_OK: message = BanMsg.GetValue()
                else: message = ''
                Silent = wx.MessageDialog(None, 'Silent Ban?', 'Question', 
                    wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
                if Silent.ShowModal() == wx.ID_YES: silent = 1
                else: silent = 0
                self.main.server.server.admin_ban(playerID, message, silent)
                self.remove( playerID )
            ###############
            elif menuItem == MENU_PLAYER_SEND_MESSAGE:
                print "send a message..."
                msg = self.GetMessageInput( "Send a message to player" )
                if len(msg): self.main.server.server.send( msg, playerID, str(groupID) )
            #Leave this in for now.
            elif menuItem == MENU_PLAYER_SEND_ROOM_MESSAGE:
                print "Send message to room..."
                msg = self.GetMessageInput( "Send message to room of this player")
                if len(msg): self.main.server.server.send_to_group('0', str(groupID), msg )
            elif menuItem == MENU_PLAYER_SEND_SERVER_MESSAGE:
                print "broadcast a message..."
                msg = self.GetMessageInput( "Broadcast Server Message" )
                # If we got a message back, send it
                if len(msg): self.main.server.server.broadcast( msg )

    def GetMessageInput( self, title ):
        prompt = "Please enter the message you wish to send:"
        msg = wx.TextEntryDialog(self, prompt, title)
        msg.ShowModal()
        msg.Destroy()
        return msg.GetValue()

class ServerGUI(wx.Frame):
    STATUS = SERVER_STOPPED
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size = (760, 560) )
        if wx.Platform == '__WXMSW__': icon = wx.Icon( dir_struct["icon"]+'WAmisc9.ico', wx.BITMAP_TYPE_ICO )
        else: icon = wx.Icon( dir_struct["icon"]+'connect.gif', wx.BITMAP_TYPE_GIF )
        self.SetIcon(icon)
        self.serverName = "Server Name"
        self.bootPwd = ""

        # Register our events to process -- notice the custom event handler
        self.Bind(wx.EVT_CLOSE, self.OnExit)
        self.Bind(EVT_LOG_MESSAGE, self.OnLogMessage)
        self.Bind(EVT_FUNCTION_MESSAGE, self.OnFunctionMessage)

        # Creat GUI
        self.build_menu()
        self.build_body()
        self.build_status()

        ### Alpha ###
        # Ban List Dialog
        self.BanListDialog = BanListDialog(self)
        #############

        # Server Callbacks
        cb = {}
        cb["log"]        = self.Log
        cb["connect"]    = self.OnConnect  ##Fixed!!
        cb["disconnect"] = self.OnDisconnect
        cb["update"]     = self.OnUpdatePlayer
        cb["data_recv"]  = self.OnDataRecv
        cb["data_sent"]  = self.OnDataSent
        cb["create_group"] = self.OnCreateGroup
        cb["delete_group"] = self.OnDeleteGroup
        cb["join_group"] = self.OnJoinGroup
        cb["role"] = self.OnSetRole
        self.callbacks = cb

        # Misc.
        self.conf = ServerConfig(self)
        self.total_messages_received = 0
        self.total_data_received = 0
        self.total_messages_sent = 0
        self.total_data_sent = 0

    """ Build GUI """

    def build_menu(self):
        """ Build the GUI menu. """
        self.mainMenu = wx.MenuBar()

        # File Menu
        menu = wx.Menu()
        menu.Append( MENU_START_SERVER, 'Start', 'Start server.')
        self.Bind(wx.EVT_MENU, self.OnStart, id=MENU_START_SERVER)
        menu.Append( MENU_STOP_SERVER, 'Stop', 'Shutdown server.')
        self.Bind(wx.EVT_MENU, self.OnStop, id=MENU_STOP_SERVER)
        menu.AppendSeparator()
        menu.Append( MENU_EXIT, 'E&xit', 'Exit application.')
        self.Bind(wx.EVT_MENU, self.OnExit, id=MENU_EXIT)
        self.mainMenu.Append(menu, '&Server')

        # Registration Menu
        menu = wx.Menu()
        menu.Append( MENU_REGISTER_SERVER, 'Register', 'Register with OpenRPG server directory.')
        self.Bind(wx.EVT_MENU, self.OnRegister, id=MENU_REGISTER_SERVER)
        menu.Append( MENU_UNREGISTER_SERVER, 'Unregister', 'Unregister from OpenRPG server directory.')
        self.Bind(wx.EVT_MENU, self.OnUnregister, id=MENU_UNREGISTER_SERVER)
        self.mainMenu.Append( menu, '&Registration' )

        # Server Configuration Menu
        menu = wx.Menu()
        menu.Append( MENU_BAN_LIST, 'Ban List', 'Modify Ban List.' )
        self.Bind(wx.EVT_MENU, self.ModifyBanList, id=MENU_BAN_LIST)
        menu.Append( MENU_START_PING_PLAYERS, 'Start Ping', 'Ping players to validate remote connection.' )
        self.Bind(wx.EVT_MENU, self.PingPlayers, id=MENU_START_PING_PLAYERS)
        menu.Append( MENU_STOP_PING_PLAYERS, 'Stop Ping', 'Stop validating player connections.' )
        self.Bind(wx.EVT_MENU, self.StopPingPlayers, id=MENU_STOP_PING_PLAYERS)
        menu.Append( MENU_PING_INTERVAL, 'Ping Interval', 'Change the ping interval.' )
        self.Bind(wx.EVT_MENU, self.ConfigPingInterval, id=MENU_PING_INTERVAL)
        self.mainMenu.Append( menu, '&Configuration' )

        self.SetMenuBar( self.mainMenu )

        self.mainMenu.Enable( MENU_STOP_SERVER, False )
        self.mainMenu.Enable( MENU_REGISTER_SERVER, False )
        self.mainMenu.Enable( MENU_UNREGISTER_SERVER, False )

        # Disable the ping menu items
        self.mainMenu.Enable( MENU_START_PING_PLAYERS, False )
        self.mainMenu.Enable( MENU_STOP_PING_PLAYERS, False )
        self.mainMenu.Enable( MENU_PING_INTERVAL, False )

    def build_body(self):
        """ Create the ViewNotebook and logger. """
        splitter = wx.SplitterWindow(self, -1, style=wx.NO_3D | wx.SP_3D)
        nb = wx.Notebook( splitter, -1 )
        self.conns = Connections( nb, self )
        nb.AddPage( self.conns, "Players" )

        #Not sure why this is Remarked TaS - Sirebral
        #nb.AddPage( self.conns, "Rooms" )
        #self.msgWindow = HTMLMessageWindow( nb )
        #nb.AddPage( self.msgWindow, "Messages" )

        log = wx.TextCtrl(splitter, -1, style=wx.TE_MULTILINE | wx.TE_READONLY | wx.HSCROLL)
        wx.Log.SetActiveTarget( wx.LogTextCtrl(log) )
        splitter.SplitHorizontally(nb, log, 400)
        splitter.SetMinimumPaneSize(40)
        self.nb = nb
        self.log = log

    def build_status(self):
        """ Create status bar and set defaults. """
        sb = wx.StatusBar(self, -1)
        sb.SetFieldsCount(5)
        sb.SetStatusWidths([-1, 115, 115, 65, 200])
        sb.SetStatusText("Sent: 0", 1)
        sb.SetStatusText("Recv: 0", 2)
        sb.SetStatusText("Stopped", 3)
        sb.SetStatusText("Unregistered", 4)
        self.SetStatusBar(sb)
        self.sb = sb

    def show_error(self, mesg, title = "Error"):
        """ Display an error.
            mesg (str) -- error message to display
            title (str) -- title of window
        """
        dlg = wx.MessageDialog(self, mesg, title, wx.OK | wx.ICON_EXCLAMATION)
        dlg.ShowModal()
        dlg.Destroy()


    # Event handler for out logging event
    def OnLogMessage( self, event ):
        self.Log( event.message )

    # Event handler for out logging event
    def OnFunctionMessage( self, event ):
        self.callbacks[event.func]( event.message )

    ### Server Callbacks #####################################
    def Log(self, log):
        wx.LogMessage(str(log))

    def OnConnect(self, player):
        self.conns.add(player)

    def OnDisconnect(self, id):
        self.conns.remove(id)

    def OnUpdatePlayer(self, data):
        self.conns.update(data)

    def OnDataSent(self, bytes):
        self.total_messages_sent += 1
        self.total_data_sent += bytes
        self.sb.SetStatusText("Sent: %s (%d)" % (format_bytes(self.total_data_sent), self.total_messages_sent), 1)

    def OnDataRecv(self, bytes):
        self.total_messages_received += 1
        self.total_data_received += bytes
        self.sb.SetStatusText("Recv: %s (%d)" % (format_bytes(self.total_data_received), self.total_messages_received), 2)

    def OnCreateGroup( self, data ):
        room_id = data[1]
        name = data[0]
        self.conns.roomList[room_id] = name
        (room, room_id, player) = data
        self.conns.updateRoom(data)

    def OnDeleteGroup( self, data ):
        (room_id, player) = data
        del self.conns.roomList[room_id]

    def OnJoinGroup( self, data ):
        self.conns.updateRoom( data )

    def OnSetRole( self, data ):
        (id, role) = data
        self.conns.setPlayerRole( id, role )

    ### Misc. ################################################
    def OnStart(self, event = None):
        """ Start server. """
        if self.STATUS == SERVER_STOPPED:
            # see if we already have name specified 
            try:
                validate.config_file( "server_ini.xml", "default_server_ini.xml" ) 
                configDom = minidom.parse(dir_struct["user"] + 'server_ini.xml') 
                configDom.normalize() 
                configDoc = configDom.documentElement 
                if configDoc.hasAttribute("name"): self.serverName = configDoc.getAttribute("name")
            except: pass 
            if self.serverName == '':
                self.serverName = 'Server Name'
                serverNameEntry = wx.TextEntryDialog( self, "Please Enter The Server Name You Wish To Use:",
                                                 "Server's Name", self.serverName, wx.OK|wx.CANCEL|wx.CENTRE )
                if serverNameEntry.ShowModal() == wx.ID_OK: self.serverName = serverNameEntry.GetValue()
            # see if we already have password specified 
            try: 
                validate.config_file( "server_ini.xml", "default_server_ini.xml" ) 
                configDom = minidom.parse(dir_struct["user"] + 'server_ini.xml') 
                configDom.normalize() 
                configDoc = configDom.documentElement 
                if configDoc.hasAttribute("admin"): self.bootPwd = configDoc.getAttribute("admin") 
                elif configDoc.hasAttribute("boot"): self.bootPwd = configDoc.getAttribute("boot") 
            except: pass 
            if self.bootPwd == '': 
                serverPasswordEntry = wx.TextEntryDialog(self, 
                                            "Please Enter The Server Admin Password:", "Server's Password", 
                                            self.bootPwd, wx.OK|wx.CANCEL|wx.CENTRE)
                if serverPasswordEntry.ShowModal() == wx.ID_OK: self.bootPwd = serverPasswordEntry.GetValue()
            if len(self.serverName):
                wx.BeginBusyCursor()
                self.server = ServerMonitor(self.callbacks, self.conf, self.serverName, self.bootPwd)
                self.server.start()
                self.STATUS = SERVER_RUNNING
                self.sb.SetStatusText("Running", 3)
                self.SetTitle(__appname__ + "- (running) - (unregistered)")
                self.mainMenu.Enable( MENU_START_SERVER, False )
                self.mainMenu.Enable( MENU_STOP_SERVER, True )
                self.mainMenu.Enable( MENU_REGISTER_SERVER, True )
                wx.EndBusyCursor()
            else: self.show_error("Server is already running.", "Error Starting Server")

    def OnStop(self, event = None):
        """ Stop server. """
        if self.STATUS == SERVER_RUNNING:
            self.OnUnregister()
            self.server.stop()
            self.STATUS = SERVER_STOPPED
            self.sb.SetStatusText("Stopped", 3)
            self.SetTitle(__appname__ + "- (stopped) - (unregistered)")
            self.mainMenu.Enable( MENU_STOP_SERVER, False )
            self.mainMenu.Enable( MENU_START_SERVER, True )
            self.mainMenu.Enable( MENU_REGISTER_SERVER, False )
            self.mainMenu.Enable( MENU_UNREGISTER_SERVER, False )
            self.conns.DeleteAllItems()

    def OnRegister(self, event = None):
        """ Call into mplay_server's register() function.
            This will begin registerThread(s) to keep server
            registered with configured metas
        """
        if len( self.serverName ):
            wx.BeginBusyCursor()
            self.server.server.register(self.serverName)
            self.sb.SetStatusText( ("%s" % (self.serverName)), 4 )
            self.mainMenu.Enable( MENU_REGISTER_SERVER, False )
            self.mainMenu.Enable( MENU_UNREGISTER_SERVER, True )
            self.mainMenu.Enable( MENU_STOP_SERVER, False )
            self.SetTitle(__appname__ + "- (running) - (registered)")
            wx.EndBusyCursor()

    def OnUnregister(self, event = None):
        """ Call into mplay_server's unregister() function.
            This will kill any registerThreads currently running
            and result in the server being de-listed
            from all metas
        """
        wx.BeginBusyCursor()
        self.server.server.unregister()
        self.sb.SetStatusText( "Unregistered", 4 )
        self.mainMenu.Enable( MENU_UNREGISTER_SERVER, False )
        self.mainMenu.Enable( MENU_REGISTER_SERVER, True )
        self.mainMenu.Enable( MENU_STOP_SERVER, True )
        self.SetTitle(__appname__ + "- (running) - (unregistered)")
        wx.EndBusyCursor()

    ### Alpha ###
    def ModifyBanList(self, event):
        if self.BanListDialog.IsShown() == True: self.BanListDialog.Hide()
        else: self.BanListDialog.Show()
    #############

    def PingPlayers( self, event = None ):
        "Ping all players that are connected at a periodic interval, detecting dropped connections."
        wx.BeginBusyCursor()
        wx.Yield()
        wx.EndBusyCursor()

    def StopPingPlayers( self, event = None ):
        "Stop pinging connected players."

    def ConfigPingInterval( self, event = None ):
        "Configure the player ping interval.  Note that all players are pinged on a single timer."

    def OnExit(self, event = None):
        """ Quit the program. """
        self.OnStop()
        self.BanListDialog.Destroy() ### Alpha ###
        wx.CallAfter(self.Destroy)

### Alpha ###
class BanListDialog(wx.Frame):
    def __init__(self, parent):
        super(BanListDialog, self).__init__(parent, -1, "Ban List")
        icon = wx.Icon(dir_struct["icon"]+'noplayer.gif', wx.BITMAP_TYPE_GIF)
        self.SetIcon( icon )
        self.BanList = wx.ListCtrl(self, wx.ID_ANY, style=wx.LC_SINGLE_SEL|wx.LC_REPORT|wx.LC_HRULES)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.BanList, 1, wx.EXPAND)
        self.BuildList()
        self.SetSizer(sizer)
        self.SetAutoLayout(True)
        self.SetSize((300, 175))
        self.Bind(wx.EVT_CLOSE, self.Min) 
        self.Min(None)

        # Ban List Dialog Pop Up Menu, more can be added
        self.menu = wx.Menu()
        self.menu.SetTitle( "Modify Ban List" )
        self.menu.Append( MENU_ADMIN_UNBAN, "Un-Ban Player" )

        # Even Association
        self.BanList.Bind(wx.EVT_RIGHT_DOWN, self.BanPopupMenu)
        self.Bind(wx.EVT_MENU, self.BanPopupMenuItem, id=MENU_ADMIN_UNBAN)

    # When we right click, cause our popup menu to appear
    def BanPopupMenu( self, event ):
        pos = wx.Point( event.GetX(), event.GetY() )
        (item, flag) = self.BanList.HitTest( pos )
        if item > -1:
            self.selectedItem = item
            self.PopupMenu( self.menu, pos )

    def BanPopupMenuItem( self, event):
        menuItem = event.GetId()
        player = str(self.BanList.GetItemData(self.selectedItem))
        playerIP = str(self.BanList.GetItem((int(player)), 1).GetText())
        if menuItem == MENU_ADMIN_UNBAN:
            server.admin_unban(playerIP)
            self.BanList.DeleteItem(self.BanList.GetItemData(self.selectedItem))
            self.BanList.Refresh()   

    def BuildList(self):
        # Build Dialog Columns
        self.BanList.ClearAll()
        self.BanList.InsertColumn(0, "User Name")
        self.BanList.InsertColumn(1, "IP")

        validate.config_file("ban_list.xml", "default_ban_list.xml" ) 
        configDom = minidom.parse(dir_struct["user"] + 'ban_list.xml')
        ban_dict = {}
        for element in configDom.getElementsByTagName('banned'):
            player = element.getAttribute('name').replace("&", "&amp;").replace("<", "&lt;").replace('"', "&quot;").replace(">", "&gt;")
            playerIP = element.getAttribute('ip')
            ban_dict[player] = playerIP
        for key in ban_dict:
            i = self.BanList.InsertImageStringItem( 0, key, 0 )
            self.BanList.SetStringItem(i, 1, ban_dict[key])
            self.BanList.RefreshItem(i)
        self.AutoAdjust()

    def AutoAdjust(self):
        self.BanList.SetColumnWidth(0, -1)
        self.BanList.SetColumnWidth(1, -1)
        self.BanList.Refresh()

    def Min(self, evt):
        self.Hide()
###############

class ServerGUIApp(wx.App):
    def OnInit(self):
        # Make sure our image handlers are loaded before we try to display anything
        wx.InitAllImageHandlers()
        self.splash = wx.SplashScreen(wx.Bitmap(dir_struct["icon"]+'splash.gif'),
                              wx.SPLASH_CENTRE_ON_SCREEN|wx.SPLASH_TIMEOUT,
                              2000,
                              None)
        self.splash.Show(True)
        wx.Yield()
        wx.CallAfter(self.AfterSplash)
        return True

    def AfterSplash(self):
        self.splash.Close(True)
        frame = ServerGUI(None, -1, __appname__ + "- (stopped) - (unregistered)")
        frame.Show(True)
        frame.Raise()
        self.SetTopWindow(frame)

class HTMLMessageWindow(wx.html.HtmlWindow):
    "Widget used to present user to admin messages, in HTML format, to the server administrator"
    # Init using the derived from class
    def __init__( self, parent ):
        wx.html.HtmlWindow.__init__( self, parent )
    def OnLinkClicked( self, ref ):
        "Open an external browser to resolve our About box links!!!"
        href = ref.GetHref()
        webbrowser.open( href )

if __name__ == '__main__':
    app = ServerGUIApp(0)
    app.MainLoop()