; rss-snippet.vnm
; test parsing an RSS feed with Protocol analyser
;
; Illustates fetching a simple http URL and use of the
; protocol analyser V2.
; Needs September 2007 or later version of Venom.

; site-specific definitions. You WILL have to change these!
define my_ip "172.16.1.150"
define my_nameserver "172.16.1.146"
define my_gateway "172.16.1.199"

TO init
  make eth protocol("eth", 1, $d)
  eth.address('i') := my_ip
  eth.address('n') := my_nameserver
  eth.address('d') := my_gateway
  make tcp protocol("tcp")
  make pa protanalyser(tcp, 0)
  make s string(100)
END

TO main
  ; note how the URL "http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/front_page/rss.xml"
 ; is broken down.
 ; HTTP uses port 80, which we use when opening the connection.
 ; "newsrss.bbc.co.uk" is is the hostname, which we use when opening the connection and
 ; again in a "host:" header after sending the GET request
 ; "/rss/newsonline_uk_edition/front_page/rss.xml" is the path we specify in the GET request
 ;
if tcp.open("newsrss.bbc.co.uk", 80)
[
  PRINT "http connection opened",CR
  PRINT TO tcp, "GET /rss/newsonline_uk_edition/front_page/rss.xml HTTP/1.1",CR,
    "host: newsrss.bbc.co.uk",CR, CR
  PRINT "=headers=",CR
  while tcp.get(s) > 0    ; read headers until we get an empty line = end of headers
    PRINT s, CR
  PRINT "==",CR
  pa.reset
; every title we want to display is a <title> element inside an <item> element.
; There are a couple of <title> elements at the beginning that do not apply.


    while pa.find("", 0)
    [
      if pa.find("<")
        convert_entity(s)
        PRINT "Title: ", s, CR
      ]
    ]
    tcp.close
    tcp.reset
]
else
  PRINT "tcp open failed, status ", tcp.status:1, CR
tcp.
reset
END


; table for converting certain HTML codes back into characters */
; the first entry in each pair is a string preceded by '&' and
; followed by ';' in the XML/HTML
; e.g. "&" represents '&'
ARRAY entities("", 8)
  "amp" "&"
  "apos" "'"
  "pound" "£"
  "quot", "\""
END

; convert XML/HTML character entity codes in a string
TO convert_entity(s)
  AUTODESTRUCT
  local s1 := new string(100) ; holder for converted string
  local pa1 := new protanalyser(s, 1)
  local c
  local n

  s.reset
  s1.empty
  while s.queue
  [
    c := pa1.get
    if c = '&'
    [
      ; this uses protanalyser "array of names" feature
      n := pa1.get(entities, ";")
      if n <> -1
        print to s1, entities.(n + 1)
    ]
    else
      s1.put(c)
  ]
  s.empty
  s.put(s1) ; copy converted string back to original
END