xref: /onnv-gate/usr/src/lib/libshell/common/scripts/rssread.sh (revision 12068:08a39a083754)
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*12068SRoger.Faulkner@Oracle.COM# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
268462SApril.Chin@Sun.COM#
278462SApril.Chin@Sun.COM
288462SApril.Chin@Sun.COM#
298462SApril.Chin@Sun.COM# rssread - a simple RSS2.0 reader with RSS to XHTML to
308462SApril.Chin@Sun.COM# plaintext conversion.
318462SApril.Chin@Sun.COM#
328462SApril.Chin@Sun.COM
338462SApril.Chin@Sun.COM# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant
348462SApril.Chin@Sun.COMexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin
358462SApril.Chin@Sun.COM
368462SApril.Chin@Sun.COMfunction printmsg
378462SApril.Chin@Sun.COM{
388462SApril.Chin@Sun.COM	print -u2 "$*"
398462SApril.Chin@Sun.COM}
408462SApril.Chin@Sun.COM
418462SApril.Chin@Sun.COMfunction debugmsg
428462SApril.Chin@Sun.COM{
438462SApril.Chin@Sun.COM#	printmsg "$*"
448462SApril.Chin@Sun.COMtrue
458462SApril.Chin@Sun.COM}
468462SApril.Chin@Sun.COM
478462SApril.Chin@Sun.COMfunction fatal_error
488462SApril.Chin@Sun.COM{
498462SApril.Chin@Sun.COM	print -u2 "${progname}: $*"
508462SApril.Chin@Sun.COM	exit 1
518462SApril.Chin@Sun.COM}
528462SApril.Chin@Sun.COM
5310898Sroland.mainz@nrubsig.orgtypeset -T urlconnection_t=(
5410898Sroland.mainz@nrubsig.org	# public
5510898Sroland.mainz@nrubsig.org	typeset user_agent="ksh93/urlconnection_t"
5610898Sroland.mainz@nrubsig.org
5710898Sroland.mainz@nrubsig.org	# private variables
5810898Sroland.mainz@nrubsig.org	typeset protocol
5910898Sroland.mainz@nrubsig.org	typeset path1
6010898Sroland.mainz@nrubsig.org	typeset host
6110898Sroland.mainz@nrubsig.org	typeset path
6210898Sroland.mainz@nrubsig.org	typeset port
6310898Sroland.mainz@nrubsig.org
6410898Sroland.mainz@nrubsig.org	compound netfd=(
6510898Sroland.mainz@nrubsig.org		integer in=-1  # incoming traffic
6610898Sroland.mainz@nrubsig.org		integer out=-1 # outgoing traffic
6710898Sroland.mainz@nrubsig.org	)
688462SApril.Chin@Sun.COM
6910898Sroland.mainz@nrubsig.org	# only used for https
7010898Sroland.mainz@nrubsig.org	compound ssl=(
7110898Sroland.mainz@nrubsig.org		compound fifo=(
7210898Sroland.mainz@nrubsig.org			typeset dir=""
7310898Sroland.mainz@nrubsig.org			typeset in=""
7410898Sroland.mainz@nrubsig.org			typeset out=""
7510898Sroland.mainz@nrubsig.org		)
7610898Sroland.mainz@nrubsig.org		integer openssl_client_pid=-1
7710898Sroland.mainz@nrubsig.org	)
7810898Sroland.mainz@nrubsig.org
7910898Sroland.mainz@nrubsig.org	# parse HTTP return code, cookies etc.
8010898Sroland.mainz@nrubsig.org	function parse_http_response
8110898Sroland.mainz@nrubsig.org	{
8210898Sroland.mainz@nrubsig.org		nameref response="$1"
8310898Sroland.mainz@nrubsig.org		typeset h statuscode statusmsg i
8410898Sroland.mainz@nrubsig.org
8510898Sroland.mainz@nrubsig.org		# we use '\r' as additional IFS to filter the final '\r'
8610898Sroland.mainz@nrubsig.org		IFS=$' \t\r' read -r h statuscode statusmsg # read HTTP/1.[01] <code>
8710898Sroland.mainz@nrubsig.org		[[ "$h" != ~(Eil)HTTP/.* ]]         && { print -u2 -f $"%s: HTTP/ header missing\n" "$0" ; return 1 ; }
8810898Sroland.mainz@nrubsig.org		[[ "$statuscode" != ~(Elr)[0-9]* ]] && { print -u2 -f $"%s: invalid status code\n"  "$0" ; return 1 ; }
8910898Sroland.mainz@nrubsig.org		response.statuscode="$statuscode"
9010898Sroland.mainz@nrubsig.org		response.statusmsg="$statusmsg"
9110898Sroland.mainz@nrubsig.org
9210898Sroland.mainz@nrubsig.org		# skip remaining headers
9310898Sroland.mainz@nrubsig.org		while IFS='' read -r i ; do
9410898Sroland.mainz@nrubsig.org			[[ "$i" == $'\r' ]] && break
958462SApril.Chin@Sun.COM
9610898Sroland.mainz@nrubsig.org			# strip '\r' at the end
9710898Sroland.mainz@nrubsig.org			i="${i/~(Er)$'\r'/}"
988462SApril.Chin@Sun.COM
9910898Sroland.mainz@nrubsig.org			case "$i" in
10010898Sroland.mainz@nrubsig.org				~(Eli)Content-Type:.*)
10110898Sroland.mainz@nrubsig.org					response.content_type="${i/~(El).*:[[:blank:]]*/}"
10210898Sroland.mainz@nrubsig.org					;;
10310898Sroland.mainz@nrubsig.org				~(Eli)Content-Length:[[:blank:]]*[0-9]*)
10410898Sroland.mainz@nrubsig.org					integer response.content_length="${i/~(El).*:[[:blank:]]*/}"
10510898Sroland.mainz@nrubsig.org					;;
10610898Sroland.mainz@nrubsig.org				~(Eli)Transfer-Encoding:.*)
10710898Sroland.mainz@nrubsig.org					response.transfer_encoding="${i/~(El).*:[[:blank:]]*/}"
10810898Sroland.mainz@nrubsig.org					;;
10910898Sroland.mainz@nrubsig.org			esac
11010898Sroland.mainz@nrubsig.org		done
11110898Sroland.mainz@nrubsig.org
11210898Sroland.mainz@nrubsig.org		return 0
11310898Sroland.mainz@nrubsig.org	}
1148462SApril.Chin@Sun.COM
11510898Sroland.mainz@nrubsig.org	function cat_http_body
11610898Sroland.mainz@nrubsig.org	{
11710898Sroland.mainz@nrubsig.org		typeset emode="$1"
11810898Sroland.mainz@nrubsig.org		typeset hexchunksize="0"
11910898Sroland.mainz@nrubsig.org		integer chunksize=0
12010898Sroland.mainz@nrubsig.org
12110898Sroland.mainz@nrubsig.org		if [[ "${emode}" == "chunked" ]] ; then
12210898Sroland.mainz@nrubsig.org			while IFS=$'\n' read hexchunksize ; do
12310898Sroland.mainz@nrubsig.org				hexchunksize="${hexchunksize//$'\r'/}"
12410898Sroland.mainz@nrubsig.org				[[ "${hexchunksize}" != "" ]] || continue
12510898Sroland.mainz@nrubsig.org				[[ "${hexchunksize}" == ~(Elri)[0-9abcdef]+ ]] || break
126*12068SRoger.Faulkner@Oracle.COM				(( chunksize=$( printf "16#%s\n" "${hexchunksize}" )  ))
12710898Sroland.mainz@nrubsig.org				(( chunksize > 0 )) || break
12810898Sroland.mainz@nrubsig.org				dd bs=1 count="${chunksize}" 2>/dev/null
12910898Sroland.mainz@nrubsig.org			done
13010898Sroland.mainz@nrubsig.org		else
13110898Sroland.mainz@nrubsig.org			cat
13210898Sroland.mainz@nrubsig.org		fi
13310898Sroland.mainz@nrubsig.org
13410898Sroland.mainz@nrubsig.org		return 0
13510898Sroland.mainz@nrubsig.org	}
13610898Sroland.mainz@nrubsig.org
13710898Sroland.mainz@nrubsig.org	function init_url
13810898Sroland.mainz@nrubsig.org	{
13910898Sroland.mainz@nrubsig.org		_.protocol="${1%://*}"
14010898Sroland.mainz@nrubsig.org		_.path1="${1#*://}" # "http://foo.bat.net/x/y.html" ----> "foo.bat.net/x/y.html"
1418462SApril.Chin@Sun.COM
14210898Sroland.mainz@nrubsig.org		if  [[ "${_.protocol}" == ~(Elr)http(|s) ]] ; then
14310898Sroland.mainz@nrubsig.org			_.host="${_.path1%%/*}"
14410898Sroland.mainz@nrubsig.org			_.path="${_.path1#*/}"
14510898Sroland.mainz@nrubsig.org			_.port="${_.host##*:}"
14610898Sroland.mainz@nrubsig.org		fi
14710898Sroland.mainz@nrubsig.org
14810898Sroland.mainz@nrubsig.org		return 0
14910898Sroland.mainz@nrubsig.org	}
15010898Sroland.mainz@nrubsig.org
15110898Sroland.mainz@nrubsig.org	# close connection
15210898Sroland.mainz@nrubsig.org	function close_connection
15310898Sroland.mainz@nrubsig.org	{
15410898Sroland.mainz@nrubsig.org		integer ret
15510898Sroland.mainz@nrubsig.org
15610898Sroland.mainz@nrubsig.org		if (( _.netfd.in != -1 )) ; then
15710898Sroland.mainz@nrubsig.org			redirect {_.netfd.in}<&-
15810898Sroland.mainz@nrubsig.org			(( _.netfd.in=-1 ))
15910898Sroland.mainz@nrubsig.org		fi
16010898Sroland.mainz@nrubsig.org
16110898Sroland.mainz@nrubsig.org		if (( _.netfd.in != _.netfd.out && _.netfd.out != -1 )) ; then
16210898Sroland.mainz@nrubsig.org			redirect {_.netfd.out}<&-
16310898Sroland.mainz@nrubsig.org			((  _.netfd.out=-1 ))
16410898Sroland.mainz@nrubsig.org		fi
1658462SApril.Chin@Sun.COM
16610898Sroland.mainz@nrubsig.org		if [[ "${_.protocol}" == "https" ]] ; then
16710898Sroland.mainz@nrubsig.org			wait ${_.ssl.openssl_client_pid} || { print -u2 -f "%s: openssl failed.\n" ; return 1 ; }
16810898Sroland.mainz@nrubsig.org			(( _.ssl.openssl_client_pid=-1 ))
16910898Sroland.mainz@nrubsig.org
17010898Sroland.mainz@nrubsig.org			rm -r \"${_.ssl.fifo.dir}\"
17110898Sroland.mainz@nrubsig.org			_.ssl.fifo.dir=""
17210898Sroland.mainz@nrubsig.org		fi
17310898Sroland.mainz@nrubsig.org
17410898Sroland.mainz@nrubsig.org		return 0
17510898Sroland.mainz@nrubsig.org	}
17610898Sroland.mainz@nrubsig.org
17710898Sroland.mainz@nrubsig.org	function open_connection
17810898Sroland.mainz@nrubsig.org	{
17910898Sroland.mainz@nrubsig.org		if [[ "${_.protocol}" == "https" ]] ; then
180*12068SRoger.Faulkner@Oracle.COM			_.ssl.fifo.dir="$(mktemp -t -d)"
18110898Sroland.mainz@nrubsig.org			_.ssl.fifo.in="${_.ssl.fifo.dir}/in"
18210898Sroland.mainz@nrubsig.org			_.ssl.fifo.out="${_.ssl.fifo.dir}/out"
1838462SApril.Chin@Sun.COM
18410898Sroland.mainz@nrubsig.org			# Use "errexit" to leave it at the first error
18510898Sroland.mainz@nrubsig.org			# (this saves lots of if/fi tests for error checking)
18610898Sroland.mainz@nrubsig.org			set -o errexit
18710898Sroland.mainz@nrubsig.org
18810898Sroland.mainz@nrubsig.org			mkfifo "${_.ssl.fifo.in}" "${_.ssl.fifo.out}"
18910898Sroland.mainz@nrubsig.org
19010898Sroland.mainz@nrubsig.org			# create async openssl child to handle https
19110898Sroland.mainz@nrubsig.org			openssl s_client -quiet -connect "${_.host}:${_.port}" <"${_.ssl.fifo.in}" >>"${_.ssl.fifo.out}" &
19210898Sroland.mainz@nrubsig.org
19310898Sroland.mainz@nrubsig.org			_.ssl.openssl_client_pid=$!
19410898Sroland.mainz@nrubsig.org		else
19510898Sroland.mainz@nrubsig.org			redirect {_.netfd.in}<> "/dev/tcp/${_.host}/${_.port}"
19610898Sroland.mainz@nrubsig.org			(( $? != 0 )) && { print -u2 -f "%s: Could not open %s\n" "$0" "${1}" ; return 1 ; }
19710898Sroland.mainz@nrubsig.org			(( _.netfd.out=_.netfd.in ))
19810898Sroland.mainz@nrubsig.org		fi
19910898Sroland.mainz@nrubsig.org		return 0
20010898Sroland.mainz@nrubsig.org	}
2018462SApril.Chin@Sun.COM
20210898Sroland.mainz@nrubsig.org	function send_request
20310898Sroland.mainz@nrubsig.org	{
20410898Sroland.mainz@nrubsig.org		typeset request="$1"
20510898Sroland.mainz@nrubsig.org
20610898Sroland.mainz@nrubsig.org		set -o errexit
20710898Sroland.mainz@nrubsig.org
20810898Sroland.mainz@nrubsig.org		if [[ "${_.protocol}" == "https" ]] ; then
20910898Sroland.mainz@nrubsig.org				print -n -- "${request}\r\n" >>	"${_.ssl.fifo.in}"
21010898Sroland.mainz@nrubsig.org
21110898Sroland.mainz@nrubsig.org				redirect {_.netfd.in}< "${_.ssl.fifo.out}"
21210898Sroland.mainz@nrubsig.org		else
21310898Sroland.mainz@nrubsig.org				print -n -- "${request}\r\n" >&${_.netfd.out}
21410898Sroland.mainz@nrubsig.org		fi
21510898Sroland.mainz@nrubsig.org		return 0
21610898Sroland.mainz@nrubsig.org	}
21710898Sroland.mainz@nrubsig.org
21810898Sroland.mainz@nrubsig.org	function cat_url
21910898Sroland.mainz@nrubsig.org	{
22010898Sroland.mainz@nrubsig.org		if [[ "${_.protocol}" == "file" ]] ; then
22110898Sroland.mainz@nrubsig.org			cat "${_.path1}"
22210898Sroland.mainz@nrubsig.org			return $?
22310898Sroland.mainz@nrubsig.org		elif [[ "${_.protocol}" == ~(Elr)http(|s) ]] ; then
22410898Sroland.mainz@nrubsig.org			compound httpresponse # http response
2258462SApril.Chin@Sun.COM
22610898Sroland.mainz@nrubsig.org			# If URL did not contain a port number in the host part then look at the
22710898Sroland.mainz@nrubsig.org			# protocol to get the port number
22810898Sroland.mainz@nrubsig.org			if [[ "${_.port}" == "${_.host}" ]] ; then
22910898Sroland.mainz@nrubsig.org				case "${_.protocol}" in
23010898Sroland.mainz@nrubsig.org					"http")  _.port=80 ;;
23110898Sroland.mainz@nrubsig.org					"https") _.port=443 ;;
23210898Sroland.mainz@nrubsig.org					*)       _.port="$(getent services "${_.protocol}" | sed 's/[^0-9]*//;s/\/.*//')" ;;
23310898Sroland.mainz@nrubsig.org				esac
23410898Sroland.mainz@nrubsig.org			else
23510898Sroland.mainz@nrubsig.org				_.host="${_.host%:*}"
23610898Sroland.mainz@nrubsig.org			fi
23710898Sroland.mainz@nrubsig.org
23810898Sroland.mainz@nrubsig.org			printmsg "protocol=${_.protocol} port=${_.port} host=${_.host} path=${_.path}"
23910898Sroland.mainz@nrubsig.org
24010898Sroland.mainz@nrubsig.org			# prechecks
24110898Sroland.mainz@nrubsig.org			[[ "${_.protocol}" != "" ]] || { print -u2 -f "%s: protocol not set.\n" "$0" ; return 1 ; }
24210898Sroland.mainz@nrubsig.org			[[ "${_.port}"     != "" ]] || { print -u2 -f "%s: port not set.\n"     "$0" ; return 1 ; }
24310898Sroland.mainz@nrubsig.org			[[ "${_.host}"     != "" ]] || { print -u2 -f "%s: host not set.\n"     "$0" ; return 1 ; }
24410898Sroland.mainz@nrubsig.org			[[ "${_.path}"     != "" ]] || { print -u2 -f "%s: path not set.\n"     "$0" ; return 1 ; }
24510898Sroland.mainz@nrubsig.org
246*12068SRoger.Faulkner@Oracle.COM			_.open_connection || return 1
2478462SApril.Chin@Sun.COM
24810898Sroland.mainz@nrubsig.org			# send HTTP request
24910898Sroland.mainz@nrubsig.org			request="GET /${_.path} HTTP/1.1\r\n"
25010898Sroland.mainz@nrubsig.org			request+="Host: ${_.host}\r\n"
25110898Sroland.mainz@nrubsig.org			request+="User-Agent: ${_.user_agent}\r\n"
25210898Sroland.mainz@nrubsig.org			request+="Connection: close\r\n"
25310898Sroland.mainz@nrubsig.org			_.send_request "${request}\r\n"
25410898Sroland.mainz@nrubsig.org
25510898Sroland.mainz@nrubsig.org			# collect response and send it to stdout
25610898Sroland.mainz@nrubsig.org			{
25710898Sroland.mainz@nrubsig.org				_.parse_http_response httpresponse
25810898Sroland.mainz@nrubsig.org				_.cat_http_body "${httpresponse.transfer_encoding}"
25910898Sroland.mainz@nrubsig.org			} <&${_.netfd.in}
26010898Sroland.mainz@nrubsig.org
26110898Sroland.mainz@nrubsig.org			_.close_connection
26210898Sroland.mainz@nrubsig.org
26310898Sroland.mainz@nrubsig.org			return 0
26410898Sroland.mainz@nrubsig.org		else
26510898Sroland.mainz@nrubsig.org			return 1
26610898Sroland.mainz@nrubsig.org		fi
26710898Sroland.mainz@nrubsig.org		# notreached
26810898Sroland.mainz@nrubsig.org	}
26910898Sroland.mainz@nrubsig.org)
2708462SApril.Chin@Sun.COM
2718462SApril.Chin@Sun.COMfunction html_entity_to_ascii
2728462SApril.Chin@Sun.COM{
2738462SApril.Chin@Sun.COM	typeset buf
2748462SApril.Chin@Sun.COM	typeset entity
2758462SApril.Chin@Sun.COM	typeset c
2768462SApril.Chin@Sun.COM	typeset value
2778462SApril.Chin@Sun.COM
2788462SApril.Chin@Sun.COM	# Todo: Add more HTML/MathML entities here
2798462SApril.Chin@Sun.COM	# Note we use a static variable (typeset -S) here to make sure we
2808462SApril.Chin@Sun.COM	# don't loose the cache data between calls
2818462SApril.Chin@Sun.COM	typeset -S -A entity_cache=(
2828462SApril.Chin@Sun.COM		# entity to ascii (fixme: add UTF-8 transliterations)
2838462SApril.Chin@Sun.COM		["nbsp"]=' '
2848462SApril.Chin@Sun.COM		["lt"]='<'
2858462SApril.Chin@Sun.COM		["le"]='<='
2868462SApril.Chin@Sun.COM		["gt"]='>'
2878462SApril.Chin@Sun.COM		["ge"]='>='
2888462SApril.Chin@Sun.COM		["amp"]='&'
2898462SApril.Chin@Sun.COM		["quot"]='"'
2908462SApril.Chin@Sun.COM		["apos"]="'"
2918462SApril.Chin@Sun.COM	)
2928462SApril.Chin@Sun.COM
2938462SApril.Chin@Sun.COM	buf=""
2948462SApril.Chin@Sun.COM	while IFS='' read -r -N 1 c ; do
2958462SApril.Chin@Sun.COM		if [[ "$c" != "&" ]] ; then
2968462SApril.Chin@Sun.COM			print -n -r -- "${c}"
2978462SApril.Chin@Sun.COM			continue
2988462SApril.Chin@Sun.COM		fi
2998462SApril.Chin@Sun.COM
3008462SApril.Chin@Sun.COM		entity=""
3018462SApril.Chin@Sun.COM		while IFS='' read -r -N 1 c ; do
3028462SApril.Chin@Sun.COM			case "$c" in
3038462SApril.Chin@Sun.COM				";")
3048462SApril.Chin@Sun.COM				break
3058462SApril.Chin@Sun.COM				;;
3068462SApril.Chin@Sun.COM			~(Eilr)[a-z0-9#])
3078462SApril.Chin@Sun.COM				entity+="$c"
3088462SApril.Chin@Sun.COM				continue
3098462SApril.Chin@Sun.COM				;;
3108462SApril.Chin@Sun.COM			*)
3118462SApril.Chin@Sun.COM#				debugmsg "error &${entity}${c}#"
3128462SApril.Chin@Sun.COM
3138462SApril.Chin@Sun.COM				print -n -r -- "${entity}${c}"
3148462SApril.Chin@Sun.COM				entity=""
3158462SApril.Chin@Sun.COM				continue 2
3168462SApril.Chin@Sun.COM				;;
3178462SApril.Chin@Sun.COM			esac
3188462SApril.Chin@Sun.COM		done
3198462SApril.Chin@Sun.COM
3208462SApril.Chin@Sun.COM		value=""
3218462SApril.Chin@Sun.COM		if [[ "${entity_cache["${entity}"]}" != "" ]] ; then
3228462SApril.Chin@Sun.COM#			debugmsg "match #${entity}# = #${entity_cache["${entity}"]}#"
3238462SApril.Chin@Sun.COM			value="${entity_cache["${entity}"]}"
3248462SApril.Chin@Sun.COM		else
3258462SApril.Chin@Sun.COM			if [[ "${entity:0:1}" == "#" ]] ; then
3268462SApril.Chin@Sun.COM				# decimal literal
3278462SApril.Chin@Sun.COM				value="${ printf "\u[${ printf "%x" "${entity:1:8}" ; }]" ; }"
3288462SApril.Chin@Sun.COM			elif [[ "${entity:0:7}" == ~(Eilr)[0-9a-f]* ]] ; then
3298462SApril.Chin@Sun.COM				# hexadecimal literal
3308462SApril.Chin@Sun.COM				value="${ printf "\u[${entity:0:7}]" ; }"
3318462SApril.Chin@Sun.COM			else
3328462SApril.Chin@Sun.COM				# unknown literal - pass-through
3338462SApril.Chin@Sun.COM				value="ENT=|${entity}|"
3348462SApril.Chin@Sun.COM			fi
3358462SApril.Chin@Sun.COM
3368462SApril.Chin@Sun.COM			entity_cache["${entity}"]="${value}"
3378462SApril.Chin@Sun.COM
3388462SApril.Chin@Sun.COM#			debugmsg "lookup #${entity}# = #${entity_cache["${entity}"]}#"
3398462SApril.Chin@Sun.COM		fi
3408462SApril.Chin@Sun.COM
3418462SApril.Chin@Sun.COM		printf "%s" "${value}"
3428462SApril.Chin@Sun.COM	done
3438462SApril.Chin@Sun.COM
3448462SApril.Chin@Sun.COM	return 0
3458462SApril.Chin@Sun.COM}
3468462SApril.Chin@Sun.COM
3478462SApril.Chin@Sun.COM# dumb xhtml handler - no CSS,  tables, images, iframes or nested
3488462SApril.Chin@Sun.COM# structures are supported (and we assume that the input is correct
3498462SApril.Chin@Sun.COM# xhtml). The code was written in a trial&&error manner and should be
3508462SApril.Chin@Sun.COM# rewritten to parse xhtml correctly.
3518462SApril.Chin@Sun.COMfunction handle_html
3528462SApril.Chin@Sun.COM{
3538462SApril.Chin@Sun.COM    # we can't use global variables here when multiple callbacks use the same
3548462SApril.Chin@Sun.COM    # callback function - but we can use the callback associative array for
3558462SApril.Chin@Sun.COM    # variable storage instead
3568462SApril.Chin@Sun.COM    nameref callbacks=${1}
3578462SApril.Chin@Sun.COM    typeset tag_type="$2"
3588462SApril.Chin@Sun.COM    typeset tag_value="$3"
3598462SApril.Chin@Sun.COM
3608462SApril.Chin@Sun.COM    case "${tag_type}" in
3618462SApril.Chin@Sun.COM        tag_begin)
3628462SApril.Chin@Sun.COM            case "${tag_value}" in
3638462SApril.Chin@Sun.COM                br) printf "\n" ;;
3648462SApril.Chin@Sun.COM                hr) printf "\n-------------------------------------\n" ;;
3658462SApril.Chin@Sun.COM                pre) callbacks["html_pre"]='true' ;;
3668462SApril.Chin@Sun.COM                p)  printf "\n" ;;
3678462SApril.Chin@Sun.COM            esac
3688462SApril.Chin@Sun.COM            ;;
3698462SApril.Chin@Sun.COM
3708462SApril.Chin@Sun.COM        tag_end)
3718462SApril.Chin@Sun.COM            case "${tag_value}" in
3728462SApril.Chin@Sun.COM                pre) callbacks["html_pre"]='false' ;;
3738462SApril.Chin@Sun.COM            esac
3748462SApril.Chin@Sun.COM            ;;
3758462SApril.Chin@Sun.COM
3768462SApril.Chin@Sun.COM        tag_text)
3778462SApril.Chin@Sun.COM            if ${callbacks["html_pre"]} ; then
3788462SApril.Chin@Sun.COM                printf "%s" "${tag_value}"
3798462SApril.Chin@Sun.COM            else
3808462SApril.Chin@Sun.COM                # compress spaces/newlines/tabs/etc.
3818462SApril.Chin@Sun.COM                printf "%s" "${tag_value//+([\n\r\t\v[:space:][:blank:]])/ }"
3828462SApril.Chin@Sun.COM            fi
3838462SApril.Chin@Sun.COM            ;;
3848462SApril.Chin@Sun.COM
3858462SApril.Chin@Sun.COM        document_start)
3868462SApril.Chin@Sun.COM            callbacks["html_pre"]='false'
3878462SApril.Chin@Sun.COM            ;;
3888462SApril.Chin@Sun.COM        document_end) ;;
3898462SApril.Chin@Sun.COM    esac
3908462SApril.Chin@Sun.COM
3918462SApril.Chin@Sun.COM    return 0
3928462SApril.Chin@Sun.COM}
3938462SApril.Chin@Sun.COM
3948462SApril.Chin@Sun.COMfunction handle_rss
3958462SApril.Chin@Sun.COM{
3968462SApril.Chin@Sun.COM	# we can't use global variables here when multiple callbacks use the same
3978462SApril.Chin@Sun.COM	# callback function - but we can use the callback associative array for
3988462SApril.Chin@Sun.COM	# variable storage instead
3998462SApril.Chin@Sun.COM	nameref callbacks=${1}
4008462SApril.Chin@Sun.COM	typeset tag_type="$2"
4018462SApril.Chin@Sun.COM	typeset tag_value="$3"
4028462SApril.Chin@Sun.COM
4038462SApril.Chin@Sun.COM	case "${tag_type}" in
4048462SApril.Chin@Sun.COM		tag_begin)
4058462SApril.Chin@Sun.COM			case "${tag_value}" in
4068462SApril.Chin@Sun.COM				item)
4078462SApril.Chin@Sun.COM					item["title"]=""
4088462SApril.Chin@Sun.COM					item["link"]=""
4098462SApril.Chin@Sun.COM					item["tag"]=""
4108462SApril.Chin@Sun.COM					item["description"]=""
4118462SApril.Chin@Sun.COM					;;
4128462SApril.Chin@Sun.COM			esac
4138462SApril.Chin@Sun.COM			callbacks["textbuf"]=""
4148462SApril.Chin@Sun.COM			;;
4158462SApril.Chin@Sun.COM		tag_end)
4168462SApril.Chin@Sun.COM			case "${tag_value}" in
4178462SApril.Chin@Sun.COM				item)
4188462SApril.Chin@Sun.COM					# note that each RSS item needs to be converted seperately from RSS to HTML to plain text
4198462SApril.Chin@Sun.COM					# to make sure that the state of one RSS item doesn't affect others
4208462SApril.Chin@Sun.COM					(
4218462SApril.Chin@Sun.COM						printf $"<br />#### RSS item: title: %s ####" "${item["title"]}"
4228462SApril.Chin@Sun.COM						printf $"<br />## author: %s" "${item["author"]}"
4238462SApril.Chin@Sun.COM						printf $"<br />## link:   %s" "${item["link"]}"
4248462SApril.Chin@Sun.COM						printf $"<br />## date:   %s" "${item["pubDate"]}"
4258462SApril.Chin@Sun.COM						printf $"<br />## begin description:"
4268462SApril.Chin@Sun.COM						printf $"<br />%s<br />" "${item["description"]}"
4278462SApril.Chin@Sun.COM						printf $"<br />## end description<br />"
4288462SApril.Chin@Sun.COM						print # extra newline to make sure the sed pipeline gets flushed
4298462SApril.Chin@Sun.COM					) |
4308462SApril.Chin@Sun.COM						html_entity_to_ascii |	# convert XML entities (e.g. decode RSS content to HTML code)
4318462SApril.Chin@Sun.COM						xml_tok "xhtmltok_cb" |	# convert HTML to plain text
4328462SApril.Chin@Sun.COM						html_entity_to_ascii	# convert HTML entities
4338462SApril.Chin@Sun.COM					;;
4348462SApril.Chin@Sun.COM				title)                item["title"]="${callbacks["textbuf"]}"        ; callbacks["textbuf"]="" ;;
4358462SApril.Chin@Sun.COM				link)                 item["link"]="${callbacks["textbuf"]}"         ; callbacks["textbuf"]="" ;;
4368462SApril.Chin@Sun.COM				dc:creator | author)  item["author"]="${callbacks["textbuf"]}"       ; callbacks["textbuf"]="" ;;
4378462SApril.Chin@Sun.COM				dc:date | pubDate)    item["pubDate"]="${callbacks["textbuf"]}"      ; callbacks["textbuf"]="" ;;
4388462SApril.Chin@Sun.COM				description)          item["description"]="${callbacks["textbuf"]}"  ; callbacks["textbuf"]="" ;;
4398462SApril.Chin@Sun.COM			esac
4408462SApril.Chin@Sun.COM			callbacks["textbuf"]=""
4418462SApril.Chin@Sun.COM			;;
4428462SApril.Chin@Sun.COM		tag_text)
4438462SApril.Chin@Sun.COM			callbacks["textbuf"]+="${tag_value}"
4448462SApril.Chin@Sun.COM			;;
4458462SApril.Chin@Sun.COM		document_start) ;;
4468462SApril.Chin@Sun.COM		document_end) ;;
4478462SApril.Chin@Sun.COM	esac
4488462SApril.Chin@Sun.COM	return 0
4498462SApril.Chin@Sun.COM}
4508462SApril.Chin@Sun.COM
4518462SApril.Chin@Sun.COMfunction xml_tok
4528462SApril.Chin@Sun.COM{
4538462SApril.Chin@Sun.COM    typeset buf=""
4548462SApril.Chin@Sun.COM    typeset namebuf=""
4558462SApril.Chin@Sun.COM    typeset attrbuf=""
4568462SApril.Chin@Sun.COM    typeset c=""
4578462SApril.Chin@Sun.COM    typeset isendtag # bool: true/false
4588462SApril.Chin@Sun.COM    typeset issingletag # bool: true/false (used for tags like "<br />")
4598462SApril.Chin@Sun.COM    nameref callbacks=${1}
4608462SApril.Chin@Sun.COM
4618462SApril.Chin@Sun.COM    [[ ! -z "${callbacks["document_start"]}" ]] && ${callbacks["document_start"]} "${1}" "document_start"
4628462SApril.Chin@Sun.COM
4638462SApril.Chin@Sun.COM    while IFS='' read -r -N 1 c ; do
4648462SApril.Chin@Sun.COM        isendtag=false
4658462SApril.Chin@Sun.COM
4668462SApril.Chin@Sun.COM        if [[ "$c" == "<" ]] ; then
4678462SApril.Chin@Sun.COM	    # flush any text content
4688462SApril.Chin@Sun.COM            if [[ "$buf" != "" ]] ; then
4698462SApril.Chin@Sun.COM                [[ ! -z "${callbacks["tag_text"]}" ]] && ${callbacks["tag_text"]} "${1}" "tag_text" "$buf"
4708462SApril.Chin@Sun.COM                buf=""
4718462SApril.Chin@Sun.COM            fi
4728462SApril.Chin@Sun.COM
4738462SApril.Chin@Sun.COM            IFS='' read -r -N 1 c
4748462SApril.Chin@Sun.COM            if [[ "$c" == "/" ]] ; then
4758462SApril.Chin@Sun.COM                isendtag=true
4768462SApril.Chin@Sun.COM            else
4778462SApril.Chin@Sun.COM                buf="$c"
4788462SApril.Chin@Sun.COM            fi
4798462SApril.Chin@Sun.COM            IFS='' read -r -d '>' c
4808462SApril.Chin@Sun.COM            buf+="$c"
4818462SApril.Chin@Sun.COM
4828462SApril.Chin@Sun.COM	    # handle comments
4838462SApril.Chin@Sun.COM	    if [[ "$buf" == ~(El)!-- ]] ; then
4848462SApril.Chin@Sun.COM	        # did we read the comment completely ?
4858462SApril.Chin@Sun.COM	        if [[ "$buf" != ~(Elr)!--.*-- ]] ; then
4868462SApril.Chin@Sun.COM		    buf+=">"
4878462SApril.Chin@Sun.COM	            while [[ "$buf" != ~(Elr)!--.*-- ]] ; do
4888462SApril.Chin@Sun.COM		        IFS='' read -r -N 1 c || break
4898462SApril.Chin@Sun.COM		        buf+="$c"
4908462SApril.Chin@Sun.COM		    done
4918462SApril.Chin@Sun.COM		fi
4928462SApril.Chin@Sun.COM
4938462SApril.Chin@Sun.COM		[[ ! -z "${callbacks["tag_comment"]}" ]] && ${callbacks["tag_comment"]} "${1}" "tag_comment" "${buf:3:${#buf}-5}"
4948462SApril.Chin@Sun.COM		buf=""
4958462SApril.Chin@Sun.COM		continue
4968462SApril.Chin@Sun.COM	    fi
4978462SApril.Chin@Sun.COM
4988462SApril.Chin@Sun.COM	    # check if the tag starts and ends at the same time (like "<br />")
4998462SApril.Chin@Sun.COM	    if [[ "${buf}" == ~(Er).*/ ]] ; then
5008462SApril.Chin@Sun.COM	        issingletag=true
5018462SApril.Chin@Sun.COM		buf="${buf%*/}"
5028462SApril.Chin@Sun.COM	    else
5038462SApril.Chin@Sun.COM	        issingletag=false
5048462SApril.Chin@Sun.COM	    fi
5058462SApril.Chin@Sun.COM
5068462SApril.Chin@Sun.COM	    # check if the tag has attributes (e.g. space after name)
5078462SApril.Chin@Sun.COM	    if [[ "$buf" == ~(E)[[:space:][:blank:]] ]] ; then
5088462SApril.Chin@Sun.COM	        namebuf="${buf%%~(E)[[:space:][:blank:]].*}"
5098462SApril.Chin@Sun.COM                attrbuf="${buf#~(E).*[[:space:][:blank:]]}"
5108462SApril.Chin@Sun.COM            else
5118462SApril.Chin@Sun.COM	        namebuf="$buf"
5128462SApril.Chin@Sun.COM		attrbuf=""
5138462SApril.Chin@Sun.COM	    fi
5148462SApril.Chin@Sun.COM
5158462SApril.Chin@Sun.COM            if ${isendtag} ; then
5168462SApril.Chin@Sun.COM                [[ ! -z "${callbacks["tag_end"]}" ]] && ${callbacks["tag_end"]} "${1}" "tag_end" "$namebuf"
5178462SApril.Chin@Sun.COM            else
5188462SApril.Chin@Sun.COM                [[ ! -z "${callbacks["tag_begin"]}" ]] && ${callbacks["tag_begin"]} "${1}" "tag_begin" "$namebuf" "$attrbuf"
5198462SApril.Chin@Sun.COM
5208462SApril.Chin@Sun.COM                # handle tags like <br/> (which are start- and end-tag in one piece)
5218462SApril.Chin@Sun.COM                if ${issingletag} ; then
5228462SApril.Chin@Sun.COM                    [[ ! -z "${callbacks["tag_end"]}" ]] && ${callbacks["tag_end"]} "${1}" "tag_end" "$namebuf"
5238462SApril.Chin@Sun.COM                fi
5248462SApril.Chin@Sun.COM            fi
5258462SApril.Chin@Sun.COM            buf=""
5268462SApril.Chin@Sun.COM        else
5278462SApril.Chin@Sun.COM            buf+="$c"
5288462SApril.Chin@Sun.COM        fi
5298462SApril.Chin@Sun.COM    done
5308462SApril.Chin@Sun.COM
5318462SApril.Chin@Sun.COM    [[ ! -z "${callbacks["document_end"]}" ]] && ${callbacks["document_end"]} "${1}" "document_end" "exit_success"
5328462SApril.Chin@Sun.COM
5338462SApril.Chin@Sun.COM    print # final newline to make filters like "sed" happy
5348462SApril.Chin@Sun.COM}
5358462SApril.Chin@Sun.COM
5368462SApril.Chin@Sun.COM# return the value of LC_MESSAGES needed for subprocesses which
5378462SApril.Chin@Sun.COM# want to run in a different locale/encoding
5388462SApril.Chin@Sun.COMfunction get_lc_messages
5398462SApril.Chin@Sun.COM{
5408462SApril.Chin@Sun.COM	[[ "${LC_ALL}"       != "" ]] && { print "${LC_ALL}"      ; return 0 ; }
5418462SApril.Chin@Sun.COM	[[ "${LC_MESSAGES}"  != "" ]] && { print "${LC_MESSAGES}" ; return 0 ; }
5428462SApril.Chin@Sun.COM	[[ "${LANG}"         != "" ]] && { print "${LANG}"        ; return 0 ; }
5438462SApril.Chin@Sun.COM	print "C" ; return 0
5448462SApril.Chin@Sun.COM}
5458462SApril.Chin@Sun.COM
5468462SApril.Chin@Sun.COMfunction do_rssread
5478462SApril.Chin@Sun.COM{
5488462SApril.Chin@Sun.COM	# set unicode locale since RSS is encoded in UTF-8
5498462SApril.Chin@Sun.COM	# (and make sure $LC_MESSAGES is set to the parent
5508462SApril.Chin@Sun.COM	# process's locale that all error messages are using
5518462SApril.Chin@Sun.COM	# the callers locale/encoding)
5528462SApril.Chin@Sun.COM	export \
5538462SApril.Chin@Sun.COM		LC_MESSAGES="${ get_lc_messages ; }" \
5548462SApril.Chin@Sun.COM		LC_MONETARY="en_US.UTF-8" \
5558462SApril.Chin@Sun.COM		LC_NUMERIC="en_US.UTF-8" \
5568462SApril.Chin@Sun.COM		LC_COLLATE="en_US.UTF-8" \
5578462SApril.Chin@Sun.COM		LC_CTYPE="en_US.UTF-8" \
5588462SApril.Chin@Sun.COM		LC_TIME="en_US.UTF-8" \
5598462SApril.Chin@Sun.COM		LANG="en_US.UTF-8"
5608462SApril.Chin@Sun.COM
56110898Sroland.mainz@nrubsig.org	# return non-zero exit code for this function if the rss processing below fails
56210898Sroland.mainz@nrubsig.org	set -o errexit
56310898Sroland.mainz@nrubsig.org
56410898Sroland.mainz@nrubsig.org	urlconnection_t hc
565*12068SRoger.Faulkner@Oracle.COM	hc.user_agent="rssread/ksh93(ssl) (2010-03-27; $(uname -s -r -p))"
56610898Sroland.mainz@nrubsig.org	hc.init_url "$1"
56710898Sroland.mainz@nrubsig.org
56810898Sroland.mainz@nrubsig.org	# need extra newline after cat_url to terminate line with $'\n'
5698462SApril.Chin@Sun.COM	# to make "xml_tok" happy
57010898Sroland.mainz@nrubsig.org	data="${ hc.cat_url ; print ; }"
57110898Sroland.mainz@nrubsig.org
57210898Sroland.mainz@nrubsig.org	print -u2 -f "# Got %d lines of RSS data, processing...\n" "${ wc -l <<< "${data}" ; }"
57310898Sroland.mainz@nrubsig.org
57410898Sroland.mainz@nrubsig.org	xml_tok "rsstok_cb" <<< "${data}"
57510898Sroland.mainz@nrubsig.org
5768462SApril.Chin@Sun.COM	return 0
5778462SApril.Chin@Sun.COM}
5788462SApril.Chin@Sun.COM
5798462SApril.Chin@Sun.COMfunction usage
5808462SApril.Chin@Sun.COM{
5818462SApril.Chin@Sun.COM	OPTIND=0
5828462SApril.Chin@Sun.COM	getopts -a "${progname}" "${rssread_usage}" OPT '-?'
5838462SApril.Chin@Sun.COM	exit 2
5848462SApril.Chin@Sun.COM}
5858462SApril.Chin@Sun.COM
5868462SApril.Chin@Sun.COM# make sure we use the ksh93 builtin versions
5878462SApril.Chin@Sun.COMbuiltin basename
5888462SApril.Chin@Sun.COMbuiltin cat
58910898Sroland.mainz@nrubsig.orgbuiltin mkfifo
5908462SApril.Chin@Sun.COM
5918462SApril.Chin@Sun.COMtypeset -A rsstok_cb # callbacks for xml_tok
5928462SApril.Chin@Sun.COMrsstok_cb["tag_begin"]="handle_rss"
5938462SApril.Chin@Sun.COMrsstok_cb["tag_end"]="handle_rss"
5948462SApril.Chin@Sun.COMrsstok_cb["tag_text"]="handle_rss"
5958462SApril.Chin@Sun.COMrsstok_cb["textbuf"]=""
5968462SApril.Chin@Sun.COM
5978462SApril.Chin@Sun.COMtypeset -A xhtmltok_cb # callbacks for xml_tok
5988462SApril.Chin@Sun.COMxhtmltok_cb["tag_begin"]="handle_html"
5998462SApril.Chin@Sun.COMxhtmltok_cb["tag_end"]="handle_html"
6008462SApril.Chin@Sun.COMxhtmltok_cb["tag_text"]="handle_html"
6018462SApril.Chin@Sun.COMxhtmltok_cb["textbuf"]=""
6028462SApril.Chin@Sun.COMxhtmltok_cb["html_pre"]='false'
6038462SApril.Chin@Sun.COM
6048462SApril.Chin@Sun.COMtypeset -A item
6058462SApril.Chin@Sun.COM
6068462SApril.Chin@Sun.COMtypeset -A bookmark_urls
6078462SApril.Chin@Sun.COM
6088462SApril.Chin@Sun.COM# "ramdom" urls for testing
6098462SApril.Chin@Sun.COMbookmark_urls=(
6108462SApril.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"
6118462SApril.Chin@Sun.COM	# some Sun staff/sites
6128462SApril.Chin@Sun.COM	["blogs_sun_com"]="http://blogs.sun.com/main/feed/entries/rss"
6138462SApril.Chin@Sun.COM	["bigadmin"]="http://www.sun.com/bigadmin/content/rss/motd.xml"
61410898Sroland.mainz@nrubsig.org	["bigadmin_scripts"]="https://www.sun.com/bigadmin/content/rss/scripts.xml"
6158462SApril.Chin@Sun.COM	["jmcp"]="http://www.jmcp.homeunix.com/roller/jmcp/feed/entries/rss"
6168462SApril.Chin@Sun.COM	["katakai"]="http://blogs.sun.com/katakai/feed/entries/rss"
6178462SApril.Chin@Sun.COM	["alanc"]="http://blogs.sun.com/alanc/feed/entries/rss"
6188462SApril.Chin@Sun.COM	["planetsun"]="http://www.planetsun.org/rss20.xml"
6198462SApril.Chin@Sun.COM	["planetsolaris"]="http://www.planetsolaris.org/rss20.xml"
6208462SApril.Chin@Sun.COM	["planetopensolaris"]="http://planet.opensolaris.org/rss20.xml"
6218462SApril.Chin@Sun.COM	["theregister_uk"]="http://www.theregister.co.uk/headlines.rss"
6228462SApril.Chin@Sun.COM	["heise"]="http://www.heise.de/newsticker/heise.rdf"
6238462SApril.Chin@Sun.COM	["slashdot"]="http://rss.slashdot.org/Slashdot/slashdot"
62410898Sroland.mainz@nrubsig.org	["wikipedia_command_shells"]="http://en.wikipedia.org/w/index.php?title=Comparison_of_command_shells&feed=rss&action=history"
6258462SApril.Chin@Sun.COM)
6268462SApril.Chin@Sun.COM
6278462SApril.Chin@Sun.COMtypeset progname="${ basename "${0}" ; }"
6288462SApril.Chin@Sun.COM
6298462SApril.Chin@Sun.COMtypeset -r rssread_usage=$'+
630*12068SRoger.Faulkner@Oracle.COM[-?\n@(#)\$Id: rssread (Roland Mainz) 2010-03-27 \$\n]
6318462SApril.Chin@Sun.COM[-author?Roland Mainz <roland.mainz@sun.com>]
6328462SApril.Chin@Sun.COM[-author?Roland Mainz <roland.mainz@nrubsig.org>]
6338462SApril.Chin@Sun.COM[+NAME?rssread - fetch RSS messages and convert them to plain text]
6348462SApril.Chin@Sun.COM[+DESCRIPTION?\brssread\b RSS to plain text converter
6358462SApril.Chin@Sun.COM        which fetches RSS streams via HTTP and converts them from
6368462SApril.Chin@Sun.COM	RSS to HTML to plain text in the current locale/encoding.]
6378462SApril.Chin@Sun.COM[I:noiconv?Do not convert data from UTF-8 to current locale/encoding.]
6388462SApril.Chin@Sun.COM
6398462SApril.Chin@Sun.COM[ url ]
6408462SApril.Chin@Sun.COM
6418462SApril.Chin@Sun.COM[+SEE ALSO?\bksh93\b(1), \bshnote\b(1)]
6428462SApril.Chin@Sun.COM'
6438462SApril.Chin@Sun.COM
6448462SApril.Chin@Sun.COMtypeset noiconv=false
6458462SApril.Chin@Sun.COM
6468462SApril.Chin@Sun.COMwhile getopts -a "${progname}" "${rssread_usage}" OPT ; do
6478462SApril.Chin@Sun.COM#	printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|"
6488462SApril.Chin@Sun.COM	case ${OPT} in
6498462SApril.Chin@Sun.COM		I)    noiconv=true  ;;
6508462SApril.Chin@Sun.COM		+I)   noiconv=false ;;
6518462SApril.Chin@Sun.COM		*)    usage ;;
6528462SApril.Chin@Sun.COM	esac
6538462SApril.Chin@Sun.COMdone
6548462SApril.Chin@Sun.COMshift $((OPTIND-1))
6558462SApril.Chin@Sun.COM
6568462SApril.Chin@Sun.COMtypeset url="$1"
6578462SApril.Chin@Sun.COM
6588462SApril.Chin@Sun.COMif [[ "${url}" == "" ]] ; then
6598462SApril.Chin@Sun.COM	fatal_error $"No url given."
6608462SApril.Chin@Sun.COMfi
6618462SApril.Chin@Sun.COM
6628462SApril.Chin@Sun.COMif [[ "${bookmark_urls[${url}]}" != "" ]] ; then
6638462SApril.Chin@Sun.COM	printmsg $"Using bookmark ${url} = ${bookmark_urls[${url}]}"
6648462SApril.Chin@Sun.COM	url="${bookmark_urls[${url}]}"
6658462SApril.Chin@Sun.COMfi
6668462SApril.Chin@Sun.COM
6678462SApril.Chin@Sun.COMif ${noiconv} ; then
6688462SApril.Chin@Sun.COM	do_rssread "${url}"
6698462SApril.Chin@Sun.COMelse
6708462SApril.Chin@Sun.COM	do_rssread "${url}" | iconv -f "UTF-8" - -
6718462SApril.Chin@Sun.COMfi
6728462SApril.Chin@Sun.COM
6738462SApril.Chin@Sun.COMexit 0
6748462SApril.Chin@Sun.COM#EOF.
675