SiteMap Search ElispArea HowTo Glossary RecentChanges News Problems Suggestions
Jordan, Independence Day, Argentina, National Day

mon-tramp-utils.el

Download

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; -*- mode: EMACS-LISP; -*-
;;; this is mon-tramp-utils.el
;;; ================================================================
;;; DESCRIPTION:
;;; mon-tramp-utils provides cross platform utilities for working with tramp.
;;; This package should be compatible with both GNU/LINUX and w32 systems.
;;; I have no idea if it will work with cygwin. 
;;;
;;; FUNCTIONS:►►►
;;; `mon-tramp-plink-example', `mon-tramp-add-default-methods', 
;;; `mon-tramp-putty-conf-status', `mon-tramp-add-pageant-keys'
;;; `mon-ssh-add-p', `mon-tramp-connect', `mon-tramp-read-conns'
;;; `mon-tramp-disconnect', `mon-tramp-su-local', `mon-tramp-syntax'
;;; FUNCTIONS:◄◄◄
;;;
;;; MACROS:
;;;
;;; METHODS:
;;;
;;; CLASSES:
;;;
;;; CONSTANTS:
;;; `mon-tramp-mode-line-buffer-ident'
;;;
;;; VARIABLES:
;;; `*mon-tramp-default-methods-l*', `*mon-tramp-putty-private-keys*',
;;; `*mon-tramp-paths-alist*'
;;;
;;; ALIASED/ADVISED/SUBST'D:
;;;
;;; DEPRECATED:
;;;
;;; RENAMED:
;;;
;;; MOVED:
;;;
;;; TODO:
;;;
;;; NOTES:
;;; Following table maps three variabls which are defined in this package but
;;; which source their values from a seperate file:
;;; ,----
;;; | `*mon-tramp-putty-private-keys*' -> `mon-pks'
;;; | `*mon-tramp-paths-alist*'        -> `mon-tramp-alist'
;;; | `*mon-tramp-default-methods-l*'  -> `mon-p-ssn'
;;; `----
;;;
;;; If the above symbols `mon-pks', `mon-tramp-alist', and `mon-p-ssn' are not
;;; present on your system they will be populated with example values and these
;;; example values will be bound at load time.
;;;
;;; In particular, this means that when this package is loaded the tramp
;;; variable `tramp-default-method-alist' will have contain these examples.
;;; These example values shouldn't pose an immediate concern as I've pointed
;;; them to a google IP - if google's ssh ports let you in then they deserve
;;; what they get :) Regardless, if you intend to use mon-tramp-utils you will
;;; want to examine the source and docstrings for these three variables and
;;; replace them with parameters suitable for your system/needs. I've attempted
;;; to document the required format these variables expect and the source is
;;; fairly well commented. :SEE below for discussion.
;;;
;;; :NOTE the argument `mon-tramp-alist' to variable `*mon-tramp-paths-alist*'
;;; is a symbol defined in an external package. You need to provide your own
;;; value for either the variable `*mon-tramp-paths-alist*' or bind it to the
;;; `mon-tramp-alist' symbol (either locally or in a separate file). In either
;;; case the provided value should reflect defined in the docstring of
;;; `*mon-tramp-paths-alist*'.
;;;
;;; :NOTE on MON systems the variable `*mon-tramp-putty-private-keys*'
;;; evaluates the symbol value of `mon-pks' which is defined in an external
;;; package. The current default value for `mon-pks' is: '(""). If you intend to
;;; use putty/plink on w32 you will need to provide your own value for either
;;; the variable `*mon-tramp-putty-private-keys*' or bind it to the `mon-pks'
;;; symbol (either locally or in a separate file). In either case the provided
;;; value should reflect the formated defined in the docstring of
;;; `*mon-tramp-putty-private-keys*'.
;;;
;;; :NOTE The `mon-tramp-add-default-methods' function calls the variable
;;; `*mon-tramp-default-methods-l*'. On MON systems the variable
;;; `*mon-tramp-default-methods-l*' takes evaluates the value of the `mon-p-ssn'
;;; symobl. The `mon-p-ssn' symbol is defined in an external package. You will
;;; need to provide your own value for either the variable
;;; `*mon-tramp-default-methods-l*' or bind it to the `mon-p-ssn' symbol (either
;;; locally or in a separate file). In either case the provided value should
;;; reflect the format defined docstrings of `*mon-tramp-default-methods-l*'
;;;
;;; :NOTE For w32 systems this package requires an environment with:
;;; a) Putty, putty-agent, and plink in your path.
;;;    You can test by evaluating: (mon-tramp-putty-conf-status)
;;;
;;; b) Putty/plink sessions saved as:
;;;   i) <USERNAME>@<HOST>; 
;;;  ii) With the correct port number when this is _NOT_ `22';
;;;
;;; c) putty-agent has the key for each given session loaded.
;;;     A utility function is provided to accommodate this.
;;;    :SEE `mon-tramp-add-pageant-keys'
;;;
;;; :NOTE For GNU/Linux this package requires an environment running ssh-agent:
;;;  a) MON does this with a script sourced at login.
;;;
;;;  b) The ssh-agent has the keys loaded via:
;;;     - SHELL> ssh-add ~/.ssh/<SOME-KEY>
;;;     For GNU/Linux systems a utility is provided to test if keys are loaded:
;;;     (mon-ssh-add-p) 
;;;     Additionally, provided is an untested function which will 
;;;     load a key via ssh-add see the commented function `mon-ssh-add-pass' 
;;;     at bottom of file:
;;;
;;; :NOTE MON systems set an environmental variable "MON_PTTY":
;;; e.g.: (getenv "MON_PTTY").
;;; This is done to make sure that putty.exe et al are in MON paths. Normally,
;;; this prob. isn't required but MON does things lysdexically :) IOW if Putty
;;; is installed on your system, then it is in your path already and prob. also
;;; has its own environmental variable set.
;;; 
;;; SNIPPETS:
;;;
;;; REQUIRES:
;;; `pushnew' <- `cl'
;;
;;; `tramp'
;;;
;;; `IS-MON-P-W32' `IS-MON-P-GNU' <- `mon-default-loads.el' (if in load-path)
;;; (featurep 'mon-default-loads)
;;;
;;; putty, plink, pageant, puttygen executables (on W32)
;;;
;;; ssh-agent, ssh-add, ssh ssh-keygen etc. executables (on GNU/Linux)
;;;
;;; THIRD PARTY CODE:
;;; constant `mon-tramp-mode-line-buffer-ident' from tramp manual.
;;;
;;; The functions `mon-ssh-add-pass' and `mon-ssh-add-p'
;;; :COURTESY Roland Winkler help.gnu.emacs :DATE 2008-03-30
;;; :SUBJECT "tramp and ssh-agent / ssh-add"
;;; :CREATED <Timestamp: #{2009-11-19T14:19:24-05:00Z}#{09474} - by MON>
;;;
;;; AUTHOR: MON KEY
;;; MAINTAINER: MON KEY
;;;
;;; PUBLIC-LINK: (URL `http://www.emacswiki.org/emacs/mon-tramp-utils.el)
;;; FIRST-PUBLISHED: <Timestamp: #{2009-11-20T13:45:12-05:00Z}#{09475} - by MON>
;;;
;;; FILE-CREATED:
;;; <Timestamp: #{2009-11-19T14:05:04-05:00Z}#{09474} - by MON>
;;; ================================================================
;;; This file is not part of GNU Emacs.
;;;
;;; 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, 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; see the file COPYING.  If not, write to
;;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
;;; Floor, Boston, MA 02110-1301, USA.
;;; ================================================================
;;; Permission is granted to copy, distribute and/or modify this
;;; document under the terms of the GNU Free Documentation License,
;;; Version 1.3 or any later version published by the Free Software
;;; Foundation; with no Invariant Sections, no Front-Cover Texts,
;;; and no Back-Cover Texts. A copy of the license is included in
;;; the section entitled "GNU Free Documentation License".
;;; A copy of the license is also available from the Free Software
;;; Foundation Web site at:
;;; (URL `http://www.gnu.org/licenses/fdl-1.3.txt').
;;; ================================================================
;;; Copyright © 2009 MON KEY 
;;; ==============================
;;; CODE:

;;; `mon-tramp-add-default-methods' uses `pushnew'.
(eval-when-compile (require 'cl)) 
;;
(unless (featurep 'tramp) (require 'tramp))

;;; :NOTE :EMACS-WIKI if :FILE mon-default-loads.el isn't in load-path.
(unless (featurep 'mon-default-loads)
  (cond ((eq system-type 'windows-nt)
         (setq IS-MON-P-W32 t)
         (setq IS-MON-P-GNU nil))
        ((or (eq system-type 'gnu/linux) (eq system-type 'linux))
         (setq IS-MON-P-W32 nil)
         (setq IS-MON-P-GNU t))))
;;
;;; :TEST-ME IS-MON-P-W32
;;; :TEST-ME IS-MON-P-GNU

;;; ==============================
;;; :NOTE Make sure our initial tramp methods are sane.
(cond (IS-MON-P-W32 (setq tramp-default-method "plinkx")) 
      ;; It isn't clear whether this should be "ssh2".
      (IS-MON-P-GNU (setq tramp-default-method "ssh"))) 

;;; ==============================
;;; :NOTE Following block :FROM (info "(tramp)Frequently Asked Questions")
;;; :CREATED <Timestamp: #{2009-11-18T15:38:32-05:00Z}#{09473} - by MON KEY>
(defconst mon-tramp-mode-line-buffer-ident
  (list '(:eval (let ((host-name
                       (or (file-remote-p default-directory 'host)
                           (system-name))))
                  (if (string-match "^[^0-9][^.]*\\(\\..*\\)" host-name)
                      (substring host-name 0 (match-beginning 1))
                      host-name)))
        ": %12b")
  "Show when visiting a Tramp buffer.
:NOTE verbatim from info node `(tramp)Frequently Asked Questions'.\n►►►")
;;
(setq-default mode-line-buffer-identification mon-tramp-mode-line-buffer-ident)
;;
(add-hook 'dired-mode-hook
          '(lambda () (setq mode-line-buffer-identification
                       mon-tramp-mode-line-buffer-ident)))

;;; ==============================
;;; :NOTE uncomment to change persistent store connection path.
;;; Set to nil to turn tramp-persistency off entirely. Don't do it!
;;; <Timestamp: #{2009-11-18T13:03:50-05:00Z}#{09473} - by MON KEY>
;;; (setq tramp-persistency-file-name "~/tramp-persistency") ;nil)

;;; ==============================
;;; :NOTE If the `mon-pks'isn't avaiable default it it to '("").
;;; :CREATED <Timestamp: #{2009-11-19T16:26:42-05:00Z}#{09474} - by MON>
(defvar *mon-tramp-putty-private-keys* (if (bound-and-true-p mon-pks) 
                                             mon-pks
                                             (setq mon-pks '("")))
  "*List of keys to add to the putty agent pageant.exe
:NOTE the symbol `mon-pks' is sourced from an external package.
You should provide your own list (or symbol) for the value of 
`*mon-tramp-putty-private-keys*'.
Each elt of list is a key string as a fully qualified path.
Path should be escaped for `w32-shell-execute' with `\\\\' not as `/'.\n
:EXAMPLE\n '\(\"C:\\\\SOME\\\\PATH\\\\TO\\\\PUTTY-KEY-1.ppk\"
   \"C:\\\\SOME\\\\PATH\\\\TO\\\\PUTTY-KEY-2.ppk\")\n
:SEE-ALSO `*mon-tramp-paths-alist*', `*mon-tramp-default-methods-l*'
`mon-tramp-add-pageant-keys', `mon-tramp-putty-conf-status'\n►►►")
;;
;;; :TEST-ME *mon-tramp-putty-private-keys*
;;
;;; (makunbound '*mon-tramp-putty-private-keys*)

;;; ==============================
;;; :NOTE `mon-tramp-alist' is sourced from an external package. 
;;; :CREATED <Timestamp: #{2009-11-19T17:04:40-05:00Z}#{09474} - by MON KEY>
(defvar *mon-tramp-paths-alist* 
  (if (bound-and-true-p mon-tramp-alist) 
      mon-tramp-alist
      (setq mon-tramp-alist 
            ;;  KEY         ;; GNU/Linux ssh tramp path  ;; W32 plinkx tramp path
            '((example-key1 "/ssh2:root@74.125.45.100:" "/plinkx:<EXAMPLE-SESSION1>:")
              (example-key2 "/ssh:gg@74.125.45.100#2200:/home/gg" "/plinkx:<EXAMPLE-SESSION2>:")
              (example-key3 "/ssh:<USER>@<HOST>:/home/<USER>:" "/plinkx:<EXAMPLE-SESSION3>:"))))
  "*An alist of paths for use with `mon-tramp-connect's completing-read.
List is formatted to be portable between GNU/Linux <-> W32 systems.
Elements of alist should be as shown below.\n\n:EXAMPLE\n\(let \(\(mta '\(\(<KEY> 
              \"/<METHOD>:<USER>@<HOST>:/PATH/ON/HOST\" 
              \"/plinkx:<PUTTY-SESSION>:/PATH/ON/HOST\"\)
             \(brazil
              \"/ssh2:aapatriota@brasilemb.org#666:/home/tony/laundry\" 
              \"/plinkx:brasile:/home/tony/dirt\"\)\)\)\)
  \(setq mta`\(,\(mapcar 'car mta\) ,\(mapcar 'cadr mta\) ,\(mapcar 'caddr mta\)\)\)
  \(format \"The keys -> %s\\nThe GNU paths -> %s\\nThe Putty paths -> %s\"
          \(car mta\) \(cadr mta\) \(caddr mta\)\)\)\n
:SEE-ALSO `*mon-tramp-putty-private-keys*', `*mon-tramp-default-methods-l*'
`mon-tramp-plink-example'.\n►►►")
;;
;;; :TEST-ME *mon-tramp-paths-alist*
;;; :TEST-ME (let ((mta (mapcar 'car *mon-tramp-paths-alist*))) mta)
;;;
;;; (makunbound '*mon-tramp-paths-alist*)

;;; ==============================
;;; :NOTE `mon-p-ssn' is sourced from an external package. 
;;; :CREATED <Timestamp: #{2009-11-19T19:41:09-05:00Z}#{09475} - by MON KEY>
(defvar *mon-tramp-default-methods-l* 
  (if (bound-and-true-p mon-p-ssn)
      mon-p-ssn
      (setq mon-p-ssn
            ;; First list for IS-MON-P-W32 - list with 3 strings.
            `(;; (elt (assoc 'example-key1 *mon-tramp-paths-alist*) 2)
              ("\\`<EXAMPLE-SESSION1>\\'"  
               ;; (elt (assoc 'example-key2 *mon-tramp-paths-alist*) 2)
               "\\`<EXAMPLE-SESSION2>\\'"  
               ;; (elt (assoc 'example-key3 *mon-tramp-paths-alist*) 2)
               "\\`<EXAMPLE-SESSION3>\\'") 
              ;; Second list for IS-MON-P-GNU - list of lists.
              (;; (elt (assoc 'example-key1 *mon-tramp-paths-alist*) 1)              
               ("\\`74\\.125\\.45\\.100\\'" "\\`root\\'" "ssh2")
               ;; (elt (assoc 'example-key2 *mon-tramp-paths-alist*) 1)
               ("\\`74\\.125\\.45\\.100#2200\\'" "\\`gg\\'" "ssh") ;; Uses port 2200
               ;; (elt (assoc 'example-key3 *mon-tramp-paths-alist*) 1)
               ("\\`<SOME.HOST.IP>\\'" "\\`<USER>\\'" "ssh")))))
  "*Two element list containing `tramp-default-methods' according to system type.
:CALLED-BY `mon-tramp-add-default-methods'.\n
:NOTE On MON systems this variable evalautes the value of the `mon-p-ssn' symbol.
The `mon-p-ssn' symbol is defined in a separate private file.
You should create and provide your own list and supply its symbol or value here.\n
Your list will contain two elements - each a list.\n
The car of the list will contain tramp \"plinkx\" style host strings.
These are for use with `IS-MON-P-W32' tramp related conditionals and should be
formatted for tramp's HOST arg with the \"plinkx\" method.
Each string in this first list is a putty/plink session name with tramp's
usual \"\\\\`HOST\\\\'\" escapes e.g.:\n
 \(\"\\\\`session1\\\\'\" \"\\\\`session2\\\\'\" \"\\\\`session3\\\\'\"\)\n
To wit, each elt of the example list above is a string comprised of:\n
 quotation-mark backslash backslash backquote sessionN backslash backslash apostrophe quotation-mark\n
:EXAMPLE \(mon-tramp-plink-example\)
                                 Subst ^^^^^ HOSTN w/ putty session name.\n
The second elt of your list (the cadr) is for `IS-MON-P-GNU' tramp conditionals.
This is a list of lists for tramp when using GNU/LINUX's ssh-agent.
Each list should containing three strings formatted as per tramps
`tramp-default-method-alist' e.g. (HOST USER METHOD) and properly escaped as:\n
  \(\"\\\\`HOST\\\\'\" \"\\\\`USER\\\\'\" \"\\\\`METHOD\\\\'\"\)\n
:SEE-ALSO `*mon-tramp-putty-private-keys*', `*mon-tramp-paths-alist*'
`mon-tramp-plink-example'.\n►►►")

;;; ==============================
;;; :CREATED <Timestamp: #{2009-11-19T20:05:54-05:00Z}#{09475} - by MON KEY>
(defun mon-tramp-plink-example ()
  "Return a momentary-string-display of correct formatting for 
car of `*mon-tramp-default-methods-l*'.\n
:EXAMPLE (mon-tramp-plink-example)\n►►►"
  (interactive)
  (let ((h-seq '(34 92 92 96 72 79 83 84 49 92 92 39 34))
        (h-sb '(49 50 51))
        (h-lst))
    (dolist (i h-sb (setq h-lst (nreverse h-lst)))
      (push (apply 'string (subst i 49 h-seq)) h-lst))
    (momentary-string-display  (format "%s" h-lst) (point))))
;;
;;; :TEST-ME (mon-tramp-plink-example)

;;; ==============================
;;; :NOTE Uses (pushnew X PLACE :test 'equal) idiom - b/c `add-to-list' bites!
;;; :CREATED <Timestamp: #{2009-11-19T14:19:29-05:00Z}#{09474} - by MON>
(defun mon-tramp-add-default-methods ()
  "Map elts of `*mon-tramp-default-methods-l*' to `tramp-default-method-alist'.
When `IS-MON-P-W32' add the the 'plinkx' methods.
When `IS-MON-P-GNU' add the the ssh-agent style methods.
:SEE-ALSO `tramp-default-method-alist', `tramp-default-method'\n►►►"
  ;; (let ((IS-MON-P-GNU t)   ; :FOR-TESTING cross-platform.
  ;;      (IS-MON-P-W32 nil)) ; :FOR-TESTING cross-platform.
  (cond (IS-MON-P-W32 
         (mapc (lambda (x) 
                 (pushnew (list x "" "plinkx") tramp-default-method-alist :test 'equal))
               (car *mon-tramp-default-methods-l*)) t) ;; Return t to obfuscate setq side-effects.
        (IS-MON-P-GNU 
         (mapc (lambda (x) 
                 (pushnew x tramp-default-method-alist :test 'equal))
               (cadr *mon-tramp-default-methods-l*)) t))
  ) ;; )) ; :CLOSE-TESTING cross-platform.
;; Evaluate it now.
(mon-tramp-add-default-methods)

;;; ==============================
;;; :CREATED <Timestamp: #{2009-11-19T15:04:05-05:00Z}#{09474} - by MON>
(defun mon-tramp-putty-conf-status ()
  "Retrun a two elt list of executable paths for pageant, putty, plink.
First elt is a formatted string of paths.Second is an alist as same.\n
:EXAMPLE\n\(mon-tramp-putty-conf-status\)
\(car \(mon-tramp-putty-conf-status\)\)
\(cadr \(mon-tramp-putty-conf-status\)\)
\(assoc 'putty \(cadr \(mon-tramp-putty-conf-status\)\)\)\n
:SEE-ALSO `*mon-tramp-putty-private-keys*', `mon-tramp-add-pageant-keys'\n►►►"
  (interactive)
(let* ((putty-stat-l
        `((pageant ,(executable-find "pageant.exe"))
          (putty   ,(executable-find "putty.exe"))
          (plink   ,(executable-find "plink.exe"))))
          ;; (bubba  ,(executable-find "bubba.exe")) ;; :DEBUG-TRACER
         (putty-stat-str           
           (mapconcat 
            #'(lambda (x) (concat (format "The %s path is -> %s" (car x) (cadr x))))
            putty-stat-l
            "\n")))
  `(,putty-stat-str ,putty-stat-l)))
;;
;;; :TEST-ME (mon-tramp-putty-conf-status)
;;; :TEST-ME (car (mon-tramp-putty-conf-status))
;;; :TEST-ME (cadr (mon-tramp-putty-conf-status))
;;; :TEST-ME (assoc 'putty (cadr (mon-tramp-putty-conf-status)))

;;; ==============================
;;; :CREATED <Timestamp: #{2009-11-19T15:20:00-05:00Z}#{09474} - by MON>
(defun mon-tramp-add-pageant-keys ()
  "Add all keys in var `*mon-tramp-putty-private-keys*' to the putty agant.
Signal error if symbol pageant is associated in `mon-tramp-putty-conf-status'
:NOTE existing keys will be over-written.
:SEE-ALSO `mon-ssh-add-p'\n►►►"
  (interactive)
  (let ((pag (cadr (assoc 'pageant (cadr (mon-tramp-putty-conf-status))))))
    (if pag 
        (setq pag (replace-regexp-in-string "/" "\\\\" pag))
        (error "No pageant.exe located"))
    (w32-shell-execute 
     "open" pag (mapconcat 'identity *mon-tramp-putty-private-keys* " "))))
;; 
;;; :TEST-ME (mon-tramp-add-pageant-keys)

;;; ==============================
;;; :COURTESY Roland Winkler help.gnu.emacs :DATE 2008-03-30
;;; :SUBJECT "tramp and ssh-agent / ssh-add"
;;; :CREATED <Timestamp: #{2009-11-19T14:19:24-05:00Z}#{09474} - by MON>
(defun mon-ssh-add-p ()
  "On GNU/LINUX return t if ssh-add -l has know identities.
On W32 message user about putty/pagent/plink.
:SEE-ALSO `mon-tramp-add-pageant-keys'.\n►►►"
(interactive)
(if IS-MON-P-GNU
    (with-temp-buffer
      (call-process "/usr/bin/ssh-add" nil t nil "-l")
      (goto-char (point-min))
      (not (search-forward "The agent has no identities." nil t)))
    (message "A ssh-agent is not available on w32; use command `mon-tramp-add-pageant-keys'")))

;;; ==============================
;;; :CREATED <Timestamp: #{2009-11-20T12:53:50-05:00Z}#{09475} - by MON KEY>
(defun mon-tramp-read-conns ()
  "Return a tramp connection for `mon-tramp-connect'.
Return value is conditional on whether `IS-MON-P-W32' or `IS-MON-P-GNU'.\n
:EXAMPLE\n(mon-tramp-read-conns)\n
:SEE-ALSO `*mon-tramp-paths-alist*'\n►►►"
  (let (;; (IS-MON-P-W32 nil) ; :FOR-TESTING cross-platform.
        ;; (IS-MON-P-GNU t)   ; :FOR-TESTING cross-platform.
        (conn-key (mapcar #'(lambda (x) 
                              (format "%s" (car x))) *mon-tramp-paths-alist*))
        (read-conn))
    (setq read-conn (read (completing-read "Choose a connection (tab completes): " conn-key nil t)))
    (setq read-conn (assoc read-conn *mon-tramp-paths-alist*))
(cond (IS-MON-P-W32
       (let ((tst-can-conn (elt read-conn 2)))
         (if (and tst-can-conn ; Is not nil.
                  (not (eq "" tst-can-conn))) ; And has a value.
                  tst-can-conn
                  (error "Can't find a connection for this system"))))
      (IS-MON-P-GNU        
       (let ((tst-can-conn (elt read-conn 1)))
         (if (and tst-can-conn ; Is not nil.
                  (not (eq "" tst-can-conn))) ; And has a value.
             tst-can-conn
             (error "Can't find a connection for this system")))))))
;;
;;; :TEST-ME (mon-tramp-read-conns)

;;; ==============================
;;; :CREATED <Timestamp: #{2009-11-15T20:10:48-05:00Z}#{09467} - by MON KEY>
(defun mon-tramp-connect (&optional tramp-path)
  "Tramp to a host in the `*mon-tramp-default-methods-l*'.
Use `mon-tramp-read-conns' to specify the host.
Completions return per current system's type `IS-MON-P-W32' or `IS-MON-P-GNU'.
When TRAMP-PATH is non-nil attempt to connect to specified host.
:SEE-ALSO `mon-tramp-disconnect', `mon-tramp-su-local'.\n►►►"
  (interactive "i")
  (if tramp-path
      (dired tramp-path)
      (dired (mon-tramp-read-conns))))
;;
;;; :TEST-ME (mon-tramp-connect)

;;; ==============================
;;; :CREATED <Timestamp: #{2009-11-18T15:14:11-05:00Z}#{09473} - by MON KEY>
(defun mon-tramp-disconnect ()
  "All remote connections are cleaned up.  
All buffers, which are related to a remote connection, are killed.
Flushes objects for all active remote connections. For more fine grained control
:SEE `tramp-cleanup-all-connections', `tramp-cleanup-all-buffers'
`tramp-cleanup-connection'.
:SEE-ALSO `mon-tramp-connect', `mon-tramp-read-conns'\n►►►"
  (interactive)
  (progn
    (tramp-cleanup-all-connections)
    (tramp-cleanup-all-buffers)))

;;; ==============================
;;; :CREATED <Timestamp: #{2009-09-27T02:36:30-04:00Z}#{09397} - by MON KEY>
(defun mon-tramp-su-local ()
  "Open a local tramp shell process with su.\n
Don't be concerned by those nagging voices in your head:\n
   \"Are you crazy God damnit?
    Don't you think its a little risky to tramp this CPU?\"\n
Steel yourself and quiet those doubts with your best Colonel Kilgore:\n
    If I say its safe to su this CPU, then its safe to su this CPU. 
    I mean I'm not afraid to su this CPU, I'll su this whole fucking CPU! 
    Tramps don't sudo!\n►►►"
  (interactive)
  (cond (IS-MON-P-GNU 
         (dired "/su::"))
	(IS-MON-P-W32 "I don't see no su 'round here...")))
;;
;;; :TEST-ME (mon-tramp-su-local)

;;; ==============================
;;; :NOTE
;;; ->  ssh:daniel@melancholia:.emacs
;;; ->  /ssh://daniel@melancholia/.emacs
;;; CREATED: <Timestamp: #{2009-11-11T16:03:52-05:00Z}#{09463} - by MON KEY>
(defun mon-tramp-syntax ()
  "Return the format of for current tramp-syntax.
:SEE info node `(tramp)Alternative Syntax'.\n
:EXAMPLE\n(mon-tramp-syntax)\n
:SEE-ALSO `mon-tramp-putty-conf-status'.\n►►►"
  (interactive "p")
  (cond ((eq tramp-syntax 'url) 
         (princ "/ssh://<NAME>@<MACHINE>/path/to/.emacs"))
        ((eq tramp-syntax 'ftp) 
         (princ "ssh:<NAME>@<MACHINE>:/path/to/.emacs"))))
;;
;;; :TEST-ME (mon-tramp-syntax)

;;; ==============================
;;; :NOTE only _think_ about using this if other solutions unavialble.
;;; :SEE Michael Albinus' response to this implementation and recs to use
;;; password.el instead. Or, consider auth-source.el as pass handler.
;;; :COURTESY Roland Winkler help.gnu.emacs :DATE 2008-03-30
;;; :SUBJECT "tramp and ssh-agent / ssh-add"
;;; :CREATED <Timestamp: #{2009-11-19T14:19:24-05:00Z}#{09474} - by MON>
;;; ==============================
;;; (defun mon-ssh-add-pass (&optional password)
;;;   "Add ssh passphrase."
;;;   (interactive)
;;;   (if (ssh-add-p)
;;;       (if (interactive-p) (message "Passphrase already entered."))
;;;     (with-temp-buffer
;;;       (insert (or password (read-passwd "Passphrase: ")) "\n")
;;;       (let ((process-environment (copy-alist process-environment)))
;;;         (setenv "DISPLAY") ;; unset DISPLAY
;;;         (call-process-region (point-min) (point-max)
;;;                              "/usr/bin/ssh-add" t t nil))
;;;       ;; Massage output
;;;       (goto-char (point-min))
;;;       ;; suppress "Enter passphrase for ...: "
;;;       (search-forward ": " nil t)
;;;       (let ((beg (point)))
;;;         (goto-char (point-max))
;;;         (skip-chars-backward " \t\n")
;;;         (message "%s" (buffer-substring-no-properties beg (point)))))))

;;; ==============================
(provide 'mon-tramp-utils)
;;; ==============================

;;; ================================================================
;;; mon-tramp-utils.el ends here
;;; EOF