17c2fbfb3SApril Chin#!/usr/bin/ksh93 27c2fbfb3SApril Chin 37c2fbfb3SApril Chin# 47c2fbfb3SApril Chin# CDDL HEADER START 57c2fbfb3SApril Chin# 67c2fbfb3SApril Chin# The contents of this file are subject to the terms of the 77c2fbfb3SApril Chin# Common Development and Distribution License (the "License"). 87c2fbfb3SApril Chin# You may not use this file except in compliance with the License. 97c2fbfb3SApril Chin# 107c2fbfb3SApril Chin# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 117c2fbfb3SApril Chin# or http://www.opensolaris.org/os/licensing. 127c2fbfb3SApril Chin# See the License for the specific language governing permissions 137c2fbfb3SApril Chin# and limitations under the License. 147c2fbfb3SApril Chin# 157c2fbfb3SApril Chin# When distributing Covered Code, include this CDDL HEADER in each 167c2fbfb3SApril Chin# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 177c2fbfb3SApril Chin# If applicable, add the following below this CDDL HEADER, with the 187c2fbfb3SApril Chin# fields enclosed by brackets "[]" replaced with your own identifying 197c2fbfb3SApril Chin# information: Portions Copyright [yyyy] [name of copyright owner] 207c2fbfb3SApril Chin# 217c2fbfb3SApril Chin# CDDL HEADER END 227c2fbfb3SApril Chin# 237c2fbfb3SApril Chin 247c2fbfb3SApril Chin# 25*3e14f97fSRoger A. Faulkner# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 267c2fbfb3SApril Chin# 277c2fbfb3SApril Chin 287c2fbfb3SApril Chin# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant 297c2fbfb3SApril Chinexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin 307c2fbfb3SApril Chin 317c2fbfb3SApril Chin# Make sure all math stuff runs in the "C" locale to avoid problems 327c2fbfb3SApril Chin# with alternative # radix point representations (e.g. ',' instead of 337c2fbfb3SApril Chin# '.' in de_DE.*-locales). This needs to be set _before_ any 347c2fbfb3SApril Chin# floating-point constants are defined in this script). 357c2fbfb3SApril Chinif [[ "${LC_ALL}" != "" ]] ; then 367c2fbfb3SApril Chin export \ 377c2fbfb3SApril Chin LC_MONETARY="${LC_ALL}" \ 387c2fbfb3SApril Chin LC_MESSAGES="${LC_ALL}" \ 397c2fbfb3SApril Chin LC_COLLATE="${LC_ALL}" \ 407c2fbfb3SApril Chin LC_CTYPE="${LC_ALL}" 417c2fbfb3SApril Chin unset LC_ALL 427c2fbfb3SApril Chinfi 437c2fbfb3SApril Chinexport LC_NUMERIC=C 447c2fbfb3SApril Chin 457c2fbfb3SApril Chinfunction fatal_error 467c2fbfb3SApril Chin{ 477c2fbfb3SApril Chin print -u2 "${progname}: $*" 487c2fbfb3SApril Chin exit 1 497c2fbfb3SApril Chin} 507c2fbfb3SApril Chin 517c2fbfb3SApril Chin# parse HTTP return code, cookies etc. 527c2fbfb3SApril Chinfunction parse_http_response 537c2fbfb3SApril Chin{ 547c2fbfb3SApril Chin nameref response="$1" 557c2fbfb3SApril Chin typeset h statuscode statusmsg i 567c2fbfb3SApril Chin 577c2fbfb3SApril Chin # we use '\r' as additional IFS to filter the final '\r' 587c2fbfb3SApril Chin IFS=$' \t\r' read -r h statuscode statusmsg # read HTTP/1.[01] <code> 597c2fbfb3SApril Chin [[ "$h" != ~(Eil)HTTP/.* ]] && { print -u2 -f $"%s: HTTP/ header missing\n" "$0" ; return 1 ; } 607c2fbfb3SApril Chin [[ "$statuscode" != ~(Elr)[0-9]* ]] && { print -u2 -f $"%s: invalid status code\n" "$0" ; return 1 ; } 617c2fbfb3SApril Chin response.statuscode="$statuscode" 627c2fbfb3SApril Chin response.statusmsg="$statusmsg" 637c2fbfb3SApril Chin 647c2fbfb3SApril Chin # skip remaining headers 657c2fbfb3SApril Chin while IFS='' read -r i ; do 667c2fbfb3SApril Chin [[ "$i" == $'\r' ]] && break 677c2fbfb3SApril Chin 687c2fbfb3SApril Chin # strip '\r' at the end 697c2fbfb3SApril Chin i="${i/~(Er)$'\r'/}" 707c2fbfb3SApril Chin 717c2fbfb3SApril Chin case "$i" in 727c2fbfb3SApril Chin ~(Eli)Content-Type:.*) 737c2fbfb3SApril Chin response.content_type="${i/~(El).*:[[:blank:]]*/}" 747c2fbfb3SApril Chin ;; 757c2fbfb3SApril Chin ~(Eli)Content-Length:[[:blank:]]*[0-9]*) 767c2fbfb3SApril Chin integer response.content_length="${i/~(El).*:[[:blank:]]*/}" 777c2fbfb3SApril Chin ;; 787c2fbfb3SApril Chin ~(Eli)Transfer-Encoding:.*) 797c2fbfb3SApril Chin response.transfer_encoding="${i/~(El).*:[[:blank:]]*/}" 807c2fbfb3SApril Chin ;; 817c2fbfb3SApril Chin esac 827c2fbfb3SApril Chin done 837c2fbfb3SApril Chin 847c2fbfb3SApril Chin return 0 857c2fbfb3SApril Chin} 867c2fbfb3SApril Chin 877c2fbfb3SApril Chinfunction cat_http_body 887c2fbfb3SApril Chin{ 897c2fbfb3SApril Chin typeset emode="$1" 907c2fbfb3SApril Chin typeset hexchunksize="0" 917c2fbfb3SApril Chin integer chunksize=0 927c2fbfb3SApril Chin 937c2fbfb3SApril Chin if [[ "${emode}" == "chunked" ]] ; then 947c2fbfb3SApril Chin while IFS=$'\r' read hexchunksize && 95*3e14f97fSRoger A. Faulkner [[ "${hexchunksize}" == ~(Elri)[0-9abcdef]+ ]] && 96*3e14f97fSRoger A. Faulkner (( chunksize=$( printf "16#%s\n" "${hexchunksize}" ) )) && (( chunksize > 0 )) ; do 977c2fbfb3SApril Chin dd bs=1 count="${chunksize}" 2>/dev/null 987c2fbfb3SApril Chin done 997c2fbfb3SApril Chin else 1007c2fbfb3SApril Chin cat 1017c2fbfb3SApril Chin fi 1027c2fbfb3SApril Chin 1037c2fbfb3SApril Chin return 0 1047c2fbfb3SApril Chin} 1057c2fbfb3SApril Chin 1067c2fbfb3SApril Chinfunction request_tinyurl 1077c2fbfb3SApril Chin{ 1087c2fbfb3SApril Chin # site setup 1097c2fbfb3SApril Chin typeset url_host="tinyurl.com" 1107c2fbfb3SApril Chin typeset url_path="/api-create.php" 1117c2fbfb3SApril Chin typeset url="http://${url_host}${url_path}" 1127c2fbfb3SApril Chin integer netfd # http stream number 1137c2fbfb3SApril Chin typeset inputurl="$1" 11434f9b3eeSRoland Mainz compound httpresponse # http response 1157c2fbfb3SApril Chin typeset request="" 1167c2fbfb3SApril Chin 1177c2fbfb3SApril Chin # we assume "inputurl" is a correctly encoded URL which doesn't 1187c2fbfb3SApril Chin # require any further mangling 1197c2fbfb3SApril Chin url_path+="?url=${inputurl}" 1207c2fbfb3SApril Chin 1217c2fbfb3SApril Chin request="GET ${url_path} HTTP/1.1\r\n" 1227c2fbfb3SApril Chin request+="Host: ${url_host}\r\n" 1237c2fbfb3SApril Chin request+="User-Agent: ${http_user_agent}\r\n" 1247c2fbfb3SApril Chin request+="Connection: close\r\n" 1257c2fbfb3SApril Chin 1267c2fbfb3SApril Chin redirect {netfd}<> "/dev/tcp/${url_host}/80" 12734f9b3eeSRoland Mainz (( $? != 0 )) && { print -u2 -f $"%s: Could not open connection to %s.\n" "$0" "${url_host}" ; return 1 ; } 1287c2fbfb3SApril Chin 1297c2fbfb3SApril Chin # send http post 1307c2fbfb3SApril Chin { 1317c2fbfb3SApril Chin print -n -- "${request}\r\n" 1327c2fbfb3SApril Chin } >&${netfd} 1337c2fbfb3SApril Chin 1347c2fbfb3SApril Chin # process reply 1357c2fbfb3SApril Chin parse_http_response httpresponse <&${netfd} 1367c2fbfb3SApril Chin response="${ cat_http_body "${httpresponse.transfer_encoding}" <&${netfd} ; }" 1377c2fbfb3SApril Chin 1387c2fbfb3SApril Chin # close connection 1397c2fbfb3SApril Chin redirect {netfd}<&- 1407c2fbfb3SApril Chin 1417c2fbfb3SApril Chin if (( httpresponse.statuscode >= 200 && httpresponse.statuscode <= 299 )) ; then 1427c2fbfb3SApril Chin print -r -- "${response}" 1437c2fbfb3SApril Chin return 0 1447c2fbfb3SApril Chin else 1457c2fbfb3SApril Chin print -u2 -f $"tinyurl response was (%s,%s):\n%s\n" "${httpresponse.statuscode}" "${httpresponse.statusmsg}" "${response}" 1467c2fbfb3SApril Chin return 1 1477c2fbfb3SApril Chin fi 1487c2fbfb3SApril Chin 1497c2fbfb3SApril Chin # not reached 1507c2fbfb3SApril Chin} 1517c2fbfb3SApril Chin 15234f9b3eeSRoland Mainzfunction request_trimurl 15334f9b3eeSRoland Mainz{ 15434f9b3eeSRoland Mainz # site setup 15534f9b3eeSRoland Mainz typeset url_host="api.tr.im" 15634f9b3eeSRoland Mainz typeset url_path="/api/trim_url.xml" 15734f9b3eeSRoland Mainz typeset url="http://${url_host}${url_path}" 15834f9b3eeSRoland Mainz integer netfd # http stream number 15934f9b3eeSRoland Mainz typeset inputurl="$1" 16034f9b3eeSRoland Mainz compound httpresponse # http response 16134f9b3eeSRoland Mainz typeset request="" 16234f9b3eeSRoland Mainz 16334f9b3eeSRoland Mainz # we assume "inputurl" is a correctly encoded URL which doesn't 16434f9b3eeSRoland Mainz # require any further mangling 16534f9b3eeSRoland Mainz url_path+="?url=${inputurl}" 16634f9b3eeSRoland Mainz 16734f9b3eeSRoland Mainz request="GET ${url_path} HTTP/1.1\r\n" 16834f9b3eeSRoland Mainz request+="Host: ${url_host}\r\n" 16934f9b3eeSRoland Mainz request+="User-Agent: ${http_user_agent}\r\n" 17034f9b3eeSRoland Mainz request+="Connection: close\r\n" 17134f9b3eeSRoland Mainz 17234f9b3eeSRoland Mainz redirect {netfd}<> "/dev/tcp/${url_host}/80" 17334f9b3eeSRoland Mainz (( $? != 0 )) && { print -u2 -f $"%s: Could not open connection to %s.\n" "$0" "${url_host}" ; return 1 ; } 17434f9b3eeSRoland Mainz 17534f9b3eeSRoland Mainz # send http post 17634f9b3eeSRoland Mainz { 17734f9b3eeSRoland Mainz print -n -- "${request}\r\n" 17834f9b3eeSRoland Mainz } >&${netfd} 17934f9b3eeSRoland Mainz 18034f9b3eeSRoland Mainz # process reply 18134f9b3eeSRoland Mainz parse_http_response httpresponse <&${netfd} 18234f9b3eeSRoland Mainz response="${ cat_http_body "${httpresponse.transfer_encoding}" <&${netfd} ; }" 18334f9b3eeSRoland Mainz 18434f9b3eeSRoland Mainz # close connection 18534f9b3eeSRoland Mainz redirect {netfd}<&- 18634f9b3eeSRoland Mainz 18734f9b3eeSRoland Mainz if (( httpresponse.statuscode >= 200 && httpresponse.statuscode <= 299 )) ; then 18834f9b3eeSRoland Mainz # the statement below should really parse the XML... 18934f9b3eeSRoland Mainz print -r -- "${response/~(Elr).*(\<url\>)(.*)(\<\/url\>).*/\2}" 19034f9b3eeSRoland Mainz return 0 19134f9b3eeSRoland Mainz else 19234f9b3eeSRoland Mainz print -u2 -f $"tr.im response was (%s,%s):\n%s\n" "${httpresponse.statuscode}" "${httpresponse.statusmsg}" "${response}" 19334f9b3eeSRoland Mainz return 1 19434f9b3eeSRoland Mainz fi 19534f9b3eeSRoland Mainz 19634f9b3eeSRoland Mainz # not reached 19734f9b3eeSRoland Mainz} 19834f9b3eeSRoland Mainz 1997c2fbfb3SApril Chinfunction usage 2007c2fbfb3SApril Chin{ 2017c2fbfb3SApril Chin OPTIND=0 2027c2fbfb3SApril Chin getopts -a "${progname}" "${shtinyurl_usage}" OPT '-?' 2037c2fbfb3SApril Chin exit 2 2047c2fbfb3SApril Chin} 2057c2fbfb3SApril Chin 2067c2fbfb3SApril Chin# program start 2077c2fbfb3SApril Chinbuiltin basename 2087c2fbfb3SApril Chinbuiltin cat 2097c2fbfb3SApril Chinbuiltin date 2107c2fbfb3SApril Chinbuiltin uname 2117c2fbfb3SApril Chin 2127c2fbfb3SApril Chintypeset progname="${ basename "${0}" ; }" 2137c2fbfb3SApril Chin 2147c2fbfb3SApril Chin# HTTP protocol client identifer 215*3e14f97fSRoger A. Faulknertypeset -r http_user_agent="shtinyurl/ksh93 (2010-03-27; ${ uname -s -r -p ; })" 2167c2fbfb3SApril Chin 2177c2fbfb3SApril Chintypeset -r shtinyurl_usage=$'+ 218*3e14f97fSRoger A. Faulkner[-?\n@(#)\$Id: shtinyurl (Roland Mainz) 2010-03-27 \$\n] 2197c2fbfb3SApril Chin[-author?Roland Mainz <roland.mainz@nrubsig.org>] 22034f9b3eeSRoland Mainz[+NAME?shtinyurl - create short alias URL from long URL] 2217c2fbfb3SApril Chin[+DESCRIPTION?\bshtinyurl\b is a small utility which passes a given URL 22234f9b3eeSRoland Mainz to internet service which creates short aliases in the 22334f9b3eeSRoland Mainz form of http://<servicename>/XXXXXXXX to redirect long URLs.] 2247c2fbfb3SApril Chin[+?The first arg \burl\b describes a long URL which is transformed into 2257c2fbfb3SApril Chin a tinyurl.com short alias.] 22634f9b3eeSRoland Mainz[P:provider?Service provider (either \'tinyurl.com\' or \'tr.im\').]:[mode] 2277c2fbfb3SApril Chin 2287c2fbfb3SApril Chinurl 2297c2fbfb3SApril Chin 23034f9b3eeSRoland Mainz[+SEE ALSO?\bksh93\b(1), \brssread\b(1), \bshtwitter\b(1), http://www.tinyurl.com, http://tr.im] 2317c2fbfb3SApril Chin' 2327c2fbfb3SApril Chin 23334f9b3eeSRoland Mainztypeset service_provider="tr.im" 23434f9b3eeSRoland Mainz 2357c2fbfb3SApril Chinwhile getopts -a "${progname}" "${shtinyurl_usage}" OPT ; do 2367c2fbfb3SApril Chin# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" 2377c2fbfb3SApril Chin case ${OPT} in 23834f9b3eeSRoland Mainz P) service_provider="${OPTARG}" ;; 2397c2fbfb3SApril Chin *) usage ;; 2407c2fbfb3SApril Chin esac 2417c2fbfb3SApril Chindone 2427c2fbfb3SApril Chinshift $((OPTIND-1)) 2437c2fbfb3SApril Chin 2447c2fbfb3SApril Chin# expecting at least one more argument 2457c2fbfb3SApril Chin(( $# >= 1 )) || usage 2467c2fbfb3SApril Chin 2477c2fbfb3SApril Chintypeset url="$1" 2487c2fbfb3SApril Chinshift 2497c2fbfb3SApril Chin 25034f9b3eeSRoland Mainzcase "${service_provider}" in 25134f9b3eeSRoland Mainz "tinyurl.com") 2527c2fbfb3SApril Chin request_tinyurl "${url}" 2537c2fbfb3SApril Chin exit $? 25434f9b3eeSRoland Mainz ;; 25534f9b3eeSRoland Mainz "tr.im") 25634f9b3eeSRoland Mainz request_trimurl "${url}" 25734f9b3eeSRoland Mainz exit $? 25834f9b3eeSRoland Mainz ;; 25934f9b3eeSRoland Mainz *) 26034f9b3eeSRoland Mainz fatal_error "Unsupported service provider." 26134f9b3eeSRoland Mainzesac 26234f9b3eeSRoland Mainz 26334f9b3eeSRoland Mainz# not reached 26434f9b3eeSRoland Mainz 2657c2fbfb3SApril Chin# EOF. 266