Mercurial > hg > xemacs-beta
diff lisp/packages/crypt.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | e04119814345 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/packages/crypt.el Mon Aug 13 08:45:50 2007 +0200 @@ -0,0 +1,2584 @@ +;;; crypt.el --- code for handling all sorts of compressed and encrypted files + +;; Author: Lawrence R. Dodd <dodd@roebling.poly.edu> +;; Rod Whitby <rwhitby@research.canon.oz.au> +;; Kyle E. Jones <kyle@uunet.uu.net> +;; Maintainer: Lawrence R. Dodd <dodd@roebling.poly.edu> +;; Created: crypt.el in 1988, crypt++.el on 18 Jan 1993 +;; Version: 2.82 +;; Date: 1994/03/31 12:30:17 +;; Keywords: extensions + +;;; Copyright (C) 1994 Lawrence R. Dodd +;;; Copyright (C) 1993 Lawrence R. Dodd and Rod Whitby +;;; Copyright (C) 1988, 1989, 1990 Kyle E. Jones +;;; +;;; 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 2 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, write to the Free Software +;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +;;; Synched up with: Not in FSF. + +;;; Commentary: + +;;; NOTE: Apparently not being maintained by the author, who now +;;; uses jka-compr.el. --ben (1/26/96) +;;; Included patch (1/26/96) + +;;; Please see notes on INSTALLATION and USAGE on the pages below. + +;;; LCD Archive Entry: +;;; crypt++|Rod Whitby and Lawrence R. Dodd|dodd@roebling.poly.edu| +;;; Code for handling all sorts of compressed and encrypted files.| +;;; 1994/03/31 12:30:17|2.82|~/misc/crypt++.el.Z| + +;;; AVAILABLE: +;;; +;;; via anonymous ftp to roebling.poly.edu [128.238.5.31] in +;;; /pub/lisp/crypt++.el.gz +;;; +;;; via anonymous ftp to archive.cis.ohio-state.edu [128.146.8.52] in +;;; /pub/gnu/emacs/elisp-archive/misc/crypt++.el.Z + +;;; BUG REPORTS +;;; +;;; Type M-x crypt-submit-report to generate a bug report template or put your +;;; cursor at the end of this line and type C-x C-e: (crypt-submit-report) +;;; +;;; Please note that this bug-report facility (crypt-submit-report) uses Barry +;;; Warsaw's reporter.el which is part of GNU Emacs v19 and bundled with many +;;; other packages. If needed, you can obtain a copy of reporter.el at +;;; /roebling.poly.edu:/pub/reporter.el or the elisp-archive. In fact, +;;; crypt-submit-report will attempt to ange-ftp a copy for you from roebling +;;; if you do not have one accessible. + +;;; Lawrence R. Dodd <dodd@roebling.poly.edu> +;;; Polytechnic University +;;; Brooklyn, New York USA + +;;; VERSION: +;;; +;;; Version: 2.82 +;;; Ident: crypt++.el,v 2.82 1994/03/31 12:30:17 dodd Exp +;;; Date: 1994/03/31 12:30:17 + + +;;; INSTALLATION: +;;; +;;; To use this package, simply put it in a file called "crypt.el" in a Lisp +;;; directory known to Emacs (see `load-path'), byte-compile it (you may get a +;;; warning saying that the function reporter-submit-bug-report is not known +;;; to be defined -- ignore it), and put the line: +;;; +;;; (require 'crypt) +;;; +;;; in your ~/.emacs file or in the file default.el in the ../lisp directory +;;; of the Emacs distribution. Do not bother trying to autoload this file; +;;; this package uses find-file and write-file hooks and thus should be loaded +;;; the first time you visit any sort of file. Any package loaded after this +;;; one that appends something to `write-file-hooks' will not be executed +;;; because this package writes out the file. Other packages that append to +;;; `write-file-hooks' should either be modified to prepend to that hook or be +;;; loaded before this one (preferably the former). + +;;; NOTE: encryption users should set `crypt-encryption-type' to one of the +;;; values in `crypt-encryption-alist' (see USAGE below). + +;;; SEE ALSO: /roebling.poly.edu:/pub/crypt++-fnf.el for file-not-found +;;; support for GNU Emacs. + +;;; SPECIAL NOTES: +;;; +;;; If crypt is dumped with the emacs executable, or if it has already been +;;; loaded in an emacs session, then modifying the variables used in building +;;; the encryption and encoding tables will have no effect until these tables +;;; are rebuilt. This may be done with `M-x crypt-rebuild-tables'. See USAGE +;;; below to determine variables for which this is needed. For example, +;;; post-load changes to `crypt-encryption-file-extension' or +;;; `crypt-freeze-vs-fortran' can be incorporated into the encryption table +;;; via `M-x crypt-rebuild-tables'. Similarly, post-load changes to +;;; `crypt-bind-insert-file' are handled with `M-x crypt-bind-insert-file'. + + +;;; USAGE: +;;; +;;; By default, intended to be transparent. User-defined variables +;;; +;;; controlling ENCRYPTION are +;;; +;;; crypt-encryption-type +;;; crypt-encryption-file-extension +;;; crypt-never-ever-decrypt +;;; crypt-auto-write-buffer-encrypted +;;; crypt-confirm-password +;;; crypt-encrypted-disable-auto-save +;;; crypt-encryption-alist +;;; +;;; controlling ENCODING are +;;; +;;; crypt-auto-decode-buffer +;;; crypt-auto-write-buffer +;;; crypt-query-if-interactive +;;; crypt-no-extension-implies-plain +;;; crypt-freeze-vs-fortran +;;; crypt-compact-vs-C++ +;;; crypt-ignored-filenames +;;; crypt-default-encoding +;;; crypt-encoded-disable-auto-save +;;; crypt-encoding-alist +;;; +;;; controlling file insertion are +;;; +;;; crypt-bind-insert-file +;;; crypt-auto-decode-insert +;;; +;;; To find out more about these variables, load this file, put your cursor at +;;; the end of any of the variable names, and hit C-h v [RET]. +;;; +;;; NOTE: encryption users should set `crypt-encryption-type' to one of the +;;; values in `crypt-encryption-alist' +;;; +;;; Although rarely needed, the following functions may be called interactively +;;; +;;; (crypt-encoded-mode) +;;; (crypt-encode-region) +;;; (crypt-encrypted-mode) +;;; (crypt-encrypt-region) +;;; (crypt-set-encryption-key) +;;; (crypt-rebuild-tables) +;;; (crypt-insert-file) +;;; (crypt-bind-insert-file) +;;; (crypt-submit-report) +;;; +;;; To find out more about these functions, load this file, put your cursor +;;; inside any of the `()' of the above lines, and hit C-h f [RET]. + + +;;; NOTES ON INTERFACES WITH OTHER PROGRAMS AND PACKAGES: +;;; +;;; GZIP: the environment variable GZIP of gzip can cause an error if it +;;; contains `--verbose' because standard output messages will be appended to +;;; gzip'ed files. This corrupts the files. The cleanest solution is to pass +;;; the `--quiet' switch in `crypt-encoding-alist' to override this. use gzip +;;; version 1.0.4 or higher from prep.ai.mit.edu:/pub/gnu +;;; +;;; TAR-MODE: works properly with version 1.28 (or higher) with v19 emacs. + + +;;; DESCRIPTION: +;;; +;;; The basic purpose of this package of Lisp functions is to recognize +;;; automatically encrypted and encoded (i.e., compressed) files when they are +;;; first visited or written. The BUFFER corresponding to the file is decoded +;;; and/or decrypted before it is presented to the user. The file itself is +;;; unchanged on the disk. When the buffer is subsequently saved to disk, a +;;; hook function re-encodes the buffer before the actual disk write takes +;;; place. +;;; +;;; This package recognizes all sorts of compressed files by a magic number at +;;; the beginning of these files but uses a heuristic to detect encrypted +;;; files. If you are asked for an encryption key for a file that is in fact +;;; not encrypted, just hit RET and the file will be accepted as is, and the +;;; crypt minor mode will not be entered. +;;; +;;; Other types of encoding programs may be added to this package by using the +;;; variable `crypt-encoding-alist' which contains a table of encoding +;;; programs such as compress, gzip (GNU zip), freeze, and compact. +;;; +;;; This new extended version of crypt now monitors the filename extensions of +;;; buffers that are written out using write-file (C-x C-w). If the filename +;;; extension matches one of the extensions listed in `crypt-encoding-alist,' +;;; then this package will write the file out using the corresponding encoding +;;; (compression) method. This is done whether or not the buffer originated +;;; from a previously encoded (compressed) file. +;;; +;;; Thus, if the user is editing a file that may or may not have been encoded +;;; originally (e.g., foobar.Z or foobar) and decides to write it to a +;;; different file (e.g., barfoo or barfoo.z or barfoo.C). This package will +;;; examine the filename extension and write the buffer in plain format or an +;;; alternate encoding (compression) format by searching through the entries +;;; in the table of encoding methods `crypt-encoding-alist.' This change in +;;; encoding state is done automatically if the variable +;;; `crypt-auto-write-buffer' is t otherwise the user is asked. + + +;;; TO DO/KNOWN BUGS/HELP WANTED/APPLY WITHIN: +;;; +;;; All Users/hackers out there are strongly encouraged to pursue any of these +;;; matters further (especially those that concern encryption and decryption!). +;;; It is important to future programmers and modifiers of crypt++.el to know +;;; about its perceived limitations. Since necessity drives invention, users +;;; who find any of the following features of crypt++.el annoying are asked to +;;; make suggestions and send patches (again, especially those that concern +;;; encryption and decryption!). +;;; +;;; * currently crypt++ assumes that if a file is both encrypted and encoded +;;; (i.e., compressed) that the order in which it was done was encryption +;;; first _then_ compression. As has been pointed by many people compression +;;; following encryption is useless since the encrypted file is basically +;;; random. On the other hand, many agree that doing encryption _following_ +;;; compression is better since it makes it harder to crack the encryption. +;;; We would like to make the ordering of these two user-configurable or if +;;; nothing else change the order. +;;; +;;; Having read the above however, Francois Pinard <pinard@iro.umontreal.ca> +;;; writes that encryption following compression may not be harder to crack +;;; since "the fact that the first few uncrypted bytes are expected (the +;;; compress signature) facilitates a serious attempt at uncrypting." +;;; jwz agrees with Francois. +;;; +;;; * get write-region and append-to-file to handle encoded and encrypted +;;; files. There is an interesting low-level encoding package by Jay Adams +;;; <jka@ece.cmu.edu> called jka-compr.el that might address some of these +;;; issues. We encourage hackers out there to come up with crypt++ versions +;;; of write-region and append-to-file. The difficulty is creating versions +;;; that mimic the originals as closely as possible. +;;; +;;; * instead of using call-process-region (which can fail badly if the region +;;; is large and there's not much room in /tmp), write the region to a temp +;;; file (with a customisable location) and use call-process directly. +;;; +;;; * users have mentioned trouble using crypt++ and hilit simultaneously since +;;; the functions in write-file-hook for both write the file to disk and +;;; return t. A possible solution is to have one of them write to a +;;; scratch buffer instead of to disk and return nil and then allow the +;;; other to do its work on the scratch buffer and write it to disk. Thanks +;;; to Wayne Folta <folta@cs.UMD.EDU> and Amir J Katz <amir@matis.ingr.com>. +;;; It would be nice to have another way in emacs to have an +;;; after-write-file-hook and a before-write-file-hook of some sort. +;;; Lucid Emacs has an after-write-file-hook. Recent versions of hilit19.el +;;; do not automatically attach to `write-file-hooks' and return t. +;;; However, the general problem of multiple packages returning t still +;;; remains. dos-mode.el and crypt.el also conflict. +;;; +;;; * another possible source of trouble is with encryption (and encoding) +;;; programs sticking verbose output into buffers prior to being written to +;;; disk. This was definitely occurring with gzip because of --verbose in +;;; the GZIP environment variable and is solved/hidden with the --quiet +;;; switch. However, I suspect that some encryption problems out there are +;;; capable of similar things so the user should be careful. +;;; +;;; * integrating crypt++ with a backgrounding package such as Olin Shivers' +;;; `background.el' might be useful too. thanks to Mark Borges +;;; <mdb@noaacrd.Colorado.EDU> for suggesting this. +;;; +;;; * Performing M-x crypt-encode-buffer or M-x crypt-encrypt-buffer and then +;;; saving the file would possibly cause errors. It is better to toggle +;;; `crypt-encoded-mode' (or `crypt-encrypted-mode') and simply save the +;;; file. It is for this reason that `crypt-encode-buffer' and +;;; `crypt-encrypt-buffer' are not interactive. +;;; +;;; * use plists instead of alists replacing calls to `nth' with `get' +;;; +;;; * merge encryption code completely into encoding code making encryption +;;; just a special case of encoding. + + +;;; Change log: +;;; +;;; 1.1 - original version of crypt.el +;;; 1.2 - +;;; jwz: works with tar-mode.el +;;; jwz: applied patch from piet, merged with Lawrence Dodd's gzip version +;;; 1.3 - +;;; lrd: fixed compress-magic-regexp +;;; 1.4, 1.5, 1.6 - +;;; lrd: write-file compresses or gzips based on file extension +;;; 2.1 - +;;; lrd: merged with Rod Whitby's table-driven version (major upgrade) +;;; 2.2 - +;;; rjw: Changed file name to crypt++.el, so archie and lispdir can find it. +;;; 2.3 - +;;; rjw: Separated the hook additions and minor mode alist additions. +;;; 2.4 - +;;; rjw: Fixed the interactive form for crypt-buffer. +;;; 2.5 - +;;; lrd: doc mods, changed GNU free software notice (was out of date), added +;;; anonymous ftp information +;;; 2.6 - +;;; lrd: added back in definition of `buffer' in defun crypt-buffer caused +;;; an error when trying to read encrypted file; modified check for minor +;;; mode alist addition; added gzip magic number warning +;;; 2.7 - [posted to gnu.emacs.sources] +;;; lrd: added `TO DO' and `KNOW BUGS' section to header +;;; 2.8 - +;;; lrd: added note about updating to v 1.24 of tar-mode.el +;;; Thanks to Mark Borges <mdb@noaacrd.Colorado.EDU> +;;; 2.9 - +;;; lrd: moved query about `crypt-freeze-vs-fortran' out of defvar for +;;; `crypt-encoding-alist,' an erroneous value of nil was being stuck into +;;; alist when user set `crypt-freeze-vs-fortran' was nil, doc mod. +;;; Thanks to Mark Borges <mdb@noaacrd.Colorado.EDU> +;;; 2.10 - +;;; rjw: moved query about `crypt-freeze-vs-fortran' back into defvar for +;;; `crypt-encoding-alist,' - used append to ignore the erroneous nil. +;;; 2.11 - +;;; rjw: fixed a bug in my fix :-( +;;; 2.12 - +;;; rjw: Defvar crypt-magic-regexp and crypt-magic-regexp-inverse and +;;; allow either a regexp or an elisp expression. +;;; Suggested by Franc,ois Pinard <pinard@iro.umontreal.ca>. +;;; 2.13 - +;;; lrd: added in info on lispdir.el, doc mods and some puttering while +;;; looking over rjw's v 2.12 mods. +;;; 2.14 - +;;; lrd: doc mod - trivial huh? switched `compact' and `gzip' in +;;; `crypt-encoding-alist' - want gzip near top +;;; 2.15 - +;;; lrd: added in LCD Archive Entry and modified comments on tar-mode.el +;;; since the version at the elisp-archive now works with crypt++.el +;;; 2.16 - +;;; lrd: provide `crypt' as well as `crypt++' allowing something like `ln -s +;;; crypt++.el crypt.el' to be meaningful +;;; Suggested (by|as) Per Abrahamsen <amanda@iesd.auc.dk> +;;; 2.17 - +;;; lrd: clarified bug report procedure, added fancy pseudo-graphics, added +;;; to the `TO DO' list, put RCS tags in LCD Archive entry +;;; 2.18 - [posted to gnu.emacs.sources] +;;; lrd: included pointer to elisp archive in crypt-version description, +;;; changed "Decode buffer %s? " to "Decode %s? " in crypt-find-file-hook +;;; to be more general (mainly for crypt-insert-file) +;;; 2.19 - +;;; rjw: Added the crypt-compact-vs-C++ switch to distinguish compacted and +;;; C++ files. +;;; 2.20 - +;;; lrd: (1) modified interactive form of crypt-buffer. (2) made search +;;; case-insensitive in crypt-submit-report. (3) modified encoded-mode and +;;; crypt-mode so that buffer-modified is not unconditionally set to nil +;;; when the mode is not changed. Thanks to Gerd Hillebrand +;;; <ggh@cs.brown.edu> for suggesting (2) and (3). +;;; 2.21 - +;;; rjw: Added an entry to the TODO list about the hazards of using +;;; call-process-region on a large region and not much room in /tmp +;;; (David Carlisle <carlisle@computer-science.manchester.ac.uk>). +;;; 2.22 - +;;; lrd: allow write-file-hooks to contain functions as well as lists. +;;; Contributed by Ken Laprade <laprade@trantor.harris-atd.com>. +;;; 2.23 - +;;; lrd: made crypt-submit-report list values of more user-defined variables +;;; 2.24 - +;;; lrd: pass the -q switch to gzip to thwart the possibility of a --verbose +;;; in the GZIP environment variable +;;; 2.25 - +;;; lrd: added some more to the TO DO list, clarified some things, also +;;; untabified the entire file (I got tired of the control I's) +;;; 2.26 - +;;; lrd: use the long-named options for GNU zip (self-documenting) +;;; 2.27 - +;;; lrd: included observation by Francois Pinard <pinard@iro.umontreal.ca> +;;; and worked on text in TO DO/KNOWN BUGS list +;;; 2.28 - +;;; lrd: added two new variables in (crypt-submit-report) to the list stuck +;;; at the bottom of the mail message; changed the comments regarding the +;;; user-defined variables. added in default values in user defined +;;; variables. added to and removed stuff to the `TO DO' list. +;;; +;;; (encoded-mode): +;;; added in code to remove any auto-save-files that may have been formed +;;; before becoming an encoded buffer (for example a plain file saved to +;;; disk encoded had orphan auto-save-files left behind). turning off +;;; auto-save-mode disables the creation of auto-save-files, but it also +;;; disables the possibility of these being removed when the buffer is +;;; saved. +;;; +;;; (crypt-region): +;;; now call the encryption and decryption program directly instead of +;;; through the shell. this is more secure since the shell will expose the +;;; password (key). thanks to Jon Cargille <jcargill@cs.wisc.edu>. defined +;;; two new variables `crypt-decryption-args' and `crypt-encryption-args' to +;;; take the arguments separately. removed (let ((opoint)...)) construct +;;; this was a throw back to some old dead code and was not being used. +;;; 2.29 - +;;; lrd: added three new variables in (crypt-submit-report); added to the +;;; `TO DO' list. +;;; +;;; (encode-region,encode-buffer,encoded-mode): fixed interactive forms - +;;; the conversion to table version had eliminated some of the interactive +;;; features of these. thanks to Kimball Collins <kpc@ptolemy.arc.nasa.gov> +;;; for point this out. new interactive form uses functions +;;; `crypt-get-encoding-type' and `crypt-symbol-alist-to-table' and variable +;;; `crypt-default-encoding' to generate completion list of encoding types. +;;; +;;; (crypt-write-file-hook): two new user-defined variables +;;; `crypt-query-if-interactive' and `crypt-no-extension-implies-plain' and +;;; the buffer-local variable `buffer-interactive-mode' are used to help +;;; determined whether or not plain output is really desired for files +;;; without a compression file-name extension. the default behavior is the +;;; same as before. +;;; 2.30 - +;;; lrd: added test for user-defined variable `crypt-never-ever-decrypt' +;;; when finding a file. some users may never wish to decrypt files +;;; and like to edit binary files. thanks to Nelson Minar +;;; <nelson@reed.edu>. added to doc-strings of +;;; `crypt-magic-regexp[-inverse]' -- these can be set to nil[t] and +;;; accomplish the same thing as setting `crypt-never-ever-decrypt' to t +;;; 2.31 - +;;; rjw: Updated the comments in the encryption check section. +;;; 2.32 - [posted to gnu.emacs.sources] +;;; lrd: added warning about `crypt-(de|en)cryption-program'; doc mod. +;;; 2.33 - +;;; lrd: if `crypt-(de|en)cryption-args' are nil then don't pass any +;;; arguments to (de|en)cryption program, nil is the default instead of +;;; "". Thanks to Joe Ilacqua <spike@world.std.com>, David J. Schur +;;; <djs@idm.com>, Peter Nuth <nuth@ai.mit.edu>, and Greg Larson +;;; <glarson@bnr.ca>. `-q' exists in gzip 1.0.3 but not `--quiet' changed +;;; GZIP NOTE. Thanks to Chris Moore <moore@src.bae.co.uk>. +;;; 2.34 - +;;; lrd: allow `crypt-(de|en)cryption-args' to be a list of strings -- more +;;; robust. query for password (key), if none is set, when writing out file +;;; for which `buffer-save-encrypted' is t. Thanks to John Interrante +;;; <interran@uluru.Stanford.EDU>. (crypt-write-file-hook): check filename +;;; extension against regexp `crypt-encryption-file-extension' and query for +;;; encryption, unless `crypt-auto-write-buffer-encrypted' is t (don't +;;; bother doing reverse check, encrypted to plain, not a common request). +;;; (crypt-mode): delete auto-save files (cf., encoded-mode), may exist now. +;;; (read-string-no-echo): applied patch from Piet van Oostrum +;;; <piet@cs.ruu.nl> -- set `cursor-in-echo-area' _after_ setting buffer +;;; (this was screwing up gnews). +;;; 2.35 - +;;; lrd: doc mod +;;; 2.36 - +;;; lrd: fixed typo, added RMAIL note. +;;; 2.37 - [posted to gnu.emacs.sources] +;;; lrd: +;;; (crypt-write-file-hook): search user-defined list +;;; `crypt-ignored-filenames' for possible match with `buffer-filename' +;;; before attempting conversion from compressed to plain format; useful for +;;; compressed incoming mail files (e.g., RMAIL, INBOX). +;;; +;;; (crypt-mode): query for key if not set already; need to switch order of +;;; recovering key and toggling crypt-mode in crypt-find-file-hook (thanks +;;; to Piet van Oostrum <piet@cs.ruu.nl>). +;;; +;;; (crypt-buffer) and (encode-buffer): remove interactive form; use +;;; (crypt-mode) and (encoded-mode) instead so encryption and compression +;;; are done at the very end; leave interactive form in (crypt-region) and +;;; (encode-region) may still be used. +;;; +;;; (set-encryption-key): remove from `command-history' if called +;;; interactively - thanks to George M. Georgiou +;;; <georgiou@silicon.csci.csusb.edu>. +;;; 2.38 - +;;; lrd: added `crypt-' prefix to `(read-string-no-echo)' and `(save-point)' +;;; changed file extension for gzip files to `.z' _or_ `.gz' (future release +;;; of gzip with use later extension by default and so this should be +;;; changed to just `.gz' someday). +;;; 2.39 - +;;; lrd: doc mod. added in patch from jwz - `(crypt-read-string-no-echo)' is +;;; more secure, put property 'permanent-local on buffer-locals works for +;;; Lucid Emacs and doesn't harm v18 emacs, change `buffer-interactive-mode' +;;; to `buffer-interactive-encoded-mode.' +;;; 2.40 - +;;; lrd: put property 'preserved in case kill-fix.el is being used. +;;; 2.41 - +;;; lrd: all functions and variables now start with `crypt-', moved REVISION +;;; HISTORY to bottom of header, interactive version of +;;; `(crypt-encrypt-region)' clearer, `(crypt-read-string-no-echo)' now +;;; echos `.' +;;; 2.42 - +;;; lrd: (crypt-check-extension-for-encoding): broke out of +;;; `(crypt-write-file-hook)'. setting user variables +;;; `crypt-compact-vs-C++' and `crypt-freeze-vs-fortran' to nil no longer +;;; completely disables the reading compact'ed and frozen files but just +;;; disables the use of the file-extension tricks of +;;; `(crypt-check-extension-for-encoding).' (crypt-encode-region): allow +;;; for a single line message from encoding program at top of region; if it +;;; is there, then remove it; kludge for `compact' program. +;;; 2.43 - +;;; lrd: (crypt-encode-region): generalize the clean up procedure; add +;;; element to `crypt-encoding-alist' and introduce new function +;;; `(crypt-encoding-cleanup-regexp)' to extract a compression specific +;;; regexp for erroneous message or lisp expression for cleanup. +;;; 2.44 - +;;; lrd: new element for `crypt-encoding-alist' handles whether or not +;;; file-name extension tricks may be play with encoding method; compact and +;;; freeze values default to `crypt-compact-vs-C++' and +;;; `crypt-freeze-vs-fortran' (thanks to rjw); +;;; (crypt-encoding-extension-tricks): new defun to handle this; +;;; (crypt-check-extension-for-encoding): monitors "tricks" entry of +;;; `crypt-encoding-alist' and adjust the bag of tricks it can apply. +;;; 2.45 - +;;; lrd: (crypt-encode-region): delete entire match of cleanup regexp by +;;; requiring newlines in GARBAGE-REGEXP-OR-LISPEXP. (crypt-submit-report): +;;; use Warsaw's reporter.el. +;;; 2.46 - +;;; lrd: (crypt-find-file-hook, crypt-write-file-hook): cleaned, documented, +;;; and replaced occurrences of `(cond (C BODY))' with `(if C BODY)'; +;;; changed `crypt-magic-regexp' to `crypt-encryption-magic-regexp' and +;;; `crypt-magic-regexp-inverse' to `crypt-encryption-magic-regexp-inverse' +;;; for consistency with other variable names. new user-defined variable +;;; `crypt-encryption-minor-mode-name' instead of always "Crypt". grouped +;;; all encryption variables together. +;;; 2.47 - +;;; lrd: somewhat major change - put program-specific encryption variables +;;; into a single table `crypt-encryption-alist' and let the variable +;;; `crypt-encryption-type' define the appropriate entry to use; new +;;; user-defined variable `crypt-confirm-password,' thanks to Jeff Clark +;;; <jclark@src.honeywell.com>. (crypt-submit-report): improved error +;;; handling, thanks to baw. (crypt-write-file-hook): fixed bug with +;;; `crypt-encoding-extension-tricks' +;;; 2.48 - +;;; lrd: added dummy argument to `crypt-encoding-alist' and +;;; `crypt-encryption-alist' and merged all defuns that work on their +;;; elements into defuns that all start with `crypt-get-' and look through +;;; both lists. simplifies some of code and closer to treating encryption +;;; as a special case of encoding; crypt-minor-mode-alist: replaced (nth *) +;;; with `(crypt-get-minor-mode)' call; (crypt-encode-region): allow +;;; arguments to be list of strings; renamed (crypt-get-encoding-type) to +;;; (crypt-read-encoding-type) for clarity. +;;; 2.49 - [posted to gnu.emacs.sources] +;;; lrd: (crypt-encode-region): ignore `args' if set to t +;;; 2.50 - +;;; lrd: (crypt-write-file-hook): in v19 we need to call `backup-buffer' +;;; ourselves -- we write out the file and return t so `basic-save-buffer' +;;; does not do it; also call `set-file-modes' +;;; 2.51 - +;;; lrd: some `defvar's are now `defconst's and tar-mode note was changed. +;;; 2.52 - +;;; lrd: make doc strings conform to GNU standards. +;;; 2.53 - +;;; lrd: made header conform to GNU Conventional Headers standard. +;;; 2.54 - +;;; lrd: `crypt-encryption-file-extension', `crypt-freeze-vs-fortran', +;;; `crypt-compact-vs-C++', `crypt-encryption-magic-regexp', and +;;; `crypt-encryption-magic-regexp-inverse' are used in defining the tables +;;; `crypt-encoding-alist' and `crypt-encryption-alist' and so need to be set +;;; _before_ loading crypt++. use `add-hook' if it is available. +;;; 2.55 - +;;; lrd: new interactive function `crypt-insert-file' mimics `insert-file' +;;; but attempts to decode or decrypt before insertion; bound `C-x i' if +;;; `crypt-bind-insert-file' is non-nil. comment out doc-strings from +;;; internal subroutines, saves space. +;;; 2.56 - +;;; tfb: change the definitions of crypt-{encoding,encryption}-alist, to +;;; call the functions crypt-make-{encoding,encryption}-alist resp. +;;; Added crypt-reinit which regenerates these variables from their +;;; functions, thus allowing this stuff to be preloaded even if people +;;; set things in their init files. +;;; Tim Bradshaw <tim.bradshaw@mid-heidelberg.de> +;;; 2.57 - +;;; lrd: untabify; remove duplicate entry in `crypt-make-encoding-alist'; +;;; change name of `crypt-make-*-alist' to `crypt-build-*-alist' and +;;; `crypt-reinit' to `crypt-rebuild-tables'; (crypt-read-string-no-echo): +;;; change local variable `form' to `help-form' so it is defined; +;;; `crypt-encryption-alist' and `crypt-encoding-alist' must be defined with +;;; `defconst' since we wish crypt++ to initialize these variables +;;; unconditionally; modify INSTALLATION section to reflect these changes. +;;; 2.58 - +;;; lrd: doc mod. +;;; 2.59 - [posted to gnu.emacs.sources] +;;; lrd: (crypt-bind-insert-file): new function for changing "C-x i" in +;;; initialization file or interactively. +;;; 2.60 - +;;; lrd: add `crypt-rebuild-tables' and `crypt-bind-insert-file' to +;;; `after-init-hook' in GNU emacs v19 and to `term-setup-hook' in Lucid +;;; emacs. Change INSTALLATION notes. +;;; 2.61 - [posted to gnu.emacs.sources] +;;; lrd: Doc mod. Clean up the installation of minor mode indicators. +;;; 2.62 - [posted to gnu.emacs.sources] +;;; lrd: installed patch from stig@hackvan.com to simplify crypt-get-* defuns +;;; (now defmacros). Don't add to `term-setup-hook' unless no +;;; `after-init-hook' _and_ definitely running v19, otherwise Rod gets an +;;; error at home :-<. Don't assume C-x i had `insert-file' bound to it: +;;; store old binding in `crypt-old-binding' before overwriting and use in +;;; function `crypt-bind-insert-file.' +;;; 2.63 - +;;; lrd: (crypt-encode-buffer, crypt-encode-region, crypt-encrypt-buffer, +;;; crypt-encrypt-region): changed argument list putting optional buffer +;;; last and making default action to encode or encrypt. (crypt-encoded-p, +;;; crypt-encrypted-p): new functions that do the actual testing of file +;;; contents. (crypt-find-file): uses these new functions. +;;; (crypt-rebuild-minor-modes-alist): new function to rebuild +;;; `minor-mode-alist' called by function crypt-rebuild-tables. +;;; (crypt-build-minor-mode-alist): new function called by +;;; `crypt-minor-mode-alist' to create itself. `crypt-minor-mode-encrypted' +;;; removed because defined in function crypt-build-minor-mode-alist. +;;; 2.64 - +;;; lrd: (crypt-find-file-hook): temporarily remove the encrytion file +;;; extension to help determine the major mode, just like is done with the +;;; encoding file extension. In order for this to work properly the file +;;; extension in `crypt-encryption-file-extension' and +;;; `crypt-encryption-alist' needs to be inside a pair of \\( \\). +;;; 2.65 - +;;; lrd: (crypt-find-file-hook): move determination of key, password, into +;;; (crypt-encrypted-p). +;;; 2.66 - +;;; lrd: (crypt-set-encryption-key): improve prompt string for encryption +;;; key. +;;; 2.67 - +;;; lrd: (crypt-write-file-hook): make check for encryption file-name +;;; extension case-sensitive. +;;; 2.68 - +;;; lrd: fixed check for previous addition to `minor-mode-alist' -- was not +;;; working. Check for an `add-hook' function; if one does not exist then +;;; use a copy of one from GNU Emacs 19. When using `add-hook' to append to +;;; the `write-file-hooks' make sure that the version accepts the optional +;;; APPEND argument -- v19's does but the one in the elisp archive by Dan +;;; LaLiberte <liberte@cs.uiuc.edu> does not append. This causes problems. +;;; Thanks to Francesco Potorti` <pot@fly.CNUCE.CNR.IT> for pointing this +;;; out. +;;; 2.69 - [posted to gnu.emacs.sources] +;;; lrd: doc mod with regards `after-init-hook' and Lucid Emacs. Add +;;; pointer to crypt++-fnf.el for people who might be interested. +;;; 2.70 - +;;; lrd: narrow conditions under which crypt-encryption-magic-regexp +;;; matches. Thanks to Philippe Michel <michel@thomson-lcr.fr> and Francois +;;; Pinard <pinard@iro.umontreal.ca> for helping explain this with regards +;;; to ISO/Latin-1. +;;; 2.71 - +;;; lrd: applied patches from Darrin Jewell <jewell@bdi.com> for DOS to UNIX +;;; support. DOS entry added to crypt-build-encoding-alist. +;;; (crypt-dos-to-unix-region, crypt-unix-to-dos-region): New +;;; functions. (crypt-dos-has-ctrl-z): New buffer-local variable. +;;; (crypt-encode-region): allow for encoding and decoding programs to be +;;; elisp expressions. If they are then apply them directly to region. +;;; Point out that crypt++.el conflicts with dos-mode.el. +;;; 2.72 - +;;; lrd: The limit for the regular expression search done by +;;; `crypt-encrypted-p' is extended to 100 by default. The enlargement of +;;; search field is needed because of previous reduction in size of regexp +;;; being searched for. (crypt-magic-search-limit): New variable defining +;;; this new limit. (crypt-encrypted-p): Uses it and cleaned up. Doc mod. +;;; Thanks to Philippe Michel <michel@thomson-lcr.fr>, Francois Pinard +;;; <pinard@iro.umontreal.ca>, and Dave Goldberg <dsg@blackbird.mitre.org>. +;;; 2.73 - [posted to gnu.emacs.sources] +;;; lrd: Apply patch from Kevin Rodgers <kevin@traffic.den.mmc.com> that +;;; uses more verbose messages and capitals. Doc mod. +;;; 2.74 - +;;; lrd: Untabify. (crypt-encrypted-p): Check value of +;;; `crypt-never-ever-decrypt' before anything else. +;;; 2.75 - +;;; lrd: (crypt-version): Remove call to `substring'. +;;; 2.76 - +;;; lrd: (crypt-encryption-magic-regexp-inverse): Add in regexp that will +;;; match ksh `.sh_history' files so that they are not interpreted as +;;; encrypted files. Thanks to Francesco Potorti` <pot@fly.CNUCE.CNR.IT>. +;;; 2.77 - [posted to gnu.emacs.sources] +;;; lrd: (crypt-bind-insert-file): Use substitute-key-definition to bind +;;; crypt-insert-file to whatever key insert-file is bound to (not +;;; necessarily C-x i). Call crypt-bind-insert-file directly in +;;; file. Variable crypt-bind-insert-file: Doc mod. Remove +;;; crypt-old-binding. Replace `M-x foobar' in doc strings with +;;; `\\[foobar]'. +;;; 2.78 - +;;; lrd: (crypt-auto-write-answer-local): New internal variable. Holds +;;; answer to query about file-extension tricks question per buffer. Thanks +;;; to George Forman <forman@cs.washington.edu>. Remove Rod from list of +;;; maintainers...he's busy enough. Merge multiple setq forms into single +;;; setq forms. +;;; 2.79 - +;;; lrd: (crypt-y-or-n-p): New internal function for querying. Tests the +;;; internal variable crypt-auto-write-answer-local to ensure single query. +;;; (crypt-check-extension-for-encoding): Replace all occurrences of queries +;;; involving y-or-no-p constructs with crypt-y-or-n-p. +;;; 2.80 - [posted to gnu.emacs.sources] +;;; lrd: (crypt-set-encryption-key): Shorten interactive prompt. Change +;;; documentation. +;;; 2.81 - +;;; lrd: (crypt-variable-list): Add shell and path variables. +;;; (crypt-confirm-password): Fix spelling error in doc. +;;; 2.82 - +;;; lrd: Applied patch from Noah Friedman <friedman@prep.ai.mit.edu>. +;;; (crypt-encoded-disable-auto-save, crypt-encrypted-disable-auto-save): +;;; New user-defined variables. (crypt-encoded-mode, crypt-encrypted-mode): +;;; Use them. + + +;;; Code: + +;;;; User definable variables. + +(defvar crypt-encryption-type 'crypt + "*Method of encryption. Must be an element of `crypt-encryption-alist.' +If you change this after crypt++ is loaded then do \\[crypt-rebuild-tables].") + +(defvar crypt-encryption-file-extension nil + "*Regexp for extension of files encrypted with `crypt-encryption-type.' +Should be of the form \"\\\\(\\\\.foo\\\\)$\". nil says use default values in +`crypt-encryption-alist.' If you change this after crypt++ is loaded then do +\\[crypt-rebuild-tables].") + +(defvar crypt-never-ever-decrypt nil + "*t says never attempt to decrypt a buffer.") + +(defvar crypt-auto-write-buffer-encrypted nil + "*t says files with `crypt-encryption-alist' file extension auto-encrypted. +nil says query. See `crypt-auto-write-buffer.'") + +(defvar crypt-confirm-password nil + "*t says confirm new passwords and when writing a newly encrypted buffer.") + +(defvar crypt-encoded-disable-auto-save t + "*If t, turn off auto-save-mode for buffers which are encoded. +If non-nil but not t, then no message is displayed. + +The default is t is because there isn't any way to tell emacs to encode the +autosave file, so the autosave would be in a different format from the +original. The disadvantage of turning off autosaves is that any work you +do in that buffer will be completely lost if the changes are not explicitly +saved. + +It is probably best to set this variable to nil and use buffer-local +variables in files for which you don't actually care about autosaves. +Unencoded recovery data is better than none at all.") + +(defvar crypt-encrypted-disable-auto-save t + "*If t, turn off auto-save-mode for buffers which are encrypted. +If non-nil but not t, then no message is displayed. + +The default is t is because there isn't any way to tell emacs to encrypt +the autosave file, so the autosave would be in cleartext form. The +disadvantage of turning off autosaves is that any work you do in that +buffer will be completely lost if the changes are not explicitly saved. + +You might consider setting this variable to nil and use buffer-local +variables in files for which security is more important than data +recovery.") + +;;; ENCRYPTION + +;;; Encrypted files have no magic number, so we have to hack a way of +;;; determining when a buffer should be decrypted. we do this only buffers +;;; that match a MAGIC-REGEXP very close to beginning of buffer and that do +;;; _NOT_ match a MAGIC-REGEXP-INVERSE. +;;; +;;; Currently MAGIC-REGEXP matches non-ASCII characters and +;;; MAGIC-REGEXP-INVERSE will match Sun OS, 4.x BSD, and Ultrix executable +;;; magic numbers, so binaries can still be edited (heh) without headaches. + +(defconst crypt-encryption-magic-regexp "[\000\200-\237]" + "Regexp that must be found very close to beginning of encrypted buffer. +This is intended to be an internal variable \(not user-visible\). If you +change this after crypt++ is loaded then do \\[crypt-rebuild-tables].") + +(defconst crypt-encryption-magic-regexp-inverse + "\\`\201\001\\|^\\(..\\)?\\([\007\010\013]\001\\|\001[\007\010\013]\\)" + "Regexp that must *not* be found very close to beginning of encrypted buffer. +This is intended to be an internal variable \(not user-visible\). If you +change this after crypt++ is loaded then do \\[crypt-rebuild-tables].") + +(defconst crypt-magic-search-limit 100 + "Limit of regular expression search used to recognize encrypted files. +Maximum position in file for presence of `crypt-encryption-magic-regexp' and +absence of `crypt-encryption-magic-regexp-inverse'.") + +(defun crypt-build-encryption-alist () + ;; Returns the encryption alist + (list + ;; crypt + (list 'crypt + crypt-encryption-magic-regexp crypt-encryption-magic-regexp-inverse + (or crypt-encryption-file-extension "\\(\\.e\\)$") + "crypt" "crypt" + nil + nil + "Crypt" + nil + t + ) + ;; DES (Cipher Block Chaining - CBC) [DES' default] + (list 'des + crypt-encryption-magic-regexp crypt-encryption-magic-regexp-inverse + (or crypt-encryption-file-extension "\\(\\.des\\)$") + "des" "des" + '("-e" "-k") + '("-d" "-k") + "DES-CBC" + nil + t + ) + ;; DES (Electronic Code Book - ECB) + (list 'des-ecb + crypt-encryption-magic-regexp crypt-encryption-magic-regexp-inverse + (or crypt-encryption-file-extension "\\(\\.des\\)$") + "des" "des" + '("-e" "-b" "-k") + '("-d" "-b" "-k") + "DES-ECB" + nil + t + ) + ;; PGP + (list 'pgp + crypt-encryption-magic-regexp crypt-encryption-magic-regexp-inverse + (or crypt-encryption-file-extension "\\(\\.pgp\\)$") + "pgp" "pgp" + '("+batchmode" "+verbose=0" "-c" "-f" "-z") + '("+batchmode" "+verbose=0" "-f" "-z") + "PGP" + nil + t + ) + ;; Add new elements here ... + )) + +(defconst crypt-encryption-alist (crypt-build-encryption-alist) + "List of elements describing the encryption methods available. +each element looks like + + \(ENCRYPTION-TYPE + MAGIC-REGEXP MAGIC-REGEXP-INVERSE + FILE-EXTENSION + ENCRYPT-PROGRAM DECRYPT-PROGRAM + ENCRYPT-ARGS + DECRYPT-ARGS + MINOR-MODE + GARBAGE-REGEXP-OR-LISPEXP + FILE-EXTENSION-TRICKS + \) + +ENCRYPTION-TYPE is a symbol denoting the encryption type. + +MAGIC-REGEXP regexp that must match very close to the beginning of an +encrypted buffer. This may also be some elisp expression to be evaluated at +\(point-min\) that will return t for an encrypted buffer. If this is set to +nil then crypt++ will never try to decrypt a buffer. Currently set to the +internal variable `crypt-encryption-magic-regexp' which will match non-ASCII +characters. + +MAGIC-REGEXP-INVERSE regexp that must _NOT_ match very close to the beginning +of an encrypted buffer. This may also be some elisp expression to be +evaluated at \(point-min\) that will return t for a NON-encrypted buffer. +If this is set to t then crypt++ will never try to decrypt a buffer. +Currently set to the internal variable `crypt-encryption-magic-regexp-inverse' +which will match Sun OS, 4.x BSD, and Ultrix executable magic numbers, so +binaries can still be edited (heh) without headaches. + +FILE-EXTENSION regexp denoting the file extension usually appended the +filename of files encrypted with ENCRYPT-PROGRAM. The variable +`crypt-encryption-file-extension' will over ride the default. + +ENCRYPT-PROGRAM name of executable file to be used for encryption. + +DECRYPT-PROGRAM name of executable file to be used for decryption. + +ENCRYPT-ARGS arguments to be passed to ENCRYPT-PROGRAM may be a string or a +list of strings or nil. + +DECRYPT-ARGS arguments to be passed to DECRYPT-PROGRAM may be a string or a +list of strings or nil. + +MINOR-MODE string denoting the name for the encrypted minor mode as it will +appear in the mode line. + +GARBAGE-REGEXP-OR-LISPEXP dummy variable for compatibility with encoding. + +FILE-EXTENSION-TRICKS is t or nil depending on whether or not tricks +converting between different encryption types can be done based on +FILE-EXTENSION; typically t. +") + + +;;; ENCODING + +(defvar crypt-auto-decode-buffer t + "*t says buffers visiting encoded files will be decoded automatically. +nil means to ask before doing the decoding.") + +(defvar crypt-auto-write-buffer nil + "*t says save files with `crypt-encoding-alist' file extensions as encoded. +nil says to ask before doing this encoding. Similarly, buffers originating +from encoded files to be written to files not ending in `crypt-encoding-alist' +file extensions will be written in plain format automatically. nil says to +ask before doing this decoding.") + +;; This is an internal variable documented here and not in a DOCSTRING in +;; order to save memory. If this variable's value has been changed from its +;; default, then it contains the answer to the question "Write out buffer +;; foobar using `compression-type'?". This question is asked only if *plain* +;; buffer foobar is being written to disk *and* it has a provocative +;; `compression-type' file-name extension (see DOCSTRING for variable +;; crypt-auto-write-buffer). The variable is local to all buffers with a +;; default value of 'ask so if the situation described above arises, then the +;; question is asked at least once, unless the user-defined variable +;; crypt-auto-write-buffer is non-nil. +(defvar crypt-auto-write-answer-local 'ask) +(make-variable-buffer-local 'crypt-auto-write-answer-local) +(setq-default crypt-auto-write-answer-local 'ask) +(put 'crypt-auto-write-answer-local 'permanent-local t) ; for v19 Emacs +(put 'crypt-auto-write-answer-local 'preserved t) ; for kill-fix.el + +(defvar crypt-query-if-interactive t + "*t says ask when saving buffers where `crypt-encoded-mode' was toggled. +nil says that even if filename extension is plain (i.e., not listed in +`crypt-encoding-alist') buffer will be written in an encoded format without +asking. + +This variable is designed for users that edit a plain file (with plain +extension) and then toggle `(crypt-encoded-mode)' and do not wish to be +queried every time that they save the buffer. + +NOTE: if `(crypt-encoded-mode)' was not called interactively (the usual +scenario) then the value of this variable has no effect on how the buffer is +written to disk. In such a case `crypt-no-extension-implies-plain' is then +the relevant variable.") + +(defvar crypt-no-extension-implies-plain t + "*t says file extensions not in `crypt-encoding-alist' may be written plain. +if `crypt-auto-write-buffer' is also t then any file ending in a plain +extension is written in plain format automatically, otherwise query user. + +nil says user works with encoded (compressed) files without file extensions +and will not be queried each time they save these files. + +NOTE: (1) this does not effect find-file (C-x C-f) since that works with a +magic regexp. (2) there is no way to distinguish between write-file and +save-buffer so nil will mean that neither will query.") + +(defvar crypt-freeze-vs-fortran t + "*t says `.F' file extension denotes a frozen file not a Fortran file. +If you change this variable after crypt++ has been loaded then do +\\[crypt-rebuild-tables].") + +(defvar crypt-compact-vs-C++ nil + "*t says `.C' file extension denotes a compacted file not a C++ file. +If you change this variable after crypt++ has been loaded then do +\\[crypt-rebuild-tables].") + +(defvar crypt-ignored-filenames nil + "*List of regexp filenames for which encoded to plain conversion is not done. +A filename with a plain extension, in encoded format, that is matched by one of +these elements will be saved in encoded format without a query for conversion to +plain format. + +This variable is provided for users that want to compress their incoming mail +for RMAIL and VM which look for files `RMAIL' and `INBOX,' respectively, to +store incoming mail. For example, the gzip extensions on `RMAIL.gz' and +`INBOX.gz' can be removed, this variable set to '\(\"INBOX$\" \"RMAIL$\"\) and +no query about conversion to plain format will be made.") + +(defvar crypt-default-encoding "gzip" + "*Default encoding type as string used when `crypt-encoded-mode' is toggled. +Must match one of the elements of `crypt-encoding-alist'.") + +(defvar crypt-dos-has-ctrl-z nil + "t if this buffer had a ctrl-z stripped from end, otherwise, nil. +Buffer local and set by `crypt-dos-to-unix-region'") +(make-variable-buffer-local 'crypt-dos-has-ctrl-z) +(setq-default crypt-dos-has-ctrl-z nil) +(put 'crypt-dos-has-ctrl-z 'permanent-local t) ; for v19 Emacs +(put 'crypt-dos-has-ctrl-z 'preserved t) ; for kill-fix.el + +(defun crypt-build-encoding-alist () + ;; Returns the encoding alist + (list + ;; compress + (list 'compress + "\037\235" nil + "\\(\\.Z\\)$" + "compress" "uncompress" + nil nil + "Compress" + nil + t) + ;; gzip (GNU zip) + (list 'gzip + "\037\213" nil + "\\(\\.g?z\\)$" + "gzip" "gzip" + "--quiet" "--decompress --quiet" + "Zip" + nil + t) + ;; freeze + (list 'freeze + "\037\236\\|\037\237" nil + "\\(\\.F\\)$" + "freeze" "freeze" + "" "-d" + "Freeze" + nil + crypt-freeze-vs-fortran) + ;; compact + (list 'compact + "\377\037" nil + "\\(\\.C\\)$" + "compact" "uncompact" + nil nil + "Compact" + "^Compression *:.*\n" + crypt-compact-vs-C++) + ;; DOS + (list 'dos + "[^\n\r]*\r$" nil + "\\(\\.DOS\\)$" + 'crypt-unix-to-dos-region 'crypt-dos-to-unix-region + nil nil + "Dos" + nil + nil) + ;; Add new elements here ... + )) + +(defconst crypt-encoding-alist (crypt-build-encoding-alist) + "List of elements describing the encoding methods available. +each element looks like + + \(ENCODING-TYPE + MAGIC-REGEXP MAGIC-REGEXP-INVERSE + FILE-EXTENSION + ENCODE-PROGRAM DECODE-PROGRAM + ENCODE-ARGS DECODE-ARGS + MINOR-MODE + GARBAGE-REGEXP-OR-LISPEXP + FILE-EXTENSION-TRICKS + \) + +ENCODING-TYPE is a symbol denoting the encoding type. Currently known +encodings are (compress compact freeze gzip). + +MAGIC-REGEXP is a regexp that matches the magic number at the +beginning of files encoded with ENCODING-TYPE. + +MAGIC-REGEXP-INVERSE dummy variable for compatibility with encryption. + +FILE-EXTENSION is a string denoting the file extension usually +appended the filename of files encoded with ENCODING-TYPE. + +ENCODE-PROGRAM is a string denoting the name of the executable used to +encode files. + +DECODE-PROGRAM is a string denoting the name of the executable used to +decode files. + +ENCODE-ARGS arguments to be passed to ENCODE-PROGRAM may be a string or a +list of strings or nil. + +DECODE-ARGS arguments to be passed to DECODE-PROGRAM may be a string or a +list of strings or nil. + +MINOR-MODE is a string denoting the name for the encoded minor mode as +it will appear in the mode line. + +GARBAGE-REGEXP-OR-LISPEXP is (1) a regexp that matches any extraneous text +that is produced by the ENCODE-COMMAND including any newlines and will be +removed from the buffer before saving to disk; (2) a lisp expression that will +clean up extraneous material in the buffer or nil. This is normally not +needed but can be derived for any ENCODE-COMMAND by checking the standard +error that results from `sh -c \"cat foo | ENCODE-COMMAND > bar\"'. + +FILE-EXTENSION-TRICKS is t or nil depending on whether or not tricks +converting between different encoding types can be done based on +FILE-EXTENSION; typically t. +") + + +;;; This allows the user to alter contents of the encoding and encryption +;;; table variables without having to reload all of crypt++. +(defun crypt-rebuild-tables () + "Rebuilds the encryption and encoding tables and `minor-mode-alist'. +Allows user to alter variables used in building these tables. May be called +interactively or in an initialization file. Part of `after-init-hook'." + (interactive) + (setq crypt-encryption-alist (crypt-build-encryption-alist) + crypt-encoding-alist (crypt-build-encoding-alist)) + (crypt-rebuild-minor-modes-alist)) + + +;;; Buffer locals. + +(defvar crypt-buffer-save-encrypted nil + "*non-nil says save buffer encrypted with `crypt-encryption-type.' +local to all buffers.") +(make-variable-buffer-local 'crypt-buffer-save-encrypted) +(put 'crypt-buffer-save-encrypted 'permanent-local t) ; for v19 Emacs +(put 'crypt-buffer-save-encrypted 'preserved t) ; for kill-fix.el + +(defvar crypt-buffer-encryption-key nil + "*Key used for encryption of current buffer. Local to all buffers.") +(make-variable-buffer-local 'crypt-buffer-encryption-key) +(put 'crypt-buffer-encryption-key 'permanent-local t) ; for v19 Emacs +(put 'crypt-buffer-encryption-key 'preserved t) ; for kill-fix.el + +(defvar crypt-buffer-save-encoded nil + "*non-nil says buffer will be saved encoded. Local to all buffers.") +(make-variable-buffer-local 'crypt-buffer-save-encoded) +(put 'crypt-buffer-save-encoded 'permanent-local t) ; for v19 Emacs +(put 'crypt-buffer-save-encoded 'preserved t) ; for kill-fix.el + +(defvar crypt-buffer-encoding-type nil + "*non-nil says buffer is encoded with ENCODING-TYPE. Local to all buffers.") +(make-variable-buffer-local 'crypt-buffer-encoding-type) +(put 'crypt-buffer-encoding-type 'permanent-local t) ; for v19 Emacs +(put 'crypt-buffer-encoding-type 'preserved t) ; for kill-fix.el + +(defvar crypt-buffer-interactive-encoded-mode nil + "t says `crypt-encoded-mode' was toggled interactively, almost always nil. +Local to all buffers.") +(make-variable-buffer-local 'crypt-buffer-interactive-encoded-mode) +(put 'crypt-buffer-interactive-encoded-mode 'permanent-local t) ; v19 Emacs +(put 'crypt-buffer-interactive-encoded-mode 'preserved t) ; kill-fix.el + + +;;; Functions and macros that search `crypt-encryption-alist' and +;;; `crypt-encoding-alist'. + +(defun crypt-get-alist-member (type n) + ;; Returns TYPE's Nth element + (nth n (or (assoc type crypt-encryption-alist) + (assoc type crypt-encoding-alist)))) + +(defmacro crypt-get-magic-regexp (type) + ;; Returns regexp found at top of files encoded/encrypted with TYPE. + (list 'crypt-get-alist-member type 1)) + +(defmacro crypt-get-magic-regexp-inverse (type) + ;; Returns regexp *not* found at top of files encoded/encrypted with TYPE. + (list 'crypt-get-alist-member type 2)) + +(defmacro crypt-get-file-extension (type) + ;; Returns regexp matching extension of files encoded/encrypted with TYPE. + (list 'crypt-get-alist-member type 3)) + +(defmacro crypt-get-encoding-program (type) + ;; Returns name of program, as string, used to encode/encrypt with TYPE. + (list 'crypt-get-alist-member type 4)) + +(defmacro crypt-get-decoding-program (type) + ;; Returns name of program, as string, used to decode/decrypt with TYPE. + (list 'crypt-get-alist-member type 5)) + +(defmacro crypt-get-encoding-args (type) + ;; Returns arguments passed to program used to encode/encrypt with TYPE. + (list 'crypt-get-alist-member type 6)) + +(defmacro crypt-get-decoding-args (type) + ;; Returns arguments passed to program used to decode/decrypt with TYPE. + (list 'crypt-get-alist-member type 7)) + +(defmacro crypt-get-minor-mode-name (type) + ;; Returns minor mode name, as string, for encoding/encrypting with TYPE. + (list 'crypt-get-alist-member type 8)) + +(defmacro crypt-get-cleanup-regexp (type) + ;; Returns regexp or lisp-exp for cleaning up encoding/encrypting with TYPE. + (list 'crypt-get-alist-member type 9)) + +(defmacro crypt-get-extension-tricks (type) + ;; Returns t if file extension tricks doable for encoding/encrypting with + ;; TYPE. + (list 'crypt-get-alist-member type 10)) + +(defun crypt-buffer-save-name (type) + ;; Returns variable `crypt-buffer-save-TYPE', set to t if encoding with TYPE. + ;; local to all buffers. + (intern (concat "crypt-buffer-save-" (symbol-name type)))) + + +;;; Create a buffer-local variable for each type of encoding. +;;; These variables are used to trigger the minor mode names. + +(defun crypt-build-minor-mode-alist () + ;; Returns minor mode alist entries for encoded and encrypted buffers. + (append + ;; First the encrypted minor mode -- only one. + (list (list 'crypt-buffer-save-encrypted + (concat " " (crypt-get-minor-mode-name crypt-encryption-type)))) + ;; Now the encoding minor modes. + (mapcar + (function + (lambda (element) + (let ((variable (crypt-buffer-save-name (car element)))) + (make-variable-buffer-local variable) + (put variable 'permanent-local t) ; for v19 Emacs + (put variable 'preserved t) ; for kill-fix.el + (list variable + (concat " " (crypt-get-minor-mode-name (car element))))))) + crypt-encoding-alist))) + +(defconst crypt-minor-mode-alist (crypt-build-minor-mode-alist) + "Alist containing encoded and encrypted minor modes. +Derived from variable `crypt-encoding-alist' and function +`crypt-build-minor-mode-encrypted'") + +(defun crypt-rebuild-minor-modes-alist () + ;; Rebuilds the encryption and encoding minor modes and `minor-mode-alist.' + ;; Allows user to alter variables used in building this alist. Called by + ;; `crypt-rebuild-tables' and so part of `after-init-hook'." + + ;; First remove old crypt minor mode entries from `minor-mode-alist'. + (if (memq (car crypt-minor-mode-alist) minor-mode-alist) + (let ((alist crypt-minor-mode-alist) elt) + (while (and alist (setq elt (car alist))) + (setq minor-mode-alist (delq elt minor-mode-alist) + alist (cdr alist))))) + + ;; Get new crypt minor mode entries and add to minor-mode-alist. + (setq crypt-minor-mode-alist (crypt-build-minor-mode-alist) + minor-mode-alist (append crypt-minor-mode-alist minor-mode-alist))) + + +(defmacro crypt-save-point (&rest body) + ;; Save value of point, evaluate FORMS, and restore value of point. If the + ;; saved value of point is no longer valid go to (point-max). This macro + ;; exists because, save-excursion loses track of point during some types of + ;; deletions. + (let ((var (make-symbol "saved-point"))) + (list 'let (list (list var '(point))) + (list 'unwind-protect + (cons 'progn body) + (list 'goto-char var))))) + + +(defun crypt-find-file-hook () + + ;; Hook run for decoding and/or decrypting the contents of a buffer. Meant + ;; to be called as part of `find-file-hooks' + + (let ((buffer-file-name buffer-file-name) + (old-buffer-file-name buffer-file-name) + (old-buffer-modified-p (buffer-modified-p)) + (case-fold-search nil) ; case-sensitive + encrypted encoded buffer-read-only) + + ;; DECODE AND/OR DECRYPT + (crypt-save-point + + ;; Do we have to DECODE? If not, then move on. + (if (and (crypt-encoded-p) + (or crypt-auto-decode-buffer + (y-or-n-p (format "Decode %s? " (buffer-name))))) + + ;; Decode, uncompress, the buffer. + (progn + + (if (and (not (null buffer-file-name)) + (string-match "\\.Z$" buffer-file-name)) + (set-visited-file-name + (substring buffer-file-name 0 (match-beginning 0))) + (if (and (not (null buffer-file-name)) + (string-match "\\.gz$" buffer-file-name)) + (set-visited-file-name + (substring buffer-file-name 0 (match-beginning 0))))) + (message "Decoding %s..." (buffer-name)) + (crypt-encode-buffer t) + + ;; Store the encoding mode. + + ;; We can not yet go into the minor modes because the major mode + ;; may change later on and blow away all local variables (and thus + ;; the minor modes). Only needed for vanilla v18. Our + ;; buffer-locals defined 'permanent-local for v19 Emacs and + ;; 'preserved for kill-fix.el. + + (setq encoded crypt-buffer-encoding-type) + + ;; Strip encoded file's extension so later we can set buffer's + ;; major mode based on its file-name sans encoding extension. + (if (string-match (crypt-get-file-extension + crypt-buffer-encoding-type) buffer-file-name) + (setq buffer-file-name + (substring buffer-file-name 0 (match-beginning 1)))) + + ;; Decoding ends. + (if (not (input-pending-p)) + (message "Decoding %s... done" (buffer-name))))) + + ;; Do we have to DECRYPT? If not, then move on. + (if (crypt-encrypted-p) + + ;; Decrypt buffer. + (progn + + (message "Decrypting %s..." (buffer-name)) + (crypt-encrypt-buffer crypt-buffer-encryption-key t) + + ;; Save key in case major mode blows all buffer-locals. + + ;; Only needed for vanilla v18. Our buffer-locals defined + ;; 'permanent-local for v19 Emacs and 'preserved for + ;; kill-fix.el. + + (setq encrypted crypt-buffer-encryption-key) + + ;; Strip encrypted file's extension so later we can set buffer's + ;; major mode based on its file-name sans encrypting extension. + (if (and (crypt-get-extension-tricks crypt-encryption-type) + (string-match (crypt-get-file-extension + crypt-encryption-type) buffer-file-name)) + (setq buffer-file-name + (substring buffer-file-name 0 (match-beginning 1)))) + + (if (not (input-pending-p)) + (message "Decrypting %s... done" (buffer-name)))))) + + ;; MAJOR AND MINOR MODES + + ;; OK, if any changes have been made to the buffer we need to rerun the + ;; code the does automatic selection of major mode. + + (if (or encoded encrypted) + + (progn + + ;; Set the major mode. + (set-auto-mode) + (hack-local-variables) + + ;; Now set our own minor mode(s). + (if encoded + ;; Recover encoding type, may have been smashed by major mode, + ;; and toggle encoded mode. + (progn (setq crypt-buffer-encoding-type encoded) + (crypt-encoded-mode 1))) + + (if encrypted + ;; Recover encryption key, may have been smashed by major mode, + ;; and toggle encrypted mode. + (progn (setq crypt-buffer-encryption-key encrypted) + (crypt-encrypted-mode 1))) + + ;; Restore buffer file name now, so that lock file entry is removed + ;; properly. + (setq buffer-file-name old-buffer-file-name) + + ;; Restore buffer modified flag to its previous value. Will also + ;; remove lock file entry for buffer if previous value was nil. + ;; This is why buffer-file-name had to be restored manually above. + (set-buffer-modified-p old-buffer-modified-p))))) + +(defun crypt-encoded-p (&optional buffer) + ;; Returns t if current buffer, or optionally BUFFER, is encoded. + ;; Sets `crypt-buffer-encoding-type' to encoding method. + (save-excursion + (and buffer (set-buffer buffer)) + (save-restriction + (widen) + (goto-char (point-min)) + (let ((alist crypt-encoding-alist) elt found) + (while (and alist (setq elt (car alist)) (not found)) + (if (looking-at (nth 1 elt)) + (setq crypt-buffer-encoding-type (nth 0 elt) + found t) + ;; Decrement + (setq alist (cdr alist)))) + found)))) + +(defun crypt-encrypted-p (&optional buffer) + ;; Returns t if current buffer, or optionally BUFFER, is encrypted. + ;; Look for MAGIC-REGEXP and absence of MAGIC-REGEXP-INVERSE. If so, then + ;; assume it is an encrypted buffer. + ;; Sets `crypt-buffer-encryption-key' to password if not set already. + + ;; Do not try to decrypt buffer if not wanted. + (if (not crypt-never-ever-decrypt) + + (save-excursion + (and buffer (set-buffer buffer)) + + (save-restriction + (widen) + (goto-char (point-min)) + + (let ((magic-regexp (crypt-get-magic-regexp crypt-encryption-type)) + (magic-regexp-inverse (crypt-get-magic-regexp-inverse + crypt-encryption-type)) + (limit (min (point-max) crypt-magic-search-limit))) + + ;; Check all encryption conditions. If any fail, then return nil + ;; value of this if-form, else check for password. + (if (and + + ;; Check for existence of MAGIC-REGEXP. + (if (stringp magic-regexp) + ;; regular expression + (re-search-forward magic-regexp limit t) + ;; lisp expression + (eval magic-regexp)) + + (goto-char (point-min)) + + ;; Check for absence of MAGIC-REGEXP-INVERSE. + (not (if (stringp magic-regexp-inverse) + ;; regular expression + (re-search-forward magic-regexp-inverse limit t) + ;; lisp expression + (eval magic-regexp-inverse)))) + + (progn + + ;; Get key, i.e., the password? + (or crypt-buffer-encryption-key + ;; Do not confirm on reading an encrypted file. + (let ((crypt-confirm-password nil)) + (call-interactively 'crypt-set-encryption-key))) + + ;; Do not turn on encryption mode if no key: may be a binary + ;; file. Thanks to Paul Dworkin (paul@media-lab.media.mit.edu). + (if (equal crypt-buffer-encryption-key "") + ;; Return nil. + (progn + (message "No key given. Assumed normal.") + nil) + ;; Return t. + t)))))))) + + +;;; + +(defun crypt-check-extension-for-encoding () + + ;; Checks file extensions for possible toggling of encoding modes. Used for + ;; buffers to be written to disk and called by `crypt-write-file-hook' + + ;; We try to flag a buffer to be written out in encoded form if the file + ;; ends in one of the file-extensions in `crypt-encoding-alist' even if + ;; `crypt-buffer-save-encoded' is nil. Conversely, we try to write out a + ;; buffer as a plain file if it does _not_ end in one of these + ;; file-extensions even if `crypt-buffer-save-encoded' is non-nil. + + (let ((alist crypt-encoding-alist) + (case-fold-search nil) + found elt) + + ;; Search through the file name extensions for a match. + (while (and alist (setq elt (car alist)) (not found)) + (if (string-match (nth 3 elt) buffer-file-name) + (setq found t) + ;; Decrement. + (setq alist (cdr alist)))) + + ;; Did we find a match? + (if found + + ;; File name ends in a very provocative extension. + + ;; Check to see if already an encoded file. + (if crypt-buffer-save-encoded + + ;; Already encoded - do the methods of encoding match? + (if (not (eq (nth 0 elt) crypt-buffer-encoding-type)) + + ;; A new encoding method is desired. + + ;; Can we play some filename extension tricks with the + ;; destination extension? + (if (crypt-get-extension-tricks (nth 0 elt)) + + ;; Can play tricks. + ;; Change the method of encoding? + (if (crypt-y-or-n-p (format "Write %s using %s? " + (buffer-name) (nth 4 elt))) + + ;; Case one. + ;; Turn off original encoding and turn on new encoding. + (progn (crypt-encoded-mode -1) + (setq crypt-buffer-encoding-type (nth 0 elt)) + (crypt-encoded-mode 1))) + + ;; Can not play tricks - maybe wants a plain file? + (if (crypt-y-or-n-p (format "Write %s a plain file? " + (buffer-name))) + + ;; Case three. + ;; Turn off the minor mode and _then_ the flags. + (progn + (crypt-encoded-mode -1) + (setq crypt-buffer-save-encoded nil + crypt-buffer-encoding-type nil))))) + + ;; Was a plain file. + (if (and + ;; Can we play some filename extension tricks? + ;; If not then we must abort. + (crypt-get-extension-tricks (nth 0 elt)) + + (crypt-y-or-n-p (format "Write %s using %s? " + (buffer-name) (nth 4 elt)))) + + ;; Case two. + ;; Turn on encoding flags and _then_ the minor mode. + (progn + (setq crypt-buffer-save-encoded t + crypt-buffer-encoding-type (nth 0 elt)) + (crypt-encoded-mode 1)))) + + ;; No match - a plain-jane file extension - but if the encoded flag is + ;; non-nil then the user may really want it written out in plain + ;; format so we must override this flag. + (if (and crypt-buffer-save-encoded + + ;; Search the list of files to be ignored. + ;; If `crypt-ignored-filenames' is nil then this let form + ;; will return t. If a match is found this form will return + ;; nil. Otherwise it will return t. + (let ((tlist crypt-ignored-filenames) + case-fold-search found elt) + + ;; Search through the list of filenames for a match. + (while (and tlist (setq elt (car tlist)) (not found)) + (if (string-match elt buffer-file-name) + (setq found t) + ;; Decrement. + (setq tlist (cdr tlist)))) + + ;; Return t if we can _not_ find a match. + (not found)) + + ;; If `(crypt-encoded-mode)' was called interactively, then + ;; there is a high probability that no matter what the file + ;; name extension the user wishes to write the file out in some + ;; encoded format. Thanks to Kimball Collins + ;; <kpc@ptolemy.arc.nasa.gov> for pointing out the need for + ;; this. Unfortunately, still can not distinguish between + ;; write-file and save-buffer. In the former the user may want + ;; to write in plain format (or indeed some other format). + + (if crypt-buffer-interactive-encoded-mode + ;; Interactive + crypt-query-if-interactive + ;; Non-interactive but still may want encoded format. + crypt-no-extension-implies-plain) + + (crypt-y-or-n-p (format "Write %s as a plain file? " + (buffer-name)))) + + ;; Case three. + ;; Turn off the minor mode and _then_ the flags. + (progn + (crypt-encoded-mode -1) + (setq crypt-buffer-save-encoded nil + crypt-buffer-encoding-type nil)))))) + + +(defun crypt-y-or-n-p (prompt) + ;; Queries user based on `crypt-auto-write-buffer' and internal buffer-local + ;; variable `crypt-auto-write-answer-local'. Returns value of + ;; `crypt-auto-write-answer-local', which is t or nil. + + ;; Check if we need to ask user. Should be 'ask, nil, or t. + (if (eq crypt-auto-write-answer-local 'ask) ; Default value. + ;; We may need to ask. + (or crypt-auto-write-buffer + ;; Ask and store the answer. + ;; Note: we only store if we asked. + (setq crypt-auto-write-answer-local (y-or-n-p prompt))) + ;; Use previous answer. + crypt-auto-write-answer-local)) ; Will be nil or t. + + +;;; This function should be called ONLY as a write-file hook. +;;; Odd things will happen if it is called elsewhere. + +(defun crypt-write-file-hook () + + ;; Hook for possibly writing out file, and backup file, in a non-plain + ;; format. Terminates calls in `write-file-hooks' and should be at end of + ;; list. + + ;; Check file-extension for possible toggling of encoding modes. + (crypt-check-extension-for-encoding) + + ;; Check extension for encryption. + (if (and + + ;; Maybe file ends with provocative extension w.r.t. encryption? + (stringp (crypt-get-file-extension crypt-encryption-type)) + (let ((case-fold-search nil)) ; Make case-sensitive. + (string-match (crypt-get-file-extension crypt-encryption-type) + buffer-file-name)) + + ;; Can we play tricks? + (crypt-get-extension-tricks crypt-encryption-type) + + ;; Match of filename extension - is file in plain format? + (not crypt-buffer-save-encrypted) + + ;; Query? + (or crypt-auto-write-buffer-encrypted + (y-or-n-p + (format "Write %s as an encrypted file? " (buffer-name))))) + + (progn + ;; Set password and toggle `crypt-encrypted-mode' + (call-interactively 'crypt-set-encryption-key) + (crypt-encrypted-mode 1))) + + ;; Now decide whether or not we need to continue with this defun. Does the + ;; buffer need to be saved in a non-plain form? If not then writing is not + ;; done here but later in the write-file-hooks - probably at the end. + + (if (or crypt-buffer-save-encoded crypt-buffer-save-encrypted) + + (save-excursion + (save-restriction + + (let + + ;; BINDINGS + ((copy-buffer (get-buffer-create " *crypt copy buffer*")) + (selective-display selective-display) + (buffer-read-only)) + + ;; FORMS + (copy-to-buffer copy-buffer 1 (1+ (buffer-size))) + (narrow-to-region (point) (point)) + + (unwind-protect + + ;; BODYFORM + (let (setmodes) + + ;; As of v19, if one of functions of the `write-file-hooks' + ;; returns a non-nil value, then `basic-save-buffer' no + ;; longer creates a backup file. We must do it ourselves. + ;; this should be a no-op in v18. + (or buffer-backed-up + (setq setmodes (backup-buffer))) + + (insert-buffer-substring copy-buffer) + (kill-buffer copy-buffer) + + ;; "Who would cross the Bridge of Death + ;; Must answer me + ;; These questions three + ;; Ere the other side he see." + ;; + ;; Bridgekeeper from Monty Python and the Holy Grail + + ;; [1] selective-display non-nil means we must convert + ;; carriage returns to newlines now, and set the variable + ;; selective-display temporarily to nil. + (if selective-display + (progn + (goto-char (point-min)) + (subst-char-in-region (point-min) (point-max) ?\r ?\n) + (setq selective-display nil))) + + ;; [2] encryption + (if crypt-buffer-save-encrypted + (progn + ;; check for password + (if (not crypt-buffer-encryption-key) + (call-interactively 'crypt-set-encryption-key)) + (if (null crypt-buffer-encryption-key) + (error "No encryption key set for buffer %s" + (buffer-name))) + (if (not (stringp crypt-buffer-encryption-key)) + (error "Encryption key is not a string")) + (message "Encrypting %s..." (buffer-name)) + (crypt-encrypt-buffer crypt-buffer-encryption-key))) + + ;; [3] encoding + (if crypt-buffer-save-encoded + (progn + (message "Encoding %s..." (buffer-name)) + (crypt-encode-buffer))) + + ;; Now write buffer/region to disk. + (write-region (point-min) (point-max) buffer-file-name nil t) + (delete-region (point-min) (point-max)) + (set-buffer-modified-p nil) + + ;; Now that the file is written, set its modes. + (if setmodes + (condition-case () + (set-file-modes buffer-file-name setmodes) + (error nil))) + + ;; Return t so that `basic-save-buffer' will know that the + ;; save has already been done. + + ;; NOTE: this TERMINATES write-file-hooks so any hooks + ;; following this one will not be executed. + + t ) + + ;; UNWINDFORMS + ;; unwind...sit back...take a load off...have a beer + + ;; If the encoded and encrypted stuff has already been removed + ;; then this is a no-op. This form is executed if BODYFORM + ;; completes normally but the value of BODYFORM is returned - + ;; i.e., t is returned. + + (delete-region (point-min) (point-max)))))))) + + +;;;; ENCRYPTION + +(defun crypt-encrypt-region (start end key &optional decrypt) + "Encrypt region START to END using KEY and `crypt-encryption-type'. When +called interactively START and END default to point and mark \(START being the +lesser of the two\), and KEY is prompted for. With optional DECRYPT non-nil, +decryption is done." + + (interactive + (let (decrypt) + (barf-if-buffer-read-only) + (list (region-beginning) + (region-end) + (crypt-read-string-no-echo + (concat (if (setq decrypt (y-or-n-p "Decrypt region? ")) "De" "En") + "crypt buffer using key: ") + ;; Do not confirm on decrypting region. + (if (not decrypt) crypt-confirm-password)) + decrypt))) + + (crypt-save-point + + ;; We define the PROGRAM as the encryption program or decryption program + ;; listed for `crypt-encryption-type' of `crypt-encryption-alist.' These + ;; should be just the name of the executable and should _not_ contain any + ;; arguments. `(call-process-region)' would be confused if we tried to + ;; pass the arguments as part of the PROGRAM. The arguments are passed + ;; through the encryption args or decryption args listed for + ;; `crypt-encryption-type' of `crypt-encryption-alist.' + + ;; Thanks to Joe Ilacqua <spike@world.std.com> and others for pointing out + ;; an error that occurs with some encryption programs (e.g., the crypt from + ;; Sun Microsystems, HPUX-8, and BSD) if `args' is `"".' This will allow + ;; nil values and lists of strings for argument. + + (let (prog args) + + ;; Get the proper program and arguments. + (if decrypt + (setq prog (crypt-get-decoding-program crypt-encryption-type) + args (crypt-get-decoding-args crypt-encryption-type)) + (setq prog (crypt-get-encoding-program crypt-encryption-type) + args (crypt-get-encoding-args crypt-encryption-type))) + + ;; Check arguments. + (cond + + ;; nil or "" args - don't pass. + ((or (not args) (equal "" args)) + (call-process-region start end prog t t nil key)) + + ;; Check if the args are in the form of a list - must use apply. + ((listp args) + (apply 'call-process-region + (append (list start end prog t t nil) args (list key)))) + + ;; Default - just a non-null string. + (t + (call-process-region start end prog t t nil args key)))))) + + +(defun crypt-encrypt-buffer (key &optional decrypt buffer) + + ;; Use KEY to encrypt current buffer and with optional DECRYPT decrypt. + ;; With optional BUFFER, encrypt or decrypt that buffer. Not meant to be + ;; called interactively, toggle `crypt-encrypted-mode' to encrypt an entire + ;; buffer. + + (or buffer (setq buffer (current-buffer))) + (save-excursion (set-buffer buffer) + (crypt-encrypt-region (point-min) (point-max) key decrypt))) + + +;;;; ENCODING + +(defun crypt-encode-region (start end &optional decode) + + "Encode region START to END. When called interactively START and END +default to point and mark \(START being the lesser of the two\). With +optional DECODE non-nil, decoding is done. + +If encoding is attempted, then checks for correct magic number at start of +newly-encoded region. If not found, then searches and deletes a user-defined +regexp, or executes a user-defined lisp expression, as defined in +`crypt-encoding-alist,' and checks again for magic number." + + (interactive "*r\nP") + + ;; If called interactively then we may need to determine the encoding type. + (if (and (interactive-p) (not crypt-buffer-encoding-type)) + (crypt-read-encoding-type)) + + (crypt-save-point + + ;; We define the PROGRAM as `shell-file-name' and have it call the encoding + ;; or decoding program with the arguments. + + (let (prog args) + + ;; Get the proper program and arguments. + (if decode + (setq prog (crypt-get-decoding-program crypt-buffer-encoding-type) + args (crypt-get-decoding-args crypt-buffer-encoding-type)) + (setq prog (crypt-get-encoding-program crypt-buffer-encoding-type) + args (crypt-get-encoding-args crypt-buffer-encoding-type))) + + (cond + + ;; prog is a string? + ((stringp prog) + + ;; Check arguments. + (cond + + ;; Check if the args are in the form of a list, will catch 'nil. + ((listp args) + + ;; Cat all the strings together. + (while args + (setq prog (concat prog " " (car args)) + args (cdr args)))) + + ;; Check if a non-null string. + ((and (not (string= "" args)) + (not (eq args t))) ; just in case... + (setq prog (concat prog " " args)))) + + (call-process-region start end shell-file-name t t nil "-c" prog)) + + ;; Otherwise try and eval it. + (t + (eval (if args + (list prog start end args) + (list prog start end)))))) + + ;; Encoding or decoding region? + (if (not decode) + + ;; Check if encoded region starts with magic number. + (let ((magic (crypt-get-magic-regexp crypt-buffer-encoding-type)) + (clean (crypt-get-cleanup-regexp crypt-buffer-encoding-type)) + (case-fold-search nil)) + + ;; Top of region. + (goto-char start) + + ;; Check for magic number. + (if (not (looking-at magic)) + + ;; Magic number not there. + + ;; Some compression programs produce an (inane) standard error + ;; message that gets piped into the buffer. For example, some + ;; versions of compact output "Compression : 35.50%." There may + ;; be some way to clean up buffer and check again. + + (cond + + ;; No mechanism to clean up - failed. + ((eq clean nil) + (error "Encoding failed!")) + + ;; Cleanup a regexp string? + ((stringp clean) + + ;; Is regexp there? + (if (looking-at clean) + + (progn + ;; Delete the match. + (delete-region (match-beginning 0) (match-end 0)) + + ;; Check for magic again. + (if (not (looking-at magic)) + (error "Encoding failed!"))))) + + ;; Default: evaluate a lisp expression and check again. + (t (eval clean) + (if (not (looking-at magic)) + (error "Encoding failed!"))))))))) + +(defun crypt-encode-buffer (&optional decode buffer) + + ;; Encode current buffer. With optional DECODE non-nil decode and optional + ;; BUFFER, encode or decode that buffer. Not meant to be called + ;; interactively, toggle `crypt-encoded-mode' to encode an entire buffer. + + (or buffer (setq buffer (current-buffer))) + (save-excursion (set-buffer buffer) + (crypt-encode-region (point-min) (point-max) decode))) + + +;;;; DOS <--> UNIX +(defun crypt-dos-to-unix-region (start end) + "Converts region from START to END, from dos to unix format. +Replaces \"\\r\\n\" with \"\\n\" and, if exists, removes ^Z at end of file. +Sets `crypt-dos-has-ctrl-z'." + (save-excursion + (save-restriction + (let ((remove-ctrl-z (equal end (point-max)))) + (narrow-to-region start end) + (goto-char (point-min)) + (while (search-forward "\r\n" nil t) + (replace-match "\n" nil t)) + (if remove-ctrl-z + (progn + (goto-char (1- (point-max))) + (setq crypt-dos-has-ctrl-z (looking-at "\C-z")) + (if crypt-dos-has-ctrl-z (replace-match "")))))))) + +(defun crypt-unix-to-dos-region (start end) + "Converts region from START to END, from dos to unix format. +Replaces \"\\n\" with \"\\r\\n\" and adds a ^Z at end of file if +`crypt-dos-has-ctrl-z' is non-nil." + (save-excursion + (save-restriction + (let ((add-ctrl-z (and crypt-dos-has-ctrl-z + (equal end (point-max))))) + (narrow-to-region start end) + (goto-char (point-min)) + (while (search-forward "\n" nil t) + (replace-match "\r\n" nil t)) + (if add-ctrl-z + (progn + (goto-char (point-max)) + (insert "\C-z"))))))) + + +;;;; MODES + +(defun crypt-encrypted-mode (&optional arg) + + "Toggle encrypted mode. With ARG, turn on iff positive, otherwise turn off. +minor mode in which buffers are automatically encrypted before being written. +if toggled and a key has been set for the current buffer, then the current +buffer is marked modified, since it needs to be rewritten with or without +encryption. + +Entering encrypted mode causes auto-saving to be turned off in the current +buffer, as there is no way in Emacs Lisp to force auto save files to be +encrypted." + + (interactive "P") + (let ((oldval crypt-buffer-save-encrypted)) + (setq crypt-buffer-save-encrypted + (if arg (> arg 0) (not crypt-buffer-save-encrypted))) + + (if crypt-buffer-save-encrypted + ;; We are going to save as encrypted, we will turn off auto-saving. + (progn +;; NEVER do this. Turning off auto-saving is one thing. But if there's +;; already an autosave for some other reason, what business does this +;; package have tampering with it? +; ;; If an auto-save file already exists, then delete it. +; (if (and (stringp buffer-auto-save-file-name) +; (file-exists-p buffer-auto-save-file-name)) +; (delete-file buffer-auto-save-file-name)) + ;; If the key is not set then ask for it. + (if (not crypt-buffer-encryption-key) + (call-interactively 'crypt-set-encryption-key)) + ;; Turn-off auto-saving if crypt-encrypted-disable-auto-save non-nil. + (and crypt-encrypted-disable-auto-save + auto-save-default + (progn + (auto-save-mode 0) + (if (eq crypt-encrypted-disable-auto-save t) + (message "Auto-save off (in this buffer)"))))) + + ;; We are not going to save as encrypted, we will turn on auto-saving + ;; but only if we are editing a file and the default says we should. + (auto-save-mode (if (and auto-save-default buffer-file-name) 1 0))) + + (if crypt-buffer-encryption-key + ;; Set buffer-modified flag to t only if the mode has been changed, + ;; old code set unconditionally to nil if mode was not changed . + ;; Modification suggested by: Gerd Hillebrand <ggh@cs.brown.edu> + (if (not (eq oldval crypt-buffer-save-encrypted)) + (set-buffer-modified-p t))))) + + +;;; Forgetting encryption keys (by jwz) +;;; This is really kind of bogus. Good behavior would be: +;;; - If a crypted buffer has not been "accessed" (edited? selected? +;;; viewed?) in N minutes, kill the buffer (since the plaintext is valuable.) +;;; - If a crypted buffer is modified, but "idle", just forget the password +;;; instead of killing the buffer (though the plaintext is valuable, it's +;;; also unsaved...) +;;; - The "idleness" of a modified buffer should be reset with every mod, so +;;; that an unsaved buffer that you have been constantly typing at for an +;;; hour doesn't lose its password. +;;; - But, if a password for a buffer has been discarded, and then an attempt +;;; is made to save that buffer, then we should confirm that the newly- +;;; typed password is the same as the password used in the file on disk. +;;; with PGP, we could check that by attempting to decrypt the file on +;;; disk into a scratch buffer and seeing if it contains the PGP error +;;; message. +;;; - BUG: if a password has been forgotten, and you save, and are prompted, +;;; the old file has already been renamed to a backup!! so if you ^G, the +;;; real file name no longer exists on disk - only as a ~ file. + +(defun crypt-forget-encryption-key () + (cond (crypt-buffer-encryption-key + (let ((inhibit-quit t)) + (fillarray crypt-buffer-encryption-key 0) + (setq crypt-buffer-encryption-key nil)) + t) + (t nil))) + +(add-hook 'kill-buffer-hook 'crypt-forget-encryption-key) + +(defvar crypt-forget-passwd-timeout (* 60 60) + "*Do not retain passwords for encrypted buffers more than this many seconds. +If nil, keep them indefinitely.") + +(defun crypt-reset-passwd-timer () + (if (fboundp 'get-itimer) ; XEmacs, or anything with itimer.el loaded. + (let ((name "crypt-forget-passwds")) + (if (get-itimer name) + (delete-itimer name)) + (if crypt-forget-passwd-timeout + (start-itimer name + 'crypt-reset-passwds-timeout + crypt-forget-passwd-timeout))))) + +(defun crypt-reset-passwds-timeout () + ;; run by the timer code to forget all passwords + (let ((buffers (buffer-list)) + (inhibit-quit t) + (keep-going nil)) + (while buffers + (save-excursion + (set-buffer (car buffers)) + (cond ((and crypt-buffer-encryption-key + (buffer-modified-p)) + ;; don't forget the password in modified buffers, but + ;; do check again later (maybe it will be unmodified.) + (setq keep-going t)) + (crypt-buffer-encryption-key + ;; forget the password in unmodified buffers. + (crypt-forget-encryption-key) + ;; Mark the buffer read only so that it's not accidentally + ;; edited; the smart thing to do is revert it, type the + ;; encryption key (to make sure they same key is used) + ;; and then edit it. + (setq buffer-read-only t) + (message "Password discarded in buffer %s" + (buffer-name (car buffers)))) + )) + (setq buffers (cdr buffers))) + (if keep-going + (crypt-reset-passwd-timer)) + nil)) + + +;;; Originally `tek-symbol-alist-to-table' from tek-highlight.el. +(defun crypt-symbol-alist-to-table (list) + ;; Converts an alist of symbols to a table suitable for `completing-read.' + ;; Called by `crypt-read-encoding-type' + (mapcar (function (lambda (x) (list (symbol-name (car x))))) + list)) + +(defun crypt-read-encoding-type () + + ;; Function called to query user for `crypt-buffer-encoding-type' uses + ;; contents of `crypt-encoding-alist' and `crypt-default-encoding.' + + ;; Use poor man's gmhist (i.e., we could have used gmhist's + ;; `completing-read-with-history-in' instead). + (let ( + ;; Find the encoding type desired by user. + (type + (completing-read + (concat "encoding type (? for list): [" crypt-default-encoding "] ") + (crypt-symbol-alist-to-table crypt-encoding-alist)))) + + ;; Test length of object returned by `completing-read'. + (if (zerop (length type)) + + ;; Nothing there, i.e., user hit return -- use default. + (setq crypt-buffer-encoding-type (intern crypt-default-encoding)) + + ;; Use the value from mini-buffer and update the default value. + (setq crypt-buffer-encoding-type (intern type) + crypt-default-encoding type)))) + +(defun crypt-encoded-mode (&optional arg) + + "Toggle encoded mode. With ARG, turn on iff positive, otherwise turn off. +minor mode in which buffers are automatically encoded before being written. if +toggled then current buffer is marked modified, since it needs to be written +with or without encoding. + +Entering encoded mode causes auto-saving to be turned off in the current +buffer, as there is no way in Emacs Lisp to force auto save files to be +encoded." + + (interactive "P") + + ;; Set flag indicating whether or not `(crypt-encoded-mode)' was called + ;; interactively. + (setq crypt-buffer-interactive-encoded-mode (interactive-p)) + + ;; If called interactively then need to determine encoding type. + (if (and crypt-buffer-interactive-encoded-mode + (not crypt-buffer-encoding-type)) + (crypt-read-encoding-type)) + + ;; Save old value of `crypt-buffer-save-encoded'. + (let ((oldval crypt-buffer-save-encoded)) + + ;; Set the variable `crypt-buffer-save-encoded' to t if the argument is + ;; positive, otherwise toggle its current value. + (setq crypt-buffer-save-encoded + (if arg (> arg 0) (not crypt-buffer-save-encoded))) + + ;; Set the variable generated by `(crypt-buffer-save-name)' to the value + ;; stored in `crypt-buffer-save-encoded.' + (set-variable (crypt-buffer-save-name crypt-buffer-encoding-type) + crypt-buffer-save-encoded) + + (if crypt-buffer-save-encoded + ;; We are going to save as encoded, we might turn off auto-saving. + (progn +;; NEVER do this. Turning off auto-saving is one thing. But if there's +;; already an autosave for some other reason, what business does this +;; package have tampering with it? +; ;; If an auto-save file already exists, then delete it. +; (if (and (stringp buffer-auto-save-file-name) +; (file-exists-p buffer-auto-save-file-name)) +; (delete-file buffer-auto-save-file-name)) + ;; Turn-off auto-saving if crypt-encoded-disable-auto-save non-nil. + (and crypt-encoded-disable-auto-save + auto-save-default + (progn + (auto-save-mode 0) + (if (eq crypt-encoded-disable-auto-save t) + (message "Auto-save off (in this buffer)"))))) + + ;; We are not going to save as encoded, we will turn on auto-saving but + ;; only if we are editing a file and the default says we should. + (auto-save-mode (if (and auto-save-default buffer-file-name) 1 0))) + + ;; Have we toggled the mode? + + ;; If yes, then mark buffer as modified. If not, then leave + ;; buffer-modified flag alone. + + ;; The old code previously set the variable `set-buffer-modified-p' to a + ;; value of t if there was a mode change and (unconditionally) to nil + ;; if there was not a mode change. + + ;; Modification suggested by: Gerd Hillebrand <ggh@cs.brown.edu>. + + (if (not (eq oldval crypt-buffer-save-encoded)) + (set-buffer-modified-p t)))) + + +;;;; Additional encryption functions + +;; For Emacs V18 compatibility +(and (not (fboundp 'buffer-disable-undo)) + (fboundp 'buffer-flush-undo) + (fset 'buffer-disable-undo 'buffer-flush-undo)) + +(fset 'crypt-read-string-no-echo 'read-passwd) + +;(defun crypt-read-string-no-echo (prompt &optional confirm) +; +; ;; Read a string from minibuffer, prompting with PROMPT, echoing periods. +; ;; Optional second argument CONFIRM non-nil means that the user will be +; ;; asked to type the string a second time for confirmation and if there is a +; ;; mismatch, the whole process is repeated. +; ;; +; ;; Line editing keys are -- +; ;; C-h, DEL rubout +; ;; C-u, C-x line kill +; ;; C-q, C-v literal next +; +; (catch 'return-value +; (save-excursion +; +; (let ((input-buffer (get-buffer-create (make-temp-name " *password*"))) +; char hold-password help-form kill-ring) +; +; (set-buffer input-buffer) +; ;; Don't add to undo ring. +; (buffer-disable-undo input-buffer) +; +; (let ((cursor-in-echo-area t) +; (echo-keystrokes 0)) +; +; (unwind-protect +; +; ;; BODYFORM +; ;; Repeat until we get a `throw'. +; (while t +; (erase-buffer) +; (message prompt) +; +; ;; Read string. +; (while (not (memq (setq char (read-char)) '(?\C-m ?\C-j))) +; (if (setq help-form +; (cdr +; (assq char +; '((?\C-h . (delete-char -1)) +; (?\C-? . (delete-char -1)) +; (?\C-u . (delete-region 1 (point))) +; (?\C-x . (delete-region 1 (point))) +; (?\C-q . (quoted-insert 1)) +; (?\C-v . (quoted-insert 1)))))) +; (condition-case error-data +; (eval help-form) +; (error t)) +; ;; Just a plain character - insert into password buffer. +; (insert char)) +; +; ;; I think crypt-read-string-no-echo should echo asterisks. +; ;; -- Jamie. How about periods like in ange-ftp? -- lrd +; ;; +; (message "%s%s" prompt (make-string (buffer-size) ?.))) +; +; ;; Do we have to confirm password? +; (cond +; +; ;; No confirmation requested - terminate. +; ((not confirm) +; (throw 'return-value (buffer-string))) +; +; ;; Can we compare (confirm) password values yet? +; (hold-password +; (if (string= hold-password (buffer-string)) +; ;; The two passwords match - terminate. +; (throw 'return-value hold-password) +; +; ;; Mismatch - start over. +; (progn +; (message (concat prompt "[Mismatch. Start over]")) +; (beep) +; (sit-for 2) +; (fillarray hold-password 0) ; destroy extra copy now +; (setq hold-password nil)))) +; +; ;; Store password and read again. +; (t +; (setq hold-password (buffer-string)) +; (message (concat prompt "[Retype to confirm]")) +; (sit-for 2)))) +; +; ;; UNWINDFORMS +; ;; Clean up. +; (set-buffer input-buffer) +; (set-buffer-modified-p nil) +; (buffer-disable-undo input-buffer) ; redundant, but why not be safe. +; (widen) +; (goto-char (point-min)) +; (while (not (eobp)) (delete-char 1) (insert "*")) ; destroy now +; (kill-buffer input-buffer))))))) + +(defun crypt-set-encryption-key (key &optional buffer) + + "Set the encryption KEY, a string, for current buffer or optionally BUFFER. +If buffer is in encrypted mode, then it is also marked as modified, since it +needs to be saved with the new key." + + (interactive + (progn + (barf-if-buffer-read-only) + (list (crypt-read-string-no-echo + (format "Encryption key for %s? [RET to ignore]: " (buffer-name)) + crypt-confirm-password)))) + + ;; For security reasons we remove `(crypt-set-encryption-key "password")' + ;; from the `command-history' list if called interactively. + (if (interactive-p) + (setq command-history (cdr command-history))) + + (or buffer (setq buffer (current-buffer))) + + (save-excursion + (set-buffer buffer) + (if (equal key crypt-buffer-encryption-key) + (message "Key is identical to original, no change.") + + (progn + ;; jwz: destroy old string + (if (and crypt-buffer-encryption-key + (not (eq crypt-buffer-encryption-key key))) + (fillarray crypt-buffer-encryption-key 0)) + (setq crypt-buffer-encryption-key key) + + ;; Don't touch the modify flag unless we're in `(crypt-encrypted-mode)'. + (if crypt-buffer-save-encrypted + (set-buffer-modified-p t)) + + (crypt-reset-passwd-timer) + )))) + + +;;;; Install hooks and mode indicators. + +;;; Check if mode indicators are not already installed and then prepend them. +(and (not (assq 'crypt-buffer-save-encrypted minor-mode-alist)) + (setq minor-mode-alist (append crypt-minor-mode-alist minor-mode-alist))) + +;;; Install the hooks. + +;;; If add-hook isn't already defined overwrite it with our own. +;;; Note the `add-hook' function must take the optional APPEND argument. +(if (not (fboundp 'add-hook)) + ;; No add-hook found. + ;; Use `add-hook' from GNU Emacs v19. + (defun add-hook (hook function &optional append) + "Add to the value of HOOK the function FUNCTION. +FUNCTION is not added if already present. +FUNCTION is added (if necessary) at the beginning of the hook list +unless the optional argument APPEND is non-nil, in which case +FUNCTION is added at the end. + +HOOK should be a symbol, and FUNCTION may be any valid function. If +HOOK is void, it is first set to nil. If HOOK's value is a single +function, it is changed to a list of functions." + (or (boundp hook) (set hook nil)) + ;; If the hook value is a single function, turn it into a list. + (let ((old (symbol-value hook))) + (if (or (not (listp old)) (eq (car old) 'lambda)) + (set hook (list old)))) + (or (if (consp function) + ;; Clever way to tell whether a given lambda-expression + ;; is equal to anything in the hook. + (let ((tail (assoc (cdr function) (symbol-value hook)))) + (equal function tail)) + (memq function (symbol-value hook))) + (set hook + (if append + (nconc (symbol-value hook) (list function)) + (cons function (symbol-value hook))))))) + +;;; Attach ourselves to the find-file-hooks and find-file-not-found-hooks. +(add-hook 'find-file-hooks 'crypt-find-file-hook) +(add-hook 'find-file-not-found-hooks 'crypt-find-file-hook) + +;; Take care when appending to write-file-hook. User's version of add-hook +;; may not have APPEND option. If it fails then do it by hand. I wish +;; everyone would upgrade - lrd 8/31/93. +(condition-case err + (add-hook 'write-file-hooks 'crypt-write-file-hook t) ; *must* append this + (error + ;; Do it by hand. Not as robust as `add-hook'. + + ;; Contributed by Ken Laprade <laprade@trantor.harris-atd.com> + ;; Really should use some sort of add-hook - 16 Feb 93 - KCL + (or (and (listp write-file-hooks) (not (eq (car write-file-hooks) 'lambda))) + (setq write-file-hooks (list write-file-hooks))) + + (cond + ((not (memq 'crypt-write-file-hook write-file-hooks)) + ;; make this hook last on purpose + (setq write-file-hooks (append write-file-hooks + (list 'crypt-write-file-hook))))))) + +;; In order that the tables and key-binding correctly reflect user's +;; preferences we add ourselves to the `after-init-hook' GNU Emacs v19 and +;; Lucid Emacs v 19.8 (or later) or `term-setup-hook' in Lucid Emacs v 19.7 +;; (or earlier). These are run *after* ~/.emacs and ../lisp/default.el are +;; loaded. Unfortunately, v18 does not have `after-init-hook' and +;; `term-setup-hook' is just a single function. It is a bit of a pain trying +;; to work our functions in properly without overwriting the user's value. +;; Therefore, we do nothing and hope they upgrade to v19 soon. + +(cond ((boundp 'after-init-hook) + ;; Must be running GNU Emacs v19 :-> + (add-hook 'after-init-hook 'crypt-rebuild-tables) + (add-hook 'after-init-hook 'crypt-rebuild-minor-modes-alist) + (add-hook 'after-init-hook 'crypt-bind-insert-file)) + + ((and (string-match "^19" emacs-version) t) + ;; Probably running Lucid Emacs v19.7 (or earlier) since it, + ;; unfortunately, does not have `after-init-hook'. Use + ;; `term-setup-hook' instead and hope they upgrade to Lucid 19.8 or GNU + ;; Emacs 19. + (add-hook 'term-setup-hook 'crypt-rebuild-tables) + (add-hook 'term-setup-hook 'crypt-rebuild-minor-modes-alist) + (add-hook 'term-setup-hook 'crypt-bind-insert-file))) + + +;;; Code for conditionally decoding/decrypting an inserted file + +(defvar crypt-bind-insert-file t + "*t value means bind `crypt-insert-file' over `insert-file'. +If you wish to change this variable after crypt++ has been loaded then do +\\[crypt-bind-insert-file].") + +(defvar crypt-auto-decode-insert nil + "*t says decode/decrypt files that are inserted with `crypt-insert-file'. +nil says to ask before doing this.") + +;;; Bind `crypt-insert-file' over wherever `insert-file' is bound? +(defun crypt-bind-insert-file () + + "Bind `crypt-insert-file' in place of `insert-file' or reverse based on +`crypt-bind-insert-file'. Part of `after-init-hook'." + + (interactive) + + (if (interactive-p) + (setq crypt-bind-insert-file + (y-or-n-p "Bind crypt-insert-file over insert-file? "))) + + (if crypt-bind-insert-file + (substitute-key-definition + 'insert-file 'crypt-insert-file (current-global-map)) + (substitute-key-definition + 'crypt-insert-file 'insert-file (current-global-map)))) + +;;; Now call it. +(crypt-bind-insert-file) + +;;; crypt++ replacement for `insert-file' +(defun crypt-insert-file (filename) + "Insert decoded/decrypted contents of file FILENAME into buffer after point. +Set mark after the inserted text. + +This function is meant for the user to run interactively. +Don't call it from programs! Use `insert-file-contents' instead. +\(Its calling sequence is different; see its documentation\). + +This version will attempt to decrypt and/or decode file before inserting. +see variable `crypt-auto-decode-insert'." + (interactive "fInsert file: ") + (if (file-directory-p filename) + (signal 'file-error (list "Opening input file" "file is a directory" + filename))) + (let ((tem (crypt-insert-file-contents filename))) ; use crypt++ to insert + (push-mark (+ (point) (car (cdr tem)))))) + +(defun crypt-insert-file-contents (file) + + ;; Similar to `insert-file-contents' except decoding/decrypting of FILE + ;; attempted. See `crypt-insert-file' and `crypt-auto-decode-insert' + + (let (temp-buffer + temp-list + (crypt-auto-decode-buffer crypt-auto-decode-insert) + (orig-buffer (current-buffer))) + + ;; Create a temporary buffer and decode and decrypt it. + (save-excursion + + ;; Temporary buffer, use the same name as the file to be inserted. + (setq temp-buffer (generate-new-buffer (file-name-nondirectory file))) + (set-buffer temp-buffer) + + ;; Original insert-file-contents - save list. + (setq temp-list (insert-file-contents file nil)) + + ;; Make temp-buffer unmodified. + (set-buffer-modified-p nil) + + ;; Need to set buffer name to file name for crypt++. + (setq buffer-file-name file) + + ;; Decode and decrypt, if necessary. + (crypt-find-file-hook) + + ;; Find the length of the file to be inserted. `insert-file-contents' + ;; returns it for the original encoded/encrypted file. + (setcdr temp-list (cons (buffer-size) ())) + + ;; Now insert temp-buffer into original buffer. + (set-buffer orig-buffer) + (insert-buffer temp-buffer) + + ;; Kill the temporary buffer. + (kill-buffer temp-buffer)) + + ;; Return modified list from `insert-file-contents'. + temp-list)) + + +;;;; BUG REPORTS + +;;; This section is provided for reports. +;;; Using Barry A. Warsaw's reporter.el + +(defconst crypt-version "2.82" + "Revision number of crypt++.el -- handles compressed and encrypted files. +Type \\[crypt-submit-report] to send a bug report. Available via anonymous +ftp in + + /roebling.poly.edu:/pub/lisp/crypt++.el.gz + /archive.cis.ohio-state.edu:/pub/gnu/emacs/elisp-archive/misc/crypt++.el.Z") + +(defconst crypt-help-address + "dodd@roebling.poly.edu" + "Address(es) accepting submission of reports on crypt++.el.") + +(defconst crypt-maintainer "Larry" + "First name(s) of people accepting submission of reports on crypt++.el.") + +(defconst crypt-file "crypt++.el" + "Name of file containing emacs lisp code.") + +(defconst crypt-variable-list + (list 'shell-file-name ; These + 'load-path ; are + 'exec-path ; useful. + 'crypt-encryption-type + 'crypt-encryption-file-extension + 'crypt-never-ever-decrypt + 'crypt-auto-write-buffer-encrypted + 'crypt-confirm-password + 'crypt-encrypted-disable-auto-save + 'crypt-auto-decode-buffer + 'crypt-auto-write-buffer + 'crypt-query-if-interactive + 'crypt-no-extension-implies-plain + 'crypt-freeze-vs-fortran + 'crypt-compact-vs-C++ + 'crypt-ignored-filenames + 'crypt-default-encoding + 'crypt-encoded-disable-auto-save + 'crypt-bind-insert-file + 'crypt-auto-decode-insert + 'crypt-encoding-alist + 'crypt-encryption-alist + ) + "List of variables to be appended to reports sent by `crypt-submit-report.'") + +(defun crypt-submit-report () + "Submit via reporter.el a bug report on program. Send report on `crypt-file' +version `crypt-version,' to `crypt-maintainer' at address `crypt-help-address' +listing variables `crypt-variable-list' in the message." + (interactive) + + ;; In case we can't find reporter... + (condition-case err + (progn + ;; Get it if we can. + (require 'reporter) + + (reporter-submit-bug-report + crypt-help-address ; address + (concat crypt-file " " crypt-version) ; pkgname + crypt-variable-list ; varlist + nil nil ; pre-hooks and post-hooks + (concat "Yo! " crypt-maintainer ","))) ; salutation + + ;; ...fail gracefully. + (error + (beep) + + ;; Do they have ange-ftp? + (if (and (featurep 'ange-ftp) + (y-or-n-p (concat "Sorry, reporter.el not found. " + "Can I ange-ftp it for you? "))) + + ;; Yes. Then Ange-ftp a copy from roebling. + (let ((ange-ftp-generate-anonymous-password t)) + ;; Might want to use the elisp archive official site? But + ;; then it would have to be uncompressed, etc. Ick! + (find-file-other-window + "/anonymous@roebling.poly.edu:/pub/reporter.el") + (eval-current-buffer) + (message (concat "Save reporter.el somewhere in `load-path' " + "and try again."))) + + ;; No ange-ftp. + (message "Sorry, reporter.el not found.") + (sit-for 3) + (message (concat "Get it from archive.cis.ohio-state.edu " + "or roebling.poly.edu")))))) + +;;; Provide this package as crypt++ as well as crypt. +(provide 'crypt++) +(provide 'crypt) + +;;; crypt++.el ends here.