shnote.sh revision 34f9b3eef6fdadbda0a846aa4d68691ac40eace5
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# CDDL HEADER START
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# The contents of this file are subject to the terms of the
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# Common Development and Distribution License (the "License").
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# You may not use this file except in compliance with the License.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# See the License for the specific language governing permissions
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# and limitations under the License.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# When distributing Covered Code, include this CDDL HEADER in each
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# If applicable, add the following below this CDDL HEADER, with the
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# fields enclosed by brackets "[]" replaced with your own identifying
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# information: Portions Copyright [yyyy] [name of copyright owner]
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# CDDL HEADER END
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# Use is subject to license terms.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# Make sure all math stuff runs in the "C" locale to avoid problems
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# with alternative # radix point representations (e.g. ',' instead of
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# '.' in de_DE.*-locales). This needs to be set _before_ any
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# floating-point constants are defined in this script).
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin content+="Content-Disposition: form-data; name=\"${element.name}\"\n"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # make sure we quote the '\' properly since we pass these data to one instance of
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin content+="${element.data//\\/\\\\}\n" # fixme: may need encoding for non-ASCII data
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # we have to de-quote the content before we can count the real numer of bytes in the payload
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # add content tail (which MUST not be added to the content length)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# parse HTTP return code, cookies etc.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # we use '\r' as additional IFS to filter the final '\r'
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin IFS=$' \t\r' read -r h statuscode statusmsg # read HTTP/1.[01] <code>
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin [[ "$h" != ~(Eil)HTTP/.* ]] && { print -u2 -f $"%s: HTTP/ header missing\n" "$0" ; return 1 ; }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin [[ "$statuscode" != ~(Elr)[0-9]* ]] && { print -u2 -f $"%s: invalid status code\n" "$0" ; return 1 ; }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin response.content_type="${i/~(El).*:[[:blank:]]*/}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin integer response.content_length="${i/~(El).*:[[:blank:]]*/}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin response.transfer_encoding="${i/~(El).*:[[:blank:]]*/}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin [[ "${hexchunksize}" == ~(Elri)[0-9abcdef]* ]] &&
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin (( chunksize=16#${hexchunksize} )) && (( chunksize > 0 )) ; do
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "title=%q description=%q date=%q provider=%q providertoken=%q url=%q\n" \
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin (( $# != 0 && $# != 1 )) && { print -u2 -f $"%s: Wrong number of arguments.\n" "$0" ; return 1 ; }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin [[ "$1" == "-l" ]] || printf "# %s\t\t\t\t\t%s\t%s\n" "<url>" "<title>" "<date>"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz (( $? != 0 )) && { print -u2 "Could not open history file." ; return 1 ; }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin while read -u${histfd} line ; do
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "%q\t%q\t%q\n" "${rec.url}" "${rec.title}" "${rec.date}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin redirect {histfd}<&-
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # key to autheticate this script against pastebin.ca
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset -r pastebin_ca_key="9CFXFyeNC3iga/vthok75kTBu5kSSLPD"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset url_path="/quiet-paste.php?api=${pastebin_ca_key}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin (( $# != 1 )) && { print -u2 -f $"%s: Wrong number of arguments.\n" "$0" ; return 1 ; }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin (( ${#1} == 0 )) && { print -u2 -f $"%s: No data.\n" "$0" ; return 1 ; }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset -r boundary="--------shnote_${RANDOM}_Xfish_${RANDOM}_Yeats_${RANDOM}_Zchicken_${RANDOM}monster_--------"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin mimeform.form=( # we use explicit index numbers since we rely on them below when filling the history
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin [3]=( name="description" data="logname=${LOGNAME};hostname=$(hostname);date=$(date)" )
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin request+="Content-Type: multipart/form-data; boundary=${boundary}\r\n"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin request+="Content-Length: $(( mimeform.content_length ))\r\n"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz (( $? != 0 )) && { print -u2 -f $"%s: Could not open connection to %s.\n" "$0" "${url_host}" ; return 1 ; }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin response="$(cat_http_body "${httpresponse.transfer_encoding}" <&${netfd})"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin redirect {netfd}<&-
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset response_token="${response/~(E).*SUCCESS:/}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "SUCCESS: http://opensolaris.pastebin.ca/%s\n" "${response_token}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin url="http://opensolaris.pastebin.ca/${response_token}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin (( $# != 1 )) && { print -u2 -f $"%s: No key or key URL.\n" "$0" ; return 1 ; }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin recordname="${recordname/~(El)http:\/\/opensolaris.pastebin.ca\/raw\//}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin recordname="${recordname/~(El)http:\/\/opensolaris.pastebin.ca\//}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin fatal_error $"Unsupported record name ${recordname}."
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin print -u2 -f "# Record name is '%s'\n" "${recordname}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # I hereby curse Solaris for not having an entry for "http" in /etc/services
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz (( $? != 0 )) && { print -u2 -f $"%s: Could not open connection to %s.\n" "$0" "${url_host}" ; return 1 ; }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin cat_http_body "${httpresponse.transfer_encoding}" <&${netfd}
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin redirect {netfd}<&-
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# program start
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# HTTP protocol client identifer
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainztypeset -r http_user_agent="shnote/ksh93 (2009-05-09; $(uname -s -r -p))"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# name of history log (the number after "history" is some kind of version
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# counter to handle incompatible changes to the history file format)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chintypeset -r history_file="${HOME}/.shnote/history0.txt"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz[-?\n@(#)\$Id: shnote (Roland Mainz) 2009-05-09 \$\n]
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin[-author?Roland Mainz <roland.mainz@nrubsig.org>]
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin[+NAME?shnote - read/write text data to internet clipboards]
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin[+DESCRIPTION?\bshnote\b is a small utilty which can read and write text
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin data to internet "clipboards" such as opensolaris.pastebin.ca.]
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin[+?The first arg \bmethod\b describes one of the methods, "put" saves a string
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin to the internet clipboard, returning an identifer and the full URL
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin where the data are stored. The method "get" retrives the raw
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin information using the identifer from the previous "put" action.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin The method "hist" prints a history of transactions created with the
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin "put" method and the keys to retrive them again using the "get" method.]
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin[+?The second arg \bstring\b contains either the string data which should be
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin stored on the clipboard using the "put" method, the "get" method uses
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin this information as identifer to retrive the raw data from the
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinmethod [ string ]
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin[+SEE ALSO?\bksh93\b(1), \brssread\b(1), \bshtwitter\b(1), \bshtinyurl\b(1), http://opensolaris.pastebin.ca]
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinwhile getopts -a "${progname}" "${shnote_usage}" OPT ; do
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# expecting at least one more argument, the single method below will do
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# the checks for more arguments if needed ("put" and "get" methods need
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# at least one extra argument, "hist" none).