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