Url handler for telnet and ssh schemas

Eric Moret eric.moret at gmail.com
Sat Sep 18 02:22:55 UTC 2010


Hi fedora-devel,

I would like to contribute a piece of bash code that handles url in
gnome for ssh and telnet schemas. The idea being that whenever a user
clicks a link the proper client opens up in the default terminal
window configured in the user's "Preferred Applications" dialog.
examples of links:
telnet://my.telnet.server/
ssh://root@my.home.server:2222/

I am not quite sure what upstream should look like for such a script.
I took some of my code from launchmail which is a somewhat similar
script for email but has no upstream (that I can tell). The xdg-open
script from the portland/xdg-utils package is a wrapper that only
calls the corresponding Desktop startup tool. In the case of gnome it
calls gnome-open with the url passed to xdg-open. Only issue is that
gnome-open does not support telnet or ssh.

I appreciate any direct feedback on the below script and suggestions
for upstream location.
__
Eric


$ cat terminal-url-handler
#!/bin/bash

# to enable URL handling in FF, open the about:config page and add a new string:
# network.protocol-handler.app.telnet with value:
/path/to/handler/terminal-url-handler
# then add 2 new boolean:
# network.protocol-handler.external.telnet and set to true
# network.protocol-handler.external.ssh and set to true
# last, select "always ask" for content type telnet in Firefox
Preferences | Applications dialog
# the first time you use the handler manually select the script file
and check the remember option
#
# to enable this handler in gnome make sure you create the following
values in gconf:
# gconftool-2 -s /desktop/gnome/url-handlers/ssh/command
'/path/to/terminal-url-handler %s' --type String
# gconftool-2 -s /desktop/gnome/url-handlers/ssh/enabled --type Boolean true
# gconftool-2 -s /desktop/gnome/url-handlers/ssh/needs_terminal --type
Boolean false
# gconftool-2 -s /desktop/gnome/url-handlers/telnet/command
'/path/to/terminal-url-handler %s' --type String
# gconftool-2 -s /desktop/gnome/url-handlers/telnet/enabled --type Boolean true
# gconftool-2 -s /desktop/gnome/url-handlers/telnet/needs_terminal
--type Boolean false

#
# URI parsing function
# taken from http://valeriu.palos.ro/537/uri-parsing-using-bash-built-in-features/
#
# The function creates global variables with the parsed results.
# It returns 0 if parsing was successful or non-zero otherwise.
#
# [schema://][user[:password]@]host[:port][/path][?[param=value]...][#fragment]
#
uri_parser () {
  # uri capture
  uri="$@"

  # safe escaping
  uri="${uri//\`/%60}"
  uri="${uri//\"/%22}"

  # top level parsing
  pattern='^(([a-z]{3,6})://)?((([^:\/]+)(:([^@\/]*))?@)?([^:\/?]+)(:([0-9]+))?)(\/[^?]*)?(\?[^#]*)?(#.*)?$'
  [[ "$uri" =~ $pattern ]] || return 1;

  # component extraction
  uri=${BASH_REMATCH[0]}
  uri_schema=${BASH_REMATCH[2]}
  uri_address=${BASH_REMATCH[3]}
  uri_user=${BASH_REMATCH[5]}
  uri_password=${BASH_REMATCH[7]}
  uri_host=${BASH_REMATCH[8]}
  uri_port=${BASH_REMATCH[10]}
  uri_path=${BASH_REMATCH[11]}
  uri_query=${BASH_REMATCH[12]}
  uri_fragment=${BASH_REMATCH[13]}

  # path parsing
  count=0
  path="$uri_path"
  pattern='^/+([^/]+)'
  while [[ $path =~ $pattern ]]; do
    eval "uri_parts[$count]=\"${BASH_REMATCH[1]}\""
    path="${path:${#BASH_REMATCH[0]}}"
    let count++
  done

  # query parsing
  count=0
  query="$uri_query"
  pattern='^[?&]+([^= ]+)(=([^&]*))?'
  while [[ $query =~ $pattern ]]; do
    eval "uri_args[$count]=\"${BASH_REMATCH[1]}\""
    eval "uri_arg_${BASH_REMATCH[1]}=\"${BASH_REMATCH[3]}\""
    query="${query:${#BASH_REMATCH[0]}}"
    let count++
  done

  # return success
  return 0
}

error_dialog () {
  echo "$1"
  if [ -x /usr/bin/zenity ]; then
    /usr/bin/zenity --error --text="$1"
  else
    xmessage "$1"
  fi
}

sanity_check () {
  unset INVALID
  echo "$1" | grep -q "terminal-url-handler" && INVALID="yes"
  echo "$1" | grep -q "gnome-open" && INVALID="yes"
  if [ "$INVALID" == "yes" ]; then
    error_dialog "Error: $1 is an invalid terminal.  Please reconfigure."
    [ -x /usr/bin/gnome-default-applications-properties ] && exec
/usr/bin/gnome-default-applications-properties
    exit 1
  fi
}

exists () {
  which "${1%% *}" 2> /dev/null > /dev/null
  return $?
}

if [ $# != 1 ]; then
  error_dialog "Usage: $0 <url>"
  exit 1
fi

uri_parser $1
if [ "$?" != 0 ]; then
  error_dialog "Error: Invalid URL"
  exit 1
fi

if [ "$uri_schema" == 'telnet' ]; then
  CLI="$uri_schema $uri_host $uri_port"
elif [ "$uri_schema" == 'ssh' ]; then
  CLI="$uri_schema -p ${uri_port:-22} ${uri_user:-$USER}@$uri_host"
else
  error_dialog "Error: telnet and ssh are the only supported url schemas"
  exit 1
fi

# Attempt to use GNOME Preferred Terminal
if [ -x /usr/bin/gconftool-2 -a -x
/usr/bin/gnome-default-applications-properties ]; then
  # Pull key from gconf, trim leading & trailing spaces
  PREFTERM=$(gconftool-2 -g /desktop/gnome/applications/terminal/exec
2>/dev/null | sed -e 's/^\ *//; s/\ *$//')
  TERMARGS=$(gconftool-2 -g
/desktop/gnome/applications/terminal/exec_arg 2>/dev/null | sed -e
's/^\ *//; s/\ *$//')

  # Remove arguments
  PREFTERM="`echo $PREFTERM | cut -f1 -d" "`"

  # sanity check (prevent infinite loops)
  sanity_check "$PREFTERM"

  if [ ! -z $DISPLAY ] &&  [ -x /usr/bin/gnome-open ]; then
    if ! exists "$PREFTERM"; then
      error_dialog "Error: The terminal $PREFTERM does not exist.
Please reconfigure."
      [ -x /usr/bin/gnome-default-applications-properties ] && exec
/usr/bin/gnome-default-applications-properties
      exit 1
    fi
  fi
else
  TERMINALS="gnome-terminal konsole urxvt rxvt aterm xterm"
  for PREFTERM in $TERMINALS; do
    exists "$terminal" && break
  done
fi

exec $PREFTERM $TERMARGS $CLI


More information about the devel mailing list