#!/bin/zsh
# ====================[ zshrc.ssh                          ]====================
#                     [ Time-stamp: "2009-04-18 19:29:36 leycec" ]
#
# --------------------( SYNOPSIS                           )--------------------
# ZSH-specific routines for mounting and unmounting remote SSH hosts to and from
# local SSHfuse-managed paths.
#
# "zshrc" explicitly sources this file on shell startup.
#
# --------------------( TODO                               )--------------------
# * Re-implement in a proper scripting language as a command-line executable:
#   "ruby" comes to mind, here.

# ....................{ CONFIGURATION                      }....................
# The root directory to which SSH hosts will be mounted.
MOUNT_ROOT="/mnt"

# The list of absolute paths to "ssh_config" files. Order is important: the
# contents of later paths override that of earlier.
SSH_CONFIGS="/etc/ssh/ssh_config:~/.ssh/ssh_config"

# Declare a global associative array mapping from SSH hostname to the local and
# remote pathnames at which that hostname is to be mounted under SSHfs. SSH
# hostnames correspond to "Host" options, in "/etc/ssh/ssh_config".
#
# The "-Ax" option to the "typeset" commands defines each such variable as an
# [A]ssociative array and e[x]ported to the global environment for later
# access within the "ssh-mount" function.
typeset -Ax SSH_HOST_TO_LOCAL_PATH
typeset -Ax SSH_HOST_TO_REMOTE_PATH
SSH_HOST_TO_LOCAL_PATH=()
SSH_HOST_TO_REMOTE_PATH=()

# Define custom mappings for the above associative arrays. The "fill_arrays"
# function will define acceptable defaults for all other mappings.
SSH_HOST_TO_REMOTE_PATH[gwydden]="/"
SSH_HOST_TO_REMOTE_PATH[rhuddin]="/"

# ....................{ INITIALIZATION                     }....................
# Fill the above associative arrays with sensible defaults.
fill_arrays() {
  local SSH_HOSTS
  local SSH_HOST

  # Split the scalar string of paths "$SSH_CONFIGS" on colons with (s.:.).
  foreach  SSH_CONFIG (${(s.:.)SSH_CONFIGS})
    [ -f "$SSH_CONFIG" ] || break

    # Extract a space-delimited set of all "Hosts" defined by this "ssh_config".
    SSH_HOSTS="$(grep --extended-regexp 'Host[ \t]' "$SSH_CONFIG" | cut --delimiter=' ' --fields=2 | tr '\n' ' ' | tr --delete '*')"

    # Split the scalar string of words "$SSH_HOSTS" on spaces with '='.
    foreach SSH_HOST (${=SSH_HOSTS})
      if [ -z "$SSH_HOST_TO_LOCAL_PATH[$SSH_HOST]" ]; then
        # Do not append a terminating '/' onto mount points. Why? We later grep
        # "/etc/mtab" for existing mount points and, since that file also does not
        # append the same terminating '/', must thus ensure the two paths conform.
        SSH_HOST_TO_LOCAL_PATH[$SSH_HOST]="$MOUNT_ROOT/$SSH_HOST"
      fi

      if [ -z "$SSH_HOST_TO_REMOTE_PATH[$SSH_HOST]" ]; then
        SSH_HOST_TO_REMOTE_PATH[$SSH_HOST]="~"
      fi
    end
  end
}
fill_arrays

# ....................{ ALIASES                            }....................
# Define low-level aliases. You may call these aliases directly; in general,
# however, it will probably be more expedient to call the higher-level
# "ssh-mount" and "ssh-umount" to perform SSH host mounting and unmounting.

# Shortcut aliases.
alias sshm="ssh-mount"
alias sshu="ssh-umount"

# FUSE aliases. 
alias sshfs="sshfs -o allow_other,kernel_cache,reconnect,transform_symlinks,compression=yes,cache_timeout=256,cache_stat_timeout=16,cache_dir_timeout=16,cache_link_timeout=16,idmap=user,workaround=rename"
alias sshfs-umount="fusermount -uz"

# FUSE aliases. (SDF-specific.)
SDF_HOME_PATH="$MOUNT_ROOT/sdf"
SDF_HTML_PATH="/www/af/b/bcurry"
sdf-umount() {
  utter "unmounting SDF <- \"$SDF_HOME_PATH\" \"$SDF_HTML_PATH\"..."
  sshfs-umount "$SDF_HOME_PATH"
  sshfs-umount "$SDF_HTML_PATH"
}

sdf-mount() {
  mkdir_if_not_found "$SDF_HOME_PATH" "$SDF_HTML_PATH"
  sdf-umount

  utter "mounting SDF -> \"$SDF_HOME_PATH\" \"$SDF_HTML_PATH\"..."
  sshfs -o uid=1000,gid=1000 sdf: "$SDF_HOME_PATH"
  sshfs -o uid=1000,gid=1000 sdf:"$SDF_HTML_PATH" "$SDF_HTML_PATH"
}

# SSH aliases.
alias scp="scp -Crv"
alias ssh="TERM=\"xterm\" ssh -v"
alias ssh-keychain-restore="keychain --clear; keychain --agents ssh --quick ~/.ssh/id_rsa"
alias ssh-secondary-control-master="ssh -o \"ControlPath ~/tmp/ssh_controlmaster2-%r@%h:%p\""

# ....................{ INTERFACE                          }....................
# Define high-level "front-facing" functions serving as this file\"s command-
# line interface to common users.

# void ssh-mount(char *host)
#
# Mount the passed SSH hostname to its corresponding local mount point.
ssh-mount() {
  [ -n "$1" ] || die "no SSH host passed!"

  local SSH_HOST="$1"
  local LOCAL_PATH="$SSH_HOST_TO_LOCAL_PATH[$SSH_HOST]"
  local REMOTE_PATH="$SSH_HOST_TO_REMOTE_PATH[$SSH_HOST]"
  [ -n "$LOCAL_PATH" ] || die "\"$SSH_HOST\" not a recognized host!"

  if [ ! -d "$LOCAL_PATH" ]; then
    USER_NAME=$(whoami)

    utter "creating \"$LOCAL_PATH\"..."
    sudo mkdir --parents "$LOCAL_PATH" ||
      die "\"$LOCAL_PATH\" cannot be created!"
    sudo chown "$USER_NAME" "$LOCAL_PATH" || 
      die "\"$LOCAL_PATH\" cannot be chowned by \"$USER_NAME\"!"
  fi

  ssh-umount "$SSH_HOST"

  # Load the "fuse" kernel module, if compiled as a module and not already loaded.
  if ! grep -qw fuse /proc/filesystems; then
    # If the "/etc/init.d/fuse" initscript exists, preferentially run that.
    if [ -x "/etc/init.d/fuse" ]; then
      sudo  "/etc/init.d/fuse" restart  ||
        die "\"fuse\" initscript cannot be started!"
    # Otherwise, load the kernel module.
    else
      sudo modprobe --quiet fuse ||
        die "\"fuse\" kernel module cannot be loaded!"
    fi
  fi

  # Mount the passed SSH hostname.
  utter "mounting \"$SSH_HOST\" to \"$LOCAL_PATH\"..."
  sshfs "${SSH_HOST}:${REMOTE_PATH}" "$LOCAL_PATH" ||
    die "\"$SSH_HOST\" cannot be mounted to \"$LOCAL_PATH\"!"
}

# void ssh-umount(char *host)
#
# Unmount the passed SSH hostname from its corresponding local mount point.
ssh-umount() {
  [ -n "$1" ] || die "no SSH host passed!"

  local SSH_HOST="$1"
  local LOCAL_PATH="$SSH_HOST_TO_LOCAL_PATH[$SSH_HOST]"
  [ -n "$LOCAL_PATH" ] || die "\"$SSH_HOST\" not a recognized host!"

  # Unmount the passed SSH hostname only if already mounted.
  if grep "$LOCAL_PATH" /etc/mtab 2>&1 1>/dev/null; then
    utter "unmounting \"$SSH_HOST\" from \"$LOCAL_PATH\"..."
    sshfs-umount "$LOCAL_PATH" ||
      die "\"$SSH_HOST\" cannot be unmounted from \"$LOCAL_PATH\"!"
  fi
}

# --------------------( COPYRIGHT AND LICENSE              )--------------------
# The information below applies to everything in this distribution,
# except where noted.
#              
# Copyleft 2007, 2008, 2009, and 2010 by Cecil Curry.
#   
#   http://www.raiazome.com
# 
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
