Attribute VB_Name = "Winsock"
Option Explicit

'-------------------------------------------'
'  Winsock Module 1.1                       '
'                                           '
'  This module handles networking.          '
'-------------------------------------------'

'-----------------------------------------------------------------------------------
'  Windows API Calls
'-----------------------------------------------------------------------------------
Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Public Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
Public Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
Public Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
Public Declare Function GlobalFree Lib "kernel32" (ByVal hMem As Long) As Long

'-----------------------------------------------------------------------------------
'  Winsock API Calls
'-----------------------------------------------------------------------------------
Public Declare Function htons Lib "wsock32.dll" (ByVal hostshort As Integer) As Integer
Public Declare Function ntohs Lib "wsock32.dll" (ByVal networkshort As Integer) As Integer
Public Declare Function WSAStartup Lib "wsock32.dll" (ByVal wVR As Long, lpWSAD As WSADataType) As Long
Public Declare Function WSACleanup Lib "wsock32.dll" () As Long
Public Declare Function Socket Lib "wsock32.dll" Alias "socket" (ByVal af As Long, ByVal s_type As Long, ByVal protocol As Long) As Long
Public Declare Function WSAAsyncSelect Lib "wsock32.dll" (ByVal S As Long, ByVal hWnd As Long, ByVal wMsg As Long, ByVal lEvent As Long) As Long
Public Declare Function inet_addr Lib "wsock32.dll" (ByVal cp As String) As Long
Public Declare Function inet_ntoa Lib "wsock32.dll" (ByVal IA As Long) As Long
Public Declare Function closesocket Lib "wsock32.dll" (ByVal S As Long) As Long
Public Declare Function Connect Lib "wsock32.dll" Alias "connect" (ByVal S As Long, addr As sockaddr, ByVal namelen As Long) As Long
Public Declare Function recv Lib "wsock32.dll" (ByVal S As Long, ByVal Buf As Any, ByVal BufLen As Long, ByVal Flags As Long) As Long
Public Declare Function Send Lib "wsock32.dll" Alias "send" (ByVal S As Long, Buf As Any, ByVal BufLen As Long, ByVal Flags As Long) As Long
Public Declare Function ioctlsocket Lib "wsock32.dll" (ByVal S As Long, ByVal cmd As Long, argp As Long) As Long
Public Declare Function WSAGetLastError Lib "wsock32" () As Long
Public Declare Function gethostbyname Lib "wsock32.dll" (ByVal host_name As String) As Long
Public Declare Function getnameinfo Lib "wsock32.dll" (SA As sockaddr, ByVal salen As Long, _
    ByVal Host As String, ByVal hostlen As Long, ByVal serv As String, ByVal servlen As Long, _
    ByVal Flags As Long) As Long
Public Declare Function accept Lib "wsock32.dll" (ByVal S As Integer, addr As sockaddr, addrlen As Integer) As Integer
Public Declare Function bind Lib "wsock32.dll" (ByVal S As Integer, addr As sockaddr, ByVal namelen As Integer) As Integer
Public Declare Function Listen Lib "wsock32.dll" Alias "listen" (ByVal S As Integer, ByVal backlog As Integer) As Integer
Public Declare Function lstrcpy Lib _
    "kernel32" Alias "lstrcpyA" (ByVal lpString1 As String, _
                                 ByVal lpString2 As Long) As Long
Public Declare Function setsockopt Lib "wsock32.dll" (ByVal S As Long, ByVal level As Long, ByVal optname As Long, optval As Long, ByVal optlen As Long) As Long
                                 
'-----------------------------------------------------------------------------------
'  Constants
'-----------------------------------------------------------------------------------
Public Const GMEM_MOVEABLE = &H2
Public Const GMEM_ZEROINIT = &H40
Public Const GHND = (GMEM_MOVEABLE Or GMEM_ZEROINIT)
Public Const GWL_WNDPROC = (-4)

Public Const WM_CLOSE = &H10
Public Const WM_USER = &H400
Public Const WM_SOCKEVENT = WM_USER + 200

Public Const FD_READ = &H1&
Public Const FD_CONNECT = &H10&
Public Const FD_CLOSE = &H20&
Public Const FIONREAD = &H4004667F
Public Const WSA_DESCRIPTIONLEN = 256
Public Const WSA_DescriptionSize = WSA_DESCRIPTIONLEN + 1
Public Const WSA_SYS_STATUS_LEN = 128
Public Const WSA_SysStatusSize = WSA_SYS_STATUS_LEN + 1
Public Const AF_INET = 2
Public Const SOCK_STREAM = 1
Public Const SOCKET_ERROR = -1
Public Const IPPROTO_TCP = 6
Public Const INADDR_NONE = &HFFFFFFFF
Public Const INADDR_ANY = 1&

Public Const TCP_NODELAY = &H1&

' All Windows Sockets error constants are biased by WSABASEERR from the "normal"

Public Const WSABASEERR = 10000

' Windows Sockets definitions of regular Microsoft C error constants

Public Const WSAEINTR = (WSABASEERR + 4)
Public Const WSAEBADF = (WSABASEERR + 9)
Public Const WSAEACCES = (WSABASEERR + 13)
Public Const WSAEFAULT = (WSABASEERR + 14)
Public Const WSAEINVAL = (WSABASEERR + 22)
Public Const WSAEMFILE = (WSABASEERR + 24)

' Windows Sockets definitions of regular Berkeley error constants

Public Const WSAEWOULDBLOCK = (WSABASEERR + 35)
Public Const WSAEINPROGRESS = (WSABASEERR + 36)
Public Const WSAEALREADY = (WSABASEERR + 37)
Public Const WSAENOTSOCK = (WSABASEERR + 38)
Public Const WSAEDESTADDRREQ = (WSABASEERR + 39)
Public Const WSAEMSGSIZE = (WSABASEERR + 40)
Public Const WSAEPROTOTYPE = (WSABASEERR + 41)
Public Const WSAENOPROTOOPT = (WSABASEERR + 42)
Public Const WSAEPROTONOSUPPORT = (WSABASEERR + 43)
Public Const WSAESOCKTNOSUPPORT = (WSABASEERR + 44)
Public Const WSAEOPNOTSUPP = (WSABASEERR + 45)
Public Const WSAEPFNOSUPPORT = (WSABASEERR + 46)
Public Const WSAEAFNOSUPPORT = (WSABASEERR + 47)
Public Const WSAEADDRINUSE = (WSABASEERR + 48)
Public Const WSAEADDRNOTAVAIL = (WSABASEERR + 49)
Public Const WSAENETDOWN = (WSABASEERR + 50)
Public Const WSAENETUNREACH = (WSABASEERR + 51)
Public Const WSAENETRESET = (WSABASEERR + 52)
Public Const WSAECONNABORTED = (WSABASEERR + 53)
Public Const WSAECONNRESET = (WSABASEERR + 54)
Public Const WSAENOBUFS = (WSABASEERR + 55)
Public Const WSAEISCONN = (WSABASEERR + 56)
Public Const WSAENOTCONN = (WSABASEERR + 57)
Public Const WSAESHUTDOWN = (WSABASEERR + 58)
Public Const WSAETOOMANYREFS = (WSABASEERR + 59)
Public Const WSAETIMEDOUT = (WSABASEERR + 60)
Public Const WSAECONNREFUSED = (WSABASEERR + 61)
Public Const WSAELOOP = (WSABASEERR + 62)
Public Const WSAENAMETOOLONG = (WSABASEERR + 63)
Public Const WSAEHOSTDOWN = (WSABASEERR + 64)
Public Const WSAEHOSTUNREACH = (WSABASEERR + 65)
Public Const WSAENOTEMPTY = (WSABASEERR + 66)
Public Const WSAEPROCLIM = (WSABASEERR + 67)
Public Const WSAEUSERS = (WSABASEERR + 68)
Public Const WSAEDQUOT = (WSABASEERR + 69)
Public Const WSAESTALE = (WSABASEERR + 70)
Public Const WSAEREMOTE = (WSABASEERR + 71)

Public Const WSAEDISCON = (WSABASEERR + 101)

' Extended Windows Sockets error constant definitions

Public Const WSASYSNOTREADY = (WSABASEERR + 91)
Public Const WSAVERNOTSUPPORTED = (WSABASEERR + 92)
Public Const WSANOTINITIALISED = (WSABASEERR + 93)

' Error return codes from gethostbyname() and gethostbyaddr()
'  (when using the resolver). Note that these errors are
'  retrieved via WSAGetLastError() and must therefore follow
'  the rules for avoiding clashes with error numbers from
'  specific implementations or language run-time systems.
'  For this reason the codes are based at WSABASEERR+1001.
'  Note also that [WSA]NO_ADDRESS is defined only for
'  compatibility purposes.

' Authoritative Answer: Host not found

Public Const WSAHOST_NOT_FOUND = (WSABASEERR + 1001)
Public Const HOST_NOT_FOUND = WSAHOST_NOT_FOUND

' Non-Authoritative: Host not found, or SERVERFAIL

Public Const WSATRY_AGAIN = (WSABASEERR + 1002)
Public Const TRY_AGAIN = WSATRY_AGAIN

' Non recoverable errors, FORMERR, REFUSED, NOTIMP

Public Const WSANO_RECOVERY = (WSABASEERR + 1003)
Public Const NO_RECOVERY = WSANO_RECOVERY

' Valid name, no data record of requested type

Public Const WSANO_DATA = (WSABASEERR + 1004)
Public Const NO_DATA = WSANO_DATA

' no address, look for MX record

Public Const WSANO_ADDRESS = WSANO_DATA
Public Const NO_ADDRESS = WSANO_ADDRESS

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

Public Type WSADataType
    wVersion As Integer
    wHighVersion As Integer
    szDescription As String * WSA_DescriptionSize
    szSystemStatus As String * WSA_SysStatusSize
    iMaxSockets As Integer
    iMaxUdpDg As Integer
    lpVendorInfo As Long
End Type

Public Type HostEnt
    h_name As Long
    h_aliases As Long
    h_addrtype As Integer
    h_length As Integer
    h_addr_list As Long
End Type

Public Type whData
    Active As Boolean
    BotKey As String
    WindowHandle As Long
    SockType As mSocketType
End Type

Public Enum mSocketType
    sBattleNet
    sBNLS
    sMCP
    sBotNet
    sInvalid
End Enum

Public Enum mSocketEvent
    sConnect
    sDisconnect
    sData
    sError
End Enum

Private Type in_addr
    S_addr As Long
End Type

'-----------------------------------------------------------------------------------
'  Variables
'-----------------------------------------------------------------------------------

Public gOldWndProc As Long
Public File As String
Public WindowMap() As whData, NextWindowMap&

'-----------------------------------------------------------------------------------
'  Message Handler
'-----------------------------------------------------------------------------------

Private Function GetBotFromWindow(hWnd As Long, BotKey As String, SockType As mSocketType) As Boolean
    Dim i&
    SockType = sInvalid
    GetBotFromWindow = False
    For i = LBound(WindowMap) To UBound(WindowMap)
        If WindowMap(i).Active And WindowMap(i).WindowHandle = hWnd Then
            With WindowMap(i)
                BotKey = .BotKey
                SockType = .SockType
            End With
            GetBotFromWindow = True
            Exit Function
        End If
    Next i
End Function

Public Function WindowProc(ByVal hWnd As Long, ByVal wMsg As Long, _
    ByVal wParam As Long, ByVal lParam As Long) As Long
'On Error Resume Next
    Dim evType&, dBot$, Count&, Buf$, tBuf$, SocketType As mSocketType, Sock&, rVal&, ec&
    Select Case wMsg
        Case WM_SOCKEVENT
            evType = lParam And &HFFFF&
            ec = LShift(lParam, 16)
            If Not GetBotFromWindow(hWnd, dBot, SocketType) Then Exit Function
            Select Case evType
                Case FD_CONNECT
                    If ec > 0 Then
                        Bot.SocketEvent sError, SocketType, GetWSAErrorString(ec), ec
                    Else
                        Bot.SocketEvent sConnect, SocketType
                    End If
                Case FD_CLOSE
                    Bot.SocketEvent sDisconnect, SocketType
                Case FD_READ
                    Sock = Bot.GetSocket(SocketType)
                    If Sock = 0 Then Exit Function
                    Call ioctlsocket(Sock, FIONREAD, Count)
                    tBuf = String$(Count&, vbNullChar)
                    rVal = recv(Sock, tBuf, Count, 0)
                    'AddC rVal & " " & Count, vbWhite
                    If rVal = SOCKET_ERROR Then
                        ec = Err.LastDllError
                        Bot.SocketEvent sError, SocketType, GetWSAErrorString(ec), ec
                        Exit Function
                    End If
                    If rVal = 0 Then Exit Function
                    While rVal < Count And rVal <> 0
                        Buf = Buf & tBuf
                        Call ioctlsocket(Sock, FIONREAD, Count)
                        tBuf = String$(Count&, vbNullChar)
                        rVal = recv(Sock, tBuf, Count, 0)
                        'AddC "More: " & rVal & " " & Count, vbWhite
                    Wend
                    Buf = Buf & tBuf
                    Bot.SocketEvent sData, SocketType, Buf, Count
            End Select
        Case WM_CLOSE
            AddC "Socket closed.", vbRed
    End Select
                    
End Function

Public Function OldWindowProc(ByVal hWnd As Long, ByVal wMsg As Long, _
    ByVal wParam As Long, ByVal lParam As Long) As Long
On Error Resume Next
    'AddC "Recieved event. (" & hWnd & ")"
    Dim BotID&, BNLS As Boolean, Sock&, Count&, hMem&, Buf$, Buffer&, ba() As Byte, i&
    BotID = -1
    
    Select Case wMsg
        Case WM_CLOSE:
            'Call WSACleanup 'Free memory.
        Case WM_SOCKEVENT:
            'MsgBox "Event"
            If (lParam And &HFFFF&) = FD_CONNECT Then
               ' MsgBox "Connect"
            ElseIf (lParam And &HFFFF&) = FD_READ Then
                'MsgBox "Data"
                Call ioctlsocket(Sock, FIONREAD, Count)
                'ReDim ba(Count) As Byte
                'hMem& = GlobalAlloc(GHND, ByVal Count&) 'allocate memory to hold the data
                'buffer& = GlobalLock(hMem&)         'lock the data
                'Call recv(Sock&, buffer&, Count&, 0)    'receive the data into our buffer
                'buf = String$(Count&, " ")    'create our string
                'Call CopyMemory(ByVal Html$, ByVal buffer&, Count&) 'copy the data from memory
                'Call GlobalUnlock(buffer&)  'unloack the mem
                Buf = String$(Count&, Chr$(0))
                Call recv(Sock, Buf, Count, 0)
                'MsgBox Count & " |" & StrToHex(buf)
                If BNLS Then
                    'Bot(BotID).BNLSData buf, Count
                Else
                    'AddC StrToHex(buf)
                    'Bot(BotID).BNetData buf, Count
                End If
            ElseIf (lParam And &HFFFF&) = FD_CLOSE Then
                If BNLS Then
                    'Bot(BotID).BNLSDisconnected
                Else
                    'Bot(BotID).BNetDisconnected
                End If
            End If
    End Select
End Function

'-----------------------------------------------------------------------------------
'  Socket Connector
'-----------------------------------------------------------------------------------

'Public Function ConnectSocket(ID As Long, Sock As Long, Location As String, Port As Long) As Long
'On Error Resume Next
'    Dim socketBuffer As sockaddr, Host As HostEnt, RealError As Long, Sock As Long
'    Sock = Socket(AF_INET, SOCK_STREAM, 0)
'    ConnectSocket = Sock
'    If Sock = -1 Then
'        BotEvent BotID, E_CONERROR, "Error allocating socket."
'    Else
'        Load frmMain.txtCon(BotID)
'        Call SetWindowLong(frmMain.txtCon(BotID).hWnd, GWL_WNDPROC, AddressOf WindowProc)
'
'        If (WSAAsyncSelect(Sock&, frmMain.txtCon(BotID).hWnd, ByVal WM_SOCKEVENT, ByVal FD_READ + FD_CLOSE + FD_CONNECT) = -1) Then
'            BotEvent BotID, E_CONERROR, "Could not set message information for socket."
'        Else
'            socketBuffer.sin_family = AF_INET
'            socketBuffer.sin_port = htons(Port)
'            socketBuffer.sin_addr = GetHostByNameAlias(Location$)
'            If (Connect(Sock, socketBuffer, Len(socketBuffer)) = -1) Then
'                RealError = WSAGetLastError()
'                If (RealError <> WSAEWOULDBLOCK) Then
'                    If RealError = 0 Then Exit Function
'                    MsgBox "Socket error " & RealError & ": " & GetWSAErrorString(RealError), vbExclamation
'                End If
'            End If
'        End If
'    End If
'End Function

Public Function GetHostByNameAlias(ByVal HostName As String) As Long
On Error Resume Next
Dim phe As Long, addrList As Long, retIP As Long
Dim heDestHost As HostEnt
    retIP = inet_addr(HostName$)    'converts a 127.0.0.1 address into a good format
        If retIP = INADDR_NONE Then 'not a dotted address
            phe = gethostbyname(HostName$)  'so we have to get it from a hostname
                If phe <> 0 Then    'not zero so it worked
                    Call CopyMemory(heDestHost, ByVal phe, 16) 'we have to move through the structure in memory
                    Call CopyMemory(addrList, ByVal heDestHost.h_addr_list, 4)
                    Call CopyMemory(retIP, ByVal addrList, heDestHost.h_length)
                Else
                    retIP = INADDR_NONE 'none of the above so we quit
                End If
        End If
    GetHostByNameAlias = retIP  'return
End Function

Public Function DNSLookup(ByVal HostName As String) As String
On Error Resume Next
Dim phe As Long, addrList As Long, retIP As Long, sai As sockaddr, OB As String
Dim heDestHost As HostEnt, rStrPtr As Long
    retIP = inet_addr(HostName$)    'converts a 127.0.0.1 address into a good format
        If retIP = INADDR_NONE Then 'not a dotted address
            phe = gethostbyname(HostName$)  'so we have to get it from a hostname
                If phe <> 0 Then    'not zero so it worked
                    Call CopyMemory(heDestHost, ByVal phe, 16) 'we have to move through the structure in memory
                    Call CopyMemory(addrList, ByVal heDestHost.h_addr_list, 4)
                    Call CopyMemory(retIP, ByVal addrList, heDestHost.h_length)
                Else
                    retIP = INADDR_NONE 'none of the above so we quit
                End If
                rStrPtr = inet_ntoa(retIP)
                OB = String$(255, vbNullChar)
                lstrcpy OB, rStrPtr
                NullTruncateString OB
                DNSLookup = OB
        Else
            With sai
                .sin_addr = retIP
                .sin_family = AF_INET
                .sin_port = 23
            End With
            OB = String$(255, vbNullChar)
            getnameinfo sai, Len(sai), OB, 255, vbNullString, 0, 0
            NullTruncateString OB
            If LenB(OB) = 0 Then
                DNSLookup = HostName
            Else
                DNSLookup = OB
            End If
        End If
End Function

Public Function GetWSAErrorString(ByVal errnum&) As String
On Error Resume Next
    Select Case errnum
        Case 10004: GetWSAErrorString = "Interrupted system call."
        Case 10009: GetWSAErrorString = "Bad file number."
        Case 10013: GetWSAErrorString = "Permission Denied."
        Case 10014: GetWSAErrorString = "Bad Address."
        Case 10022: GetWSAErrorString = "Invalid Argument."
        Case 10024: GetWSAErrorString = "Too many open files."
        Case 10035: GetWSAErrorString = "Operation would block."
        Case 10036: GetWSAErrorString = "Operation now in progress."
        Case 10037: GetWSAErrorString = "Operation already in progress."
        Case 10038: GetWSAErrorString = "Socket operation on nonsocket."
        Case 10039: GetWSAErrorString = "Destination address required."
        Case 10040: GetWSAErrorString = "Message too long."
        Case 10041: GetWSAErrorString = "Protocol wrong type for socket."
        Case 10042: GetWSAErrorString = "Protocol not available."
        Case 10043: GetWSAErrorString = "Protocol not supported."
        Case 10044: GetWSAErrorString = "Socket type not supported."
        Case 10045: GetWSAErrorString = "Operation not supported on socket."
        Case 10046: GetWSAErrorString = "Protocol family not supported."
        Case 10047: GetWSAErrorString = "Address family not supported by protocol family."
        Case 10048: GetWSAErrorString = "Address already in use."
        Case 10049: GetWSAErrorString = "Can't assign requested address."
        Case 10050: GetWSAErrorString = "Network is down."
        Case 10051: GetWSAErrorString = "Network is unreachable."
        Case 10052: GetWSAErrorString = "Network dropped connection."
        Case 10053: GetWSAErrorString = "Software caused connection abort."
        Case 10054: GetWSAErrorString = "Connection reset by peer."
        Case 10055: GetWSAErrorString = "No buffer space available."
        Case 10056: GetWSAErrorString = "Socket is already connected."
        Case 10057: GetWSAErrorString = "Socket is not connected."
        Case 10058: GetWSAErrorString = "Can't send after socket shutdown."
        Case 10059: GetWSAErrorString = "Too many references: can't splice."
        Case 10060: GetWSAErrorString = "Connection timed out."
        Case 10061: GetWSAErrorString = "Connection refused."
        Case 10062: GetWSAErrorString = "Too many levels of symbolic links."
        Case 10063: GetWSAErrorString = "File name too long."
        Case 10064: GetWSAErrorString = "Host is down."
        Case 10065: GetWSAErrorString = "No route to host."
        Case 10066: GetWSAErrorString = "Directory not empty."
        Case 10067: GetWSAErrorString = "Too many processes."
        Case 10068: GetWSAErrorString = "Too many users."
        Case 10069: GetWSAErrorString = "Disk quota exceeded."
        Case 10070: GetWSAErrorString = "Stale NFS file handle."
        Case 10071: GetWSAErrorString = "Too many levels of remote in path."
        Case 10091: GetWSAErrorString = "Network subsystem is unusable."
        Case 10092: GetWSAErrorString = "Winsock DLL cannot support this application."
        Case 10093: GetWSAErrorString = "Winsock not initialized."
        Case 10101: GetWSAErrorString = "Disconnect."
        Case 11001: GetWSAErrorString = "Host not found."
        Case 11002: GetWSAErrorString = "Nonauthoritative host not found."
        Case 11003: GetWSAErrorString = "Nonrecoverable error."
        Case 11004: GetWSAErrorString = "Valid name, no data record of requested type."
        Case Else: GetWSAErrorString = CStr(errnum)
    End Select
End Function

Public Function SendData(ByVal S&, vMessage As Variant) As Long
    Dim TheMsg() As Byte, sTemp$
    TheMsg = ""
    Select Case VarType(vMessage)
        Case 8209   'byte array
            sTemp = vMessage
            TheMsg = sTemp
        Case 8      'string, if we recieve a string, its assumed we are linemode
            #If Win32 Then
                sTemp = StrConv(vMessage, vbFromUnicode)
            #Else
                sTemp = vMessage
            #End If
        Case Else
            sTemp = CStr(vMessage)
            #If Win32 Then
                sTemp = StrConv(vMessage, vbFromUnicode)
            #Else
                sTemp = vMessage
            #End If
    End Select
    TheMsg = sTemp
    If UBound(TheMsg) > -1 Then
        SendData = Send(S, TheMsg(0), UBound(TheMsg) + 1, 0)
    End If
End Function

Public Function IPToString(IP As Long) As String
On Error Resume Next
    Dim bWk(3) As Byte
    CopyMemory bWk(0), IP, 4
    IPToString = bWk(0) & "." & bWk(1) & "." & bWk(2) & "." & bWk(3)
End Function

'Checks if the given address is a dotted-quad
'IP by seeing if the string only contains
'periods (.) and numbers.
Public Function IsIPAddress(Address As String) As Boolean
    Dim i&, a%
    IsIPAddress = False
    For i = 1 To Len(Address)
        a = Asc(Mid$(Address, 1, 1))
        If (a <> 46) And ((a > 57) Or (a < 48)) Then _
            Exit Function
    Next i
    IsIPAddress = True
End Function
