home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Source Code / Visual Basic Source Code.iso / vbsource / vbrowser / vbrowser.bas < prev    next >
Encoding:
BASIC Source File  |  1995-10-24  |  28.1 KB  |  823 lines

  1. Declare Function getmodulehandle% Lib "Kernel" (ByVal lpModuleName$)
  2. Declare Function lstrcpy& Lib "Kernel" (ByVal dststring As Any, ByVal srcstring As Any)
  3. Declare Sub hmemcpy Lib "Kernel" (dst As Any, src As Any, ByVal bytecount As Long)
  4.  
  5.  
  6.  
  7. Global debugging
  8. Global cr$, lf$, crlf$, crlfcrlf$, lflf$
  9. Global quit_flag
  10. Global main_hwnd%           'Handle of main window to where
  11.                             'WSAAsync NAME messages are sent. Msgblast
  12.                             'will intercept them.
  13. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  14. Global name_msg%            'Message number of any get name request
  15. Global got_name_response    'Flag that indicates WSAsync Name call
  16.                             'got a message(response).
  17. Global event_error%         'Hiword is returned error code, if any.
  18. Global event_type%          'Loword is event type.
  19. Global event_wparam%        'Returned handle of caller
  20. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  21. Global event_msg%           'Message number for a ASYNC event.
  22. Global server_addr&
  23. Global server_domain$
  24. Global server_dotaddr$
  25. Global document$            'Document to get from server
  26. Global current_msg$         'Current received message
  27. Global current_header$      'Current header after split routine
  28. Global callsocket%          'Current socket(handle) assigned
  29.                             'to the server
  30.  
  31. Global closed
  32. Global urls$(), numurls, urlnum
  33.  
  34. '''''''''''''''''''''''''''''''''''''''''''''''''''''
  35. 'Winsock declarations needed for VBrowser
  36.  
  37. Type sockaddr_in_type
  38.   sin_family As Integer
  39.   sin_port As Integer
  40.   sin_addr As Long
  41.   sin_zero As String * 8
  42. End Type
  43. Global call_sockaddr_in As sockaddr_in_type
  44.  
  45. Type WSAdata_type
  46.    wVersion As Integer
  47.    wHighVersion As Integer
  48.    szDescription As String * 257
  49.    szSystemStatus As String * 129
  50.    iMaxSockets As Integer
  51.    iMaxUdpDg As Integer
  52.    lpVendorInfo As String * 200
  53. End Type
  54. Global WSAdata As WSAdata_type
  55.  
  56. Type namehostent_type               'Where Winsock, after
  57.     h_name As Long                  'WSAAsyncGetHostByAddr/Name
  58.     h_aliases As Long               'places the hostent data.
  59.     h_addrtype As Integer           'Winsock also palces the data
  60.     h_length As Integer             'pointed to by these pointers
  61.     h_addr_list As Long             'at the end of the hostent data.
  62.     buff As String * 100            'The data 'pointed' to by the
  63.                                     'above pointers.
  64. End Type
  65. Global namehostent As namehostent_type
  66.  
  67. Type sockopt_bool_type               'Used for setting socket options
  68.   val As Integer
  69. End Type
  70. Global sockopt_bool As sockopt_bool_type
  71.  
  72. 'Winsock calls in VB format
  73. Declare Function bind Lib "winsock.dll" (ByVal s As Integer, addr As sockaddr_in_type, ByVal namelen As Integer) As Integer
  74. Declare Function inet_addr Lib "winsock.dll" (ByVal s As String) As Long
  75. Declare Function gethostbyname Lib "winsock.dll" (ByVal hostname As String) As Long
  76. Declare Function gethostbyaddr Lib "winsock.dll" (hostaddress As Long, ByVal lenaddress As Integer, ByVal pftype As Integer) As Long
  77. Declare Function inet_ntoa Lib "winsock.dll" (ByVal iaddr As Long) As Long
  78. Declare Function socket Lib "winsock.dll" (ByVal af As Integer, ByVal typesock As Integer, ByVal protocol As Integer) As Integer
  79. Declare Function connect Lib "winsock.dll" (ByVal sock As Integer, sockstruct As sockaddr_in_type, ByVal structlen As Integer) As Integer
  80. Declare Function send Lib "winsock.dll" (ByVal sock As Integer, ByVal msg As String, ByVal msglen As Integer, ByVal flag As Integer) As Integer
  81. Declare Function recv Lib "winsock.dll" (ByVal sock As Integer, ByVal msg As String, ByVal msglen As Integer, ByVal flag As Integer) As Integer
  82. Declare Function closesocket Lib "winsock.dll" (ByVal sock As Integer) As Integer
  83. Declare Function setsockopt Lib "winsock.dll" (ByVal sock As Integer, ByVal level As Integer, ByVal optname As Integer, optval As sockopt_bool_type, ByVal optlen As Integer) As Integer
  84. Declare Function htons Lib "winsock.dll" (ByVal a As Integer) As Integer
  85.  
  86. 'These are the Win specific calls which use messages
  87. Declare Function WSAStartup Lib "winsock.dll" (ByVal a As Integer, b As WSAdata_type) As Integer
  88. Declare Function WSACleanup Lib "winsock.dll" () As Integer
  89. Declare Function WSAAsyncSelect Lib "winsock.dll" (ByVal sock As Integer, ByVal hWnd As Integer, ByVal msg As Integer, ByVal event As Long) As Integer
  90. Declare Function WSAGetLastError Lib "winsock.dll" () As Integer
  91. Declare Function WSAAsyncGetHostByAddr Lib "winsock.dll" (ByVal hWnd As Integer, ByVal msg As Integer, hostaddr As Long, ByVal lenhostaddr As Integer, ByVal pftype As Integer, namehostent As namehostent_type, ByVal lenstruc As Integer) As Integer
  92. Declare Function WSAAsyncGetHostByName Lib "winsock.dll" (ByVal hWnd As Integer, ByVal msg As Integer, ByVal hostname As String, namehostent As namehostent_type, ByVal lenanmehostent As Integer) As Integer
  93.  
  94. 'Some constants declarations
  95. Global Const SOCKET_ERROR = -1
  96. Global Const INVALID_SOCKET = -1
  97.  
  98. Global Const SOCK_STREAM = 1
  99. Global Const AF_INET = 2
  100. Global Const PF_INET = 2
  101.  
  102. Global Const IPPROTO_TCP = 6
  103. Global Const SOL_SOCKET = &HFFFF
  104. Global Const SO_DEBUG = &H1
  105. Global Const SO_ACCEPTCONN = &H2
  106. Global Const SO_REUSEADDR = &H4
  107. Global Const SO_KEEPALIVE = &H8
  108. Global Const SO_DONTROUTE = &H10
  109. Global Const SO_BROADCAST = &H20
  110. Global Const SO_USELOOPBACK = &H40
  111. Global Const SO_LINGER = &H80
  112. Global Const SO_OOBINLINE = &H100
  113. Global Const SO_DONTLINGER = &HFF7F
  114.  
  115. Global Const AF_UNSPEC = 0
  116.  
  117. Global Const FD_READ = 1
  118. Global Const FD_WRITE = 2
  119. Global Const FD_OOB = 4
  120. Global Const FD_ACCEPT = 8
  121. Global Const FD_CONNECT = &H10
  122. Global Const FD_CLOSE = &H20
  123.  
  124. Function ask_server (req_msg$)
  125. DoEvents
  126. mlen = Len(req_msg$)
  127. 'Clear the inbound message buffer
  128. current_msg$ = ""
  129. dprint "Send request"
  130. send_next_segment:
  131. status% = send(callsocket%, req_msg$, mlen, 0)
  132. If status% = SOCKET_ERROR Then
  133.     status% = WSAGetLastError()
  134.     dprint "Send ERROR " & sockerror$(status%)
  135.     GoTo exit_ask_server
  136. ElseIf status% = mlen Then
  137.     dprint "Send was OK...waiting for response."
  138. Else
  139.     dprint "Partial send of " & mlen & " bytes"
  140.     req_msg$ = Mid$(req_msg$, status% + 1)
  141.     mlen = Len(req_msg$)
  142.     GoTo send_next_segment
  143. End If
  144. 'Now wait for the response from the server.
  145. 'Keep trying to receive until the server disconnects.
  146. 'At that time the receive will fail
  147. Do
  148.     DoEvents
  149.     'We should also place a timeout routine...just in
  150.     'case. I'll let you write that.
  151.     If quit_flag Then
  152.         Exit Do
  153.     End If
  154.     If closed Then
  155.         'Msgblast routine dprints the close message and
  156.         'sets the global flag 'closed'
  157.         dprint "Closed received"
  158.         Exit Do
  159.     End If
  160. Loop
  161. status% = close_sock(callsocket%)
  162. callsocket% = 0
  163. 'Current_msg$ is global and is where the receive event
  164. 'code in Msgblast placed the received data.
  165. ok = True
  166. exit_ask_server:
  167. ask_server = ok
  168. End Function
  169.  
  170. Sub call_server (n$)
  171. browserfrm.Text1.Text = ""
  172. If get_server_address(n$) Then
  173.     If get_callsock() Then
  174.         If connect_server() Then
  175.             'ask for document
  176.             If Len(document$) = 0 Then
  177.                 'The operator did't ask for a specific
  178.                 'document, so use the HTTP standard request
  179.                 'for the server root directory. It will return
  180.                 'its 'index.htm'.
  181.                 document$ = "/"
  182.             End If
  183.             browserfrm.url.Caption = "http://" + server_domain$ + document$
  184.             msg$ = "GET " + document$ + " HTTP/1.0" + crlf$
  185.             msg$ = msg$ + "Accept: */*" + crlf$
  186.             msg$ = msg$ + "Accept: text/html" + crlf$
  187.             msg$ = msg$ + crlf$
  188.             browserfrm.Text1.Text = "Our request:" + crlfcrlf$ + msg$
  189.             If ask_server(msg$) Then
  190.                 'Places received message in current_msg$
  191.                 parse_current_msg
  192.             End If
  193.         End If
  194.     End If
  195. Else
  196.     'Invalid name or can't get DNS resolution of
  197.     'User entered server dot address or domain name.
  198.     'Called function gave a error so do nothing.
  199. End If
  200. End Sub
  201.  
  202. Function close_sock (socket%)
  203. status% = closesocket(socket%)
  204. If status% = SOCKET_ERROR Then
  205.     status% = WSAGetLastError()
  206.     dprint "Close socket ERROR " & sockerror$(status%) & " on socket " & socket%
  207.     GoTo exit_close_callsock
  208. Else
  209.     dprint "Closed socket " & socket% & " OK"
  210. End If
  211. ok = True
  212. exit_close_callsock:
  213. close_callsock = ok
  214. End Function
  215.  
  216. Function connect_server ()
  217. 'Set up structure (type) we will pass in connect call.
  218. 'Notice that we have to pass the Internet address of the
  219. 'server we want to connect to in sin_addr. Also the port
  220. 'for Web servers is 80 but we have to call Winsock to convert
  221. 'it into the correct byte order.
  222. call_sockaddr_in.sin_family = AF_INET
  223. call_sockaddr_in.sin_port = htons(80)     'converts byte order from PC to Network
  224. call_sockaddr_in.sin_addr = server_addr&
  225. call_sockaddr_in.sin_zero = " "
  226.  
  227. 'We sometimes get a refused message so we'll just loop
  228. 'until success or timeout.
  229. connect_server_again:
  230. DoEvents
  231. dprint "Connect socket " & callsocket%
  232. status% = connect(callsocket%, call_sockaddr_in, Len(call_sockaddr_in))
  233. If status% = SOCKET_ERROR Then
  234.     status% = WSAGetLastError()
  235.     dprint "Connect server error " & sockerror$(status%)
  236.     If status% = 10060 Then
  237.         'Winsock timed out.
  238.         'This usually means that the server is not answering
  239.         dprint "Connect server timed out...the server is not answering."
  240.         'Can't go any further
  241.         status% = close_sock(callsocket%)
  242.         Exit Function
  243.     ElseIf status% = ISCONN Then    'We connected last try
  244.         'OK. We did connect last shot but the status didn't
  245.         'update or something. This does happen sometimes...I don't know
  246.         'why? Maybe it's an 'undocumented' Winsock feature.
  247.     Else
  248.         'Some other kind of error. Try 10 times.
  249.         retrys = retrys + 1
  250.         If retrys < 10 Then
  251.             GoTo connect_server_again
  252.         End If
  253.     End If
  254. Else
  255.     dprint "Connected to server OK."
  256. End If
  257.  
  258. 'Setup to get a message when server disconnects
  259. 'This tells Winsock to send a message to Msgblast whenever
  260. 'this socket gets a read(data) or a close.
  261. dprint "Select (arm) READ & CLOSE messages."
  262. net_event& = FD_CLOSE + FD_READ
  263. status% = WSAAsyncSelect(callsocket%, main_hwnd%, event_msg%, net_event&)
  264. If status% = SOCKET_ERROR Then
  265.     status% = WSAGetLastError()
  266.     dprint "WSAAsyncSelect error " & sockerror$(status%)
  267.     GoTo exit_connect_server
  268. Else
  269.     dprint "WSAASyncSelect OK"
  270. End If
  271. ok = True
  272. exit_connect_server:
  273. connect_server = ok
  274. End Function
  275.  
  276. Sub dprint (msg$)
  277. browserfrm.Sockstatus.Caption = msg$
  278. If debugging Then
  279.     Debug.Print msg$ + crlf$
  280. End If
  281. End Sub
  282.  
  283. Function get_callsock ()
  284. closed = False
  285. dprint "Open socket"
  286. 'Get a socket/handle from Winsock
  287. callsocket% = socket(PF_INET, SOCK_STREAM, AF_UNSPEC)
  288. If callsocket% = INVALID_SOCKET Then
  289.     dprint "Socket error " & sockerror$(WSAGetLastError())
  290.     GoTo exit_get_callsock
  291. Else
  292.     dprint "Got socket handle " & callsocket%
  293. End If
  294.  
  295. 'Some Winsocks want you to do this if you are using
  296. 'multiple sockets. If you don't, even though you
  297. 'closed a socket Winsock won't ever use that handle
  298. 'again, which means you'll run out of handles after a while.
  299. dprint "Set Reuse option for socket " & callsocket%
  300. sockopt_bool.val = -1
  301. DoEvents
  302. status% = setsockopt(callsocket%, SOL_SOCKET, SO_REUSEADDR, sockopt_bool, 2)
  303. If status% = SOCKET_ERROR Then
  304.     status% = WSAGetLastError()
  305.     dprint "Setsockopt error " & sockerror$(status%)
  306.     GoTo exit_get_callsock
  307. Else
  308.     dprint "Reuse issued OK"
  309. End If
  310. DoEvents
  311.  
  312. 'Now bind the socket
  313. dprint "Bind socket " & cllsocket%
  314. 'We pass this structure during a bind.
  315. call_sockaddr_in.sin_family = AF_INET
  316. call_sockaddr_in.sin_port = htons(80)
  317. call_sockaddr_in.sin_addr = 0
  318. call_sockaddr_in.sin_zero = " "
  319.  
  320. status% = bind(callsocket%, call_sockaddr_in, Len(call_sockaddr_in))
  321. If status% = SOCKET_ERROR Then
  322.     status% = WSAGetLastError()
  323.     dprint "Bind error " & sockerror$(status%)
  324.     GoTo exit_get_callsock
  325. Else
  326.     dprint "Bind OK"
  327. End If
  328.  
  329. 'If we got here then all is OK
  330. ok = True
  331. exit_get_callsock:
  332. get_callsock = ok
  333.  
  334. End Function
  335.  
  336. Function get_server_address (n$)
  337. 'There are 3 pieces of information needed for server ops:
  338. '1. The server domain name.
  339. '2. The server Internet address in Long format.
  340. '3. The server dot address in String format. This is
  341. 'really the Internet address formatted into human readable
  342. 'form.
  343. 'Given any one of the three we can get the others.
  344. 'server_domain$, server_addr&, and server_dotaddr$ are all Global
  345. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  346. 'Either a dot address or a name was passed as n$
  347. 'A document URL may have been appended to n$.
  348. '(http://wwwdev.com or http://165.247.64.3)
  349. '(http://wwwdev.com/docs/adoc.htm or
  350. 'http://165.247.64.3/docs/adoc.htm)
  351. 'At this time, we only do www servers 'http://'
  352. 'After all, Web servers support file transfers, so let
  353. 'the UNIX weenies mess with FTP.
  354.  
  355. ok = True
  356. pos% = 1
  357. pos% = InStr(n$, "http://")
  358. If pos% Then
  359.     'check for possible dot address
  360.     pos% = InStr(n$, "//") + 2
  361.     For i = 1 To 4
  362.         t$ = parsestring$(pos%, n$, ".")
  363.         If IsNumeric(t$) Then
  364.             'so far so good
  365.             server_dotaddr$ = server_dotaddr$ + t$ + "."
  366.         Else
  367.             ok = False
  368.             Exit For
  369.         End If
  370.     Next
  371.     If Not ok Then
  372.         'wasn't a dot address
  373.         ok = True
  374.         pos% = 8    'start past 'http://' again
  375.         server_domain$ = parsestring$(pos%, n$, "/")
  376.         If Len(server_domain$) Then
  377.             'got something
  378.             got_domain = True
  379.         Else
  380.             ok = False
  381.         End If
  382.     Else
  383.         'was a dot address
  384.         server_dotaddr$ = Left$(server_dotaddr$, Len(server_dotaddr$) - 1)
  385.     End If
  386.     If pos% Then
  387.         'Got something PAST the URL. (a directory entry (document))
  388.         'save it
  389.         document$ = Mid$(n$, pos%)
  390.     End If
  391. Else
  392.     'Invalid name field, no 'http://'
  393.     ok = False
  394. End If
  395. If ok Then
  396.     'Here we either have a validated dot address (human
  397.     'readable Internet address) or a Domain name.
  398.     If got_domain Then
  399.         'SEE Winsock.txt
  400.         'Now have to get server Internet address by name.
  401.         'ie. ask for a DNS lookup against a Domain name.
  402.         'The call returns the address of a winsock hostent
  403.         'structure which is an area of the Winsock's memory
  404.         'that is mapped (laid out) in the hostent structure
  405.         'format.
  406.         'Use the Async or non-blocking call. In English this
  407.         'means call Winsock, who will initiate the call and
  408.         'will return immediately. This allows us to control
  409.         'how long we wait for a response and to check our network
  410.         'connected status. Otherwise, if we use the 'blocking'
  411.         'call we have to wait until Winsock times out. The
  412.         'response from Winsock is a message which we trap
  413.         'with msgblast.
  414.         dprint "WSAAsyncGetHostByName for " & server_domain$
  415.         namehandle% = WSAAsyncGetHostByName(main_hwnd%, name_msg%, server_domain$, namehostent, Len(namehostent))
  416.         
  417.         ''''''''''''''''''''''''''''''''''''
  418.         'FYI, this is the blocking call, that is, Winsock "hangs" until
  419.         'a DNS response is received or Winsock times out.
  420.         'ha& = gethostbyname(n$)
  421.         ''''''''''''''''''''''''''''''''''''
  422.         If namehandle% Then
  423.             'Call was successful. Wait for a response.
  424.             got_name_response = False
  425.             Do
  426.                 DoEvents
  427.                 'Don't wait forever
  428.                 'Here check for a timeout against how long
  429.                 'you want to wait. Set OK to false if
  430.                 'you time out.
  431.                 If got_name_response Then
  432.                     Exit Do
  433.                 Else
  434.                     'check for timeout
  435.                     'If timeout then
  436.                     '   ok=false
  437.                     '   exit do
  438.                     'end if
  439.                 End If
  440.                 If quit_flag Then
  441.                     Exit Function
  442.                 End If
  443.             Loop
  444.             If ok Then
  445.                 'Didn't time out but check for any errors.
  446.                 'Global 'name_errcode%' is set by the msgblast
  447.                 'message routine.
  448.                 If event_error% Then
  449.                     dprint "Get Host by Name failed with error code " & sockerror$(event_error%)
  450.                     ok = False
  451.                 Else
  452.                     'We have the domain name.
  453.                     'We need the Internet address and the dot address.
  454.  
  455.                     'We now have the hostent structure plus data pointed
  456.                     'to in our namehostent structure.
  457.                     'One of the variables is a memory address (pointer)
  458.                     'pointing to a memory address (pointer) pointing to
  459.                     'a list of Internet addresses.
  460.                     listaa& = namehostent.h_addr_list
  461.                     If listaa& = 0 Then
  462.                         'Insurance...some Winsocks say it's OK
  463.                         'but return null buffer pointers which
  464.                         'cause GPF's in hmemcpy
  465.                         dprint "Bad name response"
  466.                         ok = False
  467.                         Exit Function
  468.                     End If
  469.                     'listaa& now points to the address of the address
  470.                     'of the list.
  471.                     hmemcpy lista&, ByVal listaa&, 4
  472.                     'lista& now points to the list itself.
  473.                     'get first list entry which is the
  474.                     'server Internet address.
  475.                     hmemcpy server_addr&, ByVal lista&, 4
  476.                     'This call converts an Internet address into
  477.                     'a dot address and returns the address of the
  478.                     'resultant string. You have to pass it the memory
  479.                     'address of the Internet address.
  480.                     dota& = inet_ntoa&(server_addr&)
  481.                     'lpstrcpy needs a blank VB target string
  482.                     server_dotaddr$ = Space$(256)
  483.                     temp& = lstrcpy&(server_dotaddr$, dota&)
  484.                     'Get rid of nulls copied from Winsock
  485.                     server_dotaddr$ = replacechar2(server_dotaddr$, Chr$(0), " ")
  486.                     'And trim it
  487.                     server_dotaddr$ = Trim$(server_dotaddr$)
  488.                     dprint server_domain & " is " & server_dotaddr$
  489.                     'Whew!
  490.                 End If
  491.             Else
  492.                 dprint "Get Host by Name timed out"
  493.                 ok = False
  494.             End If
  495.                 
  496.         Else
  497.             'Something wrong. Find out what.
  498.             errcode% = WSAGetLastError()
  499.             MsgBox "Get Host by Name failed with error " & sockerror$(errcode%)
  500.             ok = False
  501.         End If
  502.     Else
  503.         'convert dot address to Internet address, then
  504.         'get server name by address. i.e. ask for DNS
  505.         'lookup against an Internet address.
  506.         'Convert dot address (human) to a long& (computer)
  507.         server_addr& = inet_addr(server_dotaddr$)
  508.         'Now call a DNS server on the network to get the assigned
  509.         'Domain name.
  510.         dprint "WSAAsyncGetHostByAddress for " & server_dotaddr$
  511.         got_name_response = False
  512.         namehandle% = WSAAsyncGetHostByAddr(main_hwnd%, name_msg%, server_addr&, 4, PF_INET, namehostent, Len(namehostent))
  513.         If namehandle% Then
  514.             'Call was a 'non-blocking call'. In English this
  515.             'means that Winsock is now doing a DNS network access.
  516.             'We'll have to wait until he's done, but this
  517.             'way we have control over how long we wait, and
  518.             'can immediately get network status instead of
  519.             'hanging in the blocking version waiting for Winsock to
  520.             'time out only to find out that we are not connected to
  521.             'the network.
  522.             'Call was successful. Wait for a response.
  523.             Do
  524.                 DoEvents
  525.                 'Don't wait forever
  526.                 'Here check for a timeout against how long
  527.                 'you want to wait. Set OK to false if
  528.                 'you time out.
  529.                 If got_name_response Then
  530.                     Exit Do
  531.                 Else
  532.                     'check for timeout
  533.                     'If timeout then
  534.                     '   ok=false
  535.                     '   exit do
  536.                     'end if
  537.                 End If
  538.             Loop
  539.             If ok Then
  540.                 'Didn't time out but check for any errors.
  541.                 'Global 'name_errcode%' is set by the msgblast
  542.                 'message routine.
  543.                 If event_error% Then
  544.                     dprint "Get Host by Address failed with error " & sockerror$(event_error%)
  545.                     ok = False
  546.                 Else
  547.                     'We have the dot address.
  548.                     'We've converted it to a long (the internet address).
  549.                     'We need the domain name.
  550.  
  551.                     'We now have the hostent structure plus data pointed
  552.                     'to in our namehostent structure.
  553.                     'get address of name
  554.                     namea& = namehostent.h_name
  555.                     'copy name
  556.                     server_domain$ = Space$(256)
  557.                     temp& = lstrcpy&(server_domain$, namea&)
  558.                     'strip nulls
  559.                     server_domain$ = Trim$(replacechar2$(server_domain$, Chr$(0), " "))
  560.                     dprint server_dotaddr$ & " is " & server_domain$
  561.                 End If
  562.             Else
  563.                 dprint "Get Host by Address timed out"
  564.                 ok = False
  565.             End If
  566.                 
  567.         Else
  568.             errcode% = WSAGetLastError()
  569.             dprint "Get Host by Addressfailed with error " & sockerror$(errcode%)
  570.             ok = False
  571.         End If
  572.     End If
  573. End If
  574. exit_get_server_address:
  575. get_server_address = ok
  576.  
  577. End Function
  578.  
  579. Sub init_all ()
  580.  
  581. main_hwnd% = browserfrm.hWnd
  582. event_msg% = &H2000         '&h2000=8192
  583. name_msg% = event_msg% + 1  '8193   (see msgblast routine)
  584.  
  585. cr$ = Chr$(13): lf$ = Chr$(10)
  586. crlf$ = cr$ + lf$
  587. crlfcrlf$ = crlf$ + crlf$
  588. lflf$ = lf$ + lf$
  589. ReDim urls$(1 To 1)
  590.  
  591. End Sub
  592.  
  593. Sub main ()
  594. debugging = True
  595. browserfrm.Show
  596. init_all
  597.  
  598. If start_winsock() Then
  599.     Do While Not quit_flag
  600.         DoEvents
  601.     Loop
  602.     status% = close_sock(callsocket%)
  603.     status% = WSACleanup()
  604.     dprint "WSACleanup status " & sockerror$(status%)
  605.     'Allow viewing of debug.print stuff before actual quit.
  606.     'Use ctl-break to break out of msgbox and into VB with
  607.     'program still active
  608.     If debugging Then
  609.         MsgBox "Debug is on, click OK to exit, ctl_break to see debug screen."
  610.     End If
  611. End If
  612. End
  613. End Sub
  614.  
  615. Sub parse_current_msg ()
  616. 'It is almost impossible to use Vanilla VB to parse and
  617. 'display an HTML document as you have to mix fonts, font sizes, text colors,
  618. 'and images(jpeg and gifs).
  619.  
  620.  
  621. 'Change single lf's to crlf's if the msg is in Unix/Mac
  622. 'format, which uses single line feeds as end of line
  623. 'indicators. The PC world uses carriage return-line feed pairs.
  624. current_msg$ = browserfrm.Text1.Text + crlfcrlf$ + "Received from server:" + crlfcrlf$ + current_msg$
  625. browserfrm.Text1.Text = set_lf_to_crlf$(current_msg$)
  626. End Sub
  627.  
  628. Function parsestring$ (start, wrk$, target$)
  629. 'Replaces Crescent Software's FUN parsestring$(). If you
  630. 'are serious about VB programming, then you must get their
  631. 'toolkit.
  632. 'This call is invaluable as it allows you to step thru delimited
  633. 'string retrieving the data BETWEEN the delimiters.
  634.  
  635. If start = 0 Then
  636.     start = 1
  637. End If
  638. delim = InStr(start, wrk$, target$)
  639. If delim Then
  640.     t$ = Mid$(wrk$, start, delim - start)
  641.     If delim > Len(wrk$) Then
  642.         start = 0
  643.     Else
  644.         start = delim + 1
  645.     End If
  646. Else
  647.     t$ = Mid$(wrk$, start)
  648.     start = 0
  649. End If
  650. parsestring$ = t$
  651. End Function
  652.  
  653. Function replacechar2$ (l$, oldchar$, newchar$)
  654. 'This function replaces Crescent Software's FUN.
  655. For i = 1 To Len(l$)
  656.     If Mid$(l$, i, 1) = oldchar$ Then
  657.         Mid$(l$, i, 1) = newchar$
  658.     End If
  659. Next
  660. replacechar2$ = l$
  661. End Function
  662.  
  663. Function set_lf_to_crlf$ (m$)
  664. 'Change Unix/Mac line feeds to carriage return - linefeeds
  665. delim = 1
  666. Do
  667.     DoEvents
  668.     delim = InStr(delim, m$, lf$)
  669.     If delim Then
  670.         If Mid$(m$, delim - 1, 1) = cr$ Then
  671.             'check the entire message
  672.             delim = delim + 1
  673.         Else
  674.             'insert a cr ahead of the lf
  675.             m$ = Left$(m$, delim - 1) + cr$ + Mid$(m$, delim)
  676.             delim = delim + 2
  677.         End If
  678.     Else
  679.         'done scanning
  680.         Exit Do
  681.     End If
  682. Loop
  683.  
  684.  
  685. set_lf_to_crlf$ = m$
  686. End Function
  687.  
  688. Function sockerror$ (n)
  689. 'Return error message for n
  690. 'n is return status from a call
  691. e$ = "WSAE"
  692. Select Case n
  693.     Case 0
  694.         e$ = "OK"
  695.     Case 10004
  696.         e$ = e$ + "INTR"
  697.     Case 10009
  698.         e$ = e$ + "BADF"
  699.     Case 10013
  700.         e$ = e$ + "ACCES"
  701.     Case 10014
  702.         e$ = e$ + "FAULT"
  703.     Case 10022
  704.         e$ = e$ + "INVAL"
  705.     Case 10024
  706.         e$ = e$ + "MFILE"
  707.     Case 10035
  708.         e$ = e$ + "WOULDBLOCK"
  709.     Case 10036
  710.         e$ = e$ + "INPROGRESS"
  711.     Case 10037
  712.         e$ = e$ + "ALREADY"
  713.     Case 10038
  714.         e$ = e$ + "NOTSOCK"
  715.     Case 10039
  716.         e$ = e$ + "DESTADDRREQ"
  717.     Case 10040
  718.         e$ = e$ + "MSGSIZE"
  719.     Case 10041
  720.         e$ = e$ + "PROTOTYPE"
  721.     Case 10042
  722.         e$ = e$ + "NOPROTOOPT"
  723.     Case 10043
  724.         e$ = e$ + "PROTONOSUPPORT"
  725.     Case 10044
  726.         e$ = e$ + "SOCKTNOSUPPORT"
  727.     Case 10045
  728.         e$ = e$ + "OPNOTSUPP"
  729.     Case 10046
  730.         e$ = e$ + "PFNOSUPPORT"
  731.     Case 10047
  732.         e$ = e$ + "AFNOSUPPORT"
  733.     Case 10048
  734.         e$ = e$ + "ADDRINUSE"
  735.     Case 10049
  736.         e$ = e$ + "ADDRNOTAVAIL"
  737.     Case 10050
  738.         e$ = e$ + "NETDOWN"
  739.     Case 10051
  740.         e$ = e$ + "NETUNREACH"
  741.     Case 10052
  742.         e$ = e$ + "NETRESET"
  743.     Case 10053
  744.         e$ = e$ + "CONNABORTED"
  745.     Case 10054
  746.         e$ = e$ + "CONNRESET"
  747.     Case 10055
  748.         e$ = e$ + "NOBUFS"
  749.     Case 10056
  750.         e$ = e$ + "ISCONN"
  751.     Case 10057
  752.         e$ = e$ + "NOTCONN"
  753.     Case 10058
  754.         e$ = e$ + "SHUTDOWN"
  755.     Case 10059
  756.         e$ = e$ + "TOOMANYREFS"
  757.     Case 10060
  758.         e$ = e$ + "TIMEDOUT"
  759.     Case 10061
  760.         e$ = e$ + "CONNREFUSED"
  761.     Case 10062
  762.         e$ = e$ + "LOOP"
  763.     Case 10063
  764.         e$ = e$ + "NAMETOOLONG"
  765.     Case 10064
  766.         e$ = e$ + "HOSTDOWN"
  767.     Case 10065
  768.         e$ = e$ + "HOSTUNREACH"
  769.     Case 10066
  770.         e$ = e$ + "NOTEMPTY"
  771.     Case 10067
  772.         e$ = e$ + "PROCLIM"
  773.     Case 10068
  774.         e$ = e$ + "USERS"
  775.     Case 10069
  776.         e$ = e$ + "DQUOT"
  777.     Case 10070
  778.         e$ = e$ + "STALE"
  779.     Case 10071
  780.         e$ = e$ + "REMOTE"
  781.     Case 10091
  782.         e$ = "WSASYSNOTREADY"
  783.     Case 10092
  784.         e$ = "WSAVERNOTSUPPORTED"
  785.     Case 10093
  786.         e$ = "WSANOTINITIALIZED"
  787.     Case 11001
  788.         e$ = e$ + "WSA_HOST_NOT_FOUND"
  789.     Case 11002
  790.         e$ = "WSATRY_AGAIN"
  791.     Case 11003
  792.         e$ = "WSANO_RECOVERY"
  793.     Case 11004
  794.         e$ = "WSANO_DATA"
  795.     Case Else
  796.         e$ = "UNKNOWN ERROR CODE" + Str$(n)
  797. End Select
  798. sockerror$ = e$
  799. End Function
  800.  
  801. Function start_winsock ()
  802. dprint "WSAStartup"
  803. reqver% = &H101
  804. status% = WSAStartup(reqver%, WSAdata)
  805. If status% Then
  806.     dprint "Startup Winsock error " & sockerror$(status%)
  807. Else
  808.     dprint "Startup status " & sockerror$(status%)
  809.     dprint "Version " & WSAdata.wVersion
  810.     dprint "High version " & WSAdata.wHighVersion
  811.     dprint "Description " & WSAdata.szDescription
  812.     dprint "System status " & WSAdata.szSystemStatus
  813.     dprint "Max sockets " & WSAdata.iMaxSockets
  814.     dprint "Max datagrams " & WSAdata.iMaxUdpDg
  815.     'Each vendor can have a structure which is their
  816.     'own design. I haven't found the specific descriptions
  817.     'for Trumpet or Microsoft.
  818.     dprint "Pointer to vendor info " & WSAdata.lpVendorInfo
  819.     start_winsock = True
  820. End If
  821. End Function
  822.  
  823.