' A "filtered" Chat Server by William Yu ' Clients can connect to this server, and talk to each other, but ' what gets filtered out are all those nasty swear words! ' If you've never programmed with sockets before, don't worry, this is ' as easy as it gets... sort of. ' Brief Overview of QSocket (Server-side) ' -- It is an interface only ' ' Transferred AS INTEGER ' -- Poll this value after any Read/Write ' -- Returns number of bytes sent/received ' Open(PortNum AS INTEGER) ' -- Used only by server, opens a TCP/IP connection ' -- Returns a socket file descriptor, store it! ' Accept(MasterSocket AS INTEGER) ' -- This function will block until a connection is established ' -- Returns a client socket file descriptor ' ConnectionReady(MasterSocket AS INTEGER) ' -- This function just checks if a connection is pending ' -- If so, then you should Accept the connection. ' -- This is a non-blocking function call, returns 0 if no connection is ready. ' IsClientReady(MasterSocket AS INTEGER, ClientSocket AS INTEGER) ' -- Non-blocking function call that determines if a client has sent ' some data to the "MasterSocket" ' ReadLine(ClientSocket AS INTEGER) AS STRING ' -- Read a complete line (ended with a linefeed character) ' -- Returns the line read, from the ClientSocket. ' -- Always check Socket.Transferred after this read operation. ' -- If Transferred = -1 then an error has occurred (client disconnected). ' WriteLine(ClientSocket AS INTEGER, Message AS STRING) AS INTEGER ' -- Function call that sends a message over to the client. ' -- Returns LEN(Message) on success, -1 on failure ' ReadBytes/WriteBytes will be implemented later, I just felt like ' releasing this as is (because of some memory leaks). $APPTYPE GUI $TYPECHECK ON '' I get in so many trouble with it OFF!!! CONST DELAY = 500 ' In Milliseconds CONST PortNum = 5000 ' Anything above 1024 should work, with some exceptions CONST False = 0 CONST True = NOT False DECLARE SUB TimerExpired DIM Socket AS QSocket CREATE Form AS QForm Height = 300 Width = 400 Caption = "Chat Server" Center CREATE ListBox AS QListBox Top = 100 Height = 200 Width = Form.ClientWidth AddItems "Chat server by William Yu", STRING$(30,"-") ItemIndex = 0 END CREATE CREATE Label1 AS QLabel Top = 10 Left = 10 Height = 14 Caption = "Server: " + Socket.GetHostName END CREATE CREATE Label2 AS QLabel Top = 29 Left = 10 Height = 14 Caption = "Port: "+STR$(PortNum) END CREATE CREATE Label3 AS QLabel Top = 48 Left = 10 Height = 14 Caption = "Connections: 0" END CREATE END CREATE DIM Timer1 AS QTimer DIM MasterSocket AS INTEGER, NumClients AS INTEGER DIM Client(1 TO 50) AS INTEGER DIM SwearCount AS INTEGER DIM Swears(1 TO 50) AS STRING Swears(1) = "ASS" Swears(2) = "BASTARD" Swears(3) = "HELL" ' Yeah, I'm skipping the most obvious :) ' Add yours here, I'm keeping this code "clean" SwearCount = 3 Timer1.Interval = DELAY ' Some Delay between checks ' Don't want to become a CPU hog Timer1.OnTimer = TimerExpired NumClients = 0 MasterSocket = Socket.Open(PortNum) IF MasterSocket = -1 THEN PRINT "Server error: could not make connection, maybe try another port..." END END IF Form.ShowModal SUB SwapClients(N AS INTEGER) '-- Get rid of disconnected client DIM I AS INTEGER FOR I = N to NumClients Client(I) = Client(I+1) NEXT END SUB FUNCTION Filter(Message AS STRING) AS STRING DIM I AS INTEGER, N AS INTEGER ' Very very simple, you should write your own filter, as this is just a ' demonstration, GRASS and ASS will both be processed! FOR I = 1 To SwearCount '' Dang, seems to seg fault sometimes... N = INSTR(UCASE$(Message), Swears(I)) WHILE N Message = LEFT$(Message, N-1) + STRING$(LEN(Swears(I)), "*") + _ MID$(Message, N+LEN(Swears(I)), LEN(Message)) N = INSTR(UCASE$(Message), Swears(I)) WEND NEXT I Filter = Message END FUNCTION SUB SendToClients (Message AS STRING) DIM I AS INTEGER, N AS INTEGER FOR I = 1 to NumClients N = Socket.WriteLine(Client(I), Message) NEXT END SUB SUB TimerExpired DIM I AS INTEGER DIM S AS STRING Timer1.Enabled = False Timer1.Interval = DELAY ' Restore delay IF Socket.ConnectionReady(MasterSocket) > 0 THEN NumClients = NumClients + 1 Client(NumClients) = Socket.Accept(MasterSocket) ListBox.AddItems "Client "+STR$(NumClients)+": Connected to server." IF Socket.WriteLine(Client(NumClients), "Welcome to William's Chat Server!") = -1 THEN ListBox.AddItems "Client "+STR$(NumClients)+": Disconnected from server." NumClients = NumClients - 1 ELSE Label3.Caption = "Connections: "+STR$(NumClients) END IF END IF FOR I = 1 to NumClients '' Check for ready clients IF Socket.IsClientReady(MasterSocket, Client(I)) > 0 THEN S = Socket.ReadLine(Client(I)) ListBox.AddItems "Client "+STR$(I)+": "+S IF Socket.Transferred = -1 THEN ListBox.DelItems ListBox.ItemCount-1 ListBox.AddItems "Client "+STR$(I)+": Disconnected from server." NumClients = NumClients - 1 Label3.Caption = "Connections: "+STR$(NumClients) SwapClients(I) SendToClients("Client "+STR$(I)+": Disconnected.") ELSE S = Filter(S) SendToClients("Client "+STR$(I)+": "+S) END IF END IF NEXT Timer1.Enabled = True END SUB