Hi!
----
[The users in irc://irc.freenode.org/#opensolaris already know it but
AFAIK it was never announced to the general public]
I've set-up an OpenSolaris-specific version of the pastebin.ca internet
clipboard, e.g. a public place to paste larger texts via browser (or the
command-line tool below) which couldn't be transfered easily via other
methods (except email) - this is AFAIK quite usefull during IRC
conversations, phone meetings and maybe things like the upcoming
opensolaris summit (e.g. genereal-purpose scripts/drafts/etc. dumping
ground).
For those who don't have a browser around to paste things like logs and
other stuff to opensolaris.pastebin.ca I wrote a small script (attached
as "shnote.ksh.txt" ; note that this script needs Solaris 11/Nevada B72
or higher) which does this without requiring a browser, e.g. install the
script with...
-- snip --
# cp shnote.ksh.txt /usr/bin/shnote
# chmod a+rx,a-w /usr/bin/shnote
-- snip --
...and then use it like this:
-- snip --
$ shnote put "demo #8932001"
SUCCESS: http://opensolaris.pastebin.ca/702814
-- snip --
... will write the string "demo #8932001" to
http://opensolaris.pastebin.ca and returns the URL where the text can be
accessed from a browser.
Sending command output works similary, e.g.
-- snip --
$ shnote put "$(ls -l)"
SUCCESS: http://opensolaris.pastebin.ca/702822
-- snip --
... will send the output of "ls -l" to http://opensolaris.pastebin.ca
and return the access URL.
Additionally the script maintains a small history containing the access
URL, title (usually the users name) and the date, e.g.
-- snip --
$ shnote hist
# <url> <title> <date>
...
...
http://opensolaris.pastebin.ca/702814 gisburn Sep 19 04:51:21 CET 2007
...
http://opensolaris.pastebin.ca/702822 gisburn Sep 19 05:02:52 CET 2007
-- snip --
Finally you can get strings/data/text/etc. from
http://opensolaris.pastebin.ca using...
-- snip --
$ shnote get http://opensolaris.pastebin.ca/702814
# Record name is '702814'
demo #8932001
-- snip --
...or just short:
-- snip --
$ shnote get 702814
# Record name is '702814'
demo #8932001
-- snip --
Suggestions/comments/rants/etc. welcome... :-)
----
Bye,
Roland
--
__ . . __
(o.\ \/ /.o) [EMAIL PROTECTED]
\__\/\/__/ MPEG specialist, C&&JAVA&&Sun&&Unix programmer
/O /==\ O\ TEL +49 641 7950090
(;O/ \/ \O;)
#!/bin/ksh93
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
#
# Solaris needs /usr/xpg4/bin/ because the tools in /usr/bin are not
POSIX-conformant
export PATH=/usr/xpg4/bin:/bin:/usr/bin
# Make sure all math stuff runs in the "C" locale to avoid problems with
alternative
# radix point representations (e.g. ',' instead of '.' in de_DE.*-locales). This
# needs to be set _before_ any floating-point constants are defined in this
script)
if [[ "${LC_ALL}" != "" ]] ; then
export \
LC_MONETARY="${LC_ALL}" \
LC_MESSAGES="${LC_ALL}" \
LC_COLLATE="${LC_ALL}" \
LC_CTYPE="${LC_ALL}"
unset LC_ALL
fi
export LC_NUMERIC=C
function fatal_error
{
print -u 2 "${progname}: $@"
exit 1
}
# fixme: use "stat" builtin instead of "ls"
function get_filesize
{
typeset filename="$1"
typeset dummy # dummy string
integer filesize=-1
if [[ -f "${filename}" ]] ; then
ls -lb "${filename}" | read dummy dummy dummy dummy filesize dummy
fi
print -- ${filesize}
return 0
}
function encode_multipart_form_data
{
#set -o xtrace
nameref formdata=$1
nameref content="${1}.content" # ToDO: should be
|content="formdata.content"|
integer numformelements=${#formdata.form[*]}
integer i
content=""
# todo: add support to upload files
for (( i=0 ; i < numformelements ; i++ )) ; do
nameref element="${1}.form[${i}]" # ToDo: should be
|element="formdata.form[${i}]"|
content+="--${formdata.boundary}\n"
content+="Content-Disposition: form-data; name=\"${element.name}\"\n"
content+="\n"
content+="${element.data}\n" # fixme: may need encoding for non-ASCII
data
done
formdata.content_length=${#content}
# add content tail (which MUST not be added to the content length)
content+="--${formdata.boundary}--\n"
return 0
}
# parse return code, cookies etc.
function parse_http_response
{
nameref response=$1
typeset h c i
IFS=$' \t' read -r h c # read HTTP/1.[01] <code>
[[ "$h" != ~(Eil)HTTP/.* ]] && { print -u2 "$0: HTTP/ header missing" ;
return 1 ; }
response.httpcode="$c"
# skip remaining headers
while IFS='' read -r i ; do
[[ "$i" = $'\r' ]] && break
done
return 0
}
function history_write_record
{
# rec: history record:
# rec.title
# rec.description
# rec.provider
# rec.providertoken
# rec.url
nameref rec="$1"
integer histfd
mkdir -p "${HOME}/.shnote"
{
# write a single-line record which can be read
# as a compound variable back into the shell
printf "title=%q description=%q date=%q provider=%q providertoken=%q
url=%q\n" \
"${rec.title}" \
"${rec.description}" \
"$(date)" \
"${rec.provider}" \
"${rec.providertoken}" \
"${rec.url}"
} >>"${history_file}"
return $?
}
function print_history
{
integer histfd # http stream number
typeset line
# default output format is:
# <access url>/<title> <date> <access url>
[[ "$1" = "-l" ]] || printf "# %s\t\t\t\t\t%s\t%s\n" "<url>" "<title>"
"<date>"
# no history file ?
if [[ ! -f "${history_file}" ]] ; then
return 0
fi
# open history file
exec {histfd}<>"${history_file}"
while read -u${histfd} line ; do
typeset rec=()
# This is a bit messy - "eval" should be avoided but there is currently
# no better way to read a serialised compound variable from a file back
# into the shell.
eval "rec=( $line )"
if [[ "$1" = "-l" ]] ; then
print -- "${rec}"
else
printf "%s\t%s\t%s\n" "${rec.url}" "${rec.title}" "${rec.date}"
fi
unset rec
done
# close history file
exec {histfd}<&-
}
function put_note_pastebin_ca
{
#set -o xtrace
# key to autheticate this script against pastebin.ca
typeset -r pastebin_ca_key="9CFXFyeNC3iga/vthok75kTBu5kSSLPD"
# site setup
typeset url_host="opensolaris.pastebin.ca"
typeset url_path="/quiet-paste.php?api=${pastebin_ca_key}"
typeset url="http://${url_host}${url_path}"
integer netfd # http stream number
# argument for "encode_multipart_form_data"
typeset mimeform=(
# input
typeset boundary
typeset -a form
# output
typeset content
integer content_length
)
typeset request=""
typeset content=""
typeset -r
boundary="--------shnote_${RANDOM}_Xfish_${RANDOM}_Yeats_${RANDOM}_Zchicken_${RANDOM}monster_--------"
# ToDo: Use "mimeform.form+=(" once ksh93 has been fixed.
mimeform.boundary="${boundary}"
mimeform.form[0]=( name="name" data="${LOGNAME}" )
mimeform.form[1]=( name="expiry" data="Never" )
mimeform.form[2]=( name="type" data="1" )
mimeform.form[3]=( name="description"
data="logname=${LOGNAME};hostname=$(hostname);date=$(date)" )
mimeform.form[4]=( name="content" data="$1" )
encode_multipart_form_data mimeform
content="${mimeform.content}"
request="POST ${url_path} HTTP/1.1\n"
request+="Host: ${url_host}\n"
request+="User-Agent: ${http_user_agent}\n"
request+="Connection: close\n"
request+="Content-Type: multipart/form-data; boundary=${boundary}\n"
request+="Content-Length: $(( ${mimeform.content_length} ))\n"
exec {netfd}<>"/dev/tcp/${url_host}/80"
(( $? != 0 )) && { print -u2 "Couldn't open connection to ${url_host}." ;
return 1 ; }
# send http post
{
print -- "${request}"
print -- "${content}"
} >&${netfd}
# process reply
parse_http_response httpresponse <&${netfd}
response="$(cat <&${netfd})"
# close connection
exec {netfd}<&-
if [[ "${response}" = ~(E).*SUCCESS.* ]] ; then
typeset response_token="${response/~(E).*SUCCESS:/}"
print "SUCCESS: http://opensolaris.pastebin.ca/${response_token}"
# write history entry
typeset histrec=(
title="${mimeform.form[0].data}"
description="${mimeform.form[3].data}"
providertoken="${response_token}"
provider="opensolaris.pastebin.ca"
url="http://opensolaris.pastebin.ca/${response_token}"
)
history_write_record histrec
else
print "ERROR: ${response}"
return 1
fi
return 0
}
function get_note_pastebin_ca
{
typeset recordname="$1"
integer netfd # http stream number
case "${recordname}" in
~(Elr)[0-9][0-9]*)
# pass-through
;;
~(Elr)http://opensolaris.pastebin.ca/raw/[0-9]*)
recordname="${recordname/~(El)http:\/\/opensolaris.pastebin.ca\/raw\//}"
;;
~(Elr)http://opensolaris.pastebin.ca/[0-9]*)
recordname="${recordname/~(El)http:\/\/opensolaris.pastebin.ca\//}"
;;
*)
fatal_error "Unsupported record name ${recordname}."
esac
print -u2 -f "# Record name is '%s'\n" "${recordname}"
typeset url_host="opensolaris.pastebin.ca"
typeset url_path="/raw/${recordname}"
typeset url="http://${url_host}${url_path}"
# I hereby curse Solaris for not having an entry for "http" in /etc/services
# open TCP channel
exec {netfd}<>"/dev/tcp/${url_host}/80"
(( $? != 0 )) && { print -u2 "Couldn't open connection to ${url_host}." ;
return 1 ; }
# send HTTP request
request="GET ${url_path} HTTP/1.1\n"
request+="Host: ${url_host}\n"
request+="User-Agent: ${http_user_agent}\n"
request+="Connection: close\n"
print -u${netfd} -- "${request}\n"
# collect response and send it to stdout
parse_http_response httpresponse <&${netfd}
cat <&${netfd}
# close connection
exec {netfd}<&-
print # add newline
return 0
}
function usage
{
OPTIND=0
getopts -a "${progname}" "${USAGE}" OPT '-?'
exit 2
}
# program start
builtin basename
builtin cat
builtin date
builtin uname
typeset progname="$(basename "${0}")"
# HTTP protocol client identifer
typeset -r http_user_agent="shnote/ksh93 (2007-09-18; $(uname -s -r -p)"
# name of history log (the number after "history" is some kind of version
# counter to handle incompatible changes to the history file format)
typeset -r history_file="${HOME}/.shnote/history0.txt"
USAGE=$'
[-?\n@(#)\$Id: shnote (Roland Mainz) 2007-09-18 \$\n]
[-author?Roland Mainz <[EMAIL PROTECTED]
[+NAME?shnote - read/write text data to internet clipboards]
[+DESCRIPTION?\bshnote\b is a small utilty which can read and write text
data to internet "clipboards" such as opensolaris.pastebin.ca.]
[+?The first arg \bmethod\b describes one of the methods, "put" saves a string
to the internet clipboard, returning an identifer and the full URL
where the data are stored. The method "get" retrives the raw
information using the identifer from the previous "put" action.]
[+?The second arg \bstring\b contains either the string data which should be
stored on the clipboard using the "put" method, the "get" method uses
this information as identifer to retrive the raw data from the
clipboard.]
method [ string ]
[+SEE ALSO?\bksh93\b(1), \brssread\b(1), http://opensolaris.pastebin.ca]
'
while getopts -a "${progname}" "${USAGE}" OPT ; do
# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|"
case ${OPT} in
*) usage ;;
esac
done
shift $((OPTIND-1))
typeset method="$1"
shift
# todo: "history" mode
case "${method}" in
put) put_note_pastebin_ca "$@" ; exit $? ;;
get) get_note_pastebin_ca "$@" ; exit $? ;;
hist) print_history "$@" ; exit $? ;;
*) usage ;;
esac
fatal_error "not reached."
# EOF.
_______________________________________________
opensolaris-discuss mailing list
opensolaris-discuss@opensolaris.org