;;; term-utils.el --- Common code used by term.el and comint.el -*- lexical-binding: t; -*- ;; Copyright (C) 2018 Tino Calancha ;; Author: Tino Calancha ;; Keywords: processes, terminals ;; 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 . ;;; Commentary: ;; ;;; code: ;; Retrieve the right defvar value according with the buffer mode. (defmacro term-utils--defvar-value (suffix) "Build a defvar with the `major-mode' and SUFFIX, return its value. The buffer major mode must be `term-mode' or `comint-mode'." (declare (debug (symbolp)) (indent 0)) `(symbol-value (intern-soft (format "%S%S" (if (derived-mode-p 'term-mode) 'term- 'comint-) ',suffix)))) ;; AIX puts the name of the person being su'd to in front of the prompt. ;; kinit prints a prompt like `Password for devnull@GNU.ORG: '. ;; ksu prints a prompt like `Kerberos password for devnull/root@GNU.ORG: '. ;; ssh-add prints a prompt like `Enter passphrase: '. ;; plink prints a prompt like `Passphrase for key "root@GNU.ORG": '. ;; Ubuntu's sudo prompts like `[sudo] password for user:' ;; Some implementations of passwd use "Password (again)" as the 2nd prompt. ;; Something called "perforce" uses "Enter password:". ;; See M-x comint-testsuite--test-comint-password-prompt-regexp. (defcustom term-utils-password-prompt-regexp (concat "\\(^ *\\|" (regexp-opt '("Enter" "enter" "Enter same" "enter same" "Enter the" "enter the" "Old" "old" "New" "new" "'s" "login" "Kerberos" "CVS" "UNIX" " SMB" "LDAP" "PEM" "SUDO" "[sudo]" "Repeat" "Bad" "Retype") t) " +\\)" "\\(?:" (regexp-opt password-word-equivalents) "\\|Response\\)" "\\(?:\\(?:, try\\)? *again\\| (empty for no passphrase)\\| (again)\\)?" ;; "[[:alpha:]]" used to be "for", which fails to match non-English. "\\(?: [[:alpha:]]+ .+\\)?[\\s  ]*[::៖][\\s  ]*\\'") "Regexp matching prompts for passwords in the inferior process. This is used by `term-utils-watch-for-password-prompt'." :version "27.1" :type 'regexp :group 'term-utils) (declare-function comint-snapshot-last-prompt "comint") (defun term-utils-send-invisible (&optional prompt) "Read a string without echoing with PROMPT. Then send it to the process running in the current buffer. The string is sent using `comint-input-sender' or `term-input-sender' depending of the buffer mode. Security bug: your string can still be temporarily recovered with \\[view-lossage]; `clear-this-command-keys' can fix that." (interactive "P") ; Defeat snooping via C-x ESC ESC (let ((proc (get-buffer-process (current-buffer))) (prefix (if (eq (window-buffer) (current-buffer)) "" (format "(In buffer %s) " (current-buffer))))) (if proc (let ((str (read-passwd (concat prefix (or prompt "Non-echoed text: "))))) (if (stringp str) (let ((input-sender-fun (term-utils--defvar-value input-sender))) (if (derived-mode-p 'comint-mode) (comint-snapshot-last-prompt)) (funcall input-sender-fun proc str)) (message "Warning: text will be echoed"))) (error "Buffer %s has no process" (current-buffer))))) (defalias 'send-invisible 'term-utils-send-invisible) (defvar term-raw-map) ; Defined in term.el (defun term-utils-term-in-line-mode-p () "Return non-nil if the buffer is in `term-mode' and line submode." (and (derived-mode-p 'term-mode) (eq (current-local-map) term-raw-map))) (defun term-utils-watch-for-password-prompt (string) "Prompt in the minibuffer for password and send without echoing. This function uses `send-invisible' to read and send a password to the buffer's process if STRING contains a password prompt defined by `term-utils-password-prompt-regexp'. This function could be in the lists `comint-output-filter-functions' and `term-output-filter-functions'." ;; Do nothing if buffer is in term-mode with line submode (unless (term-utils-term-in-line-mode-p) (when (let ((case-fold-search t)) (string-match term-utils-password-prompt-regexp string)) (when (string-match "^[ \n\r\t\v\f\b\a]+" string) (setq string (replace-match "" t t string))) (term-utils-send-invisible string)))) (provide 'term-utils) ;;; term-utils.el ends here