home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / lucid / lemacs-19.6 / lisp / packages / crypt.el < prev    next >
Encoding:
Text File  |  1993-01-21  |  25.1 KB  |  683 lines

  1. ;;; crypt.el -- Compaction, compression, gzip'sion, and encryption
  2. ;;; version: Revision: 1.5 
  3.  
  4. ;;; Copyright (C) 1988, 1989, 1990 Kyle E. Jones
  5. ;;; Copyright (C) 1993 Free Software Foundation, Inc.
  6. ;;;
  7. ;;; jwz: works with tar-mode.el
  8. ;;; jwz: applied patch from piet, merged with Lawrence Dodd's gzip version
  9. ;;; lrd: v1.3 fixed compress-magic-regexp 
  10. ;;; lrd: v1.4 write-file compresses or gzips based on file extension
  11. ;;; 
  12. ;;; This program is free software; you can redistribute it and/or modify
  13. ;;; it under the terms of the GNU General Public License as published by
  14. ;;; the Free Software Foundation; either version 1, or (at your option)
  15. ;;; any later version.
  16. ;;;
  17. ;;; This program is distributed in the hope that it will be useful,
  18. ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20. ;;; GNU General Public License for more details.
  21. ;;;
  22. ;;; A copy of the GNU General Public License can be obtained from this
  23. ;;; program's author (send electronic mail to kyle@cs.odu.edu) or from
  24. ;;; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
  25. ;;; 02139, USA.
  26. ;;;
  27. ;;; Id: crypt.el,v 1.5 1993/01/08 20:54:56 dodd Exp 
  28. ;;; Send bug reports to Larry Dodd <dodd@roebling.poly.edu>
  29. ;;; Department of Chemical Engineering
  30. ;;; Polymer Research Institute
  31. ;;; Polytechnic University, Brooklyn, NY
  32.  
  33. ;; INSTALLATION:
  34. ;;
  35. ;; To use this package, put it in a file called "crypt.el" in a Lisp
  36. ;; directory that Emacs knows about, byte-compile it, and put the line:
  37. ;;    (require 'crypt)
  38. ;; in your .emacs file or in the file default.el in the "lisp" directory
  39. ;; of the Emacs distribution.  Don't bother trying to autoload this file;
  40. ;; this package uses a find-file hook and thus should be loaded the
  41. ;; first time you visit any sort of file.
  42. ;;
  43. ;; You also may wish to modify the value of `auto-decode-buffer' and 
  44. ;; `auto-write-buffer-coded'
  45. ;;
  46. ;; The basic purpose of this package of Lisp functions is to automatically
  47. ;; recognize encrypted, compacted, gzip'ed or compressed files when they
  48. ;; are first visited and decode the file's BUFFER before it is presented to
  49. ;; the user.  The file itself is unchanged.  When the buffer is subsequently
  50. ;; saved to disk, a hook function re-encodes the buffer before the actual disk
  51. ;; write takes place.
  52. ;;
  53. ;; This package recognizes compacted, gzip'ed and compressed files by a magic
  54. ;; number at the beginning of these files, but a heuristic is used to detect
  55. ;; encrypted files.  If you are asked for an encryption key for a file that is
  56. ;; in fact not encrypted, just hit RET and the file will be accepted as is,
  57. ;; and the crypt minor mode will not be entered.
  58.  
  59. (provide 'crypt)
  60.  
  61. (defvar crypt-encryption-program "des -f -e -k")
  62. (defvar crypt-decryption-program "des -f -d -k")
  63.  
  64. (defvar encryption-program "des -e -k")
  65. (defvar decryption-program "des -d -k")
  66.  
  67. (defvar auto-decode-buffer t
  68.   "*Non-nil value means that the buffers associated with encoded files will
  69. be decoded automatically, without requesting confirmation from the user.
  70. Nil means to ask before doing the decoding.")
  71.  
  72. (defvar auto-write-buffer-coded nil
  73.   "*Non-nil value means buffers to be written to files ending in .z (or .Z)
  74. will be gzip'ed (or compressed) automatically, without requesting confirmation
  75. from the user. Nil means to ask before doing this decoding.")
  76.  
  77. (defvar buffer-save-encrypted nil
  78.   "*Non-nil means that when this buffer is saved it will be written out
  79. encrypted, as with the UNIX crypt(1) command.  Automatically local to all
  80. buffers.")
  81. (make-variable-buffer-local 'buffer-save-encrypted)
  82.  
  83. (defvar buffer-save-compacted nil
  84.   "*Non-nil means that when this buffer is saved it will be written out
  85. compacted, as with the UNIX compact(1) command.  Automatically local to all
  86. buffers.")
  87. (make-variable-buffer-local 'buffer-save-compacted)
  88.  
  89. (defvar buffer-save-compressed nil
  90.   "*Non-nil means that when this buffer is saved it will be written out
  91. compressed, as with the UNIX compress(1) command.  Automatically local to all
  92. buffers.")
  93. (make-variable-buffer-local 'buffer-save-compressed)
  94.  
  95. ;; gzip (GNU zip)
  96. (defvar buffer-save-gzipped nil
  97.   "*Non-nil means that when this buffer is saved it will be written out
  98. gzip'ed, as with the gzip (GNU zip) command.  Automatically local to all
  99. buffers.")
  100. (make-variable-buffer-local 'buffer-save-gzipped)
  101.  
  102. (defvar buffer-encryption-key nil
  103.   "*Key to use when encrypting the current buffer, prior to saving it.
  104. Automatically local to all buffers.")
  105. (make-variable-buffer-local 'buffer-encryption-key)
  106.  
  107. (defconst compact-magic-regexp "\377\037"
  108.   "Regexp that matches the magic number at the beginning of files created
  109. by the compact(1) command.")
  110.  
  111. (defconst compress-magic-regexp "\037\235"
  112.   "Regexp that matches the magic number at the beginning of files created
  113. by the compress(1) command.")
  114.  
  115. ;; gzip (GNU zip)
  116. (defconst gzip-magic-regexp "\037\213"
  117.   "Regexp that matches the magic number at the beginning of files created
  118. by the gzip command.")
  119.  
  120. ;; Encrypted files have no magic number, so we have to hack a way of
  121. ;; determining which new buffers start in crypt mode.  The current setup is
  122. ;; that we use only buffers that have a non-ASCII character very close to
  123. ;; beginning of buffer and that do NOT match crypt-magic-regexp-inverse.
  124. ;; Currently crypt-magic-regexp-inverse will match Sun OS, 4.x BSD, and
  125. ;; Ultrix executable magic numbers, so binaries can still be edited (heh)
  126. ;; without headaches.
  127.  
  128. (defconst crypt-magic-regexp-inverse
  129.   "\\(..\\)?\\([\007\010\013]\001\\|\001[\007\010\013]\\)"
  130.   "Regexp that must NOT match the beginning of an encrypted buffer.")
  131.  
  132. (defmacro save-point (&rest body)
  133.   "Save value of point, evalutes FORMS and restore value of point.
  134. If the saved value of point is no longer valid go to (point-max).
  135. This macro exists because, save-excursion loses track of point during
  136. some types of deletions."
  137.   (let ((var (make-symbol "saved-point")))
  138.     (list 'let (list (list var '(point)))
  139.       (list 'unwind-protect
  140.         (cons 'progn body)
  141.         (list 'goto-char var)))))
  142.  
  143.  
  144. (defun find-crypt-file-hook ()
  145.   (let ((buffer-file-name buffer-file-name)
  146.     (old-buffer-file-name buffer-file-name)
  147.     (old-buffer-modified-p (buffer-modified-p))
  148.     encrypted compressed gzipped compacted
  149.     case-fold-search buffer-read-only)
  150.     ;; We can reasonably assume that either compaction or compression will
  151.     ;; be used, or neither, but not both.
  152.     (save-point
  153.      (save-restriction
  154.        (widen)
  155.        (goto-char (point-min))
  156.        (cond 
  157.     
  158.     ;; 
  159.     ;; compact
  160.     ;;
  161.     ((and (looking-at compact-magic-regexp)
  162.           (or auto-decode-buffer
  163.           (y-or-n-p (format "Uncompact buffer %s? "
  164.                     (buffer-name)))))
  165.      (message "Uncompacting %s..." (buffer-name))
  166.      (compact-buffer (current-buffer) t)
  167.      ;; We can't actually go into compact mode yet because the major
  168.      ;; mode may change later on and blow away all local variables
  169.      ;; (and thus the minor modes).  So we make a note to go into
  170.      ;; compact mode later.
  171.      (setq compacted t)
  172.      ;; here we strip the compacted file's .C extension so that later
  173.      ;; we can set the buffer's major mode based on this modified
  174.      ;; name instead of the name with the .C extension.
  175.      ;; note: case-fold-search is `nil'
  176.      (if (string-match "\\(\\.C\\)$" buffer-file-name)
  177.          (setq buffer-file-name
  178.            (substring buffer-file-name 0 (match-beginning 1))))
  179.      (if (not (input-pending-p))
  180.          (message "Uncompacting %s... done" (buffer-name))))
  181.     
  182.     ;;
  183.     ;; compress
  184.     ;;
  185.     ((and (looking-at compress-magic-regexp)
  186.           (or auto-decode-buffer
  187.           (y-or-n-p (format "Uncompress buffer %s? "
  188.                     (buffer-name)))))
  189.      (message "Uncompressing %s..." (buffer-name))
  190.      (compress-buffer (current-buffer) t)
  191.      (setq compressed t)
  192.      ;; note: case-fold-search is `nil'
  193.      (if (string-match "\\(\\.Z\\)$" buffer-file-name)
  194.          (setq buffer-file-name
  195.            (substring buffer-file-name 0 (match-beginning 1))))
  196.      (if (not (input-pending-p))
  197.          (message "Uncompressing %s... done" (buffer-name))))
  198.     
  199.     ;; 
  200.     ;; gzip (GNU zip)
  201.     ;; 
  202.     ((and (looking-at gzip-magic-regexp)
  203.           (or auto-decode-buffer
  204.           (y-or-n-p (format "gunzip buffer %s? "
  205.                     (buffer-name)))))
  206.      (message "gunzip'ing %s..." (buffer-name))
  207.      (gzip-buffer (current-buffer) t)
  208.      (setq gzipped t)
  209.      ;; note: case-fold-search is `nil'
  210.      (if (string-match "\\(\\.z\\)$" buffer-file-name)
  211.          (setq buffer-file-name
  212.            (substring buffer-file-name 0 (match-beginning 1))))
  213.      (if (not (input-pending-p))
  214.          (message "gunzip'ing %s... done" (buffer-name))))
  215.     )
  216.        ;; Now peek at the file and see if it still looks like a binary file.
  217.        ;; If so, try the crypt-magic-regexp-inverse against it and if it FAILS
  218.        ;; we assume that this is an encrypted buffer.
  219.        (cond ((and (not (eobp))
  220.            (re-search-forward "[\200-\377]" (min (point-max) 15) t)
  221.            (goto-char (point-min))
  222.            (not (looking-at crypt-magic-regexp-inverse)))
  223.           (if (not buffer-encryption-key)
  224.           (call-interactively 'set-encryption-key))
  225.           ;; if user did not enter a key, turn off crypt mode.
  226.           ;; good for binaries that crypt-magic-regexp-inverse
  227.           ;; doesn't recognize.
  228.           ;; -- thanx to Paul Dworkin (paul@media-lab.media.mit.edu)
  229.           (if (equal buffer-encryption-key "")
  230.           (message "No key given, buffer %s assumed normal."
  231.                (buffer-name))
  232.         (message "Decrypting %s..." (buffer-name))
  233.         (crypt-buffer buffer-encryption-key nil)
  234.         ;; Tuck the key away for safe keeping since setting the major
  235.         ;; mode may well blow it away.
  236.         (setq encrypted buffer-encryption-key)
  237.         (if (not (input-pending-p))
  238.             (message "Decrypting %s... done" (buffer-name))))))
  239.        ))
  240.     ;; OK, if any changes have been made to the buffer we need to rerun the
  241.     ;; code the does automatic selection of major mode.
  242.     (cond ((or compressed gzipped compacted encrypted)
  243.        (set-auto-mode)
  244.        (hack-local-variables)
  245.        ;; Now set our minor modes.
  246.        (if compressed (compress-mode 1))
  247.        (if gzipped (gzip-mode 1))
  248.        (if compacted (compact-mode 1))
  249.        (if encrypted
  250.            (progn (crypt-mode 1)
  251.               (setq buffer-encryption-key encrypted)))
  252.        ;; Restore buffer file name now, so that lock file entry is
  253.        ;; removed properly.
  254.        (setq buffer-file-name old-buffer-file-name)
  255.        ;; Restore buffer modified flag to its previous value.
  256.        ;; This will also remove the lock file entry for the buffer
  257.        ;; if the previous value was nil; this is why buffer-file-name
  258.        ;; had to be manually restored above.
  259.        (set-buffer-modified-p old-buffer-modified-p)))))
  260.  
  261.  
  262. ;; This function should be called ONLY as a write-file hook.
  263. ;; Odd things will happen if it is called elsewhere.
  264.  
  265. (defun write-crypt-file-hook ()
  266.   "Writes out file, if need be, in a compressed format."
  267.   
  268.   ;; write out non-plain if the filename ends in `.Z' or `.z'
  269.   (let (case-fold-search)
  270.  
  271.     ;; compress
  272.     (setq buffer-save-compressed
  273.       (or buffer-save-compressed 
  274.           ;; original file is not in compressed format but 
  275.           ;; does the file name end in `.Z'? 
  276.           (and (string-match "\\.Z$" buffer-file-name)
  277.            (or auto-write-buffer-coded
  278.                (y-or-n-p "write file compressed? ")))))
  279.  
  280.     ;; gzip (GNU zip)
  281.     (setq buffer-save-gzipped
  282.       (or buffer-save-gzipped 
  283.           ;; original file is not in gzip'ed format but 
  284.           ;; does the file name end in `.z'? 
  285.           (and (string-match "\\.z$" buffer-file-name)
  286.            (or auto-write-buffer-coded 
  287.                (y-or-n-p "write file gzip'ed? "))))))
  288.  
  289.   ;; does the buffer needed to be saved in a non-plain form?
  290.   (cond
  291.    ((or buffer-save-encrypted buffer-save-compacted
  292.     buffer-save-compressed buffer-save-gzipped)
  293.     (save-excursion
  294.       (save-restriction
  295.     (let ((copy-buffer (get-buffer-create " *crypt copy buffer*"))
  296.           (selective-display selective-display)
  297.           (buffer-read-only nil)
  298.           (before-change-function nil) ; don't slow things down too much...
  299.           (after-change-function nil)
  300.           )
  301.       (copy-to-buffer copy-buffer 1 (1+ (buffer-size)))
  302.       (narrow-to-region (point) (point))
  303.       (unwind-protect
  304.           (progn
  305.         (insert-buffer-substring copy-buffer)
  306.         (kill-buffer copy-buffer)
  307.         ;; selective-display non-`nil' means we must convert carriage
  308.         ;; returns to newlines now, and set selective-display
  309.         ;; temporarily to nil.
  310.         (cond (selective-display
  311.                (goto-char (point-min))
  312.                (subst-char-in-region (point-min) (point-max) ?\r ?\n)
  313.                (setq selective-display nil)))
  314.  
  315.         (cond
  316.          (buffer-save-encrypted
  317.           (if (null buffer-encryption-key)
  318.               (error "No encryption key set for buffer %s"
  319.                  (buffer-name)))
  320.           (if (not (stringp buffer-encryption-key))
  321.               (error "Encryption key is not a string"))
  322.           (message "Encrypting %s..." (buffer-name))
  323.           (crypt-buffer buffer-encryption-key t)))
  324.  
  325.         (cond
  326.          ;; error?
  327.          ((and buffer-save-compacted buffer-save-compressed)
  328.           (error "Cannot compact and compress buffer %s"
  329.              (buffer-name)))
  330.          (buffer-save-compacted
  331.           (message "Compacting %s..." (buffer-name))
  332.           (compact-buffer))
  333.  
  334.          (buffer-save-compressed
  335.           (let ((case-fold-search nil))
  336.             (cond
  337.              ;;
  338.              ;; compress iff file name ends in `.Z'
  339.              ((string-match "\\.Z$" buffer-file-name)
  340.               ;; write compressed
  341.               (message "Compressing %s..." (buffer-name))
  342.               (compress-buffer))
  343.              ;;
  344.              ;; gzip iff file name ends in `.z'
  345.              ((string-match "\\.z$" buffer-file-name)
  346.               ;; write gzip'ed - compress mode off, gzip mode on
  347.               (message "gzip'ing %s..." (buffer-name))
  348.               (compress-mode -1)
  349.               (gzip-mode 1)
  350.               (gzip-buffer))
  351.              ;;
  352.              ;; write as plain file -- turn off compress mode
  353.              (t (compress-mode -1)
  354.             (message "Writing %s..." (buffer-name))))))
  355.          ;;
  356.          ;; gzip (GNU zip)
  357.          (buffer-save-gzipped
  358.           (let (case-fold-search)
  359.             (cond
  360.              ;;
  361.              ;; gzip iff file name ends in `.z'
  362.              ((string-match "\\.z$" buffer-file-name)
  363.               ;; write gzip'ed
  364.               (message "gzip'ing %s..." (buffer-name))
  365.               (gzip-buffer))
  366.              ;;
  367.              ;; compress iff file name ends in `.Z'
  368.              ((string-match "\\.Z$" buffer-file-name)
  369.               ;; write compressed - gzip mode off, compress mode on
  370.               (message "Compressing %s..." (buffer-name))
  371.               (gzip-mode -1)
  372.               (compress-mode 1)
  373.               (compress-buffer))
  374.                
  375.              ;; write as plain file -- turn off gzip mode
  376.              (t (gzip-mode -1)
  377.             (message "Writing %s..." (buffer-name))))))
  378.          )
  379.         ;;
  380.         ;; write buffer/region to disk
  381.         (write-region (point-min) (point-max) buffer-file-name nil t)
  382.         (delete-region (point-min) (point-max))
  383.         (set-buffer-modified-p nil)
  384.         ;;  
  385.         ;; return t so that basic-save-buffer will
  386.         ;; know that the save has already been done.
  387.         ;; note that this terminates write-file-hooks.
  388.         t)
  389.         ;; unwind...
  390.         ;; If the crypted stuff has already been removed
  391.         ;; then this is a no-op.
  392.         (delete-region (point-min) (point-max)))))))))
  393.  
  394.               
  395. (defun crypt-region (start end encrypt key)
  396.   "Encrypt/decrypt the text in the region.
  397. From a program, this function takes four args: START, END, ENCRYPT and KEY.
  398. When called interactively START and END default to point and mark
  399. \(START being the lesser of the two), KEY is prompted for."
  400.   (interactive
  401.    (progn
  402.      (barf-if-buffer-read-only)
  403.      (list
  404.       (region-beginning)
  405.       (region-end)
  406.       (y-or-n-p "Encrypt? ")
  407.       (read-string-no-echo "Crypt region using key: "))))
  408.   (save-point
  409.    (let ((opoint-max (point-max)))
  410.      (call-process-region start end shell-file-name t t nil "-c"
  411.               (concat (if encrypt
  412.                       encryption-program decryption-program)
  413.                   " " key)))))
  414.  
  415. (defun crypt-buffer (key encrypt &optional buffer)
  416.   "Using KEY, encrypt/decrypt BUFFER.
  417. BUFFER defaults to the current buffer."
  418.   (interactive
  419.    (progn
  420.      (barf-if-buffer-read-only)
  421.      (list (read-string-no-echo "Crypt buffer using key: "))))
  422.   (or buffer (setq buffer (current-buffer)))
  423.   (save-excursion
  424.     (set-buffer buffer)
  425.     (crypt-region (point-min) (point-max) encrypt key)))
  426.  
  427. (defun compact-region (start end &optional undo)
  428.   "Compact the text in the region.
  429. From a program, this function takes three args: START, END and UNDO.
  430. When called interactively START and END default to point and mark
  431. \(START being the lesser of the two).
  432. Prefix arg (or optional second arg non-nil) UNDO means uncompact."
  433.   (interactive "*r\nP")
  434.   (save-point
  435.    (call-process-region start end shell-file-name t t nil "-c"
  436.             (if undo "uncompact" "compact"))
  437.    (cond ((not undo)
  438.       (goto-char start)
  439.       (let (case-fold-search)
  440.         (if (not (looking-at compact-magic-regexp))
  441.         (error "%s failed!" (if undo
  442.                     "Uncompaction"
  443.                       "Compaction"))))))))
  444.  
  445. (defun compact-buffer (&optional buffer undo)
  446.   "Compact BUFFER.
  447. BUFFER defaults to the current buffer.
  448. Prefix arg (or second arg non-nil from a program) UNDO means uncompact."
  449.   (interactive (list (current-buffer) current-prefix-arg))
  450.   (or buffer (setq buffer (current-buffer)))
  451.   (save-excursion
  452.     (set-buffer buffer)
  453.     (compact-region (point-min) (point-max) undo)))
  454.  
  455. (defun compress-region (start end &optional undo)
  456.   "Compress the text in the region.
  457. From a program, this function takes three args: START, END and UNDO.
  458. When called interactively START and END default to point and mark
  459. \(START being the lesser of the two).
  460. Prefix arg (or optional second arg non-nil) UNDO means uncompress."
  461.   (interactive "*r\nP")
  462.   (save-point
  463.    (call-process-region start end shell-file-name t t nil "-c"
  464.             (if undo "compress -d" "compress"))
  465.    (cond ((not undo)
  466.       (goto-char start)
  467.       (let (case-fold-search)
  468.         (if (not (looking-at compress-magic-regexp))
  469.         (error "%s failed!" (if undo
  470.                     "Uncompression"
  471.                       "Compression"))))))))
  472.  
  473. (defun compress-buffer (&optional buffer undo)
  474.   "Compress BUFFER.
  475. BUFFER defaults to the current buffer.
  476. Prefix arg (or second arg non-nil from a program) UNDO means uncompress."
  477.   (interactive (list (current-buffer) current-prefix-arg))
  478.   (or buffer (setq buffer (current-buffer)))
  479.   (save-excursion
  480.     (set-buffer buffer)
  481.     (compress-region (point-min) (point-max) undo)))
  482.  
  483. ;; gzip (GNU zip)
  484. (defun gzip-region (start end &optional undo)
  485.   "gzip the text in the region.
  486. From a program, this function takes three args: START, END and UNDO.
  487. When called interactively START and END default to point and mark
  488. \(START being the lesser of the two).
  489. Prefix arg (or optional second arg non-nil) UNDO means gunzip."
  490.   (interactive "*r\nP")
  491.   (save-point
  492.    (call-process-region start end shell-file-name t t nil "-c"
  493.             (if undo "gzip -d" "gzip"))
  494.    (cond ((not undo)
  495.       (goto-char start)
  496.       (let (case-fold-search)
  497.         (if (not (looking-at gzip-magic-regexp))
  498.         (error "%s failed!" (if undo
  499.                     "gunzip'ing"
  500.                       "gzip'ing"))))))))
  501.  
  502. ;; gzip (GNU zip)
  503. (defun gzip-buffer (&optional buffer undo)
  504.   "gzip BUFFER.
  505. BUFFER defaults to the current buffer.
  506. Prefix arg (or second arg non-nil from a program) UNDO means gunzip."
  507.   (interactive (list (current-buffer) current-prefix-arg))
  508.   (or buffer (setq buffer (current-buffer)))
  509.   (save-excursion
  510.     (set-buffer buffer)
  511.     (gzip-region (point-min) (point-max) undo)))
  512.  
  513. (defun set-encryption-key (key &optional buffer)
  514.   "Set the encryption KEY for BUFFER.
  515. KEY should be a string.
  516. BUFFER should be a buffer or the name of one;
  517. it defaults to the current buffer.  If BUFFER is in crypt mode, then it is
  518. also marked as modified, since it needs to be saved with the new key."
  519.   (interactive
  520.    (progn
  521.      (barf-if-buffer-read-only)
  522.      (list
  523.       (read-string-no-echo
  524.        (format "Set encryption key for buffer %s: " (buffer-name))))))
  525.   (or buffer (setq buffer (current-buffer)))
  526.   (save-excursion
  527.     (set-buffer buffer)
  528.     (if (equal key buffer-encryption-key)
  529.     (message "Key is identical to original, no change.")
  530.       (setq buffer-encryption-key key)
  531.       ;; don't touch the modify flag unless we're in crypt-mode.
  532.       (if buffer-save-encrypted
  533.       (set-buffer-modified-p t)))))
  534.  
  535. (defun crypt-mode (&optional arg)
  536.   "Toggle crypt mode.
  537. With arg, turn crypt mode on iff arg is positive, otherwise turn it off.
  538. In crypt mode, buffers are automatically encrypted before being written.
  539. If crypt mode is toggled and a key has been set for the current buffer, then
  540. the current buffer is marked modified, since it needs to be rewritten
  541. with (or without) encryption.
  542.  
  543. Use \\[set-encryption-key] to set the encryption key for the current buffer.
  544.  
  545. Entering crypt mode causes auto-saving to be turned off in the current buffer,
  546. as there is no way (in Emacs Lisp) to force auto save files to be encrypted."
  547.   (interactive "P")
  548.   (let ((oldval buffer-save-encrypted))
  549.     (setq buffer-save-encrypted
  550.       (if arg (> arg 0) (not buffer-save-encrypted)))
  551.     (if buffer-save-encrypted
  552.     (auto-save-mode 0)
  553.       (auto-save-mode (if (and auto-save-default buffer-file-name) 1 0)))
  554.     (if buffer-encryption-key
  555.     (set-buffer-modified-p
  556.      (not (eq oldval buffer-save-encrypted))))))
  557.  
  558. (defun compact-mode (&optional arg)
  559.   "Toggle compact mode.
  560. With arg, turn compact mode on iff arg is positive, otherwise turn it off.
  561. In compact mode, buffers are automatically compacted before being written.
  562. If compact mode is toggled, the current buffer is marked modified, since
  563. it needs to be written with (or without) compaction.
  564.  
  565. Entering compact mode causes auto-saving to be turned off in the current
  566. buffer, as there is no way (in Emacs Lisp) to force auto save files to be
  567. compacted."
  568.   (interactive "P")
  569.   (let ((oldval buffer-save-compacted))
  570.     (setq buffer-save-compacted
  571.       (if arg (> arg 0) (not buffer-save-compacted)))
  572.     (if buffer-save-compacted
  573.     (auto-save-mode 0)
  574.       (auto-save-mode (if (and auto-save-default buffer-file-name) 1 0)))
  575.     (set-buffer-modified-p (not (eq oldval buffer-save-compacted)))))
  576.  
  577. (defun compress-mode (&optional arg)
  578.   "Toggle compress mode.
  579. With arg, turn compress mode on iff arg is positive, otherwise turn it off.
  580. In compress mode, buffers are automatically compressed before being written.
  581. If compress mode is toggled, the current buffer is marked modified, since
  582. it needs to be written with (or without) compression.
  583.  
  584. Entering compress mode causes auto-saving to be turned off in the current
  585. buffer, as there is no way (in Emacs Lisp) to force auto save files to be
  586. compressed."
  587.   (interactive "P")
  588.   (let ((oldval buffer-save-compressed))
  589.     (setq buffer-save-compressed
  590.       (if arg (> arg 0) (not buffer-save-compressed)))
  591.     (if buffer-save-compressed
  592.     (auto-save-mode 0)
  593.       (auto-save-mode (if (and auto-save-default buffer-file-name) 1 0)))
  594.     (set-buffer-modified-p (not (eq oldval buffer-save-compressed)))))
  595.  
  596. ;; gzip (GNU zip)
  597. (defun gzip-mode (&optional arg)
  598.   "Toggle gzip mode.
  599. With arg, turn gzip mode on iff arg is positive, otherwise turn it off.
  600. In gzip mode, buffers are automatically gzip'ed before being written.
  601. If gzip mode is toggled, the current buffer is marked modified, since
  602. it needs to be written with \(or without\) gzip.
  603.  
  604. Entering gzip mode causes auto-saving to be turned off in the current
  605. buffer, as there is no way \(in Emacs Lisp\) to force auto save files to be
  606. gzip'ed."
  607.   (interactive "P")
  608.   (let ((oldval buffer-save-gzipped))
  609.     (setq buffer-save-gzipped
  610.       (if arg (> arg 0) (not buffer-save-gzipped)))
  611.     (if buffer-save-gzipped
  612.     (auto-save-mode 0)
  613.       (auto-save-mode (if (and auto-save-default buffer-file-name) 1 0)))
  614.     (set-buffer-modified-p (not (eq oldval buffer-save-gzipped)))))
  615.  
  616. (defun read-string-no-echo (prompt &optional confirm)
  617.   "Read a string from the minibuffer, prompting with PROMPT.
  618. Optional second argument CONFIRM non-nil means that the user will be asked
  619.   to type the string a second time for confirmation and if there is a
  620.   mismatch, the process is repeated.
  621.  
  622. Line editing keys are:
  623.   C-h, DEL    rubout
  624.   C-u, C-x      line kill
  625.   C-q, C-v      literal next"
  626.   (catch 'return-value
  627.     (save-excursion
  628.       (let ((input-buffer (get-buffer-create " *password*"))
  629.         (cursor-in-echo-area t)
  630.         (echo-keystrokes 0)
  631.         char string help-form done kill-ring)
  632.     (set-buffer input-buffer)
  633.     (unwind-protect
  634.         (while t
  635.           (erase-buffer)
  636.           (message prompt)
  637.           (while (not (memq (setq char (read-char)) '(?\C-m ?\C-j)))
  638.         (if (setq form
  639.               (cdr
  640.                (assq char
  641.                  '((?\C-h . (delete-char -1))
  642.                    (?\C-? . (delete-char -1))
  643.                    (?\C-u . (delete-region 1 (point)))
  644.                    (?\C-x . (delete-region 1 (point)))
  645.                    (?\C-q . (quoted-insert 1))
  646.                    (?\C-v . (quoted-insert 1))))))
  647.             (condition-case error-data
  648.             (eval form)
  649.               (error t))
  650.           (insert char))
  651.         (message prompt))
  652.           (cond ((and confirm string)
  653.              (cond ((not (string= string (buffer-string)))
  654.                 (message
  655.                  (concat prompt "[Mismatch... try again.]"))
  656.                 (ding)
  657.                 (sit-for 2)
  658.                 (setq string nil))
  659.                (t (throw 'return-value string))))
  660.             (confirm
  661.              (setq string (buffer-string))
  662.              (message (concat prompt "[Retype to confirm...]"))
  663.              (sit-for 2))
  664.             (t (throw 'return-value (buffer-string)))))
  665.       (set-buffer-modified-p nil)
  666.       (kill-buffer input-buffer))))))
  667.  
  668. ;; Install the hooks, then add the mode indicators to the minor mode alist.
  669.  
  670. (add-hook 'find-file-hooks        'find-crypt-file-hook)
  671. (add-hook 'find-file-not-found-hooks    'find-crypt-file-hook)
  672. (add-hook 'write-file-hooks        'write-crypt-file-hook t) ; at end
  673.  
  674. (or (assq 'buffer-save-compressed minor-mode-alist)
  675.     (setq minor-mode-alist
  676.       (nconc (mapcar 'purecopy '((buffer-save-encrypted  " Crypt")
  677.                      (buffer-save-compacted  " Compact")
  678.                      (buffer-save-compressed " Compress")
  679.                      (buffer-save-gzipped    " GNU-zip")))
  680.          minor-mode-alist)))
  681.  
  682. (provide 'crypt)
  683.