Attribute VB_Name = "WinSockLib"
Option Explicit

Private Declare Function CreateWindowEx Lib "user32" Alias "CreateWindowExA" (ByVal dwExStyle As Long, ByVal lpClassName As String, ByVal lpWindowName As String, ByVal dwStyle As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hWndParent As Long, ByVal hMenu As Long, ByVal hInstance As Long, lpParam As Any) As Long
Private Declare Function DestroyWindow Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function WSAAsyncSelect Lib "wsock32.dll" (ByVal S As Long, ByVal hWnd As Long, ByVal wMsg As Long, ByVal lEvent As Long) As Long
Private Declare Function WSAStartup Lib "wsock32.dll" (ByVal wVR As Long, lpWSAD As WSAdata) As Long
Private Declare Function WSACleanup Lib "wsock32.dll" () As Long
Private Declare Function gethostbyname Lib "wsock32.dll" (ByVal host_name As String) As Long
Private Declare Function bind Lib "wsock32.dll" (ByVal S As Long, addr As sockaddr, ByVal namelen As Long) As Long
Private Declare Function closesocket Lib "wsock32.dll" (ByVal S As Long) As Long
Private Declare Function htons Lib "wsock32.dll" (ByVal hostshort As Long) As Integer
Private Declare Function inet_addr Lib "wsock32.dll" (ByVal CP As String) As Long
Private Declare Function recvfrom Lib "wsock32.dll" (ByVal S As Long, buf As Any, ByVal buflen As Long, ByVal flags As Long, from As sockaddr, fromlen As Long) As Long
Private Declare Function sendto Lib "wsock32.dll" (ByVal S As Long, buf As Any, ByVal buflen As Long, ByVal flags As Long, to_addr As sockaddr, ByVal tolen As Long) As Long
Private Declare Function Socket Lib "wsock32.dll" Alias "socket" (ByVal af As Long, ByVal s_type As Long, ByVal protocol As Long) As Long

Public Type sockaddr
    sin_family          As Integer
    sin_port            As Integer
    sin_addr            As Long
    sin_zero            As String * 8
End Type

Public Type SocketData
    Remote              As sockaddr
    SockID              As Long
End Type

Private Type WSAdata
    wVersion            As Integer
    wHighVersion        As Integer
    szDescription       As String * 257
    szSystemStatus      As String * 129
    iMaxSockets         As Integer
    iMaxUdpDg           As Integer
    lpVendorInfo        As Long
End Type

Private OldWndProc      As Long
Private WSAdata         As WSAdata
Private sockaddr        As sockaddr
Private MyHWnd          As Long
Public MySock           As SocketData

Private Const AF_INET = 2
Private Const FD_READ = &H1
Private Const INADDR_NONE = &HFFFF
Private Const INADDR_ANY = &H0
Private Const IPPROTO_UDP = 17
Private Const SOCK_STREAM = 1
Private Const SOCK_DGRAM = 2
Private Const PF_INET = 2
Private Const WS_POPUP = &H80000000
Private Const GWL_WNDPROC = -4

Public Sub AlertPlayers(ServerID As Integer, Message As String)
    Dim I As Integer

    For I = 1 To ServerList(ServerID).TotalPlayers
        If ServerList(ServerID).pList(I).YellNewbies = True Then
            SendArena ServerID, ServerList(ServerID).pList(I).UserID, Message
        End If
    Next
End Sub

Public Sub LoadChannels(ServerID As Integer, PlayerID As Integer, UnParsed As String)
    Dim O As String, S As String, I As Integer

    With ServerList(ServerID).pList(PlayerID)
        S = UnParsed
        If S = "" Then .TotalChannels = 0: Exit Sub

        Do
            O = LParse(S, ",")
            If O <> "" Then
                If I >= 9 Then Exit Do
                I = I + 1
                .ChannelName(I) = O
            Else
                If I >= 9 Then Exit Do
                I = I + 1
                .ChannelName(I) = S
            End If
            S = RParse(S, ",")
        Loop While S <> ""

        .TotalChannels = I
    End With
End Sub

'Which zone is he in?
Public Function GetLocation(Name As String) As String
    Dim x As Integer, y As Integer

    For x = 1 To TotalServers
        For y = 1 To ServerList(x).TotalPlayers
            If LCase(Name) = LCase(TrimZero(ServerList(x).pList(y).PlayerName)) Then
                GetLocation = ServerList(x).ServerName
                Exit Function
            End If
        Next
    Next

    GetLocation = ""
End Function

'Broadcast an arena message to all zones on the data server
Public Sub MessageBroadcast(Message As String)
    Dim x As Integer

    For x = 1 To TotalServers
        UDPSend ServerList(x).Remote, Chr(0) + Chr(3) + NextSessionID(x) + Chr(3) + Chr(184) + Chr(11) + Chr(0) + Chr(0) + Chr(2) + Chr(0) + Message + Chr(0)
    Next
End Sub

'Broadcast an arena message to one zone on the data server
Public Sub PrivateBroadcast(ServerID As Long, Message As String)
    UDPSend ServerList(ServerID).Remote, Chr(0) + Chr(3) + NextSessionID(CInt(ServerID)) + Chr(3) + Chr(184) + Chr(11) + Chr(0) + Chr(0) + Chr(2) + Chr(0) + Message + Chr(0)
End Sub

'Broadcast an arena message to all BanOps on the data server
Public Sub BroadcastBanOp(Message As String)
    Dim x As Integer, y As Integer

    For x = 1 To TotalServers
        With ServerList(x)
            For y = 1 To .TotalPlayers
                If .pList(y).Op(LEVEL.Ban) = True Then Call SendArena(x, .pList(y).UserID, Message)
            Next
        End With
    Next
End Sub

'Broadcast a chat message to everyone on the channel
Public Sub BroadcastChat(SourceServer As Integer, Sender As Integer, ChannelString As String, Message As String)
    Dim x As Integer, y As Long, Z As Long, Channel As Integer

    Select Case Asc(ChannelString)
        Case 0: Channel = 1
        Case Else
            Channel = Asc(ChannelString) - 48
    End Select

    If Channel > ServerList(SourceServer).pList(Sender).TotalChannels Or Channel <= 0 Then Exit Sub

    For x = 1 To TotalServers
        For y = 1 To ServerList(x).TotalPlayers
            If y <> Sender Or x <> SourceServer Then
                For Z = 1 To ServerList(x).pList(y).TotalChannels
                    If LCase(ServerList(SourceServer).pList(Sender).ChannelName(Channel)) = LCase(ServerList(x).pList(y).ChannelName(Z)) Then
                        Call SendChat(x, ServerList(SourceServer).pList(Sender).PlayerName, ServerList(x).pList(y).UserID, Z, Message)
                    End If
                Next
            End If
        Next
    Next
End Sub

'List chatters
Public Sub SendChatters(ServerID As Integer, SenderID As Integer)
    Dim x As Long, y As Long, Z As Long, I As Integer, S As String

    With ServerList(ServerID).pList(SenderID)
        If .TotalChannels = 0 Then
            SendArena ServerID, .UserID, "No chat channel"
            Exit Sub
        End If

        For I = 1 To .TotalChannels
            S = CStr(I) + " -> " + .ChannelName(I) + ": "
            For x = 1 To TotalServers
                For y = 1 To ServerList(x).TotalPlayers
                    For Z = 1 To ServerList(x).pList(y).TotalChannels
                        If LCase(.ChannelName(I)) = LCase(ServerList(x).pList(y).ChannelName(Z)) Then
                            S = S + ServerList(x).pList(y).PlayerName + ","
                        End If
                    Next
                Next
            Next
            SendArena ServerID, .UserID, Left(S, Len(S) - 1)
        Next
    End With
End Sub

'Send a private arena message to one player only
Public Sub SendArena(ServerID As Integer, PlayerIndex As Long, Message As String)
    UDPSend ServerList(ServerID).Remote, Chr(0) + Chr(3) + NextSessionID(ServerID) + Chr(9) + GetString(PlayerIndex) + Message + Chr(0)
End Sub

'Send a chat message
Public Sub SendChat(ServerID As Integer, SourceName As String, TargetID As Long, DestChannel As Long, Message As String)
    UDPSend ServerList(ServerID).Remote, Chr(0) + Chr(3) + NextSessionID(ServerID) + Chr(10) + GetString(TargetID) + Chr(DestChannel) + TrimZero(SourceName) + "> " + Message
End Sub

'Event from WindowProc()
Public Sub OnRecv(Sender As sockaddr, Message As String)
    On Error GoTo ErrHandler
    Dim ServerID As Integer, I As Integer, User As String, L As Long, S As String

    ServerID = getServerID(Sender)
    If ServerID = 0 Then
        'The server is not logged in
        If Left(Message, 2) = Chr(0) + Chr(1) And Right(Message, 2) = Chr(1) + Chr(0) Then
            'Yes, I'm a billing server
            UDPSend Sender, Chr(0) + Chr(2) + mID(Message, 3, 4)
        ElseIf Left(Message, 2) = Chr(0) + Chr(3) Then
            'A Game Server wants to connect; ACK and Check Login

            If GetLong(mID(Message, 16, 4)) = 0 Then Exit Sub

            Select Case GetProfileString("Zones", CStr(GetLong(mID(Message, 16, 4))))
                Case ""
                    'Unknown server
                    If BillingSettings.AllowNewZones = 1 Then
                        UDPSend Sender, Chr(0) + Chr(4) + mID(Message, 3, 4)
                        NewServer Sender, TrimZero(mID(Message, 20)), GetLong(mID(Message, 16, 4))
                        SetProfile "Zones", CStr(GetLong(mID(Message, 16, 4))), TrimZero(mID(Message, 148, 24))
                        AddDebug TrimZero(mID(Message, 20)) + "(" + CStr(GetLong(mID(Message, 16, 4))) + ") - Unregistered zone: Added and Connected"
                    Else
                        UDPSend Sender, Chr(0) + Chr(7)
                        AddDebug TrimZero(mID(Message, 20)) + "(" + CStr(GetLong(mID(Message, 16, 4))) + ") - Unregistered zone: Booted"
                    End If
                Case TrimZero(mID(Message, 148, 24))
                    'Valid password
                    UDPSend Sender, Chr(0) + Chr(4) + mID(Message, 3, 4)
                    For I = 1 To TotalServers
                        If ServerList(I).ScoreID = GetLong(mID(Message, 16, 4)) Then
                            UDPSend ServerList(I).Remote, Chr(0) + Chr(7)
                            AddDebug ServerList(I).ServerName + "(" + CStr(ServerList(I).ScoreID) + ") - Zone booted as " + TrimZero(mID(Message, 20)) + "(" + CStr(GetLong(mID(Message, 16, 4))) + ") logged in"
                            DeleteServer I
                        End If
                    Next
                    NewServer Sender, TrimZero(mID(Message, 20)), GetLong(mID(Message, 16, 4))
                    AddDebug TrimZero(mID(Message, 20)) + "(" + CStr(GetLong(mID(Message, 16, 4))) + ") - Valid zone password: Connected"
                Case Else
                    'Invalid password
                    UDPSend Sender, Chr(0) + Chr(7)
                    AddDebug TrimZero(mID(Message, 20)) + "(" + CStr(GetLong(mID(Message, 16, 4))) + ") - Invalid zone password: Booted"
            End Select
        Else
            'Nope, not what you're looking for
            UDPSend Sender, Chr(0) + Chr(7)
        End If
    Else
        'The server is logged in
        
        'Message format:
        '<Connection Status(2)> (<Session ID(4)> {<Message Type(2)> <Parameters(?)>}})
        
        Select Case Left(Message, 2)
            Case Chr(0) + Chr(3)
                'This message requires an ACK in response at LEAST
                UDPSend Sender, Chr(0) + Chr(4) + mID(Message, 3, 4)
            
                Select Case mID(Message, 7, 1)
                    Case Chr(1)
                        'Keep-alive, just ACK
                    
                    Case Chr(2)
                        'Not supposed to happen
                    
                    Case Chr(3)
                        'Not supposed to happen
                    
                    Case Chr(4)
                        'A user entered -> .TimeZoneBias = GetInteger(mID(Message, 85, 2))
                        Dim mStr As String

                        'Ban system
                        L = MatchBan(ServerID, mID(Message, 13, 24), mID(Message, 81, 4), mID(Message, 9, 4))
                        If L > 0 Then
                            If FindBanfree(ServerID, mID(Message, 13, 24)) = 0 Then
                                'He's been banned
                                'Call UDPSend(Sender, Chr(0) + Chr(3) + NextSessionID(ServerID) + Chr(1) + Chr(2) + mID(Message, 77, 4) + String(197 - 12, Chr(0)))
                                AddDebug ServerList(ServerID).ServerName + "(" + CStr(ServerList(ServerID).ScoreID) + ") - User Connecting: " + TrimZero(mID(Message, 13, 32)) + "  (" + GetIPString(mID(Message, 9, 4)) + ")  M:" + CStr(GetLong(mID(Message, 81, 4))) + "  C:" + CStr(GetLong(mID(Message, 77, 4)))
                                Call AddDebug(ServerList(ServerID).ServerName + "(" + CStr(ServerList(ServerID).ScoreID) + ") ^ Banned user: Booted")
                                Call BroadcastBanOp(ServerList(ServerID).ServerName + " -> " + TrimZero(mID(Message, 13, 24)) + ": Banned user #" + CStr(L) + " booted")
                                Exit Sub
                            End If
                        End If
                        
                        User = mID(Message, 13, 24)
                        L = FindPlayer(ServerID, User)
                        
                        If L > 0 Then
                            AddDebug ServerList(ServerID).ServerName + "(" + CStr(ServerList(ServerID).ScoreID) + ") - User Connecting: " + TrimZero(mID(Message, 13, 32)) + "  (" + GetIPString(mID(Message, 9, 4)) + ")  M:" + CStr(GetLong(mID(Message, 81, 4))) + "  C:" + CStr(GetLong(mID(Message, 77, 4)))
                            Select Case GetData(ServerID, L, P_Password)
                                Case pwEncryption(mID(Message, 13 + 32, 24))
                                    'The saved password = the one sent
                                    NewUser ServerID, User, GetLong(mID(Message, 81, 4)), GetLong(mID(Message, 9, 4)), GetLong(mID(Message, 77, 4)), L
                                    mStr = Chr(0) + Chr(3) + NextSessionID(ServerID) + Chr(1) + Chr(0) + mID(Message, 77, 4)
                                    mStr = mStr + mID(Message, 13, 24) + GetData(ServerID, L, P_Squad) + String(156 - 24 - 24 - 12, Chr(0))
                                    mStr = mStr + Reverse(GetData(ServerID, L, P_TotalSeconds)) + GetData(ServerID, L, P_CreateDate)
                                    mStr = mStr + String(4, Chr(0)) + GetString(L) + String(4, Chr(0)) + GetData(ServerID, L, P_Score)
                                    UDPSend Sender, mStr
                                    AddDebug ServerList(ServerID).ServerName + "(" + CStr(ServerList(ServerID).ScoreID) + ") ^ Valid Password: Entering Game"
                                    AlertPlayers ServerID, TrimZero(User) + " entering game"
                                
                                Case Else
                                    'The saved password != the one sent
                                    UDPSend Sender, Chr(0) + Chr(3) + NextSessionID(ServerID) + Chr(1) + Chr(2) + mID(Message, 77, 4) + String(197 - 12, Chr(0))
                                    AddDebug ServerList(ServerID).ServerName + "(" + CStr(ServerList(ServerID).ScoreID) + ") ^ Invalid Password: Booted"
                            
                            End Select
                        Else
                            'There is no saved password (new user)
                            If BillingSettings.AllowNewUsers = 1 Then
                                Select Case mID(Message, 8, 1)
                                    Case Chr(0)
                                        If BillingSettings.AskNewUsers = 1 Then
                                            Call UDPSend(Sender, Chr(0) + Chr(3) + NextSessionID(ServerID) + Chr(1) + Chr(1) + mID(Message, 77, 4) + String(197 - 12, Chr(0)))
                                            'Call AddDebug(ServerList(ServerID).ServerName + "(" + CStr(ServerList(ServerID).ScoreID) + ") ^ New User: Is he sure?")
                                        Else
                                            Call AddPlayerEntry(User, mID(Message, 13 + 32, 24), mID(Message, 9, 4), mID(Message, 77, 4))
                                            L = ServerList(ServerID).TotalLoggedPlayers
                                            Call NewUser(ServerID, TrimZero(mID(Message, 13, 24)), GetLong(mID(Message, 81, 4)), GetLong(mID(Message, 9, 4)), GetLong(mID(Message, 77, 4)), L)
                                            mStr = Chr(0) + Chr(3) + NextSessionID(ServerID) + Chr(1) + Chr(0) + mID(Message, 77, 4)
                                            mStr = mStr + mID(Message, 13, 24) + GetData(ServerID, L, P_Squad) + String(156 - 24 - 24 - 12, Chr(0))
                                            mStr = mStr + Reverse(GetData(ServerID, L, P_TotalSeconds)) + GetData(ServerID, L, P_CreateDate)
                                            mStr = mStr + String(4, Chr(0)) + GetString(L) + String(4, Chr(0)) + GetData(ServerID, L, P_Score)
                                            UDPSend Sender, mStr
                                            AddDebug ServerList(ServerID).ServerName + "(" + CStr(ServerList(ServerID).ScoreID) + ") - User Connecting: " + TrimZero(mID(Message, 13, 32)) + "  (" + GetIPString(mID(Message, 9, 4)) + ")  M:" + CStr(GetLong(mID(Message, 81, 4))) + "  C:" + CStr(GetLong(mID(Message, 77, 4)))
                                            Call AddDebug(ServerList(ServerID).ServerName + "(" + CStr(ServerList(ServerID).ScoreID) + ") ^ New User: Entering Game")
                                            AlertPlayers ServerID, TrimZero(User) + " entering game for the first time"
                                        End If
                                    
                                    Case Chr(1)
                                        Call AddPlayerEntry(User, mID(Message, 13 + 32, 24), mID(Message, 9, 4), mID(Message, 77, 4))
                                        L = ServerList(ServerID).TotalLoggedPlayers
                                        Call NewUser(ServerID, TrimZero(mID(Message, 13, 24)), GetLong(mID(Message, 81, 4)), GetLong(mID(Message, 9, 4)), GetLong(mID(Message, 77, 4)), L)
                                        mStr = Chr(0) + Chr(3) + NextSessionID(ServerID) + Chr(1) + Chr(0) + mID(Message, 77, 4)
                                        mStr = mStr + mID(Message, 13, 24) + GetData(ServerID, L, P_Squad) + String(156 - 24 - 24 - 12, Chr(0))
                                        mStr = mStr + Reverse(GetData(ServerID, L, P_TotalSeconds)) + GetData(ServerID, L, P_CreateDate)
                                        mStr = mStr + String(4, Chr(0)) + GetString(L) + String(4, Chr(0)) + GetData(ServerID, L, P_Score)
                                        UDPSend Sender, mStr
                                        AddDebug ServerList(ServerID).ServerName + "(" + CStr(ServerList(ServerID).ScoreID) + ") - User Connecting: " + TrimZero(mID(Message, 13, 32)) + "  (" + GetIPString(mID(Message, 9, 4)) + ")  M:" + CStr(GetLong(mID(Message, 81, 4))) + "  C:" + CStr(GetLong(mID(Message, 77, 4)))
                                        Call AddDebug(ServerList(ServerID).ServerName + "(" + CStr(ServerList(ServerID).ScoreID) + ") ^ New User: Entering Game")
                                        AlertPlayers ServerID, TrimZero(User) + " entering game for the first time"
                                
                                End Select
                            Else
                                Call UDPSend(Sender, Chr(0) + Chr(3) + NextSessionID(ServerID) + Chr(1) + Chr(2) + mID(Message, 77, 4) + String(197 - 12, Chr(0)))
                                AddDebug ServerList(ServerID).ServerName + "(" + CStr(ServerList(ServerID).ScoreID) + ") - User Connecting: " + TrimZero(mID(Message, 13, 32)) + "  (" + GetIPString(mID(Message, 9, 4)) + ")  M:" + CStr(GetLong(mID(Message, 81, 4))) + "  C:" + CStr(GetLong(mID(Message, 77, 4)))
                                Call AddDebug(ServerList(ServerID).ServerName + "(" + CStr(ServerList(ServerID).ScoreID) + ") ^ New User: Booted")
                            End If
                        End If
                    
                    Case Chr(5)
                        'A user left the game
                        L = CLng(getPlayerID(ServerID, GetLong(mID(Message, 8, 4))))
                        If L > ServerList(ServerID).TotalPlayers Or L < 1 Then
                            'Not added as a player
                            Exit Sub
                        Else
                            'Legal disconnect
                            User = TrimZero(ServerList(ServerID).pList(L).PlayerName)
                            Call DeleteUser(ServerID, CInt(L))
                            If Len(Message) > 21 Then Call UpdatePlayer(ServerID, ServerList(ServerID).pList(L).StoredID, mID(Message, 22, 14), Reverse(mID(Message, 19, 2)))
                            Call AlertPlayers(ServerID, User + " quit")
                            AddDebug ServerList(ServerID).ServerName + "(" + CStr(ServerList(ServerID).ScoreID) + ") - " + User + " quit"
                        End If
                    
                    Case Chr(7)
                        Select Case mID(Message, 8, 4)
                            Case Chr(255) + Chr(255) + Chr(255) + Chr(255)
                                ':name:messages
                                Call MessageBroadcast(mID(Message, 18))
                                I = getPlayerID(ServerID, GetLong(mID(Message, 12, 4)))
                                ServerList(ServerID).pList(I).AttemptedMsgs = ServerList(ServerID).pList(I).AttemptedMsgs + 1
                            Case Else
                                '**messages
                                If ServerList(ServerID).pList(getPlayerID(ServerID, GetLong(mID(Message, 8, 4)))).Op(LEVEL.Messaging) = True Or BillingSettings.ZonecastLock = 0 Then Call MessageBroadcast(mID(Message, 18))
                        End Select
                    
                    Case Chr(14)
                        'Chat messages??
                        I = getPlayerID(ServerID, GetLong(mID(Message, 8, 4)))
                        BroadcastChat ServerID, I, mID(Message, 12, 1), mID(Message, 44)
                        ServerList(ServerID).pList(I).AttemptedMsgs = ServerList(ServerID).pList(I).AttemptedMsgs + 1
                    
                    Case Chr(15)
                        AddDebug ServerList(ServerID).ServerName + "(" + CStr(ServerList(ServerID).ScoreID) + ") [" + TrimZero(ServerList(ServerID).pList(getPlayerID(ServerID, GetLong(mID(Message, 8, 4)))).PlayerName) + "] - " + TrimZero(mID(Message, 12))
                    
                    Case Chr(19)
                        'Billing command
                        I = getPlayerID(ServerID, GetLong(mID(Message, 8, 4)))
                        User = ServerList(ServerID).pList(I).PlayerName
                        
                        With ServerList(ServerID).pList(I)
                        
                        If Left(TrimZero(LCase(mID(Message, 12))), 11) = "?squadjoin " Then
                            L = FindSquad(ServerID, LParse(mID(Message, 23), ":"))
                            If L = 0 Then
                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Specified squad does not exist")
                            Else
                                If LCase(GetSData(ServerID, L, S_Owner)) = LCase(FillZero(User, 24)) Or pwEncryption(FillZero(RParse(mID(Message, 23), ":"), 24)) = GetSData(ServerID, L, S_Password) Then
                                    Call PutData(ServerID, .StoredID, P_Squad, LParse(mID(Message, 23), ":"))
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Squad successfully joined.  Reenter for it to take effect")
                                Else
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Invalid password for specified squad")
                                End If
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 12) = "?squadgrant " Then
                            If Left(mID(Message, 24), 24) = "" Then
                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Format: ?squadgrant <player>")
                            Else
                                L = FindSquad(ServerID, GetData(ServerID, .StoredID, P_Squad))
                                If L = 0 Then
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "You are not in a squad")
                                Else
                                    If LCase(GetSData(ServerID, L, S_Owner)) = LCase(FillZero(User, 24)) Then
                                        L = FindPlayer(ServerID, Left(mID(Message, 24), 24))
                                        If L = 0 Then
                                            Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Specified player is unkown")
                                        Else
                                            Call PutSData(ServerID, FindSquad(ServerID, GetData(ServerID, ServerList(ServerID).pList(I).StoredID, P_Squad)), S_Owner, Left(mID(Message, 24), 24))
                                            Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Player was successfully made the owner of your squad.")
                                        End If
                                    Else
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "You are not the owner of this squad")
                                    End If
                                End If
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 13) = "?squadcreate " Then
                            L = FindSquad(ServerID, LParse(mID(Message, 25), ":"))
                            If RParse(mID(Message, 25), ":") = "" Or LParse(mID(Message, 25), ":") = "" Then
                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Format: ?squadcreate <name>:<password>")
                            Else
                                If L = 0 Then
                                    AddSquadEntry ServerID, LParse(mID(Message, 25), ":"), RParse(mID(Message, 25), ":"), User
                                    Call PutData(ServerID, .StoredID, P_Squad, LParse(mID(Message, 25), ":"))
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Squad successfully created.  Reenter for it to take effect")
                                Else
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Squad already exists")
                                End If
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 6) = "?bset " Then
                            Dim Section As String, Key As String, Value As String
                            If .Op(LEVEL.Server) = True Then
                                Section = LParse(LCase(TrimZero(mID(Message, 18))), ":")
                                Key = LParse(RParse(LCase(TrimZero(mID(Message, 18))), ":"), ":")
                                Value = RParse(RParse(TrimZero(mID(Message, 18)), ":"), ":")
                                Select Case Section
                                    Case "messaging"
                                        Call SetProfile(Section, Key, Value)
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(TrimZero(mID(Message, 18)), ":") + ":" + LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":") + ":" + GetProfileString(LParse(TrimZero(mID(Message, 18)), ":"), LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":")))
                                    Case "abs"
                                        Call SetProfile(Section, Key, Value)
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(TrimZero(mID(Message, 18)), ":") + ":" + LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":") + ":" + GetProfileString(LParse(TrimZero(mID(Message, 18)), ":"), LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":")))
                                    Case "account"
                                        Call SetProfile(Section, Key, Value)
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(TrimZero(mID(Message, 18)), ":") + ":" + LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":") + ":" + GetProfileString(LParse(TrimZero(mID(Message, 18)), ":"), LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":")))
                                    Case "server"
                                        Call SetProfile(Section, Key, Value)
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(TrimZero(mID(Message, 18)), ":") + ":" + LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":") + ":" + GetProfileString(LParse(TrimZero(mID(Message, 18)), ":"), LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":")))
                                    Case "zones"
                                        Call SetProfile(Section, Key, Value)
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(TrimZero(mID(Message, 18)), ":") + ":" + LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":") + ":" + GetProfileString(LParse(TrimZero(mID(Message, 18)), ":"), LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":")))
                                    Case "login"
                                        Select Case Key
                                            Case "port"
                                                Call SetProfile(Section, Key, Value)
                                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(TrimZero(mID(Message, 18)), ":") + ":" + LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":") + ":" + GetProfileString(LParse(TrimZero(mID(Message, 18)), ":"), LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":")))
                                            Case "allownewusers"
                                                Call SetProfile(Section, Key, Value)
                                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(TrimZero(mID(Message, 18)), ":") + ":" + LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":") + ":" + GetProfileString(LParse(TrimZero(mID(Message, 18)), ":"), LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":")))
                                            Case "asknewusers"
                                                Call SetProfile(Section, Key, Value)
                                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(TrimZero(mID(Message, 18)), ":") + ":" + LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":") + ":" + GetProfileString(LParse(TrimZero(mID(Message, 18)), ":"), LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":")))
                                        End Select
                                    Case "misc"
                                        Select Case Key
                                            Case "maxqueueforlogin"
                                                Call SetProfile(Section, Key, Value)
                                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(TrimZero(mID(Message, 18)), ":") + ":" + LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":") + ":" + GetProfileString(LParse(TrimZero(mID(Message, 18)), ":"), LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":")))
                                            Case "lowpriority"
                                                Call SetProfile(Section, Key, Value)
                                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(TrimZero(mID(Message, 18)), ":") + ":" + LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":") + ":" + GetProfileString(LParse(TrimZero(mID(Message, 18)), ":"), LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":")))
                                            Case "kickoutdelay"
                                                Call SetProfile(Section, Key, Value)
                                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(TrimZero(mID(Message, 18)), ":") + ":" + LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":") + ":" + GetProfileString(LParse(TrimZero(mID(Message, 18)), ":"), LParse(RParse(TrimZero(mID(Message, 18)), ":"), ":")))
                                        End Select
                                End Select
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 6) = "?bget " Then
                            If .Op(LEVEL.Server) = True Then
                                S = LCase(TrimZero(mID(Message, 18)))
                                Select Case LParse(S, ":")
                                    Case "server"
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(S, ":") + ":" + RParse(S, ":") + ":" + GetProfileString(LParse(S, ":"), RParse(S, ":")))
                                    Case "account"
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(S, ":") + ":" + RParse(S, ":") + ":" + GetProfileString(LParse(S, ":"), RParse(S, ":")))
                                    Case "abs"
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(S, ":") + ":" + RParse(S, ":") + ":" + GetProfileString(LParse(S, ":"), RParse(S, ":")))
                                    Case "messaging"
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(S, ":") + ":" + RParse(S, ":") + ":" + GetProfileString(LParse(S, ":"), RParse(S, ":")))
                                    Case "zones"
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(S, ":") + ":" + RParse(S, ":") + ":" + GetProfileString(LParse(S, ":"), RParse(S, ":")))
                                    Case "login"
                                        Select Case RParse(S, ":")
                                            Case "port"
                                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(S, ":") + ":" + RParse(S, ":") + ":" + GetProfileString(LParse(S, ":"), RParse(S, ":")))
                                            Case "allownewusers"
                                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(S, ":") + ":" + RParse(S, ":") + ":" + GetProfileString(LParse(S, ":"), RParse(S, ":")))
                                            Case "asknewusers"
                                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(S, ":") + ":" + RParse(S, ":") + ":" + GetProfileString(LParse(S, ":"), RParse(S, ":")))
                                        End Select
                                    Case "misc"
                                        Select Case RParse(S, ":")
                                            Case "maxqueueforlogin"
                                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(S, ":") + ":" + RParse(S, ":") + ":" + GetProfileString(LParse(S, ":"), RParse(S, ":")))
                                            Case "lowpriority"
                                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(S, ":") + ":" + RParse(S, ":") + ":" + GetProfileString(LParse(S, ":"), RParse(S, ":")))
                                            Case "kickoutdelay"
                                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), LParse(S, ":") + ":" + RParse(S, ":") + ":" + GetProfileString(LParse(S, ":"), RParse(S, ":")))
                                        End Select
                                End Select
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 10) = "?password " Then
                            Call PutData(ServerID, .StoredID, P_Password, Left(mID(Message, 22), 24))
                            Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Password changed successfully.")
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 15) = "?squadpassword " Then
                            If Left(mID(Message, 27), 24) = "" Then
                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Format: ?squadpassword <password>")
                            Else
                                L = FindSquad(ServerID, GetData(ServerID, ServerList(ServerID).pList(I).StoredID, P_Squad))
                                If L = 0 Then
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "You are not in a squad")
                                Else
                                    If LCase(GetSData(ServerID, L, S_Owner)) = LCase(FillZero(User, 24)) Then
                                        Call PutSData(ServerID, L, S_Password, Left(mID(Message, 27), 24))
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Squad password changed successfully.")
                                    Else
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "You are not the owner of this squad")
                                    End If
                                End If
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 11) = "?squadkick " Then
                            If Left(mID(Message, 23), 24) = "" Then
                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Format: ?squadkick <player>")
                            Else
                                L = FindSquad(ServerID, GetData(ServerID, ServerList(ServerID).pList(I).StoredID, P_Squad))
                                If L = 0 Then
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "You are not in a squad")
                                Else
                                    If LCase(GetSData(ServerID, L, S_Owner)) = LCase(FillZero(User, 24)) Then
                                        L = FindPlayer(ServerID, Left(mID(Message, 23), 24))
                                        If L = 0 Then
                                            Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Specified player is unkown")
                                        Else
                                            Call PutData(ServerID, L, P_Squad, "")
                                            Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Player was successfully removed from your squad.")
                                        End If
                                    Else
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "You are not the owner of this squad")
                                    End If
                                End If
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 12) = "?squadowner " Then
                            If Left(mID(Message, 24), 24) = "" Then
                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Format: ?squadowner <squad>")
                            Else
                                L = FindSquad(ServerID, mID(Message, 24))
                                If L = 0 Then
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Unkown squad")
                                Else
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Squad owner: " + TrimZero(GetSData(ServerID, L, S_Owner)))
                                End If
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 6) = "?chat " Then
                            LoadChannels ServerID, CLng(I), TrimZero(mID(Message, 18))
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 6) = "?chat=" Then
                            LoadChannels ServerID, CLng(I), TrimZero(mID(Message, 18))
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 7) = "?login " Then
                            If .AttemptedLogins > 2 Then Exit Sub
                            Message = TrimZero(mID(Message, 19))
                            If Message = GetProfileString("Messaging", TrimZero(.PlayerName)) Then .Op(LEVEL.Messaging) = True: L = 1
                            If Message = GetProfileString("ABS", TrimZero(.PlayerName)) Then .Op(LEVEL.Ban) = True: L = 1
                            If Message = GetProfileString("Account", TrimZero(.PlayerName)) Then .Op(LEVEL.Account) = True: L = 1
                            If Message = GetProfileString("Server", TrimZero(.PlayerName)) Then .Op(LEVEL.Server) = True: L = 1
                            If L = 0 Then
                                .AttemptedLogins = .AttemptedLogins + 1
                            Else
                                If .Op(LEVEL.Messaging) = True Then S = S + "Messaging/"
                                If .Op(LEVEL.Ban) = True Then S = S + "Ban/"
                                If .Op(LEVEL.Account) = True Then S = S + "Account/"
                                If .Op(LEVEL.Server) = True Then S = S + "Server/"
                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Logged into SSBilling as " + Left(S, Len(S) - 1) + "'Op")
                                .Op(LEVEL.AnyStatus) = True
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 9) = "?comment " Then
                            If ServerList(ServerID).pList(I).Op(LEVEL.Ban) = True Then
                                If RParse(TrimZero(mID(Message, 21)), ":") = "" Then
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Format: ?comment <number>:<comment>")
                                Else
                                    L = CLng(LParse(TrimZero(mID(Message, 21)), ":"))
                                    If L > ServerList(ServerID).TotalLoggedBans Or L < 1 Then
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Unable to find specified banned player")
                                    Else
                                        Call PutBData(ServerID, L, B_Comment, RParse(TrimZero(mID(Message, 21)), ":"))
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Ban comment updated.")
                                    End If
                                End If
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 5) = "?ban " Then
                            If ServerList(ServerID).pList(I).Op(LEVEL.Ban) = True Then
                                If FindBan(ServerID, TrimZero(mID(Message, 17))) > 0 Then
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Specified player is already banned")
                                Else
                                    L = FindPlayer(ServerID, TrimZero(mID(Message, 17)))
                                    If L > 0 Then
                                        Call AddBanEntry(ServerID, GetData(ServerID, L, P_Name), User, GetData(ServerID, L, P_LastID), GetData(ServerID, L, P_LastIP))
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Ban #" + CStr(ServerList(ServerID).TotalLoggedBans) + " activated: " + TrimZero(mID(Message, 17)))
                                    Else
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Specified player is unknown")
                                    End If
                                End If
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 9) = "?banfree " Then
                            If ServerList(ServerID).pList(I).Op(LEVEL.Ban) = True Then
                                If FindBanfree(ServerID, TrimZero(mID(Message, 21))) > 0 Then
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Specified player is already banfreed")
                                Else
                                    Call AddBanfreeEntry(ServerID, TrimZero(mID(Message, 21)), User)
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Banfree #" + CStr(ServerList(ServerID).TotalLoggedBanfrees) + " activated: " + TrimZero(mID(Message, 21)))
                                End If
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 7) = "?where " Then
                            S = GetLocation(TrimZero(mID(Message, 19)))
                            If S <> "" Then
                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), TrimZero(mID(Message, 19)) + " @ " + S)
                            Else
                                Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), TrimZero(mID(Message, 19)) + " is not online")
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 7) = "?alias " Then
                            If .Op(LEVEL.AnyStatus) Then
                                L = FindPlayer(ServerID, TrimZero(mID(Message, 19)))
                                If L = 0 Then
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Unknown player")
                                Else
                                    S = MatchAlias(ServerID, S, GetData(ServerID, L, P_LastID), GetData(ServerID, L, P_LastIP))
                                    If S <> "" Then
                                        For I = 1 To Len(S) Step 64
                                            Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Alias: " + mID(S, I, 64))
                                        Next
                                    Else
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "No alias")
                                    End If
                                End If
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 13) = "?recyclezone " Then
                            If .Op(LEVEL.Server) Then
                                If IsNumeric(TrimZero(mID(Message, 25))) = False Then
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Format: ?recyclezone <number>")
                                Else
                                    L = CLng(TrimZero(mID(Message, 25)))
                                    If L > TotalServers Or L < 1 Then
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Specified zone is unknown")
                                    Else
                                        AddDebug ServerList(L).ServerName + "(" + CStr(ServerList(L).ScoreID) + ") - Recycled by " + TrimZero(User) + "(BSysOp)"
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), ServerList(L).ServerName + " recycled.")
                                        Call UDPSend(Sender, Chr(0) + Chr(3) + NextSessionID(ServerID) + Chr(4) + Chr(0) + Chr(1) + Chr(0) + Chr(0) + Chr(0) + Chr(2) + Chr(0) + Chr(0) + Chr(0))
                                        Call DeleteServer(CInt(L))
                                    End If
                                End If
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 11) = "?closezone " Then
                            If .Op(LEVEL.Server) Then
                                If IsNumeric(TrimZero(mID(Message, 23))) = False Then
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Format: ?killzone <number>")
                                Else
                                    L = CLng(TrimZero(mID(Message, 23)))
                                    If L > TotalServers Or L < 1 Then
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Specified zone is unknown")
                                    Else
                                        Call PrivateBroadcast(L, "NOTICE: Server shutting down...")
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), ServerList(L).ServerName + " shutdown.")
                                        AddDebug ServerList(L).ServerName + "(" + CStr(ServerList(L).ScoreID) + ") - Shutdown by " + TrimZero(User) + "(BSysOp)"
                                        Call UDPSend(Sender, Chr(0) + Chr(3) + NextSessionID(ServerID) + Chr(2) + Chr(0) + Chr(1) + Chr(0) + Chr(0) + Chr(0) + Chr(2) + Chr(0) + Chr(0) + Chr(0))
                                        Call DeleteServer(CInt(L))
                                    End If
                                End If
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 11) = "?resetzone " Then
                            If .Op(LEVEL.Server) Then
                                If IsNumeric(TrimZero(mID(Message, 23))) = False Then
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Format: ?resetzone <number>")
                                Else
                                    L = CLng(TrimZero(mID(Message, 23)))
                                    If L > TotalServers Or L < 1 Then
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Specified zone is unknown")
                                    Else
                                        For I = 1 To ServerList(L).TotalLoggedPlayers
                                            Call PutData(CInt(L), CLng(I), P_Score, String(14, Chr(0)))
                                        Next
                                        Call PrivateBroadcast(L, "NOTICE: Server recycling for a zone-wide score reset.  Log back in soon")
                                        AddDebug ServerList(L).ServerName + "(" + CStr(ServerList(L).ScoreID) + ") - Recycled and Reset by " + TrimZero(User) + "(BSysOp)"
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), ServerList(L).ServerName + " recycled and reset.")
                                        Call UDPSend(Sender, Chr(0) + Chr(3) + NextSessionID(ServerID) + Chr(4) + Chr(0) + Chr(1) + Chr(0) + Chr(0) + Chr(0) + Chr(2) + Chr(0) + Chr(0) + Chr(0))
                                        Call DeleteServer(CInt(L))
                                    End If
                                End If
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 9) = "?liftban " Then
                            If .Op(LEVEL.Ban) Then
                                If IsNumeric(TrimZero(mID(Message, 21))) Then
                                    L = CLng(TrimZero(mID(Message, 21)))
                                    If L > ServerList(ServerID).TotalLoggedBans Or L < 1 Then
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Specified ban is unknown")
                                    Else
                                        RemoveBan ServerID, L
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Ban lifted")
                                    End If
                                Else
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Format: ?liftban <number>")
                                End If
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 13) = "?liftbanfree " Then
                            If .Op(LEVEL.Ban) Then
                                If IsNumeric(TrimZero(mID(Message, 25))) Then
                                    L = CLng(TrimZero(mID(Message, 25)))
                                    If L > ServerList(ServerID).TotalLoggedBanfrees Or L < 1 Then
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Specified banfree is unknown")
                                    Else
                                        RemoveBanfree ServerID, L
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Banfree lifted")
                                    End If
                                Else
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Format: ?liftbanfree <number>")
                                End If
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 16) = "?changepassword " Then
                            If .Op(LEVEL.Account) Then
                                If RParse(TrimZero(mID(Message, 28)), ":") = "" Then
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Format: ?changepassword <name>:<new password>")
                                Else
                                    L = FindPlayer(ServerID, LParse(TrimZero(mID(Message, 28)), ":"))
                                    If L = 0 Then
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Specified player is not in the database")
                                    Else
                                        Call PutData(ServerID, L, P_Password, RParse(TrimZero(mID(Message, 28)), ":"))
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Player password changed.")
                                    End If
                                End If
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 12) = "?changename " Then
                            If .Op(LEVEL.Account) Then
                                If RParse(TrimZero(mID(Message, 24)), ":") = "" Then
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Format: ?changename <name>:<new name>")
                                Else
                                    L = FindPlayer(ServerID, LParse(TrimZero(mID(Message, 24)), ":"))
                                    If L = 0 Then
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Specified player is not in the database")
                                    Else
                                        Call PutData(ServerID, L, P_Name, RParse(TrimZero(mID(Message, 24)), ":"))
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Player name changed. Operator status and squad ownership not transferred")
                                    End If
                                End If
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 9) = "?setname " Then
                            If .Op(LEVEL.Account) Then
                                If RParse(TrimZero(mID(Message, 21)), ":") = "" Then
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Format: ?setname <name>:<new name>")
                                Else
                                    L = FindSquad(ServerID, LParse(TrimZero(mID(Message, 21)), ":"))
                                    If L = 0 Then
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Specified squad is not in the database")
                                    Else
                                        S = LCase(GetSData(ServerID, L, S_Name))
                                        For L = 1 To ServerList(ServerID).TotalLoggedPlayers
                                            If LCase(GetData(ServerID, L, P_Squad)) = S Then
                                                Call PutData(ServerID, L, P_Squad, LParse(TrimZero(mID(Message, 21)), ":"))
                                            End If
                                        Next
                                        Call PutSData(ServerID, L, S_Name, RParse(TrimZero(mID(Message, 21)), ":"))
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Squad name changed. Squad members must reenter for it to take effect")
                                    End If
                                End If
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 10) = "?setowner " Then
                            If .Op(LEVEL.Account) Then
                                If RParse(TrimZero(mID(Message, 22)), ":") = "" Then
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Format: ?setowner <squad>:<new owner>")
                                Else
                                    L = FindSquad(ServerID, LParse(TrimZero(mID(Message, 22)), ":"))
                                    If L = 0 Then
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Specified squad is not in the database")
                                    Else
                                        Call PutSData(ServerID, L, S_Owner, RParse(TrimZero(mID(Message, 22)), ":"))
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Squad owner changed.")
                                    End If
                                End If
                            End If
                            Exit Sub
                        
                        ElseIf Left(TrimZero(LCase(mID(Message, 12))), 6) = "?info " Then
                            If .Op(LEVEL.AnyStatus) Then
                                L = FindPlayer(ServerID, TrimZero(mID(Message, 18)))
                                If L = 0 Then
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Specified player is not in the database")
                                Else
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), TrimZero(mID(Message, 18)) + "[" + TrimZero(GetData(ServerID, L, P_Squad)) + "]:")
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Total logins:" + CStr(GetLong(GetData(ServerID, L, P_TotalLogins))) + "  LastPlayed:" + GetStringTime(GetData(ServerID, L, P_LastPlayed)) + "  LastIP:" + GetIPString(GetData(ServerID, L, P_LastIP)) + "  LastID:" + CStr(GetLong(GetData(ServerID, L, P_LastID))))
                                End If
                            End If
                            Exit Sub
                        End If
                        
                        Select Case TrimZero(LCase(mID(Message, 12)))
                            Case "?help"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "Catagory listing.  (Type ?help <catagory>)"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "player    - Player/Squad commands"
                                If .Op(LEVEL.AnyStatus) = True Then SendArena ServerID, GetLong(mID(Message, 8, 4)), "all       - General 'Op commands"
                                If .Op(LEVEL.Messaging) = True Then SendArena ServerID, GetLong(mID(Message, 8, 4)), "messaging - Messaging SysOp commands"
                                If .Op(LEVEL.Ban) = True Then SendArena ServerID, GetLong(mID(Message, 8, 4)), "banop     - BanOp commands"
                                If .Op(LEVEL.Account) = True Then SendArena ServerID, GetLong(mID(Message, 8, 4)), "account   - Account SysOp commands"
                                If .Op(LEVEL.Server) = True Then SendArena ServerID, GetLong(mID(Message, 8, 4)), "server    - Billing SysOp commands"
                            
                            Case "?help player"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "Sub-catagory listing.  (Type ?help <command>)"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "version,where,event,squadowner,squadgrant,login"
                            Case "?help all"
                                If .Op(LEVEL.AnyStatus) = True Then
                                    SendArena ServerID, GetLong(mID(Message, 8, 4)), "Sub-catagory listing.  (Type ?help <command>)"
                                    SendArena ServerID, GetLong(mID(Message, 8, 4)), "listop,info,alias"
                                End If
                            Case "?help messaging"
                                If .Op(LEVEL.Messaging) = True Then
                                    SendArena ServerID, GetLong(mID(Message, 8, 4)), "Sub-catagory listing.  (Type ?help <command>)"
                                    SendArena ServerID, GetLong(mID(Message, 8, 4)), "**messages - require sysop to send"
                                End If
                            Case "?help banop"
                                If .Op(LEVEL.Ban) = True Then
                                    SendArena ServerID, GetLong(mID(Message, 8, 4)), "Sub-catagory listing.  (Type ?help <command>)"
                                    SendArena ServerID, GetLong(mID(Message, 8, 4)), "ban,banfree,listban,listbanfree,liftban,liftbanfree,comment"
                                End If
                            Case "?help account"
                                If .Op(LEVEL.Account) = True Then
                                    SendArena ServerID, GetLong(mID(Message, 8, 4)), "Sub-catagory listing.  (Type ?help <command>)"
                                    SendArena ServerID, GetLong(mID(Message, 8, 4)), "changepassword,changename,setowner,setname"
                                End If
                            Case "?help server"
                                If .Op(LEVEL.Server) = True Then
                                    SendArena ServerID, GetLong(mID(Message, 8, 4)), "Sub-catagory listing.  (Type ?help <command>)"
                                    SendArena ServerID, GetLong(mID(Message, 8, 4)), "bset,bget,listzone,recyclezone,resetzone,closezone"
                                End If
                                
                            Case "?help version"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?version - Display SSBilling version information"
                            Case "?help where"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?where <player name> - Display the connected zone he is in"
                            Case "?help event"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?event - Toggles on/off entering game and leaving game messages"
                            Case "?help squadowner"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?squadowner <squad name> - Display owner of given squad"
                            Case "?help squadgrant"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?squadgrant <name> - Pass squad ownership to given player"
                            Case "?help login"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?login <password> - Gain operator status"
                            
                            Case "?help listop"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?listop - Display online operators and access levels"
                            Case "?help info"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?info <player name> - Display stored player information"
                            Case "?help alias"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?alias <player name> - Display all other names a player has"
                            
                            Case "?help **messages"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "**<hello> - Send an arena message to all connected zones"
                            
                            Case "?help ban"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?ban <player name> - Ban a player for life or until removed"
                            Case "?help banfree"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?banfree <player name> - Specified player cannot be banned"
                            Case "?help listban"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?listban - List all bans in the zone"
                            Case "?help listbanfree"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?listbanfree - List all banfrees in the zone"
                            Case "?help liftban"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?liftban <number> - Remove a ban"
                            Case "?help liftbanfree"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?liftbanfree <number> - Remove a banfree"
                            Case "?help comment"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?comment <number>:<comment> - Add a ban comment"
                            
                            Case "?help changepassword"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?changepassword <player name>:<new password - Change a player's password"
                            Case "?help changename"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?changename <player name>:<new name> - Change a player's name"
                            Case "?help setowner"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?setowner <squad name>:<player name> - Change a squad's owner"
                            Case "?help setname"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?setname <squad name>:<new name? - Change a squad's name"
                                    
                            Case "?help bget"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?bget <section>:<key> - Like *g*, but for subbill.ini"
                            Case "?help bset"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?bset <section>:<key>:<value> - Like *s*, but for subbill.ini"
                            Case "?help listzone"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?listzone - List all connected zones"
                            Case "?help recyclezone"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?recyclezone <number> - Recycle a zone"
                            Case "?help resetzone"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?resetzone <number> - Executes a single-zone scorereset"
                            Case "?help closezone"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "?closezone <number> - Shuts down the given server"
                            
                            Case "?event"
                                If ServerList(ServerID).pList(I).YellNewbies = True Then
                                    ServerList(ServerID).pList(I).YellNewbies = False
                                    SendArena ServerID, GetLong(mID(Message, 8, 4)), "Enter/Quit messages OFF"
                                Else
                                    ServerList(ServerID).pList(I).YellNewbies = True
                                    SendArena ServerID, GetLong(mID(Message, 8, 4)), "Enter/Quit messages ON"
                                End If
                            
                            Case "?version"
                                SendArena ServerID, GetLong(mID(Message, 8, 4)), "Version info: " + PROG_TITLE

                            Case "?listop"
                                If .Op(LEVEL.AnyStatus) Then
                                    For I = 1 To TotalServers
                                        For L = 1 To ServerList(I).TotalPlayers
                                            If ServerList(I).pList(L).Op(LEVEL.AnyStatus) = True Then
                                                If ServerList(I).pList(L).Op(LEVEL.Messaging) = True Then S = S + "Messaging/"
                                                If ServerList(I).pList(L).Op(LEVEL.Ban) = True Then S = S + "Ban/"
                                                If ServerList(I).pList(L).Op(LEVEL.Account) = True Then S = S + "Account/"
                                                If ServerList(I).pList(L).Op(LEVEL.Server) = True Then S = S + "Server/"
                                                SendArena ServerID, GetLong(mID(Message, 8, 4)), TrimZero(ServerList(I).pList(L).PlayerName) + " -> " + Left(S, Len(S) - 1) + "'Op @ " + ServerList(I).ServerName
                                            End If
                                        Next
                                    Next
                                End If

                            Case "?listzone"
                                If .Op(LEVEL.Server) Then
                                    For I = 1 To TotalServers
                                        SendArena ServerID, GetLong(mID(Message, 8, 4)), CStr(I) + " -> " + ServerList(I).ServerName + "(" + CStr(ServerList(I).ScoreID) + ") [" + CStr(ServerList(I).TotalPlayers) + " players]"
                                    Next
                                End If
                            
                            Case "?listban"
                                If .Op(LEVEL.Ban) Then
                                    If ServerList(ServerID).TotalLoggedBans > 0 Then
                                        For L = 1 To ServerList(ServerID).TotalLoggedBans
                                            SendArena ServerID, GetLong(mID(Message, 8, 4)), CStr(L) + " -> " + GetBanInfo(ServerID, L)
                                            If TrimZero(GetBData(ServerID, L, B_Comment)) <> "" Then SendArena ServerID, GetLong(mID(Message, 8, 4)), TrimZero(GetBData(ServerID, L, B_Comment))
                                        Next
                                    Else
                                        SendArena ServerID, GetLong(mID(Message, 8, 4)), "No bans"
                                    End If
                                End If
                            
                            Case "?listbanfree"
                                If .Op(LEVEL.Ban) Then
                                    If ServerList(ServerID).TotalLoggedBanfrees > 0 Then
                                        For L = 1 To ServerList(ServerID).TotalLoggedBanfrees
                                            SendArena ServerID, GetLong(mID(Message, 8, 4)), CStr(L) + " -> " + GetBanfreeInfo(ServerID, L)
                                        Next
                                    Else
                                        SendArena ServerID, GetLong(mID(Message, 8, 4)), "No banfrees"
                                    End If
                                End If
                            
                            Case "?squadleave"
                                L = FindSquad(ServerID, TrimZero(GetData(ServerID, ServerList(ServerID).pList(I).StoredID, P_Squad)))
                                If L = 0 Then
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "You are not in a squad")
                                Else
                                    Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "You left the specified squad.  Reenter for it to take effect")
                                    Call PutData(ServerID, ServerList(ServerID).pList(I).StoredID, P_Squad, "")
                                    If LCase(GetSData(ServerID, L, S_Owner)) = LCase(FillZero(User, 24)) Then
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "You are still the owner of this squad")
                                    End If
                                End If
                            
                            Case "?squaddissolve"
                                L = FindSquad(ServerID, TrimZero(GetData(ServerID, ServerList(ServerID).pList(I).StoredID, P_Squad)))
                                If L = 0 Then
                                    SendArena ServerID, GetLong(mID(Message, 8, 4)), "You are not in a squad"
                                Else
                                    If LCase(GetSData(ServerID, L, S_Owner)) = LCase(FillZero(User, 24)) Then
                                        Call RemoveSquad(ServerID, L)
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "Squad dissolved.  Reenter for it to take effect")
                                    Else
                                        Call SendArena(ServerID, GetLong(mID(Message, 8, 4)), "You are not the squad owner")
                                    End If
                                End If
                            
                            Case "?chat"
                                Call SendChatters(ServerID, I)
                        End Select
                        
                        End With
                        
                    Case Chr(20)
                        'Chat message???
                        I = getPlayerID(ServerID, GetLong(mID(Message, 8, 4)))
                        BroadcastChat ServerID, I, mID(Message, 12, 1), mID(Message, 44)
                        ServerList(ServerID).pList(I).AttemptedMsgs = ServerList(ServerID).pList(I).AttemptedMsgs + 1
                        
                    Case Else
                        'Dunno what this user-related packet does yet
                        AddDebug ServerList(ServerID).ServerName + "(" + CStr(ServerList(ServerID).ScoreID) + ") - Warning: Unknown packet flag " + CStr(Asc(mID(Message, 7, 1)))
                        Open "serverLog." + CStr(Asc(mID(Message, 7, 1))) For Output As #15: Close
                        Open "serverLog." + CStr(Asc(mID(Message, 7, 1))) For Binary As #15
                            Put #15, 1, Message
                        Close
                    End Select
            
            Case Chr(0) + Chr(4)
                'Game Server ACKed something of mine, just ignore for now
            
            Case Chr(0) + Chr(7)
                'Game Server shutdown/recycled
                Call DeleteServer(ServerID)
                AddDebug ServerList(ServerID).ServerName + "(" + CStr(ServerList(ServerID).ScoreID) + ") - Disconnected"
            
            Case Else
                'I dunno what it does, so simply ACK it
                UDPSend Sender, Chr(0) + Chr(4) + mID(Message, 3, 4)
                AddDebug ServerList(ServerID).ServerName + "(" + CStr(ServerList(ServerID).ScoreID) + ") - Warning: Unrecognized response type " + CStr(Asc(mID(Message, 2, 1)))
                Open "unknownLog." + CStr(Asc(mID(Message, 2, 1))) For Output As #15: Close
                Open "unknownLog." + CStr(Asc(mID(Message, 2, 1))) For Binary As #15
                    Put #15, 1, Message
                Close
        
        End Select
    End If
Exit Sub

ErrHandler:
    MsgBox Err.Description + " - Report this error to catid@pacbell.net", vbInformation, "Possibly Fatal Error " + CStr(Err.Number)
    Resume Next
End Sub

'Load the overhead
Public Sub UDPStartWinsock()
    WSAStartup &H101, WSAdata
    MyHWnd = CreateWindowEx(0, "#32770", "SSBilling_Winsock", 0&, 0, 0, 1, 1, 0&, 0&, App.hInstance, 0&)
    OldWndProc = SetWindowLong(MyHWnd, GWL_WNDPROC, AddressOf WindowProc)
End Sub

'Unload the overhead
Public Sub UDPEndWinsock()
    SetWindowLong MyHWnd, GWL_WNDPROC, OldWndProc
    DestroyWindow MyHWnd
    WSACleanup
End Sub

'Create a SocketData structure
Public Function UDPMakeSocket(Port%) As SocketData
    Dim RetStruct As SocketData, S As Long

    S = Socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)
        sockaddr.sin_family = AF_INET
        sockaddr.sin_port = htons(Port)
        sockaddr.sin_addr = 0
    Call bind(S, sockaddr, 16)
        RetStruct.SockID = S
        RetStruct.Remote.sin_family = AF_INET
    Call UDPBindCallBack(RetStruct)

    UDPMakeSocket = RetStruct
End Function

'Bind a SocketID to my CallBack function
Public Sub UDPBindCallBack(SockData As SocketData)
    WSAAsyncSelect SockData.SockID, MyHWnd, 5150, FD_READ
End Sub

'UnBind a SocketID to my CallBack function
Public Sub UDPUnBindCallBack(SockData As SocketData)
    WSAAsyncSelect SockData.SockID, MyHWnd, 0, 0
End Sub

'Send the message to the given IP/Port
Public Sub UDPSend(SockData As sockaddr, Message As String)
    sendto MySock.SockID, ByVal Message, Len(Message), 0, SockData, 16
End Sub

'The CallBack
Public Function WindowProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Dim mStr As String * 255, mLen As Integer

    Select Case uMsg
        Case 5150
            mLen = recvfrom(wParam, ByVal mStr, 255, 0, sockaddr, 16)
            If mLen > 0 Then OnRecv sockaddr, Left(mStr, mLen)
        Case Else
            WindowProc = CallWindowProc(OldWndProc, hWnd, uMsg, wParam, ByVal lParam)
    End Select
End Function
