Advertisement
Guest User

Untitled

a guest
Jun 24th, 2017
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
VB.NET 89.77 KB | None | 0 0
  1. Imports ArkDLL
  2. Imports System.Runtime.Serialization
  3. Imports System.Runtime.Serialization.Formatters
  4. Imports System.Net.Sockets
  5. Imports System.Xml
  6. Imports System.IO
  7.  
  8. ''' <summary>
  9. ''' The Self Contained Server Class.
  10. ''' </summary>
  11. ''' <remarks>Well here we are.
  12. ''' Update Log:
  13. ''' -6/18/2010-
  14. ''' 1. Fixed several explots that could easily tank the server and flood it with requests.
  15. ''' 2. Incorporated an IRC-style permission system for the Groups.
  16. ''' 3. Several other small bug fixes that improved the speed and reliablity of the server.
  17. ''' -6/10/2010-
  18. ''' Initial Release.</remarks>
  19. Public Class TCPV2
  20.  
  21. #Region " Sub Classes "
  22.  
  23.     ''' <summary>
  24.     ''' The Group Sub Class.
  25.     ''' </summary>
  26.     ''' <remarks>This Class contains all the code required to maintain groups.</remarks>
  27.     Public Class Group
  28.  
  29. #Region " Variables "
  30.         Private m_Name As String = String.Empty
  31.         Private m_Maker As User
  32.         Private m_Public As Boolean = False
  33.         Private m_UserList As New List(Of User)
  34. #End Region
  35.  
  36. #Region " Sub Classes "
  37.  
  38.         Public Class User
  39.  
  40.             ''' <summary>
  41.             ''' Permission Enum.
  42.             ''' </summary>
  43.             ''' <remarks></remarks>
  44.             Public Enum Permission As Integer
  45.                 MUTE = 0
  46.                 VOICE = 1
  47.                 HALFOP = 2
  48.                 OP = 3
  49.                 ADMIN = 4
  50.                 OWNER = 5
  51.             End Enum
  52.  
  53.             Private Property Client As Client
  54.  
  55.             ''' <summary>
  56.             ''' Get or Set the User's Permission Level
  57.             ''' </summary>
  58.             ''' <value></value>
  59.             ''' <returns></returns>
  60.             ''' <remarks></remarks>
  61.             Public Property PermissionLevel As Permission = Permission.MUTE
  62.  
  63.             ''' <summary>
  64.             ''' Creates a new Group User
  65.             ''' </summary>
  66.             ''' <param name="cli">The Client</param>
  67.             ''' <remarks></remarks>
  68.             Public Sub New(ByVal cli As Client)
  69.                 Client = cli
  70.             End Sub
  71.  
  72.             ''' <summary>
  73.             ''' Sends a Message to the User.
  74.             ''' </summary>
  75.             ''' <param name="obj">The Message to Send.</param>
  76.             ''' <remarks></remarks>
  77.             Public Sub SendMessage(ByVal obj As Object)
  78.                 Client.SendMessage(obj)
  79.             End Sub
  80.  
  81.             ''' <summary>
  82.             ''' Returns the Client Name.
  83.             ''' </summary>
  84.             ''' <value></value>
  85.             ''' <returns></returns>
  86.             ''' <remarks></remarks>
  87.             Public ReadOnly Property Name As String
  88.                 Get
  89.                     Return Client.Name
  90.                 End Get
  91.             End Property
  92.  
  93.             ''' <summary>
  94.             ''' Returns the String Representation of the User
  95.             ''' </summary>
  96.             ''' <returns></returns>
  97.             ''' <remarks></remarks>
  98.             Public Overrides Function ToString() As String
  99.                 Return Me.Name
  100.             End Function
  101.  
  102.         End Class
  103.  
  104. #End Region
  105.  
  106. #Region " Events "
  107.         ''' <summary>
  108.         ''' Event is raised when a Message is received.
  109.         ''' </summary>
  110.         ''' <param name="sender">The Client who sent the message.</param>
  111.         ''' <param name="message">The actual message.</param>
  112.         ''' <remarks></remarks>
  113.         Friend Event Message(ByVal sender As Client, ByVal message As String, ByVal grp As Group)
  114.  
  115.         ''' <summary>
  116.         ''' The Logging Event
  117.         ''' </summary>
  118.         ''' <param name="msg">The Message to Log</param>
  119.         ''' <remarks></remarks>
  120.         Friend Event Log(ByVal msg As String)
  121.  
  122.         ''' <summary>
  123.         ''' Raised when the group is empty.
  124.         ''' </summary>
  125.         ''' <param name="sender">The Group that is empty.</param>
  126.         ''' <remarks></remarks>
  127.         Friend Event Empty(ByVal sender As Group)
  128. #End Region
  129.  
  130. #Region " Initialization and User Management "
  131.  
  132.         ''' <summary>
  133.         ''' Create a new Chat Group
  134.         ''' </summary>
  135.         ''' <param name="name">The name of the Group.</param>
  136.         ''' <param name="creator">The client that created the group.</param>
  137.         ''' <param name="IsPublic">Is the Group a Public or Private group?</param>
  138.         ''' <remarks></remarks>
  139.         Public Sub New(ByVal name As String, ByVal creator As Client, ByVal IsPublic As Boolean)
  140.             m_Name = name 'Set the Chatroom name (this is not changeable as of yet).
  141.             m_Maker = New User(creator) 'Set the creator (the only administrator).
  142.             m_Maker.PermissionLevel = User.Permission.OWNER 'Set to Owner.
  143.             m_Public = IsPublic 'Set the room to public if it is or not.
  144.             Me.Add(m_Maker) 'Add the creator to the userlist.
  145.         End Sub
  146.  
  147.         ''' <summary>
  148.         ''' Add a Client to the Group.
  149.         ''' </summary>
  150.         ''' <param name="client">The client to add.</param>
  151.         ''' <remarks></remarks>
  152.         Public Sub Add(ByVal client As Client)
  153.             Dim NewUser As New User(client)
  154.             Call Add(NewUser)
  155.         End Sub
  156.  
  157.         ''' <summary>
  158.         ''' Add's a User to the group
  159.         ''' </summary>
  160.         ''' <param name="User">The user to add.</param>
  161.         ''' <remarks></remarks>
  162.         Public Sub Add(ByVal User As User)
  163.             If Not IsUserInGroup(User) Then
  164.                 If User.PermissionLevel = User.Permission.MUTE Then User.PermissionLevel = User.Permission.VOICE
  165.                 If User.Name = Admin.Name Then User.PermissionLevel = TCPV2.Group.User.Permission.OWNER
  166.                 m_UserList.Add(User)
  167.                 User.SendMessage(New GroupInfo With {.Added = True, .GroupName = Me.Name, .User = User.Name})
  168.                 Call ServerMessage(String.Format("{0} has entered the chatroom.", User.Name))
  169.                 Call Update()
  170.             End If
  171.         End Sub
  172.  
  173.         ''' <summary>
  174.         ''' Remove a client from the group
  175.         ''' </summary>
  176.         ''' <param name="User">The User to remove. This cannot be the creator.</param>
  177.         ''' <remarks></remarks>
  178.         Public Sub Remove(ByVal User As User)
  179.             m_UserList.Remove(User)
  180.             Call ServerMessage(String.Format("{0} has left the chatroom.", User.Name))
  181.             Call Update()
  182.             If m_UserList.Count = 0 Then RaiseEvent Empty(Me)
  183.         End Sub
  184.  
  185.         ''' <summary>
  186.         ''' Removes a Client from the group
  187.         ''' </summary>
  188.         ''' <param name="client">The Client to remove</param>
  189.         ''' <remarks></remarks>
  190.         Public Sub Remove(ByVal client As Client)
  191.             Dim Usr As User = FindUser(client)
  192.             If Usr IsNot Nothing Then
  193.                 Call Remove(Usr)
  194.             End If
  195.         End Sub
  196.  
  197.         ''' <summary>
  198.         ''' Removes a Client based on their name.
  199.         ''' </summary>
  200.         ''' <param name="name">The Name to remove.</param>
  201.         ''' <remarks></remarks>
  202.         Public Sub Remove(ByVal name As String)
  203.             Dim Usr As User = FindUser(name)
  204.             If Usr IsNot Nothing Then Call Remove(Usr)
  205.         End Sub
  206.  
  207. #End Region
  208.  
  209. #Region " Message Handling "
  210.  
  211.         ''' <summary>
  212.         ''' Send a Message from the Server to the chatroom.
  213.         ''' </summary>
  214.         ''' <param name="message">The Message to send.</param>
  215.         ''' <remarks></remarks>
  216.         Public Sub ServerMessage(ByVal message As String)
  217.             Dim Msg As New ArkDLL.GroupMessage With {.GroupName = Me.m_Name, .Message = message, .Sender = "SERVER"}
  218.             For Each usr As User In m_UserList
  219.                 usr.SendMessage(Msg)
  220.             Next
  221.         End Sub
  222.  
  223.         ''' <summary>
  224.         ''' Send a new Userlist to each person.
  225.         ''' </summary>
  226.         ''' <remarks></remarks>
  227.         Public Sub Update()
  228.             RaiseEvent Log("Creating a GroupList.")
  229.             Dim newList As New GroupList With {.GroupName = Me.Name}
  230.             Dim UserList As List(Of String) = Me.Group(True)
  231.             newList.GroupList = UserList
  232.             For Each cli As User In m_UserList
  233.                 RaiseEvent Log(String.Format("Sent list to {0}", cli.Name))
  234.                 cli.SendMessage(newList)
  235.             Next
  236.         End Sub
  237.  
  238.         ''' <summary>
  239.         ''' Send a Message to the Group.
  240.         ''' </summary>
  241.         ''' <param name="sender">The Client that's sending the message.</param>
  242.         ''' <param name="message">The message to send.</param>
  243.         ''' <remarks></remarks>
  244.         Public Sub Send(ByVal sender As User, ByVal message As String)
  245.             If IsUserInGroup(sender) AndAlso sender.PermissionLevel > 0 Then 'make sure the user is in the group.
  246.                 'See if it's a command we can parse.
  247.  
  248.                 If message.StartsWith("/command") Then
  249.                     'Now to find out what to do.
  250.                     Dim MsgArr() As String = message.Split(" "c)
  251.                     Select Case MsgArr(1).ToLower
  252.                         Case "voice"
  253.                             'Set to Voice.
  254.                             Call SetStatus(sender, MsgArr(2), User.Permission.VOICE)
  255.                         Case "devoice"
  256.                             'Set to None.
  257.                             Call SetStatus(sender, MsgArr(2), User.Permission.MUTE)
  258.                         Case "hop"
  259.                             'Set to Half Operator
  260.                             Call SetStatus(sender, MsgArr(2), User.Permission.HALFOP)
  261.                         Case "dehop"
  262.                             'Set to Voice.
  263.                             Call SetStatus(sender, MsgArr(2), User.Permission.VOICE)
  264.                         Case "op"
  265.                             'Set to Operator.
  266.                             Call SetStatus(sender, MsgArr(2), User.Permission.OP)
  267.                         Case "deop"
  268.                             'Set to Voice.
  269.                             Call SetStatus(sender, MsgArr(2), User.Permission.VOICE)
  270.                         Case "admin"
  271.                             'Set to Admin.
  272.                             Call SetStatus(sender, MsgArr(2), User.Permission.ADMIN)
  273.                         Case "deadmin"
  274.                             'Set to Voice.
  275.                             Call SetStatus(sender, MsgArr(2), User.Permission.VOICE)
  276.                         Case "kick"
  277.                             Call KickUser(sender, MsgArr(2))
  278.                     End Select
  279.  
  280.                 Else
  281.  
  282.                     'Raise an event.
  283.                     'RaiseEvent Message(sender.Client, message, Me)
  284.                     Dim MessageToSend As New GroupMessage With {.GroupName = Me.Name, .Message = message, .Sender = sender.Name}
  285.                     'create the message
  286.                     For Each UsrClient As User In m_UserList
  287.                         'create a for loop to send the message to each person.
  288.                         UsrClient.SendMessage(MessageToSend) 'send message.
  289.                     Next
  290.  
  291.                 End If
  292.             ElseIf sender.PermissionLevel = 0 Then
  293.                 sender.SendMessage("You do not have the required permission levels to speak!")
  294.             End If
  295.         End Sub
  296.  
  297. #End Region
  298.  
  299. #Region " Properties and Functions "
  300.  
  301.         ''' <summary>
  302.         ''' Return the Group Name
  303.         ''' </summary>
  304.         ''' <value></value>
  305.         ''' <returns></returns>
  306.         ''' <remarks></remarks>
  307.         Public ReadOnly Property Name() As String
  308.             Get
  309.                 Return m_Name 'Return the name of the chatroom.
  310.             End Get
  311.         End Property
  312.  
  313.         ''' <summary>
  314.         ''' Returns the Administrator of the Chatroom.
  315.         ''' </summary>
  316.         ''' <value></value>
  317.         ''' <returns></returns>
  318.         ''' <remarks></remarks>
  319.         Public ReadOnly Property Admin() As User
  320.             Get
  321.                 Return m_Maker 'return admin.
  322.             End Get
  323.         End Property
  324.  
  325.         ''' <summary>
  326.         ''' Returns if the Group is a Public group or not.
  327.         ''' </summary>
  328.         ''' <value></value>
  329.         ''' <returns></returns>
  330.         ''' <remarks></remarks>
  331.         Public Property IsPublic As Boolean
  332.             Get
  333.                 Return m_Public
  334.             End Get
  335.             Set(ByVal value As Boolean)
  336.                 m_Public = value
  337.             End Set
  338.         End Property
  339.  
  340.         ''' <summary>
  341.         ''' Return the User list as a List(Of String)
  342.         ''' </summary>
  343.         ''' <param name="sorted">If the List is sorted or not.</param>
  344.         ''' <returns></returns>
  345.         ''' <remarks></remarks>
  346.         Public Function Group(ByVal sorted As Boolean) As List(Of String)
  347.             'Create a list of string to store the returned values
  348.             Dim ClientList As New List(Of String)
  349.             'make a for loop
  350.             For Each item As User In m_UserList
  351.                 'add the client's name to the list.
  352.                 Dim PreLetter As String = String.Empty
  353.                 Select Case item.PermissionLevel
  354.                     Case User.Permission.ADMIN
  355.                         PreLetter = "[Adm] "
  356.                     Case User.Permission.HALFOP
  357.                         PreLetter = "[H] "
  358.                     Case User.Permission.MUTE
  359.                         PreLetter = "[M] "
  360.                     Case User.Permission.OP
  361.                         PreLetter = "[Op] "
  362.                     Case User.Permission.OWNER
  363.                         PreLetter = "[Own] "
  364.                     Case User.Permission.VOICE
  365.                         PreLetter = "[V] "
  366.                 End Select
  367.                 ClientList.Add(String.Format("{0}{1}", PreLetter, item.Name))
  368.             Next
  369.             'if we want it sorted, then sort
  370.             If sorted Then ClientList.Sort()
  371.             'return the list.
  372.             Return ClientList
  373.         End Function
  374.  
  375.         ''' <summary>
  376.         ''' Returns the User list as a List(Of Client)
  377.         ''' </summary>
  378.         ''' <returns></returns>
  379.         ''' <remarks></remarks>
  380.         Public Function Group() As List(Of User)
  381.             'return the client list.
  382.             Return m_UserList
  383.         End Function
  384.  
  385.         ''' <summary>
  386.         ''' See if a user is in the group.
  387.         ''' </summary>
  388.         ''' <param name="User">The User to check.</param>
  389.         ''' <returns></returns>
  390.         ''' <remarks></remarks>
  391.         Public Function IsUserInGroup(ByVal User As User) As Boolean
  392.             'Setup a for loop to see if the user exists in the group.
  393.             For Each item As User In m_UserList
  394.                 'If we found them, return true.
  395.                 If item Is User Then Return True
  396.             Next
  397.             'user wasn't found, return false.
  398.             Return False
  399.         End Function
  400.  
  401.         ''' <summary>
  402.         ''' See if a user is in the group.
  403.         ''' </summary>
  404.         ''' <param name="client">The client to look for.</param>
  405.         ''' <returns></returns>
  406.         ''' <remarks></remarks>
  407.         Public Function IsUserInGroup(ByVal client As Client) As Boolean
  408.             Dim Usr As User = FindUser(client)
  409.             If Usr IsNot Nothing Then
  410.                 Return IsUserInGroup(Usr)
  411.             End If
  412.             Return False
  413.         End Function
  414.  
  415.         ''' <summary>
  416.         ''' See ifa user is in the group.
  417.         ''' </summary>
  418.         ''' <param name="name">The name to look for.</param>
  419.         ''' <returns></returns>
  420.         ''' <remarks></remarks>
  421.         Public Function IsUserInGroup(ByVal name As String) As Boolean
  422.             'Setup a for loop to see if the user exists in the group.
  423.             For Each item As User In m_UserList
  424.                 'If we found them, return true.
  425.                 If item.Name = name Then Return True
  426.             Next
  427.             'user wasn't found, return false.
  428.             Return False
  429.         End Function
  430.  
  431.         ''' <summary>
  432.         ''' Returns a User based on the username.
  433.         ''' </summary>
  434.         ''' <param name="username">The Username to look for.</param>
  435.         ''' <returns></returns>
  436.         ''' <remarks></remarks>
  437.         Public Function ReturnUser(ByVal username As String) As User
  438.             SyncLock m_UserList
  439.                 For Each item As User In m_UserList
  440.                     If item.Name = username Then Return item
  441.                 Next
  442.             End SyncLock
  443.             Return Nothing
  444.         End Function
  445.  
  446.         ''' <summary>
  447.         ''' Returns the String Representation of the Group
  448.         ''' </summary>
  449.         ''' <returns></returns>
  450.         ''' <remarks></remarks>
  451.         Public Overrides Function ToString() As String
  452.             Return Me.Name
  453.         End Function
  454.  
  455. #End Region
  456.  
  457. #Region " Misc. Subs "
  458.  
  459.         ''' <summary>
  460.         ''' Disposes of the Group.
  461.         ''' </summary>
  462.         ''' <remarks></remarks>
  463.         Public Sub Dispose()
  464.             Dim GMsg As New GroupMessage With {.Sender = "SERVER", .Message = "DISPOSE", .GroupName = Me.Name}
  465.             For Each cli As User In m_UserList
  466.                 cli.SendMessage(GMsg)
  467.             Next
  468.         End Sub
  469.  
  470.         ''' <summary>
  471.         ''' Returns the User Object based on the Client Object.
  472.         ''' </summary>
  473.         ''' <param name="Cli">The Client Object to locate.</param>
  474.         ''' <returns>The User Object</returns>
  475.         ''' <remarks></remarks>
  476.         Public Function FindUser(ByVal Cli As Client) As User
  477.             Return FindUser(Cli.Name)
  478.         End Function
  479.  
  480.         ''' <summary>
  481.         ''' Returns the User Object based on the Client's Name.
  482.         ''' </summary>
  483.         ''' <param name="Name">The Name of the User to locate.</param>
  484.         ''' <returns>The User Object</returns>
  485.         ''' <remarks></remarks>
  486.         Public Function FindUser(ByVal Name As String) As User
  487.             For i As Integer = m_UserList.Count - 1 To 0 Step -1
  488.                 If m_UserList(i).Name = Name Then Return m_UserList(i)
  489.             Next
  490.             Return Nothing
  491.         End Function
  492.  
  493. #End Region
  494.  
  495. #Region " Group Administration Commands "
  496.  
  497.         ''' <summary>
  498.         ''' An Administrative Only sub. It kicks the specified person.
  499.         ''' </summary>
  500.         ''' <param name="sender">The Client sending the kick request.</param>
  501.         ''' <param name="PersonToKick">The name of the client to kick.</param>
  502.         ''' <remarks></remarks>
  503.         Private Sub KickUser(ByVal sender As User, ByVal PersonToKick As String)
  504.             RaiseEvent Log("Kicking attempt.")
  505.             'If the sender is half op or higher, is in the group, not kicking the owner, AND sender is also above the person being kicked.
  506.             If (sender.PermissionLevel >= User.Permission.HALFOP) AndAlso IsUserInGroup(sender) AndAlso (FindUser(PersonToKick).PermissionLevel < User.Permission.OWNER) AndAlso (FindUser(PersonToKick).PermissionLevel < sender.PermissionLevel) Then
  507.                 RaiseEvent Log(String.Format("Valid attempt by a half op or higher. {0}", sender.Name))
  508.                 'Since the sender is the Admin, we can do this.
  509.                 For i As Integer = m_UserList.Count - 1 To 0 Step -1
  510.                     'Work down the list, looking for the user.
  511.                     'If the name and the person to kick is true
  512.                     If m_UserList(i).Name = PersonToKick Then
  513.                         'Remove them.
  514.                         Call ServerMessage(String.Format("{0} has removed {1} from the chat room.", sender.Name, PersonToKick))
  515.                         m_UserList.RemoveAt(i)
  516.                         'Now call the update
  517.                         Call Update()
  518.                     End If
  519.                 Next
  520.             End If
  521.         End Sub
  522.  
  523.         ''' <summary>
  524.         ''' Set's a User's new status.
  525.         ''' </summary>
  526.         ''' <param name="sender">The Person doing the modifiying.</param>
  527.         ''' <param name="modified">The name of the user being modified.</param>
  528.         ''' <param name="NewLevel">The level they are being sent to.</param>
  529.         ''' <remarks></remarks>
  530.         Public Sub SetStatus(ByVal sender As User, ByVal modified As String, ByVal NewLevel As User.Permission)
  531.             'If they aren't just standard voice, and their permission is greater than or equal to the New Level.
  532.             If (sender.PermissionLevel > User.Permission.VOICE) AndAlso (sender.PermissionLevel >= NewLevel) Then
  533.                 Dim Usr As User = FindUser(modified)
  534.                 'If User isn't nothing, Permission isn't the same, they aren't the owner, and if the sender is actually the same or higher (to prevent half ops from fucking over operators, etc)
  535.                 If (Usr IsNot Nothing) AndAlso (Usr.PermissionLevel <> NewLevel) AndAlso (Usr.PermissionLevel < User.Permission.OWNER) AndAlso (sender.PermissionLevel >= Usr.PermissionLevel) Then
  536.                     If (sender Is Admin) AndAlso (Usr Is Admin) AndAlso (NewLevel < User.Permission.OWNER) Then
  537.                     Else
  538.                         'Awesome. All requirements met.
  539.                         Usr.PermissionLevel = NewLevel
  540.                         'Tell the chatroom.
  541.                         Call ServerMessage(String.Format("{0} has changed {1}'s level to {2}", sender.Name, modified, NewLevel.ToString))
  542.                         'Update the user list.
  543.                         Call Update()
  544.                     End If
  545.                 End If
  546.             End If
  547.         End Sub
  548.  
  549.         ''' <summary>
  550.         ''' Server Side Edit on a user. It will not override the Owner Level, nor set someone else to owner.
  551.         ''' </summary>
  552.         ''' <param name="username">The Username to manipulate.</param>
  553.         ''' <param name="NewStatus">The new status.</param>
  554.         ''' <remarks></remarks>
  555.         Public Sub SetOverrideStatus(ByVal username As String, ByVal NewStatus As User.Permission)
  556.             If IsUserInGroup(username) Then
  557.                 Dim User As User = ReturnUser(username)
  558.                 If User.PermissionLevel < TCPV2.Group.User.Permission.OWNER AndAlso NewStatus <> TCPV2.Group.User.Permission.OWNER Then
  559.                     User.PermissionLevel = NewStatus
  560.                     ServerMessage(String.Format("Override from server. {0} is now {1}", username, NewStatus.ToString))
  561.                     Call Update()
  562.                 End If
  563.             End If
  564.         End Sub
  565.  
  566.         ''' <summary>
  567.         ''' Invokes a Server kick, which will remove any user BUT the owner.
  568.         ''' </summary>
  569.         ''' <param name="username">The Username to kick.</param>
  570.         ''' <remarks></remarks>
  571.         Public Sub KickOverrideUser(ByVal username As String)
  572.             For i As Integer = m_UserList.Count - 1 To 0 Step -1
  573.                 'Work down the list, looking for the user.
  574.                 'If the name and the person to kick is true
  575.                 If m_UserList(i).Name = username Then
  576.                     'Remove them.
  577.                     'If Not ReturnUser(username).PermissionLevel = User.Permission.OWNER Then
  578.                     Call ServerMessage(String.Format("{0} has been removed from the chat room by the server.", username))
  579.                     m_UserList.RemoveAt(i)
  580.                     'Now call the update
  581.                     Call Update()
  582.                     'End If
  583.                 End If
  584.             Next
  585.         End Sub
  586.  
  587. #End Region
  588.  
  589.     End Class
  590.  
  591.     ''' <summary>
  592.     ''' The Client Sub Class.
  593.     ''' </summary>
  594.     ''' <remarks>This Class contains all the code required to maintain connections to clients.</remarks>
  595.     Public Class Client
  596.  
  597. #Region " Variables "
  598.         Private readThread As Threading.Thread 'Reader thread.
  599.         Private m_Name As String = String.Empty 'client's name.
  600.         Private m_Client As TcpClient 'the tcp client, do not ever dispose this!
  601.         Private BinFormatter As Binary.BinaryFormatter 'The binary formatter that handles our queries.
  602.         Private m_FriendList As New List(Of User) 'the friends list!
  603.         Private m_Status As String = String.Empty 'The client's status.
  604.         Private m_Password As String = String.Empty 'the client's password.
  605.         Private m_Display As String = String.Empty 'the client's display name.
  606.         Private m_Read As Boolean = True
  607.         Friend UIC As New UserInterfaceClass
  608. #End Region
  609.  
  610. #Region " Sub Class "
  611.         Public Class UserInterfaceClass
  612.             'Variable Declarations
  613.             'Used for saving and loading.
  614.  
  615. #Region " Properties "
  616.             Public Property Password As String = String.Empty
  617.             Public Property Status As String = String.Empty
  618.             Public Property Display As String = String.Empty
  619.             Public Property Friends As New List(Of String)
  620.             Public Property IP As String = String.Empty
  621. #End Region
  622.  
  623.             ''' <summary>
  624.             ''' Save the User to an XML file.
  625.             ''' </summary>
  626.             ''' <param name="FileName">The Username to save.</param>
  627.             ''' <returns></returns>
  628.             ''' <remarks></remarks>
  629.             Friend Function SaveUser(ByVal FileName As String) As Boolean
  630.                 If FileName = String.Empty Then Return False
  631.                 Try
  632.                     FileName = String.Format("{0}\Users\{1}.xml", Application.StartupPath, FileName)
  633.                     Debug.WriteLine(FileName)
  634.  
  635.                     If File.Exists(FileName) Then File.Delete(FileName)
  636.                     Dim XmlDoc As New XmlTextWriter(FileName, System.Text.Encoding.UTF8) With {.Formatting = Formatting.Indented}
  637.  
  638.                     XmlDoc.WriteStartDocument() 'Start
  639.  
  640.                     XmlDoc.WriteStartElement("information") '<information>
  641.  
  642.                     XmlDoc.WriteStartElement("password") '<password>
  643.                     XmlDoc.WriteString(Me.Password)
  644.                     XmlDoc.WriteEndElement() '</password>
  645.  
  646.                     XmlDoc.WriteStartElement("display") '<display>
  647.                     XmlDoc.WriteString(Me.Display)
  648.                     XmlDoc.WriteEndElement() '</display>
  649.  
  650.                     XmlDoc.WriteStartElement("status") '<status>
  651.                     XmlDoc.WriteString(Me.Status)
  652.                     XmlDoc.WriteEndElement() '</status>
  653.  
  654.                     XmlDoc.WriteStartElement("ip") '<ip>
  655.                     XmlDoc.WriteString(Me.IP)
  656.                     XmlDoc.WriteEndElement() '</ip>
  657.  
  658.                     If Me.Friends.Count > 0I Then
  659.                         XmlDoc.WriteStartElement("friends") '<friends>
  660.                         For Each item As String In Me.Friends
  661.                             XmlDoc.WriteStartElement("name") '<name>
  662.                             XmlDoc.WriteString(item) '<item>
  663.                             XmlDoc.WriteEndElement() '</name>
  664.                         Next
  665.                         XmlDoc.WriteEndElement() '</friends>
  666.                     End If
  667.  
  668.                     XmlDoc.WriteEndElement() '</information>
  669.                     XmlDoc.WriteEndDocument() 'End
  670.                     XmlDoc.Close()
  671.                 Catch ex As Exception
  672.                     Return False
  673.                 End Try
  674.                 Return True
  675.             End Function
  676.  
  677.             ''' <summary>
  678.             ''' Load the selected Username.
  679.             ''' </summary>
  680.             ''' <param name="FileName">The Username to load.</param>
  681.             ''' <returns>True/False</returns>
  682.             ''' <remarks></remarks>
  683.             Friend Function LoadUser(ByVal FileName As String) As Boolean
  684.  
  685.                 Me.Dispose()
  686.                 Dim XmlDoc As New XmlDocument
  687.                 FileName = String.Format("{0}\Users\{1}.xml", Application.StartupPath, FileName)
  688.  
  689.                 Try
  690.                     XmlDoc.Load(FileName)
  691.                     Dim InformationList As XmlNodeList = XmlDoc.SelectNodes("information")
  692.                     Dim FriendsList As XmlNodeList = XmlDoc.SelectNodes("friends")
  693.  
  694.                     If InformationList.Count > 0I Then
  695.  
  696.                         With InformationList(0)
  697.                             Me.Password = .Item("password").InnerText
  698.                             Me.Status = .Item("status").InnerText
  699.                             Me.Display = .Item("display").InnerText
  700.                             Try
  701.                                 Me.IP = .Item("ip").InnerText
  702.                             Catch ex As Exception
  703.                                 'No IP? We'll save it next time.
  704.                             End Try
  705.                         End With
  706.  
  707.                         FriendsList = InformationList(0).SelectNodes("friends/name")
  708.  
  709.                         For FriendsCounter As Integer = FriendsList.Count - 1I To 0I Step -1
  710.                             With FriendsList(FriendsCounter)
  711.                                 Try
  712.                                     If .InnerText <> String.Empty Then
  713.                                         Debug.WriteLine(.InnerText)
  714.                                         Me.Friends.Add(.InnerText)
  715.                                     End If
  716.                                 Catch ex As NullReferenceException
  717.                                     Debug.WriteLine("He has no friends!")
  718.                                 End Try
  719.                             End With
  720.                         Next FriendsCounter
  721.  
  722.                     End If
  723.  
  724.                     XmlDoc = Nothing
  725.                     Return True
  726.                 Catch ex As Exception
  727.                     Debug.WriteLine(ex.ToString)
  728.                     Return False
  729.                 Finally
  730.                     XmlDoc = Nothing
  731.                 End Try
  732.  
  733.             End Function
  734.  
  735.             ''' <summary>
  736.             ''' Reset the UIC
  737.             ''' </summary>
  738.             ''' <remarks></remarks>
  739.             Friend Sub Dispose()
  740.                 Me.Password = String.Empty
  741.                 Me.Status = String.Empty
  742.                 Me.Display = String.Empty
  743.                 Me.Friends.Clear()
  744.             End Sub
  745.  
  746.         End Class
  747. #End Region
  748.  
  749. #Region " Events "
  750.  
  751.         ''' <summary>
  752.         ''' The Message Received Event.
  753.         ''' </summary>
  754.         ''' <param name="cli">The Client that sent the message.</param>
  755.         ''' <param name="obj">The Object the client sent.</param>
  756.         ''' <remarks></remarks>
  757.         Friend Event Message(ByVal cli As Client, ByVal obj As Object)
  758.  
  759.         ''' <summary>
  760.         ''' The Error Event for a Client.
  761.         ''' </summary>
  762.         ''' <param name="cli">The Client that threw the error.</param>
  763.         ''' <param name="err">The exception data.</param>
  764.         ''' <remarks></remarks>
  765.         Friend Event ErrorOut(ByVal cli As Client, ByVal err As Exception)
  766.  
  767.         ''' <summary>
  768.         ''' Our Timer for checking for timeouts.
  769.         ''' </summary>
  770.         ''' <remarks></remarks>
  771.         Private WithEvents TimeoutTimer As New System.Timers.Timer With {.Interval = 5000, .AutoReset = True, .Enabled = False}
  772.  
  773. #End Region
  774.  
  775. #Region " Properties "
  776.         ''' <summary>
  777.         ''' Get or Set the Name of the Client.
  778.         ''' </summary>
  779.         ''' <value></value>
  780.         ''' <returns></returns>
  781.         ''' <remarks></remarks>
  782.         Public Property Name() As String
  783.             Get
  784.                 Return m_Name
  785.             End Get
  786.             Set(ByVal value As String)
  787.                 m_Name = value
  788.             End Set
  789.         End Property
  790.  
  791.         ''' <summary>
  792.         ''' Get or Set the Client's Friend List.
  793.         ''' </summary>
  794.         ''' <value></value>
  795.         ''' <returns></returns>
  796.         ''' <remarks></remarks>
  797.         Public Property Friends As List(Of User)
  798.             Get
  799.                 Return m_FriendList
  800.             End Get
  801.             Set(ByVal value As List(Of User))
  802.                 m_FriendList = value
  803.             End Set
  804.         End Property
  805.  
  806.         ''' <summary>
  807.         ''' Get or Set the Client's Status
  808.         ''' </summary>
  809.         ''' <value></value>
  810.         ''' <returns></returns>
  811.         ''' <remarks></remarks>
  812.         Public Property Status As String
  813.             Get
  814.                 Return m_Status
  815.             End Get
  816.             Set(ByVal value As String)
  817.                 m_Status = value
  818.                 If value <> String.Empty Then SendMessage(New User With {.User = Name, .Status = Status, .Online = True, .Display = Display})
  819.             End Set
  820.         End Property
  821.  
  822.         ''' <summary>
  823.         ''' Get or Set the Client's Password
  824.         ''' </summary>
  825.         ''' <value></value>
  826.         ''' <returns></returns>
  827.         ''' <remarks></remarks>
  828.         Public Property Password() As String
  829.             Get
  830.                 Return m_Password
  831.             End Get
  832.             Set(ByVal value As String)
  833.                 m_Password = value
  834.             End Set
  835.         End Property
  836.  
  837.         ''' <summary>
  838.         ''' Get or Set the Client's Display Name
  839.         ''' </summary>
  840.         ''' <value></value>
  841.         ''' <returns></returns>
  842.         ''' <remarks></remarks>
  843.         Public Property Display() As String
  844.             Get
  845.                 Return m_Display
  846.             End Get
  847.             Set(ByVal value As String)
  848.                 m_Display = value
  849.                 If value <> String.Empty Then SendMessage(New User With {.User = Name, .Status = Status, .Online = True, .Display = Display})
  850.             End Set
  851.         End Property
  852. #End Region
  853.  
  854. #Region " Friend Subs "
  855.  
  856.         ''' <summary>
  857.         ''' Add a friend to the Client's Friend List.
  858.         ''' </summary>
  859.         ''' <param name="friendName">The Friend name to add.</param>
  860.         ''' <param name="friendStatus">The status of the friend to add.</param>
  861.         ''' <remarks></remarks>
  862.         Public Sub AddFriend(ByVal friendName As String, ByVal friendStatus As String, ByVal online As Boolean, ByVal Display As String)
  863.             SyncLock m_FriendList
  864.                 If Not IsUserInFriendList(friendName) Then
  865.                     Dim NewFriend As New User With {.User = friendName, .Status = friendStatus, .Online = online, .Display = Display}
  866.                     m_FriendList.Add(NewFriend)
  867.                     If online Then
  868.                         SendMessage(NewFriend)
  869.                     End If
  870.                 End If
  871.             End SyncLock
  872.         End Sub
  873.  
  874.         ''' <summary>
  875.         ''' Add a friend to the Client's Friend List.
  876.         ''' </summary>
  877.         ''' <param name="FriendData">The User Structure.</param>
  878.         ''' <remarks></remarks>
  879.         Public Sub AddFriend(ByVal FriendData As User)
  880.             Call AddFriend(FriendData.User, FriendData.Status, FriendData.Online, FriendData.Display)
  881.         End Sub
  882.  
  883.         ''' <summary>
  884.         ''' Update a friend's Status.
  885.         ''' </summary>
  886.         ''' <param name="friendName">The Friend's Name.</param>
  887.         ''' <param name="newStatus">Their new Status.</param>
  888.         ''' <remarks></remarks>
  889.         Public Sub UpdateFriend(ByVal friendName As String, ByVal newStatus As String, ByVal online As Boolean, ByVal display As String)
  890.             Call UpdateFriend(New User With {.User = friendName, .Status = newStatus, .Online = online, .Display = display})
  891.         End Sub
  892.  
  893.         ''' <summary>
  894.         ''' Update a friend's Status
  895.         ''' </summary>
  896.         ''' <param name="User">The User to update.</param>
  897.         ''' <remarks></remarks>
  898.         Public Sub UpdateFriend(ByVal User As User)
  899.             SendMessage(User)
  900.         End Sub
  901.  
  902.         ''' <summary>
  903.         ''' Construct the User's Friend List.
  904.         ''' </summary>
  905.         ''' <returns></returns>
  906.         ''' <remarks></remarks>
  907.         Public ReadOnly Property BuildFriendList() As String
  908.             Get
  909.                 Dim StrBld As New System.Text.StringBuilder
  910.                 For Each item As User In m_FriendList
  911.                     StrBld.Append(String.Format("{0}|", item.User))
  912.                 Next
  913.                 Return StrBld.ToString.Trim("|"c)
  914.             End Get
  915.         End Property
  916.  
  917.         ''' <summary>
  918.         ''' Send the Friends List
  919.         ''' </summary>
  920.         ''' <remarks></remarks>
  921.         Public Sub SendFriendList()
  922.             Dim FList As New FriendList
  923.             Dim UList As New List(Of User)
  924.             For Each item As User In Friends
  925.                 If item.Online Then UList.Add(item)
  926.             Next
  927.             FList.Friends = UList
  928.             SendMessage(FList)
  929.         End Sub
  930.  
  931.         ''' <summary>
  932.         ''' Send a Friends List
  933.         ''' </summary>
  934.         ''' <param name="friendList">The Friends List to send.</param>
  935.         ''' <remarks></remarks>
  936.         Public Sub SendFriendList(ByVal friendList As FriendList)
  937.             SendMessage(friendList)
  938.         End Sub
  939.  
  940.         ''' <summary>
  941.         ''' Remove a Friend from the Client's Friend List.
  942.         ''' </summary>
  943.         ''' <param name="name">The name of the Friend to remove.</param>
  944.         ''' <remarks></remarks>
  945.         Public Sub RemoveFriend(ByVal name As String)
  946.             For i As Integer = Friends.Count - 1 To 0 Step -1
  947.                 If Friends(i).User = name Then
  948.                     SendMessage(New User With {.User = Friends(i).User, .Status = "Offline", .Online = False, .Display = Friends(i).Display})
  949.                     Friends.RemoveAt(i)
  950.                 End If
  951.             Next
  952.         End Sub
  953.  
  954.         ''' <summary>
  955.         ''' Checks to see if someone exists in your friend's list.
  956.         ''' </summary>
  957.         ''' <param name="name">The name to look for.</param>
  958.         ''' <returns></returns>
  959.         ''' <remarks></remarks>
  960.         Public Function IsUserInFriendList(ByVal name As String) As Boolean
  961.             SyncLock Me.Friends
  962.                 For Each item As User In Me.Friends
  963.                     If item.User = name Then Return True
  964.                 Next
  965.                 Return False
  966.             End SyncLock
  967.         End Function
  968.  
  969. #End Region
  970.  
  971. #Region " Subs "
  972.  
  973.         ''' <summary>
  974.         ''' Create a new Client.
  975.         ''' </summary>
  976.         ''' <param name="client">The TCP Client that's connecting.</param>
  977.         ''' <remarks></remarks>
  978.         Public Sub New(ByVal client As TcpClient)
  979.             m_Client = client 'Transfer over the TcpClient to this class.
  980.             readThread = New System.Threading.Thread(AddressOf client_doRead) 'create new reading thread.
  981.             readThread.IsBackground = True 'set it to the background to not disturb the server
  982.             readThread.Start() 'start it.
  983.             TimeoutTimer.Enabled = True 'create our timeout timer.
  984.         End Sub
  985.  
  986.         ''' <summary>
  987.         ''' This should only be called internally by the program. DO NOT MAKE DIRECT CALLS TO THIS!
  988.         ''' </summary>
  989.         ''' <remarks></remarks>
  990.         Public Sub New()
  991.  
  992.         End Sub
  993.  
  994.         ''' <summary>
  995.         ''' The infinite doRead() sub. Handles all reading from the client.
  996.         ''' </summary>
  997.         ''' <remarks></remarks>
  998.         Private Sub client_doRead()
  999.             Try
  1000.                 Do While m_Read = True
  1001.                     BinFormatter = New Binary.BinaryFormatter()
  1002.                     'create a generic object
  1003.                     Dim obj As New Object
  1004.                     'deserialize the stream when a message comes in.
  1005.                     obj = BinFormatter.Deserialize(m_Client.GetStream)
  1006.                     RaiseEvent Message(Me, obj)
  1007.                 Loop
  1008.             Catch ex As Threading.ThreadAbortException
  1009.                 'Thread aborting. That's OK. I'm game with this.
  1010.                 Debug.WriteLine("Threading Exception, probably aborted.")
  1011.             Catch ex As SerializationException
  1012.                 Debug.WriteLine("Serialization Error, that's not good.")
  1013.                 RaiseEvent ErrorOut(Me, ex)
  1014.                 Me.Dispose()
  1015.             Catch ex As IOException
  1016.                 Debug.WriteLine("IO Exception. Stream died.")
  1017.                 RaiseEvent ErrorOut(Me, ex)
  1018.                 Me.Dispose()
  1019.             Catch ex As Exception
  1020.                 Debug.WriteLine("General Exception")
  1021.                 RaiseEvent ErrorOut(Me, ex)
  1022.                 Me.Dispose()
  1023.             End Try
  1024.         End Sub
  1025.  
  1026.         ''' <summary>
  1027.         ''' Send a Serialized Message to the Client. The Types are in the ArkDLL.
  1028.         ''' </summary>
  1029.         ''' <param name="message">The Object to send.</param>
  1030.         ''' <remarks></remarks>
  1031.         Public Sub SendMessage(ByVal message As Object)
  1032.             Dim SMAT As New Threading.Thread(New Threading.ParameterizedThreadStart(AddressOf SendMessageAsync))
  1033.             SMAT.Start(message)
  1034.         End Sub
  1035.  
  1036.         ''' <summary>
  1037.         ''' Sends a message across the stream Asynchronously.
  1038.         ''' </summary>
  1039.         ''' <param name="message">The message to send.</param>
  1040.         ''' <remarks></remarks>
  1041.         Private Sub SendMessageAsync(ByVal message As Object)
  1042.             Try
  1043.                 SyncLock m_Client.GetStream
  1044.                     BinFormatter = New Binary.BinaryFormatter()
  1045.                     BinFormatter.Serialize(m_Client.GetStream, message)
  1046.                     BinFormatter = Nothing
  1047.                 End SyncLock
  1048.             Catch BSE As SerializationException
  1049.                 Debug.WriteLine(BSE.ToString)
  1050.                 Me.Dispose()
  1051.             Catch exi As InvalidOperationException
  1052.                 'Debug.WriteLine(exi.StackTrace)
  1053.                 Debug.WriteLine(exi.Data.Item(0).ToString)
  1054.                 Me.Dispose()
  1055.             Catch ex As Exception
  1056.                 'The stream is broken.
  1057.                 Debug.WriteLine(ex.ToString)
  1058.                 Me.Dispose()
  1059.             End Try
  1060.         End Sub
  1061.  
  1062.         ''' <summary>
  1063.         ''' Save the User to file. Generally, this is called whenever the user is logging off and whenever the
  1064.         ''' server shuts down.
  1065.         ''' </summary>
  1066.         ''' <remarks></remarks>
  1067.         Public Sub SaveUser()
  1068.             Try
  1069.                 'Update the XML Information
  1070.                 UIC.Password = Me.Password
  1071.                 UIC.Status = Me.Status
  1072.                 UIC.Display = Me.Display
  1073.                 UIC.IP = Me.PublicIPAddress
  1074.                 UIC.Friends.Clear()
  1075.                 SyncLock Me.Friends
  1076.                     For Each item As User In Me.Friends
  1077.                         UIC.Friends.Add(item.User)
  1078.                     Next
  1079.                 End SyncLock
  1080.                 'Save the User
  1081.                 UIC.SaveUser(Me.Name)
  1082.             Catch ex As Exception
  1083.                 RaiseEvent ErrorOut(Me, ex)
  1084.             End Try
  1085.  
  1086.         End Sub
  1087.  
  1088.         ''' <summary>
  1089.         ''' Load the User from a file. This can only be called once.
  1090.         ''' It is recommended to send a Friends List AFTER loading is complete.
  1091.         ''' </summary>
  1092.         ''' <param name="user">The User to load.</param>
  1093.         ''' <remarks></remarks>
  1094.         Public Function LoadUser(ByVal user As String, ByVal pass As String) As Boolean
  1095.             If UIC.LoadUser(user) Then
  1096.                 'Compare Passwords
  1097.                 If UIC.Password = pass Then
  1098.                     'Hooray! Passwords check out.
  1099.                     Me.Name = user 'Set User
  1100.                     Me.Password = pass 'Set Pass
  1101.                     Me.Status = UIC.Status 'Set Status
  1102.                     Me.Display = UIC.Display 'Set Display
  1103.  
  1104.                     'Set Friends List.
  1105.                     For Each item As String In UIC.Friends
  1106.                         Me.Friends.Add(New User With {.User = item})
  1107.                     Next
  1108.                     Return True
  1109.                 End If
  1110.             End If
  1111.             Return False
  1112.         End Function
  1113.  
  1114.         ''' <summary>
  1115.         ''' Dispose of the Client
  1116.         ''' </summary>
  1117.         ''' <remarks></remarks>
  1118.         Public Sub Dispose()
  1119.             'Save just in case
  1120.             Me.SaveUser()
  1121.             'Throw the error.
  1122.             RaiseEvent ErrorOut(Me, New Exception("Client is Disposed."))
  1123.         End Sub
  1124.  
  1125.         ''' <summary>
  1126.         ''' Resets a few variables to nothing.
  1127.         ''' </summary>
  1128.         ''' <remarks></remarks>
  1129.         Public Sub VariableReset()
  1130.             TimeoutTimer.Stop()
  1131.             TimeoutTimer.Dispose()
  1132.             m_Name = String.Empty
  1133.             m_Display = String.Empty
  1134.             m_Status = String.Empty
  1135.             m_Password = String.Empty
  1136.             m_Read = False
  1137.             BinFormatter = Nothing
  1138.             Try
  1139.                 readThread.Abort()
  1140.             Catch
  1141.             End Try
  1142.             m_Client.Close()
  1143.             m_Client.Client.Close()
  1144.             GC.Collect()
  1145.         End Sub
  1146.  
  1147.         ''' <summary>
  1148.         ''' Check to see if the client has been f**ked.
  1149.         ''' </summary>
  1150.         ''' <param name="sender"></param>
  1151.         ''' <param name="e"></param>
  1152.         ''' <remarks></remarks>
  1153.         Private Sub TimeoutTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles TimeoutTimer.Elapsed
  1154.             RaiseEvent Message(Me, New Message With {.Sender = Me.Name, .Receiver = "SERVER", .Message = String.Format("Ping to {0}", Me.Name)})
  1155.             Me.SendMessage(New Message With {.Message = "ping"})
  1156.         End Sub
  1157.  
  1158.         Public Overrides Function ToString() As String
  1159.             Return Me.Name
  1160.         End Function
  1161.  
  1162.         Private PublicIP As String = String.Empty
  1163.  
  1164.         ''' <summary>
  1165.         ''' Returns the IP address of the Client.
  1166.         ''' </summary>
  1167.         ''' <value></value>
  1168.         ''' <returns></returns>
  1169.         ''' <remarks></remarks>
  1170.         Public ReadOnly Property PublicIPAddress() As String
  1171.             Get
  1172.                 If PublicIP = String.Empty Then
  1173.                     Try
  1174.                         ' Get the clients IP address using Client property            
  1175.  
  1176.                         Dim ipend As Net.IPEndPoint = CType(m_Client.Client.RemoteEndPoint, Net.IPEndPoint)
  1177.                         If Not ipend Is Nothing Then
  1178.                             PublicIP = ipend.Address.ToString
  1179.                         End If
  1180.                     Catch ex As System.ObjectDisposedException
  1181.                         PublicIP = String.Empty
  1182.                     Catch ex As SocketException
  1183.                         PublicIP = String.Empty
  1184.                     End Try
  1185.                 End If
  1186.                 Return PublicIP
  1187.             End Get
  1188.         End Property
  1189.  
  1190. #End Region
  1191.  
  1192.     End Class
  1193.  
  1194.     ''' <summary>
  1195.     ''' The Item Queue Class. Very important for managing offline messages and friend requests.
  1196.     ''' </summary>
  1197.     ''' <remarks></remarks>
  1198.     Public Class ItemQueue
  1199.  
  1200. #Region " Variables "
  1201.  
  1202.         Private TCPLoop As TCPV2
  1203.  
  1204. #End Region
  1205.  
  1206. #Region " Misc. Subs "
  1207.  
  1208.         ''' <summary>
  1209.         ''' Creates a new ItemQueue Class to store data for offline people.
  1210.         ''' </summary>
  1211.         ''' <param name="server">A reference to the TCP Server</param>
  1212.         ''' <remarks></remarks>
  1213.         Public Sub New(ByRef server As TCPV2)
  1214.             TCPLoop = server
  1215.         End Sub
  1216.  
  1217. #End Region
  1218.  
  1219. #Region " Structures "
  1220.  
  1221.         ''' <summary>
  1222.         ''' User Queue Structure. Fill all the data in.
  1223.         ''' </summary>
  1224.         ''' <remarks></remarks>
  1225.         Public Structure UserQueueData
  1226.  
  1227.             ''' <summary>
  1228.             ''' Gets or Sets the User that the data is for.
  1229.             ''' </summary>
  1230.             ''' <value></value>
  1231.             ''' <returns></returns>
  1232.             ''' <remarks></remarks>
  1233.             Public Property User As String
  1234.  
  1235.             ''' <summary>
  1236.             ''' The User that is to be added to the friend list
  1237.             ''' when someone comes online.
  1238.             ''' </summary>
  1239.             ''' <value></value>
  1240.             ''' <returns></returns>
  1241.             ''' <remarks></remarks>
  1242.             Public Property Data As User
  1243.  
  1244.         End Structure
  1245.  
  1246.         ''' <summary>
  1247.         ''' Message Queue Structure. For Offline Messages.
  1248.         ''' </summary>
  1249.         ''' <remarks></remarks>
  1250.         Public Structure MessageQueueData
  1251.  
  1252.             ''' <summary>
  1253.             ''' Gets or Sets the User that the data is for.
  1254.             ''' </summary>
  1255.             ''' <value></value>
  1256.             ''' <returns></returns>
  1257.             ''' <remarks></remarks>
  1258.             Public Property User As String
  1259.  
  1260.             ''' <summary>
  1261.             ''' Gets or Sets the Message to transmit.
  1262.             ''' </summary>
  1263.             ''' <value></value>
  1264.             ''' <returns></returns>
  1265.             ''' <remarks></remarks>
  1266.             Public Property Message As Message
  1267.  
  1268.         End Structure
  1269.  
  1270.         ''' <summary>
  1271.         ''' Structure for Removing a User.
  1272.         ''' </summary>
  1273.         ''' <remarks></remarks>
  1274.         Public Structure RemoveUserQueueData
  1275.  
  1276.             ''' <summary>
  1277.             ''' Gets or Sets the User that the data is for.
  1278.             ''' </summary>
  1279.             ''' <value></value>
  1280.             ''' <returns></returns>
  1281.             ''' <remarks></remarks>
  1282.             Public Property User As String
  1283.  
  1284.             ''' <summary>
  1285.             ''' The name of the friend to remove.
  1286.             ''' </summary>
  1287.             ''' <value></value>
  1288.             ''' <returns></returns>
  1289.             ''' <remarks></remarks>
  1290.             Public Property RemoveFriend As String
  1291.  
  1292.         End Structure
  1293.  
  1294. #End Region
  1295.  
  1296. #Region " Properties "
  1297.  
  1298.         ''' <summary>
  1299.         ''' The User Queue is a list used to store what user needs to add new
  1300.         ''' friends when they login.
  1301.         ''' </summary>
  1302.         ''' <value></value>
  1303.         ''' <returns></returns>
  1304.         ''' <remarks></remarks>
  1305.         Private Property UserQueue As New List(Of UserQueueData)
  1306.  
  1307.         ''' <summary>
  1308.         ''' The Message Queue is used to store offline messages.
  1309.         ''' </summary>
  1310.         ''' <value></value>
  1311.         ''' <returns></returns>
  1312.         ''' <remarks></remarks>
  1313.         Private Property MessageQueue As New List(Of MessageQueueData)
  1314.  
  1315.         ''' <summary>
  1316.         ''' The Queue used to store remove friend requests.
  1317.         ''' </summary>
  1318.         ''' <value></value>
  1319.         ''' <returns></returns>
  1320.         ''' <remarks></remarks>
  1321.         Private Property RemoveQueue As New List(Of RemoveUserQueueData)
  1322.  
  1323. #End Region
  1324.  
  1325. #Region " Evaluation Subs "
  1326.  
  1327.         ''' <summary>
  1328.         ''' Evaluates Offline friend requests.
  1329.         ''' </summary>
  1330.         ''' <param name="user">The Client to manipulate.</param>
  1331.         ''' <remarks></remarks>
  1332.         Public Sub EvaluateUserQueue(ByRef user As Client)
  1333.             'Get the Username.
  1334.             Dim ClientName As String = user.Name
  1335.             Debug.WriteLine(ClientName)
  1336.             'Lock the User Queue.
  1337.             SyncLock UserQueue
  1338.                 'For Loop, going in reverse.
  1339.                 For i As Integer = UserQueue.Count - 1 To 0 Step -1
  1340.                     'Check to see if this is the right user.
  1341.                     If UserQueue(i).User = ClientName Then
  1342.                         Debug.WriteLine(String.Format("Offline Friend Request for {0}!", ClientName))
  1343.                         'it is, so add the friend.
  1344.                         Dim Data As User = UserQueue(i).Data
  1345.                         Data.Online = TCPLoop.UserLoggedIn(Data.User)
  1346.                         user.AddFriend(Data)
  1347.                         'Remove it from the queue since we're done.
  1348.                         UserQueue.RemoveAt(i)
  1349.                     End If
  1350.                     'Item was checked, go on to the next one.
  1351.                 Next
  1352.             End SyncLock
  1353.         End Sub
  1354.  
  1355.         ''' <summary>
  1356.         ''' Evaluates the Message Queue for offline messages.
  1357.         ''' </summary>
  1358.         ''' <param name="user">The Client to modify.</param>
  1359.         ''' <remarks></remarks>
  1360.         Public Sub EvaluateMessageQueue(ByRef user As Client)
  1361.             Try
  1362.                 'Get the Username.
  1363.                 Dim ClientName As String = user.Name
  1364.                 Debug.WriteLine(ClientName)
  1365.                 'Lock the User Queue.
  1366.                 SyncLock MessageQueue
  1367.                     'Setup the loop, going normal way
  1368.                     For i As Integer = 0 To MessageQueue.Count - 1
  1369.                         'If this is the right user.
  1370.                         If MessageQueue(i).User = ClientName Then
  1371.                             Debug.WriteLine(String.Format("Offline Message Found for {0}!", ClientName))
  1372.                             'send them a message.
  1373.                             user.SendMessage(MessageQueue(i).Message)
  1374.                             'now remove it
  1375.                             MessageQueue.RemoveAt(i)
  1376.                             'go back one.
  1377.                             i -= 1
  1378.                         End If
  1379.                     Next
  1380.                 End SyncLock
  1381.             Catch ex As IndexOutOfRangeException
  1382.             Catch ex As ArgumentOutOfRangeException
  1383.             End Try
  1384.         End Sub
  1385.  
  1386.         ''' <summary>
  1387.         ''' Evaluates the Remove Queue for the user.
  1388.         ''' </summary>
  1389.         ''' <param name="user">Reference to the User.</param>
  1390.         ''' <remarks></remarks>
  1391.         Public Sub EvaluateRemoveQueue(ByRef user As Client)
  1392.             'Get the Username.
  1393.             Dim ClientName As String = user.Name
  1394.             'Lock the Queue.
  1395.             SyncLock RemoveQueue
  1396.                 'For Loop, going in reverse.
  1397.                 For i As Integer = RemoveQueue.Count - 1 To 0 Step -1
  1398.                     'Check to see if this is the right user.
  1399.                     If RemoveQueue(i).User = ClientName Then
  1400.                         'it is, so add the friend.
  1401.                         user.RemoveFriend(RemoveQueue(i).RemoveFriend)
  1402.                         RemoveQueue.RemoveAt(i)
  1403.                     End If
  1404.                 Next
  1405.             End SyncLock
  1406.         End Sub
  1407.  
  1408. #End Region
  1409.  
  1410. #Region " Adding Subs "
  1411.  
  1412.         ''' <summary>
  1413.         ''' Adds a new item to the Offline Message Queue.
  1414.         ''' </summary>
  1415.         ''' <param name="user">The User that the message is being sent to.</param>
  1416.         ''' <param name="message">The Message that needs to be stored.</param>
  1417.         ''' <remarks></remarks>
  1418.         Public Sub AddOfflineMessage(ByVal user As String, ByVal message As Message)
  1419.             MessageQueue.Add(New MessageQueueData With {.User = user, .Message = message})
  1420.             Debug.WriteLine(String.Format("New Offline Message for {0} from {1}", user, message.Sender))
  1421.         End Sub
  1422.  
  1423.         ''' <summary>
  1424.         ''' Adds a new item to the Offline Friend Request Queue.
  1425.         ''' </summary>
  1426.         ''' <param name="user">The user to send the request to.</param>
  1427.         ''' <param name="FriendData">The Friend Data.</param>
  1428.         ''' <remarks></remarks>
  1429.         Public Sub AddOfflineFriendRequest(ByVal user As String, ByVal FriendData As User)
  1430.             UserQueue.Add(New UserQueueData With {.User = user, .Data = FriendData})
  1431.             Debug.WriteLine(String.Format("New Friend Request for {0} from {1}", user, FriendData.User))
  1432.         End Sub
  1433.  
  1434.         ''' <summary>
  1435.         ''' Adds a new item to the Offline Removal Request Queue
  1436.         ''' </summary>
  1437.         ''' <param name="user">The one who's friend list needs to be modified.</param>
  1438.         ''' <param name="name">The name of the friend to remove.</param>
  1439.         ''' <remarks></remarks>
  1440.         Public Sub AddOfflineRemoveRequest(ByVal user As String, ByVal name As String)
  1441.             RemoveQueue.Add(New RemoveUserQueueData With {.RemoveFriend = name, .User = user})
  1442.         End Sub
  1443.  
  1444. #End Region
  1445.  
  1446.     End Class
  1447.  
  1448. #End Region
  1449.  
  1450. #Region " Event Structures & Enums "
  1451.  
  1452.     Public Enum MessageTypeEnum
  1453.         Standard = 0
  1454.         Group = 1
  1455.     End Enum
  1456.  
  1457.     Public Structure MessageEventArgs
  1458.  
  1459.         ''' <summary>
  1460.         ''' The Message to pass in.
  1461.         ''' </summary>
  1462.         ''' <value></value>
  1463.         ''' <returns></returns>
  1464.         ''' <remarks></remarks>
  1465.         Public Property Message As String
  1466.  
  1467.         Public Property Type As MessageTypeEnum
  1468.  
  1469.         Public Property sender As Client
  1470.  
  1471.     End Structure
  1472.  
  1473.     Public Structure GroupCreationEventArgs
  1474.         Public Group As Group
  1475.     End Structure
  1476.  
  1477.     Public Structure LoginEventArgs
  1478.         ''' <summary>
  1479.         ''' The client that logged in.
  1480.         ''' </summary>
  1481.         ''' <value></value>
  1482.         ''' <returns></returns>
  1483.         ''' <remarks></remarks>
  1484.         Public Property Client As Client
  1485.     End Structure
  1486.  
  1487.     Public Structure LogoffEventArgs
  1488.         ''' <summary>
  1489.         ''' The client that logged in.
  1490.         ''' </summary>
  1491.         ''' <value></value>
  1492.         ''' <returns></returns>
  1493.         ''' <remarks></remarks>
  1494.         Public Property Client As Client
  1495.     End Structure
  1496.  
  1497.     Public Structure RegistrationEventArgs
  1498.         Public Property Client As Client
  1499.     End Structure
  1500.  
  1501. #End Region
  1502.  
  1503. #Region " Variables "
  1504.  
  1505.     Private m_GroupList As New List(Of Group)
  1506.     Private m_Users As New List(Of Client)
  1507.  
  1508.     Private ServerListener As TcpListener
  1509.     Private IncomingClient As TcpClient
  1510.     Private ListenThread As System.Threading.Thread
  1511.  
  1512.     Private QueueList As New ItemQueue(Me)
  1513.  
  1514.     Private ReadOnly m_DataDirectory As String = String.Format("{0}\Users\", Application.StartupPath)
  1515.  
  1516. #End Region
  1517.  
  1518. #Region " Properties "
  1519.     Public ReadOnly Property Groups As List(Of Group)
  1520.         Get
  1521.             Return m_GroupList
  1522.         End Get
  1523.     End Property
  1524.     Public ReadOnly Property Users As List(Of Client)
  1525.         Get
  1526.             Return m_Users
  1527.         End Get
  1528.     End Property
  1529.  
  1530.     Private WriteOnly Property Add As Client
  1531.         Set(ByVal value As Client)
  1532.             m_Users.Add(value)
  1533.         End Set
  1534.     End Property
  1535.     Private WriteOnly Property Remove As Client
  1536.         Set(ByVal value As Client)
  1537.             m_Users.Remove(value)
  1538.         End Set
  1539.     End Property
  1540. #End Region
  1541.  
  1542. #Region " Events "
  1543.  
  1544.     Public Event Message(ByVal sender As Object, ByVal e As MessageEventArgs) 'Message
  1545.     Public Event Login(ByVal sender As Object, ByVal e As LoginEventArgs) 'Someone logging in.
  1546.     Public Event Logoff(ByVal sender As Object, ByVal e As LogoffEventArgs) 'Someone logging out.
  1547.     Public Event Registration(ByVal sender As Object, ByVal e As RegistrationEventArgs) 'Registration.
  1548.     Public Event GroupCreated(ByVal sender As Object, ByVal e As GroupCreationEventArgs) 'Group created.
  1549.  
  1550.     ''' <summary>
  1551.     ''' Called when a message comes in.
  1552.     ''' </summary>
  1553.     ''' <param name="msg">The message that is called.</param>
  1554.     ''' <remarks></remarks>
  1555.     Protected Overridable Sub OnMessageReceived(ByVal msg As MessageEventArgs)
  1556.         RaiseEvent Message(Me, msg)
  1557.     End Sub
  1558.  
  1559.     ''' <summary>
  1560.     ''' Called when a Client Message comes in.
  1561.     ''' </summary>
  1562.     ''' <param name="msg">The Arguments.</param>
  1563.     ''' <remarks></remarks>
  1564.     Protected Overridable Sub OnClientMessageReceived(ByVal msg As MessageEventArgs)
  1565.         RaiseEvent Message(Me, msg)
  1566.     End Sub
  1567.  
  1568.     ''' <summary>
  1569.     ''' Called when a Client logs in.
  1570.     ''' </summary>
  1571.     ''' <param name="data">Login Event Argument data</param>
  1572.     ''' <remarks></remarks>
  1573.     Protected Overridable Sub OnClientLogin(ByVal data As LoginEventArgs)
  1574.         RaiseEvent Login(Me, data)
  1575.     End Sub
  1576.  
  1577.     ''' <summary>
  1578.     ''' Called when a Client logs off.
  1579.     ''' </summary>
  1580.     ''' <param name="data"></param>
  1581.     ''' <remarks></remarks>
  1582.     Protected Overridable Sub OnClientLogoff(ByVal data As LogoffEventArgs)
  1583.         RaiseEvent Logoff(Me, data)
  1584.     End Sub
  1585.  
  1586.     ''' <summary>
  1587.     ''' Called when a Client registers.
  1588.     ''' </summary>
  1589.     ''' <param name="data"></param>
  1590.     ''' <remarks></remarks>
  1591.     Protected Overridable Sub OnClientRegistration(ByVal data As RegistrationEventArgs)
  1592.         RaiseEvent Registration(Me, data)
  1593.     End Sub
  1594.  
  1595.     Protected Overridable Sub OnGroupCreation(ByVal data As GroupCreationEventArgs)
  1596.         RaiseEvent GroupCreated(Me, data)
  1597.     End Sub
  1598.  
  1599. #End Region
  1600.  
  1601. #Region " Server Code "
  1602.  
  1603.     ''' <summary>
  1604.     ''' Create a new Server Class on the specified port.
  1605.     ''' </summary>
  1606.     ''' <param name="port">Optional. Defaults to port 6110 if not specified.</param>
  1607.     ''' <remarks></remarks>
  1608.     Public Sub New(Optional ByVal port As Integer = 6110I)
  1609.         ServerListener = New TcpListener(Net.IPAddress.Any, port)
  1610.         GroupPurgeTimer.AutoReset = True
  1611.         GroupPurgeTimer.Enabled = True
  1612.         GroupPurgeTimer.Interval = 30000I
  1613.     End Sub
  1614.  
  1615.     ''' <summary>
  1616.     ''' Initialize the Server.
  1617.     ''' </summary>
  1618.     ''' <remarks></remarks>
  1619.     Public Sub Initialize()
  1620.         Me.OnMessageReceived(New MessageEventArgs With {.Message = "Starting Server...."})
  1621.         ServerListener.Start()
  1622.         Me.OnMessageReceived(New MessageEventArgs With {.Message = "Server started, creating Listener Thread."})
  1623.         ListenThread = New System.Threading.Thread(AddressOf Listener)
  1624.         Me.OnMessageReceived(New MessageEventArgs With {.Message = "Listener Thread Created, setting to Background."})
  1625.         ListenThread.IsBackground = True
  1626.         Me.OnMessageReceived(New MessageEventArgs With {.Message = "Starting listener..."})
  1627.         ListenThread.Start()
  1628.         Me.OnMessageReceived(New MessageEventArgs With {.Message = "Server Startup Complete."})
  1629.     End Sub
  1630.  
  1631.     ''' <summary>
  1632.     ''' The Listener Sub, constantly looping, waiting for new Clients.
  1633.     ''' </summary>
  1634.     ''' <remarks></remarks>
  1635.     Private Sub Listener()
  1636.         Try
  1637.             Do
  1638.                 IncomingClient = ServerListener.AcceptTcpClient()
  1639.                 Dim Client As New Client(IncomingClient)
  1640.                 'Perform IP filter here. If function returns true, they're
  1641.                 'safe to pass.
  1642.                 Me.OnMessageReceived(New MessageEventArgs With {.Message = ("Client Accepted, registering handlers.")})
  1643.                 AddHandler Client.Message, AddressOf GeneralMessageHandler
  1644.                 AddHandler Client.ErrorOut, AddressOf ErrorHandler
  1645.                 Me.OnMessageReceived(New MessageEventArgs With {.Message = ("Adding to Online List.")})
  1646.                 Add = Client
  1647.                 Me.OnMessageReceived(New MessageEventArgs With {.Message = ("Waiting for Response.")})
  1648.             Loop
  1649.         Catch ex As Exception
  1650.             Me.OnMessageReceived(New MessageEventArgs With {.Message = (ex.Message.ToString)})
  1651.         End Try
  1652.     End Sub
  1653.  
  1654.     ''' <summary>
  1655.     ''' Error handling sub that logs all exceptions by the server.
  1656.     ''' </summary>
  1657.     ''' <param name="sender">The Client that threw the error.</param>
  1658.     ''' <param name="ex">The exception.</param>
  1659.     ''' <remarks></remarks>
  1660.     Private Sub ErrorHandler(ByVal sender As Client, ByVal ex As Exception)
  1661.         'Remove from the online list.
  1662.         Remove = sender
  1663.  
  1664.         'Save the Client if nothing is wrong and if the name isn't empty (invalid client?)
  1665.         If sender.Name <> String.Empty Then sender.SaveUser()
  1666.  
  1667.         'log the exception
  1668.         Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("The client '{0}' threw an error:{1}{2}", sender.Name, Environment.NewLine, ex.ToString))})
  1669.         'Remove them from any possible groups. (SyncLocking just in case)
  1670.         SyncLock m_GroupList
  1671.             For i As Integer = m_GroupList.Count - 1 To 0 Step -1
  1672.                 Try
  1673.                     If m_GroupList(i).IsUserInGroup(sender) Then m_GroupList(i).Remove(sender)
  1674.                 Catch RemoveFromGroupException As Exception
  1675.                     Me.OnMessageReceived(New MessageEventArgs With {.Message = String.Format("Error removing {0} from a group.{1}{2}", sender.Name, Environment.NewLine, RemoveFromGroupException.ToString)})
  1676.                 End Try
  1677.             Next
  1678.         End SyncLock
  1679.  
  1680.         'Now alert his friends.
  1681.         SyncLock sender.Friends
  1682.             For Each item As User In sender.Friends
  1683.                 If UserLoggedIn(item.User) Then
  1684.                     Dim PersonToUpdate As Client = ReturnClient(item.User)
  1685.                     PersonToUpdate.UpdateFriend(New User With {.User = sender.Name, .Status = sender.Status, .Online = False, .Display = sender.Display})
  1686.                 End If
  1687.             Next
  1688.         End SyncLock
  1689.  
  1690.         'Remove Handlers
  1691.         RemoveHandler sender.Message, AddressOf GeneralMessageHandler
  1692.         RemoveHandler sender.ErrorOut, AddressOf ErrorHandler
  1693.  
  1694.         'Reset their variables.
  1695.         sender.VariableReset()
  1696.         'Now raise the logoff signal.
  1697.         Me.OnClientLogoff(New LogoffEventArgs With {.Client = sender})
  1698.         'Run garbage collection
  1699.         GC.Collect()
  1700.     End Sub
  1701.  
  1702.     ''' <summary>
  1703.     ''' The General Message Handler (GMH). This sub directs all calls to the respective handlers.
  1704.     ''' </summary>
  1705.     ''' <param name="sender">The Client that is sending the data.</param>
  1706.     ''' <param name="Data">The data the Client sent.</param>
  1707.     ''' <remarks></remarks>
  1708.     Private Sub GeneralMessageHandler(ByVal sender As Client, ByVal Data As Object)
  1709.         If Data.GetType Is GetType(Register) Then Call RegistrationHandler(sender, CType(Data, Register)) : Return
  1710.         If Data.GetType Is GetType(Login) Then Call LoginHandler(sender, CType(Data, Login)) : Return
  1711.         If Data.GetType Is GetType(Message) Then Call MessageHandler(sender, CType(Data, Message)) : Return
  1712.         If Data.GetType Is GetType(AddFriend) Then Call AddFriendHandler(sender, CType(Data, AddFriend)) : Return
  1713.         If Data.GetType Is GetType(RemoveFriend) Then Call RemoveFriendHandler(sender, CType(Data, RemoveFriend)) : Return
  1714.         If Data.GetType Is GetType(User) Then Call UserHandler(sender, CType(Data, User)) : Return
  1715.         If Data.GetType Is GetType(CreateGroup) Then Call CreateGroupHandler(sender, CType(Data, CreateGroup)) : Return
  1716.         If Data.GetType Is GetType(GroupInfo) Then Call GroupInformationHandler(sender, CType(Data, GroupInfo)) : Return
  1717.         If Data.GetType Is GetType(GroupInvitation) Then Call GroupInvitationHandler(sender, CType(Data, GroupInvitation)) : Return
  1718.         If Data.GetType Is GetType(GroupMessage) Then Call GroupMessageHandler(sender, CType(Data, GroupMessage)) : Return
  1719.         sender.Dispose()
  1720.     End Sub
  1721.  
  1722.     ''' <summary>
  1723.     ''' Disposes of the TCPV2 Server.
  1724.     ''' </summary>
  1725.     ''' <remarks></remarks>
  1726.     Public Sub Dispose()
  1727.         'Stop Listening for new connections.
  1728.         ServerListener.Stop()
  1729.         'Disconnect all users.
  1730.         For i As Integer = m_Users.Count - 1 To 0 Step -1
  1731.             'Tell them.
  1732.             m_Users(i).SendMessage(New Message With {.Sender = "SERVER", .Message = "The Server is shutting down."})
  1733.             'Dispose
  1734.             m_Users(i).Dispose()
  1735.             'Remove handlers
  1736.             RemoveHandler m_Users(i).Message, AddressOf GeneralMessageHandler
  1737.             RemoveHandler m_Users(i).ErrorOut, AddressOf ErrorHandler
  1738.             'Remove from list.
  1739.             m_Users.RemoveAt(i)
  1740.         Next
  1741.         'Raise message.
  1742.         Me.OnMessageReceived(New MessageEventArgs With {.Message = "Server shutdown."})
  1743.     End Sub
  1744.  
  1745. #End Region
  1746.  
  1747. #Region " Normal Handlers "
  1748.  
  1749.     ''' <summary>
  1750.     ''' The Registration Handler. It runs whenever registration attempts flow through the server.
  1751.     ''' </summary>
  1752.     ''' <param name="sender">The Client sending the registration attempt.</param>
  1753.     ''' <param name="registration">The Registration information.</param>
  1754.     ''' <remarks></remarks>
  1755.     Private Sub RegistrationHandler(ByVal sender As Client, ByVal registration As Register)
  1756.  
  1757.         Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("Registration attempt with username '{0}' and password '{1}'.", registration.User, registration.Pass))})
  1758.  
  1759.         If (registration.User <> String.Empty) AndAlso
  1760.             (registration.User <> "SERVER") AndAlso
  1761.             (registration.Pass <> String.Empty) AndAlso
  1762.             Not UserExists(registration.User) Then
  1763.  
  1764.             'All checks passed
  1765.  
  1766.             Me.OnMessageReceived(New MessageEventArgs With {.Message = ("All checks passed, clear for registration")})
  1767.  
  1768.             'Store the details.
  1769.             sender.Name = registration.User
  1770.             sender.Password = registration.Pass()
  1771.             sender.Status = "Online"
  1772.             sender.Display = registration.User
  1773.  
  1774.             'Save the user.
  1775.             sender.SaveUser()
  1776.  
  1777.             'Tell them everything checks out.
  1778.             sender.SendMessage(New Message With {.Sender = "SERVER", .Message = "registered"})
  1779.  
  1780.             Me.OnClientRegistration(New RegistrationEventArgs With {.Client = sender})
  1781.  
  1782.         Else
  1783.  
  1784.             'Check failed somewhere, oops
  1785.             sender.SendMessage(New Message With {.Sender = "SERVER", .Message = "notregistered"})
  1786.  
  1787.         End If
  1788.  
  1789.         'Now that we're done, get rid of them.
  1790.         sender.Dispose()
  1791.  
  1792.     End Sub
  1793.  
  1794.     ''' <summary>
  1795.     ''' The Login Handler. It runs whenever a login attempt occurs and controls verification.
  1796.     ''' </summary>
  1797.     ''' <param name="sender">The Client sending the request.</param>
  1798.     ''' <param name="login">The Login information.</param>
  1799.     ''' <remarks></remarks>
  1800.     Private Sub LoginHandler(ByVal sender As Client, ByVal login As Login)
  1801.         Me.OnMessageReceived(New MessageEventArgs With {.Message = ("Login request.")})
  1802.  
  1803.         'Check to see if they're NOT logged in and they exist.
  1804.         If Not UserLoggedIn(login.User) AndAlso UserExists(login.User) Then
  1805.             Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("Username '{0}' is registered, see if we supplied proper password.", login.User))})
  1806.  
  1807.             'See if credientials are valid.
  1808.             Select Case sender.LoadUser(login.User, login.Pass)
  1809.                 Case True
  1810.                     Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("{0} successfully logged in!", sender.Name))})
  1811.                     sender.SendMessage(New Message With {.Sender = "SERVER", .Message = "loggedin"})
  1812.                     Me.OnClientLogin(New LoginEventArgs With {.Client = sender})
  1813.                     'Process the Queues
  1814.                     Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("Processing Queues for {0}", sender.Name))})
  1815.                     QueueList.EvaluateUserQueue(sender)
  1816.                     QueueList.EvaluateMessageQueue(sender)
  1817.                     QueueList.EvaluateRemoveQueue(sender)
  1818.                     'now tell all his friends.
  1819.                     Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("Queues Processed, send out notifications!"))})
  1820.                     Call LoginNotificationHandler(sender)
  1821.                 Case False
  1822.                     Me.OnMessageReceived(New MessageEventArgs With {.Message = ("Login failed. Notify the user. Invalid password.")})
  1823.                     sender.SendMessage(New Message With {.Sender = "SERVER", .Message = "invalid"})
  1824.                     sender.Dispose()
  1825.             End Select
  1826.  
  1827.         Else
  1828.             Me.OnMessageReceived(New MessageEventArgs With {.Message = ("Login failed. Notify the user. Invalid username.")})
  1829.             sender.SendMessage(New Message With {.Sender = "SERVER", .Message = "invalid"})
  1830.             sender.Dispose()
  1831.  
  1832.         End If
  1833.  
  1834.     End Sub
  1835.  
  1836.     ''' <summary>
  1837.     ''' The LoginNotificationHandler tells everyone on the sender's friendlist that they are online.
  1838.     ''' </summary>
  1839.     ''' <param name="sender">The Client that has logged in.</param>
  1840.     ''' <remarks></remarks>
  1841.     Private Sub LoginNotificationHandler(ByVal sender As Client)
  1842.         SyncLock sender.Friends
  1843.             For i As Integer = sender.Friends.Count - 1 To 0 Step -1
  1844.                 'if the person is online...
  1845.                 Dim FriendName As String = sender.Friends(i).User
  1846.                 If UserLoggedIn(FriendName) Then
  1847.                     Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("{0} is online, see if they are friends with {1} and viseversa.", FriendName, sender.Name))})
  1848.                     'Make the reference to them.
  1849.                     Dim Cli_Friend As Client = ReturnClient(FriendName)
  1850.                     'If the one we want to send the information to has them then tell them.
  1851.                     If Cli_Friend.IsUserInFriendList(sender.Name) Then
  1852.                         'Raise a log message.
  1853.                         Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("Telling {0} that {1} is online.", FriendName, sender.Name))})
  1854.                         'Tell the friend.
  1855.                         Cli_Friend.UpdateFriend(New User With {.User = sender.Name, .Status = sender.Status, .Online = True, .Display = sender.Display})
  1856.                         'Tell the sender.
  1857.                         sender.UpdateFriend(New User With {.User = Cli_Friend.Name, .Status = Cli_Friend.Status, .Online = True, .Display = Cli_Friend.Display})
  1858.                     End If
  1859.                 End If
  1860.             Next
  1861.         End SyncLock
  1862.     End Sub
  1863.  
  1864.     ''' <summary>
  1865.     ''' The Message Handler. It will be processed ONLY if the sender is logged in.
  1866.     ''' </summary>
  1867.     ''' <param name="sender">The client sending the Messages.</param>
  1868.     ''' <param name="message">The Message data.</param>
  1869.     ''' <remarks></remarks>
  1870.     Private Sub MessageHandler(ByVal sender As Client, ByVal message As Message)
  1871.  
  1872.         If message.Receiver = "SERVER" Then
  1873.             Call ServerProcessing(sender, message.Message.ToLower)
  1874.             Return
  1875.         End If
  1876.  
  1877.         If (message.Sender <> String.Empty) AndAlso (sender.Name <> String.Empty) Then
  1878.             message.Sender = sender.Name 'set the name
  1879.             message.Display = sender.Display 'set the display
  1880.             Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("Message from {0} to {1}.{2}Contents: {3}", sender.Name, message.Receiver, Environment.NewLine, message.Message))})
  1881.  
  1882.             If UserLoggedIn(message.Receiver) Then
  1883.                 Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("{0} was found, sending them a message.", message.Receiver))})
  1884.                 'Send them a message
  1885.                 ReturnClient(message.Receiver).SendMessage(message)
  1886.             Else
  1887.                 'person isn't online, say they are offline.
  1888.                 sender.SendMessage(New Message With {.Sender = message.Receiver, .Message = "This user is currently offline and will receive your messages when they log back in.", .Display = message.Receiver})
  1889.                 'Add it to the message queue.
  1890.                 QueueList.AddOfflineMessage(message.Receiver, message)
  1891.             End If
  1892.  
  1893.         End If
  1894.  
  1895.     End Sub
  1896.  
  1897.     ''' <summary>
  1898.     ''' Processes any messages meant for the Server.
  1899.     ''' </summary>
  1900.     ''' <param name="sender">The client requesting the data.</param>
  1901.     ''' <param name="message">The message.</param>
  1902.     ''' <remarks></remarks>
  1903.     Private Sub ServerProcessing(ByVal sender As Client, ByVal message As String)
  1904.         Select Case message
  1905.             Case "loggedin" 'logging in.
  1906.                 sender.SendMessage(New User With {.User = sender.Name, .Status = sender.Status, .Online = True, .Display = sender.Display})
  1907.             Case "groupdata" 'used for joining public groups
  1908.                 sender.SendMessage(CreatePublicGroupList)
  1909.         End Select
  1910.     End Sub
  1911.  
  1912.     ''' <summary>
  1913.     ''' The User Handler.
  1914.     ''' </summary>
  1915.     ''' <param name="sender">The Client sending the Handler.</param>
  1916.     ''' <param name="User">The User Data</param>
  1917.     ''' <remarks></remarks>
  1918.     Private Sub UserHandler(ByVal sender As Client, ByVal User As User)
  1919.         'See if it's about me.
  1920.         If sender.Name = User.User Then
  1921.             Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("User Update. Old Status: {0}, New Status: {1}.{2}Old Display Name: {3}. New Display Name: {4}", sender.Status, User.Status, Environment.NewLine, sender.Display, User.Display))})
  1922.             'it's just a status update, could also be a new display name
  1923.             sender.Status = User.Status
  1924.             sender.Display = User.Display
  1925.             Me.OnMessageReceived(New MessageEventArgs With {.Message = ("Status was updated")})
  1926.             'tell all his friends of the new status.
  1927.             SyncLock sender.Friends
  1928.                 For Each userFriend As User In sender.Friends
  1929.                     If UserLoggedIn(userFriend.User) Then
  1930.                         'send out update.
  1931.                         Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("Sending update to '{0}'", userFriend.User))})
  1932.                         ReturnClient(userFriend.User).UpdateFriend(User)
  1933.                     End If
  1934.                 Next
  1935.             End SyncLock
  1936.         End If
  1937.     End Sub
  1938.  
  1939. #End Region
  1940.  
  1941. #Region " Friend Handlers "
  1942.  
  1943.     ''' <summary>
  1944.     ''' Add a new Friend.
  1945.     ''' </summary>
  1946.     ''' <param name="sender">The Client who's adding the friend.</param>
  1947.     ''' <param name="AddFriendInfo">The Friend information</param>
  1948.     ''' <remarks></remarks>
  1949.     Private Sub AddFriendHandler(ByVal sender As Client, ByVal AddFriendInfo As AddFriend)
  1950.         'First up, see if they're trying to add themselves..
  1951.         If Not AddFriendInfo.User = sender.Name Then
  1952.             'Look for the user.
  1953.             Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("Incoming friend request from {0}", sender.Name))})
  1954.             SyncLock sender.Friends
  1955.                 Try
  1956.                     If Not sender.IsUserInFriendList(AddFriendInfo.User) Then
  1957.                         'create the user data and pre-populate it.
  1958.                         Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("{0} not found on {1}'s list, create some data.", AddFriendInfo.User, sender.Name))})
  1959.                         Dim NewUser As New User With {.User = AddFriendInfo.User, .Status = "Offline.", .Online = False}
  1960.                         'see if they're online.
  1961.                         If UserLoggedIn(AddFriendInfo.User) Then
  1962.                             Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("{0} is also online. Let's tell them about the news.", AddFriendInfo.User))})
  1963.                             Call PopulateFriendData(NewUser)
  1964.                             Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("Add {0} to {1}'s list as well.", sender.Name, AddFriendInfo.User))})
  1965.                             ReturnClient(AddFriendInfo.User).AddFriend(New User With {.User = sender.Name, .Status = sender.Status, .Online = True, .Display = sender.Display})
  1966.                         Else
  1967.                             'Not online, add it to the item queue
  1968.                             QueueList.AddOfflineFriendRequest(AddFriendInfo.User, New User With {.Display = sender.Display, .Online = False, .Status = sender.Status, .User = sender.Name})
  1969.                             'Tell the person.
  1970.                             sender.SendMessage(New Message With {.Sender = "SERVER", .Message = String.Format("{0} was added to your friends list. They are currently offline and will appear when they login.", AddFriendInfo.User), .Receiver = sender.Name})
  1971.                         End If
  1972.                         Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("Update {0}'s friend list now.", sender.Name))})
  1973.                         sender.AddFriend(NewUser)
  1974.                     End If
  1975.                 Catch ex As Exception
  1976.                     Me.OnMessageReceived(New MessageEventArgs With {.Message = (ex.ToString)})
  1977.                 End Try
  1978.             End SyncLock
  1979.         End If
  1980.     End Sub
  1981.  
  1982.     ''' <summary>
  1983.     ''' Populates a User Structure with Data.
  1984.     ''' </summary>
  1985.     ''' <param name="Data">The User Structure to modify.</param>
  1986.     ''' <remarks></remarks>
  1987.     Private Sub PopulateFriendData(ByRef Data As User)
  1988.         If UserLoggedIn(Data.User) Then
  1989.             Dim Client As Client = ReturnClient(Data.User)
  1990.             Data.Online = True
  1991.             Data.Display = Client.Display
  1992.             Data.Status = Client.Status
  1993.         End If
  1994.     End Sub
  1995.  
  1996.     ''' <summary>
  1997.     ''' Remove a Friend from the Friends List.
  1998.     ''' </summary>
  1999.     ''' <param name="sender">The Client to remove the friend from.</param>
  2000.     ''' <param name="DelFriendInfo">The friend to delete.</param>
  2001.     ''' <remarks></remarks>
  2002.     Private Sub RemoveFriendHandler(ByVal sender As Client, ByVal DelFriendInfo As RemoveFriend)
  2003.         'Remove from the sender.
  2004.         sender.RemoveFriend(DelFriendInfo.m_Friend)
  2005.         'Remove from the other if we can.
  2006.         If UserLoggedIn(DelFriendInfo.m_Friend) Then
  2007.             'logged in, remove it.
  2008.             ReturnClient(DelFriendInfo.m_Friend).RemoveFriend(sender.Name)
  2009.         Else
  2010.             'not logged in, add it to queues.
  2011.             QueueList.AddOfflineRemoveRequest(DelFriendInfo.m_Friend, sender.Name)
  2012.         End If
  2013.  
  2014.     End Sub
  2015.  
  2016. #End Region
  2017.  
  2018. #Region " Group Handlers "
  2019.  
  2020.     Private Sub CreateGroupHandler(ByVal sender As Client, ByVal information As CreateGroup)
  2021.         'See if a group chat exists
  2022.         If Not GroupExists(information.GroupName) Then
  2023.             'Group doesn't exist, create the group!
  2024.             Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("Creating Group {0}, Admin: {1}", information.GroupName, information.Administrator))})
  2025.             Dim Grp As New Group(information.GroupName, sender, information.IsPublic)
  2026.             AddHandler Grp.Empty, AddressOf GroupEmpty
  2027.             AddHandler Grp.Message, AddressOf GroupMessage
  2028.             AddHandler Grp.Log, AddressOf GroupLog
  2029.             m_GroupList.Add(Grp)
  2030.             Me.OnGroupCreation(New GroupCreationEventArgs With {.Group = Grp})
  2031.         Else
  2032.             sender.SendMessage(New Message With {.Sender = "SERVER", .Receiver = sender.Name, .Message = String.Format("The Group '{0}' already exists.", information.GroupName)})
  2033.         End If
  2034.     End Sub
  2035.  
  2036.     Private Sub GroupInformationHandler(ByVal sender As Client, ByVal information As GroupInfo)
  2037.         'Break it down.
  2038.         'first find the group
  2039.         Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("Group Information Update from {0}", sender.Name))})
  2040.         If GroupExists(information.GroupName) Then
  2041.             'group found. use it.
  2042.             Dim Grp As Group = ReturnGroup(information.GroupName)
  2043.             'find the user. if found perform desired action.
  2044.             If UserExists(information.User) AndAlso _
  2045.                 Not ReturnGroup(information.GroupName). _
  2046.                 IsUserInGroup(ReturnClient(information.User)) Then
  2047.                 Select Case information.Added
  2048.                     Case True 'add them into the group.
  2049.                         Grp.Add(ReturnClient(information.User))
  2050.                     Case False 'remove them from the group.
  2051.                         Grp.Remove(information.User)
  2052.                 End Select
  2053.             End If
  2054.         End If
  2055.     End Sub
  2056.  
  2057.     Private Sub GroupInvitationHandler(ByVal sender As Client, ByVal invitation As GroupInvitation)
  2058.         If UserLoggedIn(invitation.invitee) Then
  2059.             'find the user and send them the invite.
  2060.             'But first make sure the group exists too.
  2061.             If GroupExists(invitation.GroupName) Then
  2062.                 'Make sure they're not in the group.
  2063.                 If Not ReturnGroup(invitation.GroupName).IsUserInGroup(ReturnClient(invitation.invitee)) Then
  2064.                     Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("Inviting {0} to {1}. Invitation from {2}.", invitation.invitee, invitation.GroupName, invitation.sender))})
  2065.                     ReturnClient(invitation.invitee).SendMessage(invitation)
  2066.                 End If
  2067.             End If
  2068.  
  2069.         End If
  2070.     End Sub
  2071.  
  2072.     Private Sub GroupMessageHandler(ByVal sender As Client, ByVal message As GroupMessage)
  2073.         'Find the group
  2074.         Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("Message for Group {0} from {1}.{2}Contents: {3}", message.GroupName, sender.Name, Environment.NewLine, message.Message))})
  2075.         If GroupExists(message.GroupName) Then
  2076.             'send message.
  2077.             Dim grp As Group = ReturnGroup(message.GroupName)
  2078.             If grp.IsUserInGroup(sender) Then
  2079.                 grp.Send(grp.FindUser(sender), message.Message)
  2080.             Else
  2081.                 sender.SendMessage(New GroupMessage With {.GroupName = message.GroupName, .Message = "You are not in this group!", .Sender = "SERVER"})
  2082.             End If
  2083.         End If
  2084.     End Sub
  2085.  
  2086.     ''' <summary>
  2087.     ''' Occurs when a Group is removed.
  2088.     ''' </summary>
  2089.     ''' <param name="sender">The Group being removed.</param>
  2090.     ''' <remarks></remarks>
  2091.     Private Sub GroupEmpty(ByVal sender As Group)
  2092.         Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("Group {0} is empty, removing from the Group List.", sender.Name))})
  2093.         m_GroupList.Remove(sender)
  2094.     End Sub
  2095.  
  2096.     ''' <summary>
  2097.     ''' Group Message Handler
  2098.     ''' </summary>
  2099.     ''' <param name="sender">The Client sending the Message</param>
  2100.     ''' <param name="message">The Message</param>
  2101.     ''' <param name="grp">The Group that the message was sent to</param>
  2102.     ''' <remarks></remarks>
  2103.     Private Sub GroupMessage(ByVal sender As Client, ByVal message As String, ByVal grp As Group)
  2104.         Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("Group Message. Group: {0}. Sender: {1}. Message: {2}", grp.Name, sender.Name, message)), .Type = MessageTypeEnum.Group})
  2105.     End Sub
  2106.  
  2107.     ''' <summary>
  2108.     ''' Capture Group Log Messages.
  2109.     ''' </summary>
  2110.     ''' <param name="log">The log message.</param>
  2111.     ''' <remarks></remarks>
  2112.     Private Sub GroupLog(ByVal log As String)
  2113.         Me.OnMessageReceived(New MessageEventArgs With {.Message = (String.Format("Group Log: {0}", log))})
  2114.     End Sub
  2115.  
  2116.     ''' <summary>
  2117.     ''' Quietly creates a list of all the public chat rooms.
  2118.     ''' </summary>
  2119.     ''' <value></value>
  2120.     ''' <returns></returns>
  2121.     ''' <remarks></remarks>
  2122.     Private ReadOnly Property CreatePublicGroupList() As ListOfGroups
  2123.         Get
  2124.             Dim GInfo As New List(Of CreateGroup)
  2125.             SyncLock m_GroupList
  2126.                 For Each item As Group In m_GroupList
  2127.                     If item.IsPublic Then
  2128.                         GInfo.Add(New CreateGroup With {.Administrator = item.Admin.Name, .GroupName = item.Name, .IsPublic = True})
  2129.                     End If
  2130.                 Next
  2131.             End SyncLock
  2132.             Return New ListOfGroups With {.List = GInfo}
  2133.         End Get
  2134.     End Property
  2135.  
  2136. #End Region
  2137.  
  2138. #Region " Server Functions "
  2139.  
  2140.     Private WithEvents GroupPurgeTimer As New System.Timers.Timer
  2141.  
  2142.     ''' <summary>
  2143.     ''' Find a User in the Data Directory. Returns a True if found and a false if not.
  2144.     ''' </summary>
  2145.     ''' <param name="user">The User to look for.</param>
  2146.     ''' <returns></returns>
  2147.     ''' <remarks></remarks>
  2148.     <DebuggerStepThrough()> Public Function UserExists(ByVal user As String) As Boolean
  2149.         Try
  2150.             For Each file As String In IO.Directory.GetFiles(m_DataDirectory, "*.xml")
  2151.                 If IO.Path.GetFileNameWithoutExtension(file) = user Then Return True
  2152.             Next
  2153.         Catch ex As Exception
  2154.             Debug.WriteLine(ex.ToString)
  2155.             Return False
  2156.         End Try
  2157.         Return False
  2158.     End Function
  2159.  
  2160.     ''' <summary>
  2161.     ''' See if a Client is online.
  2162.     ''' </summary>
  2163.     ''' <param name="clientName">The Client Name to look for.</param>
  2164.     ''' <returns></returns>
  2165.     ''' <remarks></remarks>
  2166.     <DebuggerStepThrough()> Public Function UserLoggedIn(ByVal clientName As String) As Boolean
  2167.         SyncLock m_Users
  2168.             For Each Client As Client In m_Users
  2169.                 If Client.Name = clientName Then Return True
  2170.             Next
  2171.             Return False
  2172.         End SyncLock
  2173.     End Function
  2174.  
  2175.     ''' <summary>
  2176.     ''' Returns the reference point to the Client (if they are online).
  2177.     ''' </summary>
  2178.     ''' <param name="clientName">The name to use.</param>
  2179.     ''' <returns></returns>
  2180.     ''' <remarks></remarks>
  2181.     <DebuggerStepThrough()> Public Function ReturnClient(ByVal clientName As String) As Client
  2182.         SyncLock m_Users
  2183.             For Each Client As Client In m_Users
  2184.                 If Client.Name = clientName Then Return Client
  2185.             Next
  2186.             Return Nothing
  2187.         End SyncLock
  2188.     End Function
  2189.  
  2190.     ''' <summary>
  2191.     ''' Locate a Group by it's name.
  2192.     ''' </summary>
  2193.     ''' <param name="name">The Group's Name.</param>
  2194.     ''' <returns></returns>
  2195.     ''' <remarks></remarks>
  2196.     <DebuggerStepThrough()> Public Function GroupExists(ByVal name As String) As Boolean
  2197.         SyncLock m_GroupList
  2198.             For Each item As Group In m_GroupList
  2199.                 If item.Name = name Then Return True
  2200.             Next
  2201.             Return False
  2202.         End SyncLock
  2203.     End Function
  2204.  
  2205.     ''' <summary>
  2206.     ''' Find a Group based on it's name and open it up for manipulation.
  2207.     ''' </summary>
  2208.     ''' <param name="name">The name of the group.</param>
  2209.     ''' <returns></returns>
  2210.     ''' <remarks></remarks>
  2211.     <DebuggerStepThrough()> Public Function ReturnGroup(ByVal name As String) As Group
  2212.         SyncLock m_GroupList
  2213.             For Each item As Group In m_GroupList
  2214.                 If item.Name = name Then Return item
  2215.             Next
  2216.             Return Nothing
  2217.         End SyncLock
  2218.     End Function
  2219.  
  2220.     <DebuggerStepThrough()> Private Sub GroupPurgeTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles GroupPurgeTimer.Elapsed
  2221.         If m_GroupList.Count > 0 Then
  2222.             Me.OnMessageReceived(New MessageEventArgs With {.Message = ("Group Purge starting.")})
  2223.             For i As Integer = m_GroupList.Count - 1 To 0 Step -1
  2224.                 If m_GroupList(i).Group.Count = 0 Then m_GroupList.RemoveAt(i)
  2225.             Next
  2226.             Me.OnMessageReceived(New MessageEventArgs With {.Message = ("Group Purging complete.")})
  2227.         End If
  2228.     End Sub
  2229.  
  2230.     ''' <summary>
  2231.     ''' Removes a Group from the GroupList.
  2232.     ''' </summary>
  2233.     ''' <param name="grp">The Group to remove.</param>
  2234.     ''' <remarks></remarks>
  2235.     Public Sub RemoveGroup(ByVal grp As Group)
  2236.         m_GroupList.Remove(grp)
  2237.     End Sub
  2238.  
  2239. #End Region
  2240.  
  2241. End Class
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement