ESChat

Developed or developing a new product in PureBasic? Tell the world about it.
User avatar
heartbone
Addict
Addict
Posts: 1058
Joined: Fri Apr 12, 2013 1:55 pm
Location: just outside of Ferguson

ESChat

Post by heartbone »

Here's another entry for the < 800 line demo program source library.
This one is more hackable than my first entry.
Novice PB users may find it interesting to add smileys, avatars, or IP address retrieval.
How about changing the room's decor?
More knowledgeable programmers might add file transfers, expand the number of guests, and guest booting.
I'm thinking about adding some primitive VoIP capability to enhance my online gaming environment.

To access a built-in smiley ☺ (☻), while typing, press Alt+1 (Alt+2) from the keypad.

Code: Select all

; ********************************
; *********  ESChat 1.0  *********
; ******  January 30, 2015  ******
; **** ELECTRONICAL  SOFTWARE ****
; ********************************
#BUFLEN= 256 : *INBUFFER = AllocateMemory(#BUFLEN)
Dim SLINES$(23) : FS1= 12 : FS2= 24
InitSprite()
OpenWindow(0,0,0,800,600,"ESChat",#PB_Window_ScreenCentered|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget)
;; NO CAN DO IN DEMO, SO USERS WHO HAVE CHANGED THEIR DESKTOP FONT SIZE WILL HAVE THE TEXT SIZE ALTERED ACCORDINGLY.
;;CompilerIf #PB_Compiler_OS=#PB_OS_Windows
;;   DPI= GetDeviceCaps_(GetDC_(0),#LOGPIXELSX)
;;   If DPI <> 96 And DPI > 15 And DPI < 193 : FS1= (FS1*100)/DPI : FS2= (FS2*100)/DPI : EndIf
;;CompilerEndIf
LoadFont(1,"Arial",FS1,#PB_Font_HighQuality)
LoadFont(2,"Arial",FS2,#PB_Font_Bold|#PB_Font_HighQuality)
LoadFont(3,"Arial",FS1,#PB_Font_Bold|#PB_Font_HighQuality)
OpenWindowedScreen(WindowID(0),0,0,800,600,#True,0,0) : CreateSprite(0,800,600)
InitKeyboard() : InitNetwork()
REFRESH= 2 : BYEBYE= 0 : CHAT= 0 : NUMLINES= 0 : FLASH= 0 : RESEND= 0
PORT= 6532 : HOSTID= 0 : CLIENTID1= 0 : CLIENTID2= 0 : CLIENTID3= 0
HOST$= "" : GUEST1$= "" : GUEST2$= "" : GUEST3$= "" : OTHERG1$= "" : OTHERG2$= ""
BLANK$= "                             "
FILESAV$= "Press Ctrl+S at any time to save the current chat text display into a file."
Repeat
   RELEASE= ElapsedMilliseconds()+ 20
   Repeat : X= WindowEvent() : If X = #PB_Event_CloseWindow : End : EndIf : Until X = 0 
   If REFRESH
      StartDrawing(SpriteOutput(0)) : DrawingMode(#PB_2DDrawing_Transparent)
      DrawingFont(FontID(2)) : Box(0,0,800,600,$000000)
      If CHAT > 99 Or FULL
         If HOST
            If FLASH
               DBUFF$= FLASH$
            Else
               DBUFF$= "* HOSTING CHAT SESSION *"
            EndIf
            DrawText(400-TextWidth(DBUFF$)/2,20,DBUFF$,$FFDD77)
            If Not FLASH And (GUEST1$ Or GUEST1$ Or GUEST3$)
               IND= 180 : DrawingFont(FontID(3))
               If GUEST1$ : DrawText(IND-TextWidth(GUEST1$)/2,2,GUEST1$,$22DD22) : IND +220 : EndIf
               If GUEST2$ : DrawText(IND-TextWidth(GUEST2$)/2,2,GUEST2$,$22DD22) : IND +220 : EndIf
               If GUEST3$ : DrawText(IND-TextWidth(GUEST3$)/2,2,GUEST3$,$22DD22) : EndIf
               DrawingFont(FontID(2))
            EndIf
         Else
            If FLASH
               DBUFF$= FLASH$
            Else
               If FULL
                  FULL= 0 : DBUFF$= ""
               Else
                  DBUFF$= "* IN CHAT SESSION *"
               EndIf
            EndIf
            DrawText(400-TextWidth(DBUFF$)/2,17,DBUFF$,$FFDD77)
            If Not FLASH
               IND= 180 : DrawingFont(FontID(3))
               DrawText(IND-TextWidth(HOST$)/2,2,HOST$,$22DD22) : IND +220
               If OTHERG1$ : DrawText(IND-TextWidth(OTHERG1$)/2,2,OTHERG1$,$22DD22) : IND +220 : EndIf
               If OTHERG2$ : DrawText(IND-TextWidth(OTHERG2$)/2,2,OTHERG2$,$22DD22) : EndIf
               DrawingFont(FontID(2))
            EndIf
         EndIf
      EndIf
      If CHAT < 100 : DrawingFont(FontID(2)) : EndIf
      If CHAT > 99
         If NUMLINES
            Box(20,63,759,449,$444444) : Box(22,65,755,445,$1C1C1C) : DrawingFont(FontID(1))
            JND= NUMLINES- 1 : If NUMLINES < 4 : JND= 23 : EndIf
            For IND= 0 To JND : DrawText(25,485-IND*18,SLINES$(IND),$00FF00) : Next IND
         EndIf
      ElseIf CHAT > 19
         DBUFF$= "* JOINING CHAT SESSION *" : DrawText(400-TextWidth(DBUFF$)/2,25,DBUFF$,$FFDD77)
         If CHAT = 21
            DBUFF$= NAME$+", ENTER THE HOST IP ADDRESS." : DrawText(400-TextWidth(DBUFF$)/2,60,DBUFF$,$FFDD77)
         ElseIf CHAT = 22
            DBUFF$= "CONNECTING TO CHAT HOST @ "+HIP$ : DrawText(400-TextWidth(DBUFF$)/2,60,DBUFF$,$FFDD77)
         ElseIf CHAT = 23
            DBUFF$= "TRANSFERRING DATA WITH CHAT HOST" : DrawText(400-TextWidth(DBUFF$)/2,60,DBUFF$,$FFDD77)
         EndIf
      ElseIf CHAT > 9
         DBUFF$= "* HOSTING CHAT SESSION *" : DrawText(400-TextWidth(DBUFF$)/2,25,DBUFF$,$FFDD77)
         If CHAT = 11
            DBUFF$= "AS "+NAME$ : DrawText(400-TextWidth(DBUFF$)/2,60,DBUFF$,$FFDD77)
         EndIf
      ElseIf Not FULL 
         DBUFF$= "PRESS H TO HOST CHAT SESSION" : DrawText(400-TextWidth(DBUFF$)/2,125,DBUFF$,$FFDD77)
         DBUFF$= "PRESS J TO JOIN CHAT SESSION" : DrawText(400-TextWidth(DBUFF$)/2,250,DBUFF$,$FFDD77)
      EndIf   
      If CHAT > 99 : If NUMLINES : DrawingFont(FontID(2)) : EndIf
         If CLIENTID1 Or CLIENTID2 Or CLIENTID3 Or CHAT > 199
            DBUFF$= "PRESS ANY KEY TO TYPE A MESSAGE" : DrawText(400-TextWidth(DBUFF$)/2,515,DBUFF$,$AAAAAA)
         EndIf
      EndIf 
      DBUFF$= "PRESS Esc KEY TO EXIT CHAT" : DrawText(400-TextWidth(DBUFF$)/2,555,DBUFF$,$AAAAAA) 
      StopDrawing() : DisplaySprite(0,0,0) : FlipBuffers() : REFRESH= 0
   EndIf
   If CHAT = 10 Or CHAT = 20 Or CHAT= 21 
      CompilerIf #PB_Compiler_OS=#PB_OS_Linux
; THE FOLLOWING 3 LINES WILL CLEAR THE STICKY KEYPRESS BUG ASSOCIATED WITH THE LINUX INPUT REQUESTER
         ONKEY= 1 : Repeat : Delay(20)
         Repeat : X= WindowEvent() : If X = #PB_Event_CloseWindow : End : EndIf : Until X = 0
         ExamineKeyboard() : If Not KeyboardPushed(#PB_Key_All) : ONKEY= 0 :EndIf : Until Not ONKEY
      CompilerEndIf 
      If CHAT < 21
         NAME$= InputRequester("ESChat","Enter Your Name",UserName())
         If NAME$ : CHAT +1 : Else : CHAT= 0 : EndIf
      Else   
         HIP$= InputRequester("ESChat","USE THE IPv4   * . * . * . *   ADDRESS FORMAT","")
         If CountString(HIP$,".")<>3 Or Len(HIP$)<7 Or Len(HIP$)>15 : HIP$= "" : EndIf
         If HIP$ : CHAT= 22 : FL$= KeyboardInkey() : Else : CHAT= 0 : EndIf
      EndIf
      REFRESH= 1
   ElseIf CHAT= 11
      Delay(1000)
      If CreateNetworkServer(0,PORT)
         CHAT= 100 : FULL= 0 : FLASH= ElapsedMilliseconds()+ 2000 : FLASH$= "* CHATROOM CREATED *"
      Else
         MessageRequester("ESChat","CAN'T CREATE CHATROOM!", 0) : CHAT= 0
      EndIf
      REFRESH= 1   
   ElseIf CHAT= 22
      HOSTID= OpenNetworkConnection(HIP$,PORT,#PB_Network_TCP,7777)
      If HOSTID
         CHAT= 23 : FULL= 0 : Delay(1000)
      Else
         MessageRequester("ESChat","CAN'T FIND HOST AT "+HIP$+"!") : CHAT= 0
      EndIf
      REFRESH= 1
   EndIf
   ExamineKeyboard()
   If KeyboardPushed(#PB_Key_Escape)
      If HOSTID : CloseNetworkConnection(HOSTID) : EndIf
      If CLIENTID1 : CloseNetworkConnection(CLIENTID1) : EndIf
      If CLIENTID2 : CloseNetworkConnection(CLIENTID2) : EndIf
      If CLIENTID3 : CloseNetworkConnection(CLIENTID3) : EndIf
      BYEBYE+ 1 
   ElseIf KeyboardPushed(#PB_Key_LeftControl) Or KeyboardPushed(#PB_Key_RightControl) 
      If KeyboardPushed(#PB_Key_S) And CHAT > 99 And NUMLINES
         TODAY$= FormatDate("%mm/%dd/%yy",Date()) : TIME$= FormatDate("%hh:%ii:%ss",Date())
         SAVEFILE$= "ESChat_@"+Mid(TIME$,1,2)+Mid(TIME$,4,2)+Mid(TIME$,7,2)+"_on"
         SAVEFILE$= SAVEFILE$+Mid(TODAY$,1,2)+Mid(TODAY$,4,2)+Mid(TODAY$,7,2)+".txt"
         OpenFile(113,SAVEFILE$) : For IND= NUMLINES-1 To 0 Step -1 : WriteStringN(113,SLINES$(IND)) : Next IND
         CloseFile(113) : ONKEY= 1
         Repeat : Delay(20)
            Repeat : X= WindowEvent() : If X = #PB_Event_CloseWindow : End : EndIf : Until X = 0   
            ExamineKeyboard() : If Not KeyboardPushed(#PB_Key_All) : ONKEY= 0 :EndIf         
         Until Not ONKEY   
      EndIf
   ElseIf KeyboardPushed(#PB_Key_H) And Not CHAT : CHAT= 10 : HOST= 1 : REFRESH= 1
   ElseIf KeyboardPushed(#PB_Key_J) And Not CHAT : CHAT= 20 : HOST= 0 : REFRESH= 1
   ElseIf CHAT > 99
      FL$= KeyboardInkey()
      CompilerIf #PB_Compiler_OS=#PB_OS_Linux
      If FL$<>"" Or KeyboardPushed(#PB_Key_Return)
         If Asc(FL$) < 32 Or KeyboardPushed(#PB_Key_Return) : FL$= "" : EndIf
; THE FOLLOWING 3 LINES WILL CLEAR THE STICKY KEYPRESS BUG ASSOCIATED WITH THE LINUX INPUT REQUESTER
         ONKEY= 1 : Repeat : Delay(20)
         Repeat : X= WindowEvent() : If X = #PB_Event_CloseWindow : End : EndIf : Until X = 0
         ExamineKeyboard() : If Not KeyboardPushed(#PB_Key_All) : ONKEY= 0 :EndIf : Until Not ONKEY
      CompilerElse
      If FL$<>""
         If Asc(FL$) < 32 : FL$= "" : EndIf
      CompilerEndIf 
         If HOST And (CLIENTID1 Or CLIENTID2 Or CLIENTID3)
            MESSAGE$= InputRequester("ESChat",NAME$+", enter chat message.",FL$)
            If MESSAGE$
               BUFFER$= "100"+NAME$+": "+MESSAGE$
               If CLIENTID1 : SendNetworkString(CLIENTID1,BUFFER$,#PB_UTF8) : EndIf
               If CLIENTID2 : SendNetworkString(CLIENTID2,BUFFER$,#PB_UTF8) : EndIf
               If CLIENTID3 : SendNetworkString(CLIENTID3,BUFFER$,#PB_UTF8) : EndIf
               For IND= 23 To 1 Step -1 : SLINES$(IND)= SLINES$(IND-1) : Next IND
               SLINES$(0)= NAME$+": "+MESSAGE$ : REFRESH= 1
               If NUMLINES < 24
                  NUMLINES +1 : If NUMLINES=1 : SLINES$(21)= BLANK$+FILESAV$ : EndIf
               EndIf
            EndIf
         ElseIf Not HOST And CHAT > 199
            MESSAGE$= InputRequester("ESChat",NAME$+", enter chat message.",FL$)
            If MESSAGE$
               BUFFER$= "100"+NAME$+": "+MESSAGE$
               SendNetworkString(HOSTID,BUFFER$,#PB_UTF8) 
               For IND= 23 To 1 Step -1 : SLINES$(IND)= SLINES$(IND-1) : Next IND
               SLINES$(0)= NAME$+": "+MESSAGE$ : REFRESH= 1
               If NUMLINES < 24
                  NUMLINES +1 : If NUMLINES=1 : SLINES$(21)= BLANK$+FILESAV$ : EndIf
               EndIf
            EndIf         
         EndIf
      EndIf
   EndIf
   If HOST And Not BYEBYE
      SERVENT= NetworkServerEvent()
      If SERVENT
         NEWEVENTCLI= EventClient()
         If NEWEVENTCLI = CLIENTID1
            Select SERVENT
               Case #PB_NetworkEvent_Data
                  FillMemory(*INBUFFER,#BUFLEN)
                  ReceiveNetworkData(CLIENTID1,*INBUFFER,#BUFLEN)
                  BUFFER$= PeekS(*INBUFFER,-1,#PB_UTF8)
                  FLAG$= Mid(BUFFER$,1,3) : MESSAGE$= Mid(BUFFER$,4,Len(BUFFER$)-3)
                  If FLAG$="101" And GUEST1$=""
                     GUEST1$= MESSAGE$ : REFRESH= 1
                     FLASH= ElapsedMilliseconds()+ 3000 : FLASH$= GUEST1$+" just connected."
                     If CLIENTID2 : G2L$= Mid(Str(Len(GUEST2$)+100),2,2)
                        SendNetworkString(CLIENTID2,"103"+GUEST1$,#PB_UTF8) 
                     Else : G2L$= "00" : EndIf
                     If CLIENTID3 : G3L$= Mid(Str(Len(GUEST3$)+100),2,2)
                        SendNetworkString(CLIENTID3,"103"+GUEST1$,#PB_UTF8)
                     Else : G3L$= "00" : EndIf
                     HL$= Mid(Str(Len(NAME$)+100),2,2)
                     BUFFER$= "102"+HL$+G2L$+G3L$+NAME$+GUEST2$+GUEST3$
                     SendNetworkString(CLIENTID1,BUFFER$,#PB_UTF8)
                  ElseIf FLAG$="100"   
                     For IND= 23 To 1 Step -1 : SLINES$(IND)= SLINES$(IND-1) : Next IND
                     SLINES$(0)= MESSAGE$ : REFRESH= 1
                     If NUMLINES < 24
                        NUMLINES +1 : If NUMLINES=1 : SLINES$(21)= BLANK$+FILESAV$ : EndIf
                     EndIf
                     If CLIENTID2 : SendNetworkString(CLIENTID2,BUFFER$,#PB_UTF8) : EndIf
                     If CLIENTID3 : SendNetworkString(CLIENTID3,BUFFER$,#PB_UTF8) : EndIf
                  EndIf 
               Case #PB_NetworkEvent_Disconnect
                  FLASH= ElapsedMilliseconds()+ 3000 : FLASH$= GUEST1$+" just left." : REFRESH= 1
                  If CLIENTID2 : SendNetworkString(CLIENTID2,"104"+GUEST1$,#PB_UTF8) : EndIf
                  If CLIENTID3 : SendNetworkString(CLIENTID3,"104"+GUEST1$,#PB_UTF8) : EndIf
                  CLIENTID1= 0 : GUEST1$= ""
            EndSelect
         ElseIf NEWEVENTCLI = CLIENTID2
            Select SERVENT
               Case #PB_NetworkEvent_Data
                  FillMemory(*INBUFFER,#BUFLEN)
                  ReceiveNetworkData(CLIENTID2,*INBUFFER,#BUFLEN)
                  BUFFER$= PeekS(*INBUFFER,-1,#PB_UTF8)
                  FLAG$= Mid(BUFFER$,1,3) : MESSAGE$= Mid(BUFFER$,4,Len(BUFFER$)-3)
                  If FLAG$="101" And GUEST2$=""
                     GUEST2$= MESSAGE$ : REFRESH= 1
                     FLASH= ElapsedMilliseconds()+ 3000 : FLASH$= GUEST2$+" just connected."
                     If CLIENTID1 : G1L$= Mid(Str(Len(GUEST1$)+100),2,2)
                        SendNetworkString(CLIENTID1,"103"+GUEST2$,#PB_UTF8) 
                     Else : G1L$= "00" : EndIf
                     If CLIENTID3 : G3L$= Mid(Str(Len(GUEST3$)+100),2,2)
                        SendNetworkString(CLIENTID3,"103"+GUEST2$,#PB_UTF8)
                     Else : G3L$= "00" : EndIf
                     HL$= Mid(Str(Len(NAME$)+100),2,2)
                     BUFFER$= "102"+HL$+G1L$+G3L$+NAME$+GUEST1$+GUEST3$
                     SendNetworkString(CLIENTID2,BUFFER$,#PB_UTF8)
                  ElseIf FLAG$="100"   
                     For IND= 23 To 1 Step -1 : SLINES$(IND)= SLINES$(IND-1) : Next IND
                     SLINES$(0)= MESSAGE$ : REFRESH= 1
                     If NUMLINES < 24
                        NUMLINES +1 : If NUMLINES=1 : SLINES$(21)= BLANK$+FILESAV$ : EndIf
                     EndIf
                     If CLIENTID1 : SendNetworkString(CLIENTID1,BUFFER$,#PB_UTF8) : EndIf
                     If CLIENTID3 : SendNetworkString(CLIENTID3,BUFFER$,#PB_UTF8) : EndIf
                  EndIf 
               Case #PB_NetworkEvent_Disconnect
                  FLASH= ElapsedMilliseconds()+ 3000 : FLASH$= GUEST2$+" just left." : REFRESH= 1
                  If CLIENTID1 : SendNetworkString(CLIENTID1,"104"+GUEST2$,#PB_UTF8) : EndIf
                  If CLIENTID3 : SendNetworkString(CLIENTID3,"104"+GUEST2$,#PB_UTF8) : EndIf
                  CLIENTID2= 0 : GUEST2$= ""
            EndSelect
         ElseIf NEWEVENTCLI = CLIENTID3
            Select SERVENT
               Case #PB_NetworkEvent_Data
                  FillMemory(*INBUFFER,#BUFLEN)
                  ReceiveNetworkData(CLIENTID3,*INBUFFER,#BUFLEN)
                  BUFFER$= PeekS(*INBUFFER,-1,#PB_UTF8)
                  FLAG$= Mid(BUFFER$,1,3) : MESSAGE$= Mid(BUFFER$,4,Len(BUFFER$)-3)
                  If FLAG$="101" And GUEST3$=""
                     GUEST3$= MESSAGE$ : REFRESH= 1
                     FLASH= ElapsedMilliseconds()+ 3000 : FLASH$= GUEST3$+" just connected."
                     If CLIENTID1 : G1L$= Mid(Str(Len(GUEST1$)+100),2,2)
                        SendNetworkString(CLIENTID1,"103"+GUEST3$,#PB_UTF8) 
                     Else : G1L$= "00" : EndIf
                     If CLIENTID2 : G2L$= Mid(Str(Len(GUEST2$)+100),2,2)
                        SendNetworkString(CLIENTID2,"103"+GUEST3$,#PB_UTF8)
                     Else : G2L$= "00" : EndIf
                     HL$= Mid(Str(Len(NAME$)+100),2,2)
                     BUFFER$= "102"+HL$+G1L$+G2L$+NAME$+GUEST1$+GUEST2$
                     SendNetworkString(CLIENTID3,BUFFER$,#PB_UTF8)
                  ElseIf FLAG$="100"   
                     For IND= 23 To 1 Step -1 : SLINES$(IND)= SLINES$(IND-1) : Next IND
                     SLINES$(0)= MESSAGE$ : REFRESH= 1
                     If NUMLINES < 24
                        NUMLINES +1 : If NUMLINES=1 : SLINES$(21)= BLANK$+FILESAV$ : EndIf
                     EndIf
                     If CLIENTID1 : SendNetworkString(CLIENTID1,BUFFER$,#PB_UTF8) : EndIf
                     If CLIENTID2 : SendNetworkString(CLIENTID2,BUFFER$,#PB_UTF8) : EndIf
                  EndIf 
               Case #PB_NetworkEvent_Disconnect
                  FLASH= ElapsedMilliseconds()+ 3000 : FLASH$= GUEST3$+" just left." : REFRESH= 1
                  If CLIENTID1 : SendNetworkString(CLIENTID1,"104"+GUEST3$,#PB_UTF8) : EndIf
                  If CLIENTID2 : SendNetworkString(CLIENTID2,"104"+GUEST3$,#PB_UTF8) : EndIf
                  CLIENTID3= 0 : GUEST3$= ""
            EndSelect
         Else
            Select SERVENT
               Case #PB_NetworkEvent_Connect
                  If Not CLIENTID1 : CLIENTID1= NEWEVENTCLI
                  ElseIf Not CLIENTID2 : CLIENTID2= NEWEVENTCLI
                  ElseIf Not CLIENTID3 : CLIENTID3= NEWEVENTCLI
                  Else
                     SendNetworkString(NEWEVENTCLI,"105ROOM FULL",#PB_UTF8)
                     Delay(200) : CloseNetworkConnection(NEWEVENTCLI)
                  EndIf
               Case #PB_NetworkEvent_Data
                  ReceiveNetworkData(NEWEVENTCLI,*INBUFFER,#BUFLEN)
            EndSelect
         EndIf
      EndIf
   ElseIf HOSTID And Not BYEBYE
      CLIVENT= NetworkClientEvent(HOSTID)
      Select CLIVENT
         Case #PB_NetworkEvent_Data
            FillMemory(*INBUFFER,#BUFLEN)
            ReceiveNetworkData(HOSTID,*INBUFFER,#BUFLEN)
            BUFFER$= PeekS(*INBUFFER,-1,#PB_UTF8)
            FLAG$= Mid(BUFFER$,1,3) : MESSAGE$= Mid(BUFFER$,4,Len(BUFFER$)-3)
            If FLAG$= "102"
               HNL= Val(Mid(MESSAGE$,1,2)) : HOST$= Mid(MESSAGE$,7,HNL) : CHAT= 200 : REFRESH= 1
               OG1NL= Val(Mid(MESSAGE$,3,2)) : If OG1NL : OTHERG1$= Mid(MESSAGE$,7+HNL,OG1NL) : EndIf
               OG2NL= Val(Mid(MESSAGE$,5,2)) : If OG2NL : OTHERG2$= Mid(MESSAGE$,7+HNL+OG1NL,OG2NL) : EndIf
               FLASH= ElapsedMilliseconds()+ 3000 : FLASH$= HOST$+" welcomes you."
            ElseIf FLAG$= "103"
               FLASH= ElapsedMilliseconds()+ 3000 : FLASH$= MESSAGE$+" just connected." : REFRESH= 1
               If OTHERG1$="" : OTHERG1$= MESSAGE$
               Else : OTHERG2$= MESSAGE$ : EndIf
            ElseIf FLAG$= "104"
               FLASH= ElapsedMilliseconds()+ 3000 : FLASH$= MESSAGE$+" just left." : REFRESH= 1
               If MESSAGE$=OTHERG1$ : OTHERG1$= ""
               Else : OTHERG2$= "" : EndIf
            ElseIf FLAG$= "105"
               FLASH= ElapsedMilliseconds()+ 3000 : FLASH$= "* FULL CHATROOM *" : REFRESH= 1
               FULL= 1 : CHAT= 0
            ElseIf FLAG$= "100"
               For IND= 23 To 1 Step -1 : SLINES$(IND)= SLINES$(IND-1) : Next IND
               SLINES$(0)= MESSAGE$ : REFRESH= 1
               If NUMLINES < 24
                  NUMLINES +1 : If NUMLINES=1 : SLINES$(21)= BLANK$+FILESAV$ : EndIf
               EndIf 
            EndIf
         Case #PB_NetworkEvent_Disconnect
            If HOST$= "" : HOST$= "The host" : EndIf
            If Not FULL : MessageRequester("ESChat",HOST$+" has closed the connection.",0) : EndIf
            CHAT= 0 : REFRESH= 1 : HOSTID= 0 : HOST$= "" : NUMLINES= 0
      EndSelect
   EndIf
   If Not BYEBYE
      If RESEND < ElapsedMilliseconds() And CHAT=23
         RESEND= ElapsedMilliseconds()+ 1000
         BUFFER$= "101"+NAME$ : SendNetworkString(HOSTID,BUFFER$,#PB_UTF8)
      EndIf
      If ElapsedMilliseconds() < RELEASE
         Repeat : Delay(2) : Until ElapsedMilliseconds() > RELEASE
      EndIf
      If FLASH > 0 And FLASH < ElapsedMilliseconds()
         FLASH= 0 : REFRESH= 1
      EndIf
   EndIf
Until BYEBYE
FreeMemory(*INBUFFER) : End
On my 32-bit Windows® XP, this compiles to a 89.0 Kb (91,136 bytes) module.
I did not include the GetExternalIPAddress() procedure because I wanted to keep the executable under 100Kb and not be redundant.

This way of communicating seems to play nice on a LAN, but my fear is that it will fail on the internet.
If anyone would like to volunteer to help me test the internet connectivity, then kindly send a PM my way.
Keep it BASIC.
User avatar
RichAlgeni
Addict
Addict
Posts: 935
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: ESChat

Post by RichAlgeni »

You seem to have a good grasp of sockets. The only thing you need for internet communications is a timeout and error checking and handling. I only (as of right now) code on Windows platforms, so I use the Win API function ioctlsocket.

socketHandle = ConnectionID(connectNumber)

; loop until we have received data, or our timeout has been exceeded

Code: Select all

Repeat
    result = ioctlsocket_(socketHandle, #FIONREAD, @length)

; if we encountered a socket error, we need to exit the loop

        If result <> 0
            errNumber  = WSAGetLastError_()
            amountRead = -1
            Break
        EndIf

; if nothing has been received, increment the attempt counter and sleep, else get out of the loop

        If length = 0
            attemptCount = attemptCount + 1
            If attemptCount > maxReadTrys
                Break
            Else
                Delay(socketTimeout)
            EndIf

; else get the data in the network receive buffer

        Else
            amountRead = ReceiveNetworkData(connectNumber, *memoryLoc, memLength)

            Break
        EndIf
    ForEver
If result is non-zero, and error has occurred and the socket has dropped. Otherwise, check the length variable, if it is non-zero, data is available to be read. Length will be the amount of data that will be read in using
ReceiveNetworkData(). Using this format, only 1 call to ReceiveNetworkData() is required.

For sending data, just check the result returned from SendNetworkData(), if it is negative, there is a socket error.

Also, for Windows, close the client socket when an error is encountered. A server socket will be closed by the system. Remember that doesn't end the server process, just that socket.

attemptCount, maxReadTrys and socketTimeout are Global variables I use, they are read in from an ini file.
User avatar
heartbone
Addict
Addict
Posts: 1058
Joined: Fri Apr 12, 2013 1:55 pm
Location: just outside of Ferguson

Re: ESChat

Post by heartbone »

Since I don't know a thing about sockets, you must be using that term to apply to a more basic concept.

Yes, I know about the extra checking and resend processing that I needed back in the wild days 11 years ago of dial-up modem connections to support a real time game at 30 FPS.
I also know that connections are better nowadays.
Still I (or others) need to get some testing on this code on the real internet where packets are not as well ordered as they are on a LAN.

I am unaware if sockets are used by the underlying system functions invoked by PureBasic, but I know for sure that my applications have no need for anything but the core PureBasic command set.
Obviously somehow you remain unconvinced that socketry is unneeded by the BASIC programmer.
So be it.
Keep it BASIC.
User avatar
TI-994A
Addict
Addict
Posts: 2698
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: ESChat

Post by TI-994A »

heartbone wrote:I am unaware if sockets are used by the underlying system functions invoked by PureBasic, but I know for sure that my applications have no need for anything but the core PureBasic command set.

Obviously somehow you remain unconvinced that socketry is unneeded by the BASIC programmer.
Hi heartbone. Besides serial port communications, almost all other communication methods utilise sockets; even PureBasic's network functions. In fact, all the PureBasic network functions are simply wrappers for the underlying socket functions.

So, it is not quite accurate to say that socketry is unneeded by the BASIC programmer. We need it, we use it, but thanks to the magic of PureBasic, we just don't see it.

Furthermore, as RichAlgeni has pointed out, your code is light on error handling. In every instance, you've called the network functions without regard or contingency to the results. That's a programming no-no; even for BASIC.
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
User avatar
heartbone
Addict
Addict
Posts: 1058
Joined: Fri Apr 12, 2013 1:55 pm
Location: just outside of Ferguson

Re: ESChat

Post by heartbone »

TI-994A wrote:Hi heartbone. Besides serial port communications, almost all other communication methods utilise sockets; even PureBasic's network functions. In fact, all the PureBasic network functions are simply wrappers for the underlying socket functions.

So, it is not quite accurate to say that socketry is unneeded by the BASIC programmer. We need it, we use it, but thanks to the magic of PureBasic, we just don't see it.
You make my point.
Advice about socketry programming to PureBasic programmers is needed in the exact same way that advice about assembly programming is... it isn't.
I can stand behind the veracity of my statement as posted.
The following was also unhelpful.
Furthermore, as RichAlgeni has pointed out, your code is light on error handling. In every instance, you've called the network functions without regard or contingency to the results.
I'll leave it to you to figure out your mistake.
That's a programming no-no; even for BASIC.
No-no?
Even for BASIC???? :shock: (that last remark tells me a lot about your mindset)
Dude if this was a real time game like SURROUND, then I'd have to check to make sure that A happened before I can move to B.
I have done it before.
But for this SIMPLE (1.5 days of programming) chat client server demo I think it might be overkill, don't you?
I wasn't programming the perfect chat client, just rolled a simple demo for educational and testing purposes.
Try to keep things in a more practical perspective.

Actual constructive criticism would arise from interaction with the program, and not from vague hand waving theoretical speculation.
You didn't test it over the net to see if it is a dysfunctional implementation, did you TI?
Did you find any ACTUAL problems, or is it that you just don't like me?
Since no one on this forum seems to have any interest or time to share, I'll probably contact this nice lady in Georgia to see if she'll help me test for problems.

After I complete an actual networked game or two, I'll probably enhance this for personal use by including file transfers, hyperlink detection, and VoIP (walkie talkie style).
And of course guest booting. :P
Keep it BASIC.
User avatar
TI-994A
Addict
Addict
Posts: 2698
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: ESChat

Post by TI-994A »

Hello again heartbone. Please allow me to apologise if I have come across as hostile. I only intended to answer your question about the underlying mechanics of PureBasic's network functions, and made a remark on RichAlgeni's observations about timeouts and error checking and handling.

Perhaps you're associating this post with our previous exchanges, which I must admit contained some hostility. But like I said there, I'm always passionate when defending PureBasic. :)

Your code looks good, although I've not tried it out. And while you're right about keeping it light, it might still be a good idea to check the return values of the various network calls - a few extra lines at the most.

Once again, sorry if I offended. :D
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
User avatar
heartbone
Addict
Addict
Posts: 1058
Joined: Fri Apr 12, 2013 1:55 pm
Location: just outside of Ferguson

Re: ESChat

Post by heartbone »

No problem, it's all good.
Although I must admit to liking the overall feel of my HP-25c over my TI-SR50 calculator. :D

About the code's functioning, I get no problems 100% functioning on a LAN.
Over the net it may totally break down, and it is unlikely but possible there may be no problems at all.
The internet of today as opposed to 2003's internet environment comprised of dial-up combined with the Windows® 98 IPX protocol is a much different critter, so I honestly don't know.
I'm hoping that the www acts more like a LAN than it used to, which is why the code is up there in the form it is for testing.
If you find problems, a good description of the steps needed to replicate it (and even a code fix) would be nice.
But at this point, problem detection is a priority, before I use the methodology elsewhere.

The only problems that I expect could happen with the limited code above at this point, would be garbled messages, missing messages, and disconnects for unknown reasons.
If file transfers were implemented for example, then they'd need more handshaking verification to insure accurate transfers.
Chat text, not so critical.
If any of the above errors are detected when using this chat client, then I'd feel it necessary to add checksums and message received notifications.
But if 99% of the time there is no problem, then personally, I'd not bother with adding it.
Keep it BASIC.
User avatar
RichAlgeni
Addict
Addict
Posts: 935
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: ESChat

Post by RichAlgeni »

heartbone wrote:Actual constructive criticism would arise from interaction with the program, and not from vague hand waving theoretical speculation.
Did you find any ACTUAL problems, or is it that you just don't like me?
Since no one on this forum seems to have any interest or time to share, I'll probably contact this nice lady in Georgia to see if she'll help me test for problems.
Ok, if you want actual constructive criticism, here it is: You have a chip on your shoulder. You take suggestions as personal criticism. You post code not for actual feedback, or to help others learn, but to stroke your own ego as an accomplished developer. The truth is that while your code may be functional, it shows you to be inexperienced and not especially proficient. You duplicate chunks of code instead of separating it out as a procedure, then calling it as needed. You hardcode file and other variables. You place looping commands with other statements on the same line. All of this makes your code harder to maintain, especially for others. An experienced developer knows that they code not only for themselves, but also for the people that come after them. You do yourself no favors by obfuscating your programs to keep yourself in a job. Instead of getting insulted, accept that there are others who have more experience, or are just better coders.

You can respond if you want, it doesn't matter to me. Until you learn some humility, one can always judge the weight of your words, just by considering the source.
User avatar
heartbone
Addict
Addict
Posts: 1058
Joined: Fri Apr 12, 2013 1:55 pm
Location: just outside of Ferguson

Re: ESChat

Post by heartbone »

RichAlgeni wrote:Ok, if you want actual constructive criticism, here it is: You have a chip on your shoulder. You take suggestions as personal criticism. You post code not for actual feedback, or to help others learn, but to stroke your own ego as an accomplished developer. The truth is that while your code may be functional, it shows you to be inexperienced and not especially proficient. You duplicate chunks of code instead of separating it out as a procedure, then calling it as needed. You hardcode file and other variables. You place looping commands with other statements on the same line. All of this makes your code harder to maintain, especially for others. An experienced developer knows that they code not only for themselves, but also for the people that come after them. You do yourself no favors by obfuscating your programs to keep yourself in a job. Instead of getting insulted, accept that there are others who have more experience, or are just better coders.

You can respond if you want, it doesn't matter to me. Until you learn some humility, one can always judge the weight of your words, just by considering the source.
Thank you for allowing me the opportunity to respond Rich.

On a personal note: Talk about ego! Someone certainly has less than "a chip" on their shoulder to insert a personal attack post like that into this thread.
It certainly has no place in this thread or on the board in general.
Next time try a PM with your concerns, that is if you are truly concerned with my lack of humility for wanting my ego stroked, or technical shortcomings.
It would have been perceived as a much more honest communication.

I'm no shrink, but I think that you have a much deeper hostility issues.
Your observations about my coding style seem a bit odd, and out of place in the context of my request for code testing.
I sincerely do not care one lick about your stupid opinions on style, but they are acceptable in the context of asking for constructive criticism about a program.
As far as your cynically flawed accusation of my coding being obfuscated to keep a job.... you by any chance wouldn't be in whorprit management would you?

(for the others)
I'll just reassert that I'm actually trying to get someone to verify that there are problems or not with running the code as it is, over the internet.
At a minimum I'd like to find out if it even makes it through the connection phase.
Keep it BASIC.
bosker
Enthusiast
Enthusiast
Posts: 105
Joined: Fri Jan 08, 2010 11:04 pm
Location: Hampshire, UK

Re: ESChat

Post by bosker »

I built EsChat as 32-bit EXE on Win 7 X64.
It works Ok on LAN but fails on network when attempting to connect a chat client with...
"CAN'T FIND HOST AT <ip address>"

Incidentally, around line 40 there's a line...
If Not FLASH And (GUEST1$ Or GUEST1$ Or GUEST3$)

I guess that middle GUEST1 should be GUEST2
User avatar
heartbone
Addict
Addict
Posts: 1058
Joined: Fri Apr 12, 2013 1:55 pm
Location: just outside of Ferguson

Re: ESChat

Post by heartbone »

Thank you bosker for taking the time to test this.
Yes that's a bug, it should be If Not FLASH And (GUEST1$ Or GUEST2$ Or GUEST3$).
If there was a guest1 & guest2 connected, and guest1 disconnected, and there was no guest3, then the host would no longer see guest2's name up top.
Thanks for finding that one.

If you have set the firewalls on both computers to allow this executable's communication,
and the host computer has port 6532 forwarded, if behind a router,
then I have some detective work to see why there is no connection. :x

I plan to get to the port forwarding in a few days, just as soon as I can get the last bugs out of my file transfer routines.
For that function I definitely needed to include a MD5 hash of the data block in each data packet.
Files under ~7MB seem to go through flawlessly every time.
Files ~7-15 MB sometimes, and over 15 MB then they'll usually end up badly, about 1-2% smaller.
I'm using longs for the various indexes, so I don't believe it's a problem with a counter overflow.
I'd forgotten how difficult network programming can be. :?
Keep it BASIC.
User avatar
heartbone
Addict
Addict
Posts: 1058
Joined: Fri Apr 12, 2013 1:55 pm
Location: just outside of Ferguson

Re: ESChat

Post by heartbone »

I do not want this example to encourage anyone to use the SendNetworkString() command,
and I do hope that a bug has been reported previously about it.
I can 10000%+ confirm that it is thoroughly and nastily bugged, and its use should be avoided in all but the simplest cases.
Keep it BASIC.
User avatar
RichAlgeni
Addict
Addict
Posts: 935
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: ESChat

Post by RichAlgeni »

I don't know whether there is anything wrong with SendNetworkString(), but I suspect there is more to the issue than you can know with that command. Regardless, you should always use the SendNetworkData() command for anything other than the most trivial data strings.

Check the result returned, it should equal the number of bytes sent. If it's less, you will need to call it again with an offset of the amount already sent. Also, subtract the amount returned from the length so that you don't get a read buffer overflow error. If the result returned is negative and it is a client socket, call the close socket routine to clean up the handle. If it's a server socket, you can just clear the variable as the system will clean up the socket.

If you plan on sending binary data, the SendNetworkData() command is required in order to send binary zeros.
User avatar
heartbone
Addict
Addict
Posts: 1058
Joined: Fri Apr 12, 2013 1:55 pm
Location: just outside of Ferguson

Re: ESChat

Post by heartbone »

RichAlgeni wrote:I don't know whether there is anything wrong with SendNetworkString(), but I suspect there is more to the issue than you can know with that command. Regardless, you should always use the SendNetworkData() command for anything other than the most trivial data strings.
Agreed. If you attempt to actually use SendNetworkString() for almost anything, it'll jump out and bite you hard.
Check the result returned, it should equal the number of bytes sent. If it's less, you will need to call it again with an offset of the amount already sent. Also, subtract the amount returned from the length so that you don't get a read buffer overflow error. If the result returned is negative and it is a client socket, call the close socket routine to clean up the handle. If it's a server socket, you can just clear the variable as the system will clean up the socket.
There you go off topic again. Why?
If you plan on sending binary data, the SendNetworkData() command is required in order to send binary zeros.
OK, but I usually use decimal and hexadecimal zeros. :P

Another reason not to use SendNetworkString() is that you can't encrypt the data if you do use that function.

This was started as a one or two day diversion from networking the DEDUCER to play with the chat a bit.
Then it morphed into a stand alone project which I apparently started two weeks ago, and hope to have finished yesterday.
If I ever get the time and gain the knowledge the only future upgrade would be to add voice.

With the code above I wanted to show how the SendNetworkString() function could be used exclusively, and I succeeded there.
Although at the same time I proved to myself that it should not be used.
I also wanted to show to you Rich that sockets are unnecessary in PB, and I succeeded there.

OK today is the port forwarding.
I'm crossing my fingers that the internet tests will work.
As soon as I determine the program works on the net, and I don't find any other problems, I'll post a link to the executable.
If anyone here wants to help me test the beta, kindly send a PM my way.
Keep it BASIC.
User avatar
heartbone
Addict
Addict
Posts: 1058
Joined: Fri Apr 12, 2013 1:55 pm
Location: just outside of Ferguson

Re: ESChat

Post by heartbone »

Besides fixing the bug that bosker caught,
I added the SNETSTRING() procedure and changed the 27 SendNetworkString(ID,STRING$,#PB_UTF8) calls to SNETSTRING(ID,STRING$) to replace all those SendNetworkString() calls with SendNetworkData().

Code: Select all

; ********************************
; *********  ESChat 1.1  *********
; ******  February 11, 2015  *****
; **** ELECTRONICAL  SOFTWARE ****
; ********************************
Procedure SNETSTRING(ID,STRING$)
; REPLACES SendNetworkString(ID,STRING$,#PB_UTF8)
   *SBUFFER= AllocateMemory(256)
   PokeS(*SBUFFER,STRING$,Len(STRING$)+1,#PB_UTF8)
   SendNetworkData(ID,*SBUFFER,Len(STRING$)+1)
   FreeMemory(*SBUFFER)
EndProcedure
#BUFLEN= 256 : *INBUFFER= AllocateMemory(#BUFLEN)
Dim SLINES$(23) : FS1= 12 : FS2= 24
InitSprite()
OpenWindow(0,0,0,800,600,"ESChat",#PB_Window_ScreenCentered|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget)
;; NO CAN DO IN DEMO, SO USERS WHO HAVE CHANGED THEIR DESKTOP FONT SIZE WILL HAVE THE TEXT SIZE ALTERED ACCORDINGLY.
;;CompilerIf #PB_Compiler_OS=#PB_OS_Windows
;;   DPI= GetDeviceCaps_(GetDC_(0),#LOGPIXELSX)
;;   If DPI <> 96 And DPI > 15 And DPI < 193 : FS1= (FS1*100)/DPI : FS2= (FS2*100)/DPI : EndIf
;;CompilerEndIf
LoadFont(1,"Arial",FS1,#PB_Font_HighQuality)
LoadFont(2,"Arial",FS2,#PB_Font_Bold|#PB_Font_HighQuality)
LoadFont(3,"Arial",FS1,#PB_Font_Bold|#PB_Font_HighQuality)
OpenWindowedScreen(WindowID(0),0,0,800,600,#True,0,0) : CreateSprite(0,800,600)
InitKeyboard() : InitNetwork()
REFRESH= 2 : BYEBYE= 0 : CHAT= 0 : NUMLINES= 0 : FLASH= 0 : RESEND= 0
PORT= 6532 : HOSTID= 0 : CLIENTID1= 0 : CLIENTID2= 0 : CLIENTID3= 0
HOST$= "" : GUEST1$= "" : GUEST2$= "" : GUEST3$= "" : OTHERG1$= "" : OTHERG2$= ""
BLANK$= "                             "
FILESAV$= "Press Ctrl+S at any time to save the current chat text display into a file."
Repeat
   RELEASE= ElapsedMilliseconds()+ 20
   Repeat : X= WindowEvent() : If X = #PB_Event_CloseWindow : End : EndIf : Until X = 0
   If REFRESH
      StartDrawing(SpriteOutput(0)) : DrawingMode(#PB_2DDrawing_Transparent)
      DrawingFont(FontID(2)) : Box(0,0,800,600,$000000)
      If CHAT > 99 Or FULL
         If HOST
            If FLASH
               DBUFF$= FLASH$
            Else
               DBUFF$= "* HOSTING CHAT SESSION *"
            EndIf
            DrawText(400-TextWidth(DBUFF$)/2,20,DBUFF$,$FFDD77)
            If Not FLASH And (GUEST1$ Or GUEST2$ Or GUEST3$)
               IND= 180 : DrawingFont(FontID(3))
               If GUEST1$ : DrawText(IND-TextWidth(GUEST1$)/2,2,GUEST1$,$22DD22) : IND +220 : EndIf
               If GUEST2$ : DrawText(IND-TextWidth(GUEST2$)/2,2,GUEST2$,$22DD22) : IND +220 : EndIf
               If GUEST3$ : DrawText(IND-TextWidth(GUEST3$)/2,2,GUEST3$,$22DD22) : EndIf
               DrawingFont(FontID(2))
            EndIf
         Else
            If FLASH
               DBUFF$= FLASH$
            Else
               If FULL
                  FULL= 0 : DBUFF$= ""
               Else
                  DBUFF$= "* IN CHAT SESSION *"
               EndIf
            EndIf
            DrawText(400-TextWidth(DBUFF$)/2,17,DBUFF$,$FFDD77)
            If Not FLASH
               IND= 180 : DrawingFont(FontID(3))
               DrawText(IND-TextWidth(HOST$)/2,2,HOST$,$22DD22) : IND +220
               If OTHERG1$ : DrawText(IND-TextWidth(OTHERG1$)/2,2,OTHERG1$,$22DD22) : IND +220 : EndIf
               If OTHERG2$ : DrawText(IND-TextWidth(OTHERG2$)/2,2,OTHERG2$,$22DD22) : EndIf
               DrawingFont(FontID(2))
            EndIf
         EndIf
      EndIf
      If CHAT < 100 : DrawingFont(FontID(2)) : EndIf
      If CHAT > 99
         If NUMLINES
            Box(20,63,759,449,$444444) : Box(22,65,755,445,$1C1C1C) : DrawingFont(FontID(1))
            JND= NUMLINES- 1 : If NUMLINES < 4 : JND= 23 : EndIf
            For IND= 0 To JND : DrawText(25,485-IND*18,SLINES$(IND),$00FF00) : Next IND
         EndIf
      ElseIf CHAT > 19
         DBUFF$= "* JOINING CHAT SESSION *" : DrawText(400-TextWidth(DBUFF$)/2,25,DBUFF$,$FFDD77)
         If CHAT = 21
            DBUFF$= NAME$+", ENTER THE HOST IP ADDRESS." : DrawText(400-TextWidth(DBUFF$)/2,60,DBUFF$,$FFDD77)
         ElseIf CHAT = 22
            DBUFF$= "CONNECTING TO CHAT HOST @ "+HIP$ : DrawText(400-TextWidth(DBUFF$)/2,60,DBUFF$,$FFDD77)
         ElseIf CHAT = 23
            DBUFF$= "TRANSFERRING DATA WITH CHAT HOST" : DrawText(400-TextWidth(DBUFF$)/2,60,DBUFF$,$FFDD77)
         EndIf
      ElseIf CHAT > 9
         DBUFF$= "* HOSTING CHAT SESSION *" : DrawText(400-TextWidth(DBUFF$)/2,25,DBUFF$,$FFDD77)
         If CHAT = 11
            DBUFF$= "AS "+NAME$ : DrawText(400-TextWidth(DBUFF$)/2,60,DBUFF$,$FFDD77)
         EndIf
      ElseIf Not FULL
         DBUFF$= "PRESS H TO HOST CHAT SESSION" : DrawText(400-TextWidth(DBUFF$)/2,125,DBUFF$,$FFDD77)
         DBUFF$= "PRESS J TO JOIN CHAT SESSION" : DrawText(400-TextWidth(DBUFF$)/2,250,DBUFF$,$FFDD77)
      EndIf   
      If CHAT > 99 : If NUMLINES : DrawingFont(FontID(2)) : EndIf
         If CLIENTID1 Or CLIENTID2 Or CLIENTID3 Or CHAT > 199
            DBUFF$= "PRESS ANY KEY TO TYPE A MESSAGE" : DrawText(400-TextWidth(DBUFF$)/2,515,DBUFF$,$AAAAAA)
         EndIf
      EndIf
      DBUFF$= "PRESS Esc KEY TO EXIT CHAT" : DrawText(400-TextWidth(DBUFF$)/2,555,DBUFF$,$AAAAAA)
      StopDrawing() : DisplaySprite(0,0,0) : FlipBuffers() : REFRESH= 0
   EndIf
   If CHAT = 10 Or CHAT = 20 Or CHAT= 21
      CompilerIf #PB_Compiler_OS=#PB_OS_Linux
; THE FOLLOWING 3 LINES WILL CLEAR THE STICKY KEYPRESS BUG ASSOCIATED WITH THE LINUX INPUT REQUESTER
         ONKEY= 1 : Repeat : Delay(20)
         Repeat : X= WindowEvent() : If X = #PB_Event_CloseWindow : End : EndIf : Until X = 0
         ExamineKeyboard() : If Not KeyboardPushed(#PB_Key_All) : ONKEY= 0 :EndIf : Until Not ONKEY
      CompilerEndIf
      If CHAT < 21
         NAME$= InputRequester("ESChat","Enter Your Name",UserName())
         If NAME$ : CHAT +1 : Else : CHAT= 0 : EndIf
      Else   
         HIP$= InputRequester("ESChat","USE THE IPv4   * . * . * . *   ADDRESS FORMAT","")
         If CountString(HIP$,".")<>3 Or Len(HIP$)<7 Or Len(HIP$)>15 : HIP$= "" : EndIf
         If HIP$ : CHAT= 22 : FL$= KeyboardInkey() : Else : CHAT= 0 : EndIf
      EndIf
      REFRESH= 1
   ElseIf CHAT= 11
      Delay(1000)
      If CreateNetworkServer(0,PORT)
         CHAT= 100 : FULL= 0 : FLASH= ElapsedMilliseconds()+ 2000 : FLASH$= "* CHATROOM CREATED *"
      Else
         MessageRequester("ESChat","CAN'T CREATE CHATROOM!", 0) : CHAT= 0
      EndIf
      REFRESH= 1   
   ElseIf CHAT= 22
      HOSTID= OpenNetworkConnection(HIP$,PORT,#PB_Network_TCP,7777)
      If HOSTID
         CHAT= 23 : FULL= 0 : Delay(1000)
      Else
         MessageRequester("ESChat","CAN'T FIND HOST AT "+HIP$+"!") : CHAT= 0
      EndIf
      REFRESH= 1
   EndIf
   ExamineKeyboard()
   If KeyboardPushed(#PB_Key_Escape)
      If HOSTID : CloseNetworkConnection(HOSTID) : EndIf
      If CLIENTID1 : CloseNetworkConnection(CLIENTID1) : EndIf
      If CLIENTID2 : CloseNetworkConnection(CLIENTID2) : EndIf
      If CLIENTID3 : CloseNetworkConnection(CLIENTID3) : EndIf
      BYEBYE+ 1
   ElseIf KeyboardPushed(#PB_Key_LeftControl) Or KeyboardPushed(#PB_Key_RightControl)
      If KeyboardPushed(#PB_Key_S) And CHAT > 99 And NUMLINES
         TODAY$= FormatDate("%mm/%dd/%yy",Date()) : TIME$= FormatDate("%hh:%ii:%ss",Date())
         SAVEFILE$= "ESChat_@"+Mid(TIME$,1,2)+Mid(TIME$,4,2)+Mid(TIME$,7,2)+"_on"
         SAVEFILE$= SAVEFILE$+Mid(TODAY$,1,2)+Mid(TODAY$,4,2)+Mid(TODAY$,7,2)+".txt"
         OpenFile(113,SAVEFILE$) : For IND= NUMLINES-1 To 0 Step -1 : WriteStringN(113,SLINES$(IND)) : Next IND
         CloseFile(113) : ONKEY= 1
         Repeat : Delay(20)
            Repeat : X= WindowEvent() : If X = #PB_Event_CloseWindow : End : EndIf : Until X = 0   
            ExamineKeyboard() : If Not KeyboardPushed(#PB_Key_All) : ONKEY= 0 :EndIf         
         Until Not ONKEY   
      EndIf
   ElseIf KeyboardPushed(#PB_Key_H) And Not CHAT : CHAT= 10 : HOST= 1 : REFRESH= 1
   ElseIf KeyboardPushed(#PB_Key_J) And Not CHAT : CHAT= 20 : HOST= 0 : REFRESH= 1
   ElseIf CHAT > 99
      FL$= KeyboardInkey()
      CompilerIf #PB_Compiler_OS=#PB_OS_Linux
      If FL$<>"" Or KeyboardPushed(#PB_Key_Return)
         If Asc(FL$) < 32 Or KeyboardPushed(#PB_Key_Return) : FL$= "" : EndIf
; THE FOLLOWING 3 LINES WILL CLEAR THE STICKY KEYPRESS BUG ASSOCIATED WITH THE LINUX INPUT REQUESTER
         ONKEY= 1 : Repeat : Delay(20)
         Repeat : X= WindowEvent() : If X = #PB_Event_CloseWindow : End : EndIf : Until X = 0
         ExamineKeyboard() : If Not KeyboardPushed(#PB_Key_All) : ONKEY= 0 :EndIf : Until Not ONKEY
      CompilerElse
      If FL$<>""
         If Asc(FL$) < 32 : FL$= "" : EndIf
      CompilerEndIf
         If HOST And (CLIENTID1 Or CLIENTID2 Or CLIENTID3)
            MESSAGE$= InputRequester("ESChat",NAME$+", enter chat message.",FL$)
            If MESSAGE$
               BUFFER$= "100"+NAME$+": "+MESSAGE$
               If CLIENTID1 : SNETSTRING(CLIENTID1,BUFFER$) : EndIf
               If CLIENTID2 : SNETSTRING(CLIENTID2,BUFFER$) : EndIf
               If CLIENTID3 : SNETSTRING(CLIENTID3,BUFFER$) : EndIf
               For IND= 23 To 1 Step -1 : SLINES$(IND)= SLINES$(IND-1) : Next IND
               SLINES$(0)= NAME$+": "+MESSAGE$ : REFRESH= 1
               If NUMLINES < 24
                  NUMLINES +1 : If NUMLINES=1 : SLINES$(21)= BLANK$+FILESAV$ : EndIf
               EndIf
            EndIf
         ElseIf Not HOST And CHAT > 199
            MESSAGE$= InputRequester("ESChat",NAME$+", enter chat message.",FL$)
            If MESSAGE$
               BUFFER$= "100"+NAME$+": "+MESSAGE$
               SNETSTRING(HOSTID,BUFFER$)
               For IND= 23 To 1 Step -1 : SLINES$(IND)= SLINES$(IND-1) : Next IND
               SLINES$(0)= NAME$+": "+MESSAGE$ : REFRESH= 1
               If NUMLINES < 24
                  NUMLINES +1 : If NUMLINES=1 : SLINES$(21)= BLANK$+FILESAV$ : EndIf
               EndIf
            EndIf         
         EndIf
      EndIf
   EndIf
   If HOST And Not BYEBYE
      SERVENT= NetworkServerEvent()
      If SERVENT
         NEWEVENTCLI= EventClient()
         If NEWEVENTCLI = CLIENTID1
            Select SERVENT
               Case #PB_NetworkEvent_Data
                  FillMemory(*INBUFFER,#BUFLEN)
                  ReceiveNetworkData(CLIENTID1,*INBUFFER,#BUFLEN)
                  BUFFER$= PeekS(*INBUFFER,-1,#PB_UTF8)
                  FLAG$= Mid(BUFFER$,1,3) : MESSAGE$= Mid(BUFFER$,4,Len(BUFFER$)-3)
                  If FLAG$="101" And GUEST1$=""
                     GUEST1$= MESSAGE$ : REFRESH= 1
                     FLASH= ElapsedMilliseconds()+ 3000 : FLASH$= GUEST1$+" just connected."
                     If CLIENTID2 : G2L$= Mid(Str(Len(GUEST2$)+100),2,2)
                        SNETSTRING(CLIENTID2,"103"+GUEST1$)
                     Else : G2L$= "00" : EndIf
                     If CLIENTID3 : G3L$= Mid(Str(Len(GUEST3$)+100),2,2)
                        SNETSTRING(CLIENTID3,"103"+GUEST1$)
                     Else : G3L$= "00" : EndIf
                     HL$= Mid(Str(Len(NAME$)+100),2,2)
                     BUFFER$= "102"+HL$+G2L$+G3L$+NAME$+GUEST2$+GUEST3$
                     SNETSTRING(CLIENTID1,BUFFER$)
                  ElseIf FLAG$="100"   
                     For IND= 23 To 1 Step -1 : SLINES$(IND)= SLINES$(IND-1) : Next IND
                     SLINES$(0)= MESSAGE$ : REFRESH= 1
                     If NUMLINES < 24
                        NUMLINES +1 : If NUMLINES=1 : SLINES$(21)= BLANK$+FILESAV$ : EndIf
                     EndIf
                     If CLIENTID2 : SNETSTRING(CLIENTID2,BUFFER$) : EndIf
                     If CLIENTID3 : SNETSTRING(CLIENTID3,BUFFER$) : EndIf
                  EndIf
               Case #PB_NetworkEvent_Disconnect
                  FLASH= ElapsedMilliseconds()+ 3000 : FLASH$= GUEST1$+" just left." : REFRESH= 1
                  If CLIENTID2 : SNETSTRING(CLIENTID2,"104"+GUEST1$) : EndIf
                  If CLIENTID3 : SNETSTRING(CLIENTID3,"104"+GUEST1$) : EndIf
                  CLIENTID1= 0 : GUEST1$= ""
            EndSelect
         ElseIf NEWEVENTCLI = CLIENTID2
            Select SERVENT
               Case #PB_NetworkEvent_Data
                  FillMemory(*INBUFFER,#BUFLEN)
                  ReceiveNetworkData(CLIENTID2,*INBUFFER,#BUFLEN)
                  BUFFER$= PeekS(*INBUFFER,-1,#PB_UTF8)
                  FLAG$= Mid(BUFFER$,1,3) : MESSAGE$= Mid(BUFFER$,4,Len(BUFFER$)-3)
                  If FLAG$="101" And GUEST2$=""
                     GUEST2$= MESSAGE$ : REFRESH= 1
                     FLASH= ElapsedMilliseconds()+ 3000 : FLASH$= GUEST2$+" just connected."
                     If CLIENTID1 : G1L$= Mid(Str(Len(GUEST1$)+100),2,2)
                        SNETSTRING(CLIENTID1,"103"+GUEST2$)
                     Else : G1L$= "00" : EndIf
                     If CLIENTID3 : G3L$= Mid(Str(Len(GUEST3$)+100),2,2)
                        SNETSTRING(CLIENTID3,"103"+GUEST2$)
                     Else : G3L$= "00" : EndIf
                     HL$= Mid(Str(Len(NAME$)+100),2,2)
                     BUFFER$= "102"+HL$+G1L$+G3L$+NAME$+GUEST1$+GUEST3$
                     SNETSTRING(CLIENTID2,BUFFER$)
                  ElseIf FLAG$="100"   
                     For IND= 23 To 1 Step -1 : SLINES$(IND)= SLINES$(IND-1) : Next IND
                     SLINES$(0)= MESSAGE$ : REFRESH= 1
                     If NUMLINES < 24
                        NUMLINES +1 : If NUMLINES=1 : SLINES$(21)= BLANK$+FILESAV$ : EndIf
                     EndIf
                     If CLIENTID1 : SNETSTRING(CLIENTID1,BUFFER$) : EndIf
                     If CLIENTID3 : SNETSTRING(CLIENTID3,BUFFER$) : EndIf
                  EndIf
               Case #PB_NetworkEvent_Disconnect
                  FLASH= ElapsedMilliseconds()+ 3000 : FLASH$= GUEST2$+" just left." : REFRESH= 1
                  If CLIENTID1 : SNETSTRING(CLIENTID1,"104"+GUEST2$) : EndIf
                  If CLIENTID3 : SNETSTRING(CLIENTID3,"104"+GUEST2$) : EndIf
                  CLIENTID2= 0 : GUEST2$= ""
            EndSelect
         ElseIf NEWEVENTCLI = CLIENTID3
            Select SERVENT
               Case #PB_NetworkEvent_Data
                  FillMemory(*INBUFFER,#BUFLEN)
                  ReceiveNetworkData(CLIENTID3,*INBUFFER,#BUFLEN)
                  BUFFER$= PeekS(*INBUFFER,-1,#PB_UTF8)
                  FLAG$= Mid(BUFFER$,1,3) : MESSAGE$= Mid(BUFFER$,4,Len(BUFFER$)-3)
                  If FLAG$="101" And GUEST3$=""
                     GUEST3$= MESSAGE$ : REFRESH= 1
                     FLASH= ElapsedMilliseconds()+ 3000 : FLASH$= GUEST3$+" just connected."
                     If CLIENTID1 : G1L$= Mid(Str(Len(GUEST1$)+100),2,2)
                        SNETSTRING(CLIENTID1,"103"+GUEST3$)
                     Else : G1L$= "00" : EndIf
                     If CLIENTID2 : G2L$= Mid(Str(Len(GUEST2$)+100),2,2)
                        SNETSTRING(CLIENTID2,"103"+GUEST3$)
                     Else : G2L$= "00" : EndIf
                     HL$= Mid(Str(Len(NAME$)+100),2,2)
                     BUFFER$= "102"+HL$+G1L$+G2L$+NAME$+GUEST1$+GUEST2$
                     SNETSTRING(CLIENTID3,BUFFER$)
                  ElseIf FLAG$="100"   
                     For IND= 23 To 1 Step -1 : SLINES$(IND)= SLINES$(IND-1) : Next IND
                     SLINES$(0)= MESSAGE$ : REFRESH= 1
                     If NUMLINES < 24
                        NUMLINES +1 : If NUMLINES=1 : SLINES$(21)= BLANK$+FILESAV$ : EndIf
                     EndIf
                     If CLIENTID1 : SNETSTRING(CLIENTID1,BUFFER$) : EndIf
                     If CLIENTID2 : SNETSTRING(CLIENTID2,BUFFER$) : EndIf
                  EndIf
               Case #PB_NetworkEvent_Disconnect
                  FLASH= ElapsedMilliseconds()+ 3000 : FLASH$= GUEST3$+" just left." : REFRESH= 1
                  If CLIENTID1 : SNETSTRING(CLIENTID1,"104"+GUEST3$) : EndIf
                  If CLIENTID2 : SNETSTRING(CLIENTID2,"104"+GUEST3$) : EndIf
                  CLIENTID3= 0 : GUEST3$= ""
            EndSelect
         Else
            Select SERVENT
               Case #PB_NetworkEvent_Connect
                  If Not CLIENTID1 : CLIENTID1= NEWEVENTCLI
                  ElseIf Not CLIENTID2 : CLIENTID2= NEWEVENTCLI
                  ElseIf Not CLIENTID3 : CLIENTID3= NEWEVENTCLI
                  Else
                     SNETSTRING(NEWEVENTCLI,"105ROOM FULL")
                     Delay(200) : CloseNetworkConnection(NEWEVENTCLI)
                  EndIf
               Case #PB_NetworkEvent_Data
                  ReceiveNetworkData(NEWEVENTCLI,*INBUFFER,#BUFLEN)
            EndSelect
         EndIf
      EndIf
   ElseIf HOSTID And Not BYEBYE
      CLIVENT= NetworkClientEvent(HOSTID)
      Select CLIVENT
         Case #PB_NetworkEvent_Data
            FillMemory(*INBUFFER,#BUFLEN)
            ReceiveNetworkData(HOSTID,*INBUFFER,#BUFLEN)
            BUFFER$= PeekS(*INBUFFER,-1,#PB_UTF8)
            FLAG$= Mid(BUFFER$,1,3) : MESSAGE$= Mid(BUFFER$,4,Len(BUFFER$)-3)
            If FLAG$= "102"
               HNL= Val(Mid(MESSAGE$,1,2)) : HOST$= Mid(MESSAGE$,7,HNL) : CHAT= 200 : REFRESH= 1
               OG1NL= Val(Mid(MESSAGE$,3,2)) : If OG1NL : OTHERG1$= Mid(MESSAGE$,7+HNL,OG1NL) : EndIf
               OG2NL= Val(Mid(MESSAGE$,5,2)) : If OG2NL : OTHERG2$= Mid(MESSAGE$,7+HNL+OG1NL,OG2NL) : EndIf
               FLASH= ElapsedMilliseconds()+ 3000 : FLASH$= HOST$+" welcomes you."
            ElseIf FLAG$= "103"
               FLASH= ElapsedMilliseconds()+ 3000 : FLASH$= MESSAGE$+" just connected." : REFRESH= 1
               If OTHERG1$="" : OTHERG1$= MESSAGE$
               Else : OTHERG2$= MESSAGE$ : EndIf
            ElseIf FLAG$= "104"
               FLASH= ElapsedMilliseconds()+ 3000 : FLASH$= MESSAGE$+" just left." : REFRESH= 1
               If MESSAGE$=OTHERG1$ : OTHERG1$= ""
               Else : OTHERG2$= "" : EndIf
            ElseIf FLAG$= "105"
               FLASH= ElapsedMilliseconds()+ 3000 : FLASH$= "* FULL CHATROOM *" : REFRESH= 1
               FULL= 1 : CHAT= 0
            ElseIf FLAG$= "100"
               For IND= 23 To 1 Step -1 : SLINES$(IND)= SLINES$(IND-1) : Next IND
               SLINES$(0)= MESSAGE$ : REFRESH= 1
               If NUMLINES < 24
                  NUMLINES +1 : If NUMLINES=1 : SLINES$(21)= BLANK$+FILESAV$ : EndIf
               EndIf
            EndIf
         Case #PB_NetworkEvent_Disconnect
            If HOST$= "" : HOST$= "The host" : EndIf
            If Not FULL : MessageRequester("ESChat",HOST$+" has closed the connection.",0) : EndIf
            CHAT= 0 : REFRESH= 1 : HOSTID= 0 : HOST$= "" : NUMLINES= 0
      EndSelect
   EndIf
   If Not BYEBYE
      If RESEND < ElapsedMilliseconds() And CHAT=23
         RESEND= ElapsedMilliseconds()+ 1000
         BUFFER$= "101"+NAME$ : SNETSTRING(HOSTID,BUFFER$)
      EndIf
      If ElapsedMilliseconds() < RELEASE
         Repeat : Delay(2) : Until ElapsedMilliseconds() > RELEASE
      EndIf
      If FLASH > 0 And FLASH < ElapsedMilliseconds()
         FLASH= 0 : REFRESH= 1
      EndIf
   EndIf
Until BYEBYE
FreeMemory(*INBUFFER) : End
Last edited by heartbone on Thu Feb 12, 2015 4:38 pm, edited 2 times in total.
Keep it BASIC.
Post Reply