18462SApril.Chin@Sun.COM#!/usr/bin/ksh93
28462SApril.Chin@Sun.COM
38462SApril.Chin@Sun.COM#
48462SApril.Chin@Sun.COM# CDDL HEADER START
58462SApril.Chin@Sun.COM#
68462SApril.Chin@Sun.COM# The contents of this file are subject to the terms of the
78462SApril.Chin@Sun.COM# Common Development and Distribution License (the "License").
88462SApril.Chin@Sun.COM# You may not use this file except in compliance with the License.
98462SApril.Chin@Sun.COM#
108462SApril.Chin@Sun.COM# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
118462SApril.Chin@Sun.COM# or http://www.opensolaris.org/os/licensing.
128462SApril.Chin@Sun.COM# See the License for the specific language governing permissions
138462SApril.Chin@Sun.COM# and limitations under the License.
148462SApril.Chin@Sun.COM#
158462SApril.Chin@Sun.COM# When distributing Covered Code, include this CDDL HEADER in each
168462SApril.Chin@Sun.COM# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
178462SApril.Chin@Sun.COM# If applicable, add the following below this CDDL HEADER, with the
188462SApril.Chin@Sun.COM# fields enclosed by brackets "[]" replaced with your own identifying
198462SApril.Chin@Sun.COM# information: Portions Copyright [yyyy] [name of copyright owner]
208462SApril.Chin@Sun.COM#
218462SApril.Chin@Sun.COM# CDDL HEADER END
228462SApril.Chin@Sun.COM#
238462SApril.Chin@Sun.COM
248462SApril.Chin@Sun.COM#
25*10898Sroland.mainz@nrubsig.org# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
268462SApril.Chin@Sun.COM# Use is subject to license terms.
278462SApril.Chin@Sun.COM#
288462SApril.Chin@Sun.COM
298462SApril.Chin@Sun.COM#
308462SApril.Chin@Sun.COM# rssread - a simple RSS2.0 reader with RSS to XHTML to
318462SApril.Chin@Sun.COM# plaintext conversion.
328462SApril.Chin@Sun.COM#
338462SApril.Chin@Sun.COM
348462SApril.Chin@Sun.COM# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant
358462SApril.Chin@Sun.COMexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin
368462SApril.Chin@Sun.COM
378462SApril.Chin@Sun.COMfunction printmsg
388462SApril.Chin@Sun.COM{
398462SApril.Chin@Sun.COM	print -u2 "$*"
408462SApril.Chin@Sun.COM}
418462SApril.Chin@Sun.COM
428462SApril.Chin@Sun.COMfunction debugmsg
438462SApril.Chin@Sun.COM{
448462SApril.Chin@Sun.COM#	printmsg "$*"
458462SApril.Chin@Sun.COMtrue
468462SApril.Chin@Sun.COM}
478462SApril.Chin@Sun.COM
488462SApril.Chin@Sun.COMfunction fatal_error
498462SApril.Chin@Sun.COM{
508462SApril.Chin@Sun.COM	print -u2 "${progname}: $*"
518462SApril.Chin@Sun.COM	exit 1
528462SApril.Chin@Sun.COM}
538462SApril.Chin@Sun.COM
54*10898Sroland.mainz@nrubsig.orgtypeset -T urlconnection_t=(
55*10898Sroland.mainz@nrubsig.org	# public
56*10898Sroland.mainz@nrubsig.org	typeset user_agent="ksh93/urlconnection_t"
57*10898Sroland.mainz@nrubsig.org
58*10898Sroland.mainz@nrubsig.org	# private variables
59*10898Sroland.mainz@nrubsig.org	typeset protocol
60*10898Sroland.mainz@nrubsig.org	typeset path1
61*10898Sroland.mainz@nrubsig.org	typeset host
62*10898Sroland.mainz@nrubsig.org	typeset path
63*10898Sroland.mainz@nrubsig.org	typeset port
64*10898Sroland.mainz@nrubsig.org
65*10898Sroland.mainz@nrubsig.org	compound netfd=(
66*10898Sroland.mainz@nrubsig.org		integer in=-1  # incoming traffic
67*10898Sroland.mainz@nrubsig.org		integer out=-1 # outgoing traffic
68*10898Sroland.mainz@nrubsig.org	)
698462SApril.Chin@Sun.COM
70*10898Sroland.mainz@nrubsig.org	# only used for https
71*10898Sroland.mainz@nrubsig.org	compound ssl=(
72*10898Sroland.mainz@nrubsig.org		compound fifo=(
73*10898Sroland.mainz@nrubsig.org			typeset dir=""
74*10898Sroland.mainz@nrubsig.org			typeset in=""
75*10898Sroland.mainz@nrubsig.org			typeset out=""
76*10898Sroland.mainz@nrubsig.org		)
77*10898Sroland.mainz@nrubsig.org		integer openssl_client_pid=-1
78*10898Sroland.mainz@nrubsig.org	)
79*10898Sroland.mainz@nrubsig.org
80*10898Sroland.mainz@nrubsig.org	# parse HTTP return code, cookies etc.
81*10898Sroland.mainz@nrubsig.org	function parse_http_response
82*10898Sroland.mainz@nrubsig.org	{
83*10898Sroland.mainz@nrubsig.org		nameref response="$1"
84*10898Sroland.mainz@nrubsig.org		typeset h statuscode statusmsg i
85*10898Sroland.mainz@nrubsig.org
86*10898Sroland.mainz@nrubsig.org		# we use '\r' as additional IFS to filter the final '\r'
87*10898Sroland.mainz@nrubsig.org		IFS=$' \t\r' read -r h statuscode statusmsg # read HTTP/1.[01] <code>
88*10898Sroland.mainz@nrubsig.org		[[ "$h" != ~(Eil)HTTP/.* ]]         && { print -u2 -f $"%s: HTTP/ header missing\n" "$0" ; return 1 ; }
89*10898Sroland.mainz@nrubsig.org		[[ "$statuscode" != ~(Elr)[0-9]* ]] && { print -u2 -f $"%s: invalid status code\n"  "$0" ; return 1 ; }
90*10898Sroland.mainz@nrubsig.org		response.statuscode="$statuscode"
91*10898Sroland.mainz@nrubsig.org		response.statusmsg="$statusmsg"
92*10898Sroland.mainz@nrubsig.org
93*10898Sroland.mainz@nrubsig.org		# skip remaining headers
94*10898Sroland.mainz@nrubsig.org		while IFS='' read -r i ; do
95*10898Sroland.mainz@nrubsig.org			[[ "$i" == $'\r' ]] && break
968462SApril.Chin@Sun.COM
97*10898Sroland.mainz@nrubsig.org			# strip '\r' at the end
98*10898Sroland.mainz@nrubsig.org			i="${i/~(Er)$'\r'/}"
998462SApril.Chin@Sun.COM
100*10898Sroland.mainz@nrubsig.org			case "$i" in
101*10898Sroland.mainz@nrubsig.org				~(Eli)Content-Type:.*)
102*10898Sroland.mainz@nrubsig.org					response.content_type="${i/~(El).*:[[:blank:]]*/}"
103*10898Sroland.mainz@nrubsig.org					;;
104*10898Sroland.mainz@nrubsig.org				~(Eli)Content-Length:[[:blank:]]*[0-9]*)
105*10898Sroland.mainz@nrubsig.org					integer response.content_length="${i/~(El).*:[[:blank:]]*/}"
106*10898Sroland.mainz@nrubsig.org					;;
107*10898Sroland.mainz@nrubsig.org				~(Eli)Transfer-Encoding:.*)
108*10898Sroland.mainz@nrubsig.org					response.transfer_encoding="${i/~(El).*:[[:blank:]]*/}"
109*10898Sroland.mainz@nrubsig.org					;;
110*10898Sroland.mainz@nrubsig.org			esac
111*10898Sroland.mainz@nrubsig.org		done
112*10898Sroland.mainz@nrubsig.org
113*10898Sroland.mainz@nrubsig.org		return 0
114*10898Sroland.mainz@nrubsig.org	}
1158462SApril.Chin@Sun.COM
116*10898Sroland.mainz@nrubsig.org	function cat_http_body
117*10898Sroland.mainz@nrubsig.org	{
118*10898Sroland.mainz@nrubsig.org		typeset emode="$1"
119*10898Sroland.mainz@nrubsig.org		typeset hexchunksize="0"
120*10898Sroland.mainz@nrubsig.org		integer chunksize=0
121*10898Sroland.mainz@nrubsig.org
122*10898Sroland.mainz@nrubsig.org		if [[ "${emode}" == "chunked" ]] ; then
123*10898Sroland.mainz@nrubsig.org			while IFS=$'\n' read hexchunksize ; do
124*10898Sroland.mainz@nrubsig.org				hexchunksize="${hexchunksize//$'\r'/}"
125*10898Sroland.mainz@nrubsig.org				[[ "${hexchunksize}" != "" ]] || continue
126*10898Sroland.mainz@nrubsig.org				[[ "${hexchunksize}" == ~(Elri)[0-9abcdef]+ ]] || break
127*10898Sroland.mainz@nrubsig.org				(( chunksize=16#${hexchunksize} ))
128*10898Sroland.mainz@nrubsig.org				(( chunksize > 0 )) || break
129*10898Sroland.mainz@nrubsig.org				dd bs=1 count="${chunksize}" 2>/dev/null
130*10898Sroland.mainz@nrubsig.org			done
131*10898Sroland.mainz@nrubsig.org		else
132*10898Sroland.mainz@nrubsig.org			cat
133*10898Sroland.mainz@nrubsig.org		fi
134*10898Sroland.mainz@nrubsig.org
135*10898Sroland.mainz@nrubsig.org		return 0
136*10898Sroland.mainz@nrubsig.org	}
137*10898Sroland.mainz@nrubsig.org
138*10898Sroland.mainz@nrubsig.org	function init_url
139*10898Sroland.mainz@nrubsig.org	{
140*10898Sroland.mainz@nrubsig.org		_.protocol="${1%://*}"
141*10898Sroland.mainz@nrubsig.org		_.path1="${1#*://}" # "http://foo.bat.net/x/y.html" ----> "foo.bat.net/x/y.html"
1428462SApril.Chin@Sun.COM
143*10898Sroland.mainz@nrubsig.org		if  [[ "${_.protocol}" == ~(Elr)http(|s) ]] ; then
144*10898Sroland.mainz@nrubsig.org			_.host="${_.path1%%/*}"
145*10898Sroland.mainz@nrubsig.org			_.path="${_.path1#*/}"
146*10898Sroland.mainz@nrubsig.org			_.port="${_.host##*:}"
147*10898Sroland.mainz@nrubsig.org		fi
148*10898Sroland.mainz@nrubsig.org
149*10898Sroland.mainz@nrubsig.org		return 0
150*10898Sroland.mainz@nrubsig.org	}
151*10898Sroland.mainz@nrubsig.org
152*10898Sroland.mainz@nrubsig.org	# close connection
153*10898Sroland.mainz@nrubsig.org	function close_connection
154*10898Sroland.mainz@nrubsig.org	{
155*10898Sroland.mainz@nrubsig.org		integer ret
156*10898Sroland.mainz@nrubsig.org
157*10898Sroland.mainz@nrubsig.org		if (( _.netfd.in != -1 )) ; then
158*10898Sroland.mainz@nrubsig.org			redirect {_.netfd.in}<&-
159*10898Sroland.mainz@nrubsig.org			(( _.netfd.in=-1 ))
160*10898Sroland.mainz@nrubsig.org		fi
161*10898Sroland.mainz@nrubsig.org
162*10898Sroland.mainz@nrubsig.org		if (( _.netfd.in != _.netfd.out && _.netfd.out != -1 )) ; then
163*10898Sroland.mainz@nrubsig.org			redirect {_.netfd.out}<&-
164*10898Sroland.mainz@nrubsig.org			((  _.netfd.out=-1 ))
165*10898Sroland.mainz@nrubsig.org		fi
1668462SApril.Chin@Sun.COM
167*10898Sroland.mainz@nrubsig.org		if [[ "${_.protocol}" == "https" ]] ; then
168*10898Sroland.mainz@nrubsig.org			wait ${_.ssl.openssl_client_pid} || { print -u2 -f "%s: openssl failed.\n" ; return 1 ; }
169*10898Sroland.mainz@nrubsig.org			(( _.ssl.openssl_client_pid=-1 ))
170*10898Sroland.mainz@nrubsig.org
171*10898Sroland.mainz@nrubsig.org			rm -r \"${_.ssl.fifo.dir}\"
172*10898Sroland.mainz@nrubsig.org			_.ssl.fifo.dir=""
173*10898Sroland.mainz@nrubsig.org		fi
174*10898Sroland.mainz@nrubsig.org
175*10898Sroland.mainz@nrubsig.org		return 0
176*10898Sroland.mainz@nrubsig.org	}
177*10898Sroland.mainz@nrubsig.org
178*10898Sroland.mainz@nrubsig.org	function open_connection
179*10898Sroland.mainz@nrubsig.org	{
180*10898Sroland.mainz@nrubsig.org		if [[ "${_.protocol}" == "https" ]] ; then
181*10898Sroland.mainz@nrubsig.org			_.ssl.fifo.dir="$(mktemp -d)"
182*10898Sroland.mainz@nrubsig.org			_.ssl.fifo.in="${_.ssl.fifo.dir}/in"
183*10898Sroland.mainz@nrubsig.org			_.ssl.fifo.out="${_.ssl.fifo.dir}/out"
1848462SApril.Chin@Sun.COM
185*10898Sroland.mainz@nrubsig.org			# Use "errexit" to leave it at the first error
186*10898Sroland.mainz@nrubsig.org			# (this saves lots of if/fi tests for error checking)
187*10898Sroland.mainz@nrubsig.org			set -o errexit
188*10898Sroland.mainz@nrubsig.org
189*10898Sroland.mainz@nrubsig.org			mkfifo "${_.ssl.fifo.in}" "${_.ssl.fifo.out}"
190*10898Sroland.mainz@nrubsig.org
191*10898Sroland.mainz@nrubsig.org			# create async openssl child to handle https
192*10898Sroland.mainz@nrubsig.org			openssl s_client -quiet -connect "${_.host}:${_.port}" <"${_.ssl.fifo.in}" >>"${_.ssl.fifo.out}" &
193*10898Sroland.mainz@nrubsig.org
194*10898Sroland.mainz@nrubsig.org			_.ssl.openssl_client_pid=$!
195*10898Sroland.mainz@nrubsig.org		else
196*10898Sroland.mainz@nrubsig.org			redirect {_.netfd.in}<> "/dev/tcp/${_.host}/${_.port}"
197*10898Sroland.mainz@nrubsig.org			(( $? != 0 )) && { print -u2 -f "%s: Could not open %s\n" "$0" "${1}" ; return 1 ; }
198*10898Sroland.mainz@nrubsig.org			(( _.netfd.out=_.netfd.in ))
199*10898Sroland.mainz@nrubsig.org		fi
200*10898Sroland.mainz@nrubsig.org		return 0
201*10898Sroland.mainz@nrubsig.org	}
2028462SApril.Chin@Sun.COM
203*10898Sroland.mainz@nrubsig.org	function send_request
204*10898Sroland.mainz@nrubsig.org	{
205*10898Sroland.mainz@nrubsig.org		typeset request="$1"
206*10898Sroland.mainz@nrubsig.org
207*10898Sroland.mainz@nrubsig.org		set -o errexit
208*10898Sroland.mainz@nrubsig.org
209*10898Sroland.mainz@nrubsig.org		if [[ "${_.protocol}" == "https" ]] ; then
210*10898Sroland.mainz@nrubsig.org				print -n -- "${request}\r\n" >>	"${_.ssl.fifo.in}"
211*10898Sroland.mainz@nrubsig.org
212*10898Sroland.mainz@nrubsig.org				redirect {_.netfd.in}< "${_.ssl.fifo.out}"
213*10898Sroland.mainz@nrubsig.org		else
214*10898Sroland.mainz@nrubsig.org				print -n -- "${request}\r\n" >&${_.netfd.out}
215*10898Sroland.mainz@nrubsig.org		fi
216*10898Sroland.mainz@nrubsig.org		return 0
217*10898Sroland.mainz@nrubsig.org	}
218*10898Sroland.mainz@nrubsig.org
219*10898Sroland.mainz@nrubsig.org	function cat_url
220*10898Sroland.mainz@nrubsig.org	{
221*10898Sroland.mainz@nrubsig.org		if [[ "${_.protocol}" == "file" ]] ; then
222*10898Sroland.mainz@nrubsig.org			cat "${_.path1}"
223*10898Sroland.mainz@nrubsig.org			return $?
224*10898Sroland.mainz@nrubsig.org		elif [[ "${_.protocol}" == ~(Elr)http(|s) ]] ; then
225*10898Sroland.mainz@nrubsig.org			compound httpresponse # http response
2268462SApril.Chin@Sun.COM
227*10898Sroland.mainz@nrubsig.org			# If URL did not contain a port number in the host part then look at the
228*10898Sroland.mainz@nrubsig.org			# protocol to get the port number
229*10898Sroland.mainz@nrubsig.org			if [[ "${_.port}" == "${_.host}" ]] ; then
230*10898Sroland.mainz@nrubsig.org				case "${_.protocol}" in
231*10898Sroland.mainz@nrubsig.org					"http")  _.port=80 ;;
232*10898Sroland.mainz@nrubsig.org					"https") _.port=443 ;;
233*10898Sroland.mainz@nrubsig.org					*)       _.port="$(getent services "${_.protocol}" | sed 's/[^0-9]*//;s/\/.*//')" ;;
234*10898Sroland.mainz@nrubsig.org				esac
235*10898Sroland.mainz@nrubsig.org			else
236*10898Sroland.mainz@nrubsig.org				_.host="${_.host%:*}"
237*10898Sroland.mainz@nrubsig.org			fi
238*10898Sroland.mainz@nrubsig.org
239*10898Sroland.mainz@nrubsig.org			printmsg "protocol=${_.protocol} port=${_.port} host=${_.host} path=${_.path}"
240*10898Sroland.mainz@nrubsig.org
241*10898Sroland.mainz@nrubsig.org			# prechecks
242*10898Sroland.mainz@nrubsig.org			[[ "${_.protocol}" != "" ]] || { print -u2 -f "%s: protocol not set.\n" "$0" ; return 1 ; }
243*10898Sroland.mainz@nrubsig.org			[[ "${_.port}"     != "" ]] || { print -u2 -f "%s: port not set.\n"     "$0" ; return 1 ; }
244*10898Sroland.mainz@nrubsig.org			[[ "${_.host}"     != "" ]] || { print -u2 -f "%s: host not set.\n"     "$0" ; return 1 ; }
245*10898Sroland.mainz@nrubsig.org			[[ "${_.path}"     != "" ]] || { print -u2 -f "%s: path not set.\n"     "$0" ; return 1 ; }
246*10898Sroland.mainz@nrubsig.org
247*10898Sroland.mainz@nrubsig.org			_.open_connection
2488462SApril.Chin@Sun.COM
249*10898Sroland.mainz@nrubsig.org			# send HTTP request
250*10898Sroland.mainz@nrubsig.org			request="GET /${_.path} HTTP/1.1\r\n"
251*10898Sroland.mainz@nrubsig.org			request+="Host: ${_.host}\r\n"
252*10898Sroland.mainz@nrubsig.org			request+="User-Agent: ${_.user_agent}\r\n"
253*10898Sroland.mainz@nrubsig.org			request+="Connection: close\r\n"
254*10898Sroland.mainz@nrubsig.org			_.send_request "${request}\r\n"
255*10898Sroland.mainz@nrubsig.org
256*10898Sroland.mainz@nrubsig.org			# collect response and send it to stdout
257*10898Sroland.mainz@nrubsig.org			{
258*10898Sroland.mainz@nrubsig.org				_.parse_http_response httpresponse
259*10898Sroland.mainz@nrubsig.org				_.cat_http_body "${httpresponse.transfer_encoding}"
260*10898Sroland.mainz@nrubsig.org			} <&${_.netfd.in}
261*10898Sroland.mainz@nrubsig.org
262*10898Sroland.mainz@nrubsig.org			_.close_connection
263*10898Sroland.mainz@nrubsig.org
264*10898Sroland.mainz@nrubsig.org			return 0
265*10898Sroland.mainz@nrubsig.org		else
266*10898Sroland.mainz@nrubsig.org			return 1
267*10898Sroland.mainz@nrubsig.org		fi
268*10898Sroland.mainz@nrubsig.org		# notreached
269*10898Sroland.mainz@nrubsig.org	}
270*10898Sroland.mainz@nrubsig.org)
2718462SApril.Chin@Sun.COM
2728462SApril.Chin@Sun.COMfunction html_entity_to_ascii
2738462SApril.Chin@Sun.COM{
2748462SApril.Chin@Sun.COM	typeset buf
2758462SApril.Chin@Sun.COM	typeset entity
2768462SApril.Chin@Sun.COM	typeset c
2778462SApril.Chin@Sun.COM	typeset value
2788462SApril.Chin@Sun.COM
2798462SApril.Chin@Sun.COM	# Todo: Add more HTML/MathML entities here
2808462SApril.Chin@Sun.COM	# Note we use a static variable (typeset -S) here to make sure we
2818462SApril.Chin@Sun.COM	# don't loose the cache data between calls
2828462SApril.Chin@Sun.COM	typeset -S -A entity_cache=(
2838462SApril.Chin@Sun.COM		# entity to ascii (fixme: add UTF-8 transliterations)
2848462SApril.Chin@Sun.COM		["nbsp"]=' '
2858462SApril.Chin@Sun.COM		["lt"]='<'
2868462SApril.Chin@Sun.COM		["le"]='<='
2878462SApril.Chin@Sun.COM		["gt"]='>'
2888462SApril.Chin@Sun.COM		["ge"]='>='
2898462SApril.Chin@Sun.COM		["amp"]='&'
2908462SApril.Chin@Sun.COM		["quot"]='"'
2918462SApril.Chin@Sun.COM		["apos"]="'"
2928462SApril.Chin@Sun.COM	)
2938462SApril.Chin@Sun.COM
2948462SApril.Chin@Sun.COM	buf=""
2958462SApril.Chin@Sun.COM	while IFS='' read -r -N 1 c ; do
2968462SApril.Chin@Sun.COM		if [[ "$c" != "&" ]] ; then
2978462SApril.Chin@Sun.COM			print -n -r -- "${c}"
2988462SApril.Chin@Sun.COM			continue
2998462SApril.Chin@Sun.COM		fi
3008462SApril.Chin@Sun.COM
3018462SApril.Chin@Sun.COM		entity=""
3028462SApril.Chin@Sun.COM		while IFS='' read -r -N 1 c ; do
3038462SApril.Chin@Sun.COM			case "$c" in
3048462SApril.Chin@Sun.COM				";")
3058462SApril.Chin@Sun.COM				break
3068462SApril.Chin@Sun.COM				;;
3078462SApril.Chin@Sun.COM			~(Eilr)[a-z0-9#])
3088462SApril.Chin@Sun.COM				entity+="$c"
3098462SApril.Chin@Sun.COM				continue
3108462SApril.Chin@Sun.COM				;;
3118462SApril.Chin@Sun.COM			*)
3128462SApril.Chin@Sun.COM#				debugmsg "error &${entity}${c}#"
3138462SApril.Chin@Sun.COM
3148462SApril.Chin@Sun.COM				print -n -r -- "${entity}${c}"
3158462SApril.Chin@Sun.COM				entity=""
3168462SApril.Chin@Sun.COM				continue 2
3178462SApril.Chin@Sun.COM				;;
3188462SApril.Chin@Sun.COM			esac
3198462SApril.Chin@Sun.COM		done
3208462SApril.Chin@Sun.COM
3218462SApril.Chin@Sun.COM		value=""
3228462SApril.Chin@Sun.COM		if [[ "${entity_cache["${entity}"]}" != "" ]] ; then
3238462SApril.Chin@Sun.COM#			debugmsg "match #${entity}# = #${entity_cache["${entity}"]}#"
3248462SApril.Chin@Sun.COM			value="${entity_cache["${entity}"]}"
3258462SApril.Chin@Sun.COM		else
3268462SApril.Chin@Sun.COM			if [[ "${entity:0:1}" == "#" ]] ; then
3278462SApril.Chin@Sun.COM				# decimal literal
3288462SApril.Chin@Sun.COM				value="${ printf "\u[${ printf "%x" "${entity:1:8}" ; }]" ; }"
3298462SApril.Chin@Sun.COM			elif [[ "${entity:0:7}" == ~(Eilr)[0-9a-f]* ]] ; then
3308462SApril.Chin@Sun.COM				# hexadecimal literal
3318462SApril.Chin@Sun.COM				value="${ printf "\u[${entity:0:7}]" ; }"
3328462SApril.Chin@Sun.COM			else
3338462SApril.Chin@Sun.COM				# unknown literal - pass-through
3348462SApril.Chin@Sun.COM				value="ENT=|${entity}|"
3358462SApril.Chin@Sun.COM			fi
3368462SApril.Chin@Sun.COM
3378462SApril.Chin@Sun.COM			entity_cache["${entity}"]="${value}"
3388462SApril.Chin@Sun.COM
3398462SApril.Chin@Sun.COM#			debugmsg "lookup #${entity}# = #${entity_cache["${entity}"]}#"
3408462SApril.Chin@Sun.COM		fi
3418462SApril.Chin@Sun.COM
3428462SApril.Chin@Sun.COM		printf "%s" "${value}"
3438462SApril.Chin@Sun.COM	done
3448462SApril.Chin@Sun.COM
3458462SApril.Chin@Sun.COM	return 0
3468462SApril.Chin@Sun.COM}
3478462SApril.Chin@Sun.COM
3488462SApril.Chin@Sun.COM# dumb xhtml handler - no CSS,  tables, images, iframes or nested
3498462SApril.Chin@Sun.COM# structures are supported (and we assume that the input is correct
3508462SApril.Chin@Sun.COM# xhtml). The code was written in a trial&&error manner and should be
3518462SApril.Chin@Sun.COM# rewritten to parse xhtml correctly.
3528462SApril.Chin@Sun.COMfunction handle_html
3538462SApril.Chin@Sun.COM{
3548462SApril.Chin@Sun.COM    # we can't use global variables here when multiple callbacks use the same
3558462SApril.Chin@Sun.COM    # callback function - but we can use the callback associative array for
3568462SApril.Chin@Sun.COM    # variable storage instead
3578462SApril.Chin@Sun.COM    nameref callbacks=${1}
3588462SApril.Chin@Sun.COM    typeset tag_type="$2"
3598462SApril.Chin@Sun.COM    typeset tag_value="$3"
3608462SApril.Chin@Sun.COM
3618462SApril.Chin@Sun.COM    case "${tag_type}" in
3628462SApril.Chin@Sun.COM        tag_begin)
3638462SApril.Chin@Sun.COM            case "${tag_value}" in
3648462SApril.Chin@Sun.COM                br) printf "\n" ;;
3658462SApril.Chin@Sun.COM                hr) printf "\n-------------------------------------\n" ;;
3668462SApril.Chin@Sun.COM                pre) callbacks["html_pre"]='true' ;;
3678462SApril.Chin@Sun.COM                p)  printf "\n" ;;
3688462SApril.Chin@Sun.COM            esac
3698462SApril.Chin@Sun.COM            ;;
3708462SApril.Chin@Sun.COM
3718462SApril.Chin@Sun.COM        tag_end)
3728462SApril.Chin@Sun.COM            case "${tag_value}" in
3738462SApril.Chin@Sun.COM                pre) callbacks["html_pre"]='false' ;;
3748462SApril.Chin@Sun.COM            esac
3758462SApril.Chin@Sun.COM            ;;
3768462SApril.Chin@Sun.COM
3778462SApril.Chin@Sun.COM        tag_text)
3788462SApril.Chin@Sun.COM            if ${callbacks["html_pre"]} ; then
3798462SApril.Chin@Sun.COM                printf "%s" "${tag_value}"
3808462SApril.Chin@Sun.COM            else
3818462SApril.Chin@Sun.COM                # compress spaces/newlines/tabs/etc.
3828462SApril.Chin@Sun.COM                printf "%s" "${tag_value//+([\n\r\t\v[:space:][:blank:]])/ }"
3838462SApril.Chin@Sun.COM            fi
3848462SApril.Chin@Sun.COM            ;;
3858462SApril.Chin@Sun.COM
3868462SApril.Chin@Sun.COM        document_start)
3878462SApril.Chin@Sun.COM            callbacks["html_pre"]='false'
3888462SApril.Chin@Sun.COM            ;;
3898462SApril.Chin@Sun.COM        document_end) ;;
3908462SApril.Chin@Sun.COM    esac
3918462SApril.Chin@Sun.COM
3928462SApril.Chin@Sun.COM    return 0
3938462SApril.Chin@Sun.COM}
3948462SApril.Chin@Sun.COM
3958462SApril.Chin@Sun.COMfunction handle_rss
3968462SApril.Chin@Sun.COM{
3978462SApril.Chin@Sun.COM	# we can't use global variables here when multiple callbacks use the same
3988462SApril.Chin@Sun.COM	# callback function - but we can use the callback associative array for
3998462SApril.Chin@Sun.COM	# variable storage instead
4008462SApril.Chin@Sun.COM	nameref callbacks=${1}
4018462SApril.Chin@Sun.COM	typeset tag_type="$2"
4028462SApril.Chin@Sun.COM	typeset tag_value="$3"
4038462SApril.Chin@Sun.COM
4048462SApril.Chin@Sun.COM	case "${tag_type}" in
4058462SApril.Chin@Sun.COM		tag_begin)
4068462SApril.Chin@Sun.COM			case "${tag_value}" in
4078462SApril.Chin@Sun.COM				item)
4088462SApril.Chin@Sun.COM					item["title"]=""
4098462SApril.Chin@Sun.COM					item["link"]=""
4108462SApril.Chin@Sun.COM					item["tag"]=""
4118462SApril.Chin@Sun.COM					item["description"]=""
4128462SApril.Chin@Sun.COM					;;
4138462SApril.Chin@Sun.COM			esac
4148462SApril.Chin@Sun.COM			callbacks["textbuf"]=""
4158462SApril.Chin@Sun.COM			;;
4168462SApril.Chin@Sun.COM		tag_end)
4178462SApril.Chin@Sun.COM			case "${tag_value}" in
4188462SApril.Chin@Sun.COM				item)
4198462SApril.Chin@Sun.COM					# note that each RSS item needs to be converted seperately from RSS to HTML to plain text
4208462SApril.Chin@Sun.COM					# to make sure that the state of one RSS item doesn't affect others
4218462SApril.Chin@Sun.COM					(
4228462SApril.Chin@Sun.COM						printf $"<br />#### RSS item: title: %s ####" "${item["title"]}"
4238462SApril.Chin@Sun.COM						printf $"<br />## author: %s" "${item["author"]}"
4248462SApril.Chin@Sun.COM						printf $"<br />## link:   %s" "${item["link"]}"
4258462SApril.Chin@Sun.COM						printf $"<br />## date:   %s" "${item["pubDate"]}"
4268462SApril.Chin@Sun.COM						printf $"<br />## begin description:"
4278462SApril.Chin@Sun.COM						printf $"<br />%s<br />" "${item["description"]}"
4288462SApril.Chin@Sun.COM						printf $"<br />## end description<br />"
4298462SApril.Chin@Sun.COM						print # extra newline to make sure the sed pipeline gets flushed
4308462SApril.Chin@Sun.COM					) |
4318462SApril.Chin@Sun.COM						html_entity_to_ascii |	# convert XML entities (e.g. decode RSS content to HTML code)
4328462SApril.Chin@Sun.COM						xml_tok "xhtmltok_cb" |	# convert HTML to plain text
4338462SApril.Chin@Sun.COM						html_entity_to_ascii	# convert HTML entities
4348462SApril.Chin@Sun.COM					;;
4358462SApril.Chin@Sun.COM				title)                item["title"]="${callbacks["textbuf"]}"        ; callbacks["textbuf"]="" ;;
4368462SApril.Chin@Sun.COM				link)                 item["link"]="${callbacks["textbuf"]}"         ; callbacks["textbuf"]="" ;;
4378462SApril.Chin@Sun.COM				dc:creator | author)  item["author"]="${callbacks["textbuf"]}"       ; callbacks["textbuf"]="" ;;
4388462SApril.Chin@Sun.COM				dc:date | pubDate)    item["pubDate"]="${callbacks["textbuf"]}"      ; callbacks["textbuf"]="" ;;
4398462SApril.Chin@Sun.COM				description)          item["description"]="${callbacks["textbuf"]}"  ; callbacks["textbuf"]="" ;;
4408462SApril.Chin@Sun.COM			esac
4418462SApril.Chin@Sun.COM			callbacks["textbuf"]=""
4428462SApril.Chin@Sun.COM			;;
4438462SApril.Chin@Sun.COM		tag_text)
4448462SApril.Chin@Sun.COM			callbacks["textbuf"]+="${tag_value}"
4458462SApril.Chin@Sun.COM			;;
4468462SApril.Chin@Sun.COM		document_start) ;;
4478462SApril.Chin@Sun.COM		document_end) ;;
4488462SApril.Chin@Sun.COM	esac
4498462SApril.Chin@Sun.COM	return 0
4508462SApril.Chin@Sun.COM}
4518462SApril.Chin@Sun.COM
4528462SApril.Chin@Sun.COMfunction xml_tok
4538462SApril.Chin@Sun.COM{
4548462SApril.Chin@Sun.COM    typeset buf=""
4558462SApril.Chin@Sun.COM    typeset namebuf=""
4568462SApril.Chin@Sun.COM    typeset attrbuf=""
4578462SApril.Chin@Sun.COM    typeset c=""
4588462SApril.Chin@Sun.COM    typeset isendtag # bool: true/false
4598462SApril.Chin@Sun.COM    typeset issingletag # bool: true/false (used for tags like "<br />")
4608462SApril.Chin@Sun.COM    nameref callbacks=${1}
4618462SApril.Chin@Sun.COM
4628462SApril.Chin@Sun.COM    [[ ! -z "${callbacks["document_start"]}" ]] && ${callbacks["document_start"]} "${1}" "document_start"
4638462SApril.Chin@Sun.COM
4648462SApril.Chin@Sun.COM    while IFS='' read -r -N 1 c ; do
4658462SApril.Chin@Sun.COM        isendtag=false
4668462SApril.Chin@Sun.COM
4678462SApril.Chin@Sun.COM        if [[ "$c" == "<" ]] ; then
4688462SApril.Chin@Sun.COM	    # flush any text content
4698462SApril.Chin@Sun.COM            if [[ "$buf" != "" ]] ; then
4708462SApril.Chin@Sun.COM                [[ ! -z "${callbacks["tag_text"]}" ]] && ${callbacks["tag_text"]} "${1}" "tag_text" "$buf"
4718462SApril.Chin@Sun.COM                buf=""
4728462SApril.Chin@Sun.COM            fi
4738462SApril.Chin@Sun.COM
4748462SApril.Chin@Sun.COM            IFS='' read -r -N 1 c
4758462SApril.Chin@Sun.COM            if [[ "$c" == "/" ]] ; then
4768462SApril.Chin@Sun.COM                isendtag=true
4778462SApril.Chin@Sun.COM            else
4788462SApril.Chin@Sun.COM                buf="$c"
4798462SApril.Chin@Sun.COM            fi
4808462SApril.Chin@Sun.COM            IFS='' read -r -d '>' c
4818462SApril.Chin@Sun.COM            buf+="$c"
4828462SApril.Chin@Sun.COM
4838462SApril.Chin@Sun.COM	    # handle comments
4848462SApril.Chin@Sun.COM	    if [[ "$buf" == ~(El)!-- ]] ; then
4858462SApril.Chin@Sun.COM	        # did we read the comment completely ?
4868462SApril.Chin@Sun.COM	        if [[ "$buf" != ~(Elr)!--.*-- ]] ; then
4878462SApril.Chin@Sun.COM		    buf+=">"
4888462SApril.Chin@Sun.COM	            while [[ "$buf" != ~(Elr)!--.*-- ]] ; do
4898462SApril.Chin@Sun.COM		        IFS='' read -r -N 1 c || break
4908462SApril.Chin@Sun.COM		        buf+="$c"
4918462SApril.Chin@Sun.COM		    done
4928462SApril.Chin@Sun.COM		fi
4938462SApril.Chin@Sun.COM
4948462SApril.Chin@Sun.COM		[[ ! -z "${callbacks["tag_comment"]}" ]] && ${callbacks["tag_comment"]} "${1}" "tag_comment" "${buf:3:${#buf}-5}"
4958462SApril.Chin@Sun.COM		buf=""
4968462SApril.Chin@Sun.COM		continue
4978462SApril.Chin@Sun.COM	    fi
4988462SApril.Chin@Sun.COM
4998462SApril.Chin@Sun.COM	    # check if the tag starts and ends at the same time (like "<br />")
5008462SApril.Chin@Sun.COM	    if [[ "${buf}" == ~(Er).*/ ]] ; then
5018462SApril.Chin@Sun.COM	        issingletag=true
5028462SApril.Chin@Sun.COM		buf="${buf%*/}"
5038462SApril.Chin@Sun.COM	    else
5048462SApril.Chin@Sun.COM	        issingletag=false
5058462SApril.Chin@Sun.COM	    fi
5068462SApril.Chin@Sun.COM
5078462SApril.Chin@Sun.COM	    # check if the tag has attributes (e.g. space after name)
5088462SApril.Chin@Sun.COM	    if [[ "$buf" == ~(E)[[:space:][:blank:]] ]] ; then
5098462SApril.Chin@Sun.COM	        namebuf="${buf%%~(E)[[:space:][:blank:]].*}"
5108462SApril.Chin@Sun.COM                attrbuf="${buf#~(E).*[[:space:][:blank:]]}"
5118462SApril.Chin@Sun.COM            else
5128462SApril.Chin@Sun.COM	        namebuf="$buf"
5138462SApril.Chin@Sun.COM		attrbuf=""
5148462SApril.Chin@Sun.COM	    fi
5158462SApril.Chin@Sun.COM
5168462SApril.Chin@Sun.COM            if ${isendtag} ; then
5178462SApril.Chin@Sun.COM                [[ ! -z "${callbacks["tag_end"]}" ]] && ${callbacks["tag_end"]} "${1}" "tag_end" "$namebuf"
5188462SApril.Chin@Sun.COM            else
5198462SApril.Chin@Sun.COM                [[ ! -z "${callbacks["tag_begin"]}" ]] && ${callbacks["tag_begin"]} "${1}" "tag_begin" "$namebuf" "$attrbuf"
5208462SApril.Chin@Sun.COM
5218462SApril.Chin@Sun.COM                # handle tags like <br/> (which are start- and end-tag in one piece)
5228462SApril.Chin@Sun.COM                if ${issingletag} ; then
5238462SApril.Chin@Sun.COM                    [[ ! -z "${callbacks["tag_end"]}" ]] && ${callbacks["tag_end"]} "${1}" "tag_end" "$namebuf"
5248462SApril.Chin@Sun.COM                fi
5258462SApril.Chin@Sun.COM            fi
5268462SApril.Chin@Sun.COM            buf=""
5278462SApril.Chin@Sun.COM        else
5288462SApril.Chin@Sun.COM            buf+="$c"
5298462SApril.Chin@Sun.COM        fi
5308462SApril.Chin@Sun.COM    done
5318462SApril.Chin@Sun.COM
5328462SApril.Chin@Sun.COM    [[ ! -z "${callbacks["document_end"]}" ]] && ${callbacks["document_end"]} "${1}" "document_end" "exit_success"
5338462SApril.Chin@Sun.COM
5348462SApril.Chin@Sun.COM    print # final newline to make filters like "sed" happy
5358462SApril.Chin@Sun.COM}
5368462SApril.Chin@Sun.COM
5378462SApril.Chin@Sun.COM# return the value of LC_MESSAGES needed for subprocesses which
5388462SApril.Chin@Sun.COM# want to run in a different locale/encoding
5398462SApril.Chin@Sun.COMfunction get_lc_messages
5408462SApril.Chin@Sun.COM{
5418462SApril.Chin@Sun.COM	[[ "${LC_ALL}"       != "" ]] && { print "${LC_ALL}"      ; return 0 ; }
5428462SApril.Chin@Sun.COM	[[ "${LC_MESSAGES}"  != "" ]] && { print "${LC_MESSAGES}" ; return 0 ; }
5438462SApril.Chin@Sun.COM	[[ "${LANG}"         != "" ]] && { print "${LANG}"        ; return 0 ; }
5448462SApril.Chin@Sun.COM	print "C" ; return 0
5458462SApril.Chin@Sun.COM}
5468462SApril.Chin@Sun.COM
5478462SApril.Chin@Sun.COMfunction do_rssread
5488462SApril.Chin@Sun.COM{
5498462SApril.Chin@Sun.COM	# set unicode locale since RSS is encoded in UTF-8
5508462SApril.Chin@Sun.COM	# (and make sure $LC_MESSAGES is set to the parent
5518462SApril.Chin@Sun.COM	# process's locale that all error messages are using
5528462SApril.Chin@Sun.COM	# the callers locale/encoding)
5538462SApril.Chin@Sun.COM	export \
5548462SApril.Chin@Sun.COM		LC_MESSAGES="${ get_lc_messages ; }" \
5558462SApril.Chin@Sun.COM		LC_MONETARY="en_US.UTF-8" \
5568462SApril.Chin@Sun.COM		LC_NUMERIC="en_US.UTF-8" \
5578462SApril.Chin@Sun.COM		LC_COLLATE="en_US.UTF-8" \
5588462SApril.Chin@Sun.COM		LC_CTYPE="en_US.UTF-8" \
5598462SApril.Chin@Sun.COM		LC_TIME="en_US.UTF-8" \
5608462SApril.Chin@Sun.COM		LANG="en_US.UTF-8"
5618462SApril.Chin@Sun.COM
562*10898Sroland.mainz@nrubsig.org	# return non-zero exit code for this function if the rss processing below fails
563*10898Sroland.mainz@nrubsig.org	set -o errexit
564*10898Sroland.mainz@nrubsig.org
565*10898Sroland.mainz@nrubsig.org	urlconnection_t hc
566*10898Sroland.mainz@nrubsig.org	hc.user_agent="rssread/ksh93(ssl) (2009-08-14; $(uname -s -r -p))"
567*10898Sroland.mainz@nrubsig.org	hc.init_url "$1"
568*10898Sroland.mainz@nrubsig.org
569*10898Sroland.mainz@nrubsig.org	# need extra newline after cat_url to terminate line with $'\n'
5708462SApril.Chin@Sun.COM	# to make "xml_tok" happy
571*10898Sroland.mainz@nrubsig.org	data="${ hc.cat_url ; print ; }"
572*10898Sroland.mainz@nrubsig.org
573*10898Sroland.mainz@nrubsig.org	print -u2 -f "# Got %d lines of RSS data, processing...\n" "${ wc -l <<< "${data}" ; }"
574*10898Sroland.mainz@nrubsig.org
575*10898Sroland.mainz@nrubsig.org	xml_tok "rsstok_cb" <<< "${data}"
576*10898Sroland.mainz@nrubsig.org
5778462SApril.Chin@Sun.COM	return 0
5788462SApril.Chin@Sun.COM}
5798462SApril.Chin@Sun.COM
5808462SApril.Chin@Sun.COMfunction usage
5818462SApril.Chin@Sun.COM{
5828462SApril.Chin@Sun.COM	OPTIND=0
5838462SApril.Chin@Sun.COM	getopts -a "${progname}" "${rssread_usage}" OPT '-?'
5848462SApril.Chin@Sun.COM	exit 2
5858462SApril.Chin@Sun.COM}
5868462SApril.Chin@Sun.COM
5878462SApril.Chin@Sun.COM# make sure we use the ksh93 builtin versions
5888462SApril.Chin@Sun.COMbuiltin basename
5898462SApril.Chin@Sun.COMbuiltin cat
590*10898Sroland.mainz@nrubsig.orgbuiltin mkfifo
5918462SApril.Chin@Sun.COM
5928462SApril.Chin@Sun.COMtypeset -A rsstok_cb # callbacks for xml_tok
5938462SApril.Chin@Sun.COMrsstok_cb["tag_begin"]="handle_rss"
5948462SApril.Chin@Sun.COMrsstok_cb["tag_end"]="handle_rss"
5958462SApril.Chin@Sun.COMrsstok_cb["tag_text"]="handle_rss"
5968462SApril.Chin@Sun.COMrsstok_cb["textbuf"]=""
5978462SApril.Chin@Sun.COM
5988462SApril.Chin@Sun.COMtypeset -A xhtmltok_cb # callbacks for xml_tok
5998462SApril.Chin@Sun.COMxhtmltok_cb["tag_begin"]="handle_html"
6008462SApril.Chin@Sun.COMxhtmltok_cb["tag_end"]="handle_html"
6018462SApril.Chin@Sun.COMxhtmltok_cb["tag_text"]="handle_html"
6028462SApril.Chin@Sun.COMxhtmltok_cb["textbuf"]=""
6038462SApril.Chin@Sun.COMxhtmltok_cb["html_pre"]='false'
6048462SApril.Chin@Sun.COM
6058462SApril.Chin@Sun.COMtypeset -A item
6068462SApril.Chin@Sun.COM
6078462SApril.Chin@Sun.COMtypeset -A bookmark_urls
6088462SApril.Chin@Sun.COM
6098462SApril.Chin@Sun.COM# "ramdom" urls for testing
6108462SApril.Chin@Sun.COMbookmark_urls=(
6118462SApril.Chin@Sun.COM	["google_blogs_ksh"]="http://blogsearch.google.com/blogsearch_feeds?hl=en&scoring=d&q=(%22ksh93%22%7C%22ksh+93%22+%7C+%22korn93%22+%7C+%22korn+93%22)&ie=utf-8&num=100&output=rss"
6128462SApril.Chin@Sun.COM	# OpenSolaris.org sites
6138462SApril.Chin@Sun.COM	["ksh93_integration"]="http://www.opensolaris.org/rss/os/project/ksh93-integration/announcements/rss2.xml"
614*10898Sroland.mainz@nrubsig.org	["ksh93_integration_ssl"]="https://www.opensolaris.org/rss/os/project/ksh93-integration/announcements/rss2.xml"
6158462SApril.Chin@Sun.COM	["shell"]="http://www.opensolaris.org/rss/os/project/shell/announcements/rss2.xml"
6168462SApril.Chin@Sun.COM	["systemz"]="http://www.opensolaris.org/rss/os/project/systemz/announcements/rss2.xml"
617*10898Sroland.mainz@nrubsig.org	["systemz_ssl"]="https://www.opensolaris.org/rss/os/project/systemz/announcements/rss2.xml"
6188462SApril.Chin@Sun.COM	# some Sun staff/sites
6198462SApril.Chin@Sun.COM	["blogs_sun_com"]="http://blogs.sun.com/main/feed/entries/rss"
6208462SApril.Chin@Sun.COM	["bigadmin"]="http://www.sun.com/bigadmin/content/rss/motd.xml"
621*10898Sroland.mainz@nrubsig.org	["bigadmin_scripts"]="https://www.sun.com/bigadmin/content/rss/scripts.xml"
6228462SApril.Chin@Sun.COM	["jmcp"]="http://www.jmcp.homeunix.com/roller/jmcp/feed/entries/rss"
6238462SApril.Chin@Sun.COM	["katakai"]="http://blogs.sun.com/katakai/feed/entries/rss"
6248462SApril.Chin@Sun.COM	["alanc"]="http://blogs.sun.com/alanc/feed/entries/rss"
6258462SApril.Chin@Sun.COM	["planetsun"]="http://www.planetsun.org/rss20.xml"
6268462SApril.Chin@Sun.COM	["planetsolaris"]="http://www.planetsolaris.org/rss20.xml"
6278462SApril.Chin@Sun.COM	["planetopensolaris"]="http://planet.opensolaris.org/rss20.xml"
6288462SApril.Chin@Sun.COM	["theregister_uk"]="http://www.theregister.co.uk/headlines.rss"
6298462SApril.Chin@Sun.COM	["heise"]="http://www.heise.de/newsticker/heise.rdf"
6308462SApril.Chin@Sun.COM	["slashdot"]="http://rss.slashdot.org/Slashdot/slashdot"
631*10898Sroland.mainz@nrubsig.org	["wikipedia_command_shells"]="http://en.wikipedia.org/w/index.php?title=Comparison_of_command_shells&feed=rss&action=history"
6328462SApril.Chin@Sun.COM)
6338462SApril.Chin@Sun.COM
6348462SApril.Chin@Sun.COMtypeset progname="${ basename "${0}" ; }"
6358462SApril.Chin@Sun.COM
6368462SApril.Chin@Sun.COMtypeset -r rssread_usage=$'+
637*10898Sroland.mainz@nrubsig.org[-?\n@(#)\$Id: rssread (Roland Mainz) 2009-08-14 \$\n]
6388462SApril.Chin@Sun.COM[-author?Roland Mainz <roland.mainz@sun.com>]
6398462SApril.Chin@Sun.COM[-author?Roland Mainz <roland.mainz@nrubsig.org>]
6408462SApril.Chin@Sun.COM[+NAME?rssread - fetch RSS messages and convert them to plain text]
6418462SApril.Chin@Sun.COM[+DESCRIPTION?\brssread\b RSS to plain text converter
6428462SApril.Chin@Sun.COM        which fetches RSS streams via HTTP and converts them from
6438462SApril.Chin@Sun.COM	RSS to HTML to plain text in the current locale/encoding.]
6448462SApril.Chin@Sun.COM[I:noiconv?Do not convert data from UTF-8 to current locale/encoding.]
6458462SApril.Chin@Sun.COM
6468462SApril.Chin@Sun.COM[ url ]
6478462SApril.Chin@Sun.COM
6488462SApril.Chin@Sun.COM[+SEE ALSO?\bksh93\b(1), \bshnote\b(1)]
6498462SApril.Chin@Sun.COM'
6508462SApril.Chin@Sun.COM
6518462SApril.Chin@Sun.COMtypeset noiconv=false
6528462SApril.Chin@Sun.COM
6538462SApril.Chin@Sun.COMwhile getopts -a "${progname}" "${rssread_usage}" OPT ; do
6548462SApril.Chin@Sun.COM#	printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|"
6558462SApril.Chin@Sun.COM	case ${OPT} in
6568462SApril.Chin@Sun.COM		I)    noiconv=true  ;;
6578462SApril.Chin@Sun.COM		+I)   noiconv=false ;;
6588462SApril.Chin@Sun.COM		*)    usage ;;
6598462SApril.Chin@Sun.COM	esac
6608462SApril.Chin@Sun.COMdone
6618462SApril.Chin@Sun.COMshift $((OPTIND-1))
6628462SApril.Chin@Sun.COM
6638462SApril.Chin@Sun.COMtypeset url="$1"
6648462SApril.Chin@Sun.COM
6658462SApril.Chin@Sun.COMif [[ "${url}" == "" ]] ; then
6668462SApril.Chin@Sun.COM	fatal_error $"No url given."
6678462SApril.Chin@Sun.COMfi
6688462SApril.Chin@Sun.COM
6698462SApril.Chin@Sun.COMif [[ "${bookmark_urls[${url}]}" != "" ]] ; then
6708462SApril.Chin@Sun.COM	printmsg $"Using bookmark ${url} = ${bookmark_urls[${url}]}"
6718462SApril.Chin@Sun.COM	url="${bookmark_urls[${url}]}"
6728462SApril.Chin@Sun.COMfi
6738462SApril.Chin@Sun.COM
6748462SApril.Chin@Sun.COMif ${noiconv} ; then
6758462SApril.Chin@Sun.COM	do_rssread "${url}"
6768462SApril.Chin@Sun.COMelse
6778462SApril.Chin@Sun.COM	do_rssread "${url}" | iconv -f "UTF-8" - -
6788462SApril.Chin@Sun.COMfi
6798462SApril.Chin@Sun.COM
6808462SApril.Chin@Sun.COMexit 0
6818462SApril.Chin@Sun.COM#EOF.
682