comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 ;;; crypt.el --- code for handling all sorts of compressed and encrypted files
2
3 ;; Author: Lawrence R. Dodd <dodd@roebling.poly.edu>
4 ;; Rod Whitby <rwhitby@research.canon.oz.au>
5 ;; Kyle E. Jones <kyle@uunet.uu.net>
6 ;; Maintainer: Lawrence R. Dodd <dodd@roebling.poly.edu>
7 ;; Created: crypt.el in 1988, crypt++.el on 18 Jan 1993
8 ;; Version: 2.82
9 ;; Date: 1994/03/31 12:30:17
10 ;; Keywords: extensions
11
12 ;;; Copyright (C) 1994 Lawrence R. Dodd
13 ;;; Copyright (C) 1993 Lawrence R. Dodd and Rod Whitby
14 ;;; Copyright (C) 1988, 1989, 1990 Kyle E. Jones
15 ;;;
16 ;;; This program is free software; you can redistribute it and/or modify
17 ;;; it under the terms of the GNU General Public License as published by
18 ;;; the Free Software Foundation; either version 2 of the License, or
19 ;;; (at your option) any later version.
20 ;;;
21 ;;; This program is distributed in the hope that it will be useful,
22 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
23 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 ;;; GNU General Public License for more details.
25 ;;;
26 ;;; You should have received a copy of the GNU General Public License
27 ;;; along with this program; if not, write to the Free Software
28 ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29
30 ;;; Synched up with: Not in FSF.
31
32 ;;; Commentary:
33
34 ;;; NOTE: Apparently not being maintained by the author, who now
35 ;;; uses jka-compr.el. --ben (1/26/96)
36 ;;; Included patch (1/26/96)
37
38 ;;; Please see notes on INSTALLATION and USAGE on the pages below.
39
40 ;;; LCD Archive Entry:
41 ;;; crypt++|Rod Whitby and Lawrence R. Dodd|dodd@roebling.poly.edu|
42 ;;; Code for handling all sorts of compressed and encrypted files.|
43 ;;; 1994/03/31 12:30:17|2.82|~/misc/crypt++.el.Z|
44
45 ;;; AVAILABLE:
46 ;;;
47 ;;; via anonymous ftp to roebling.poly.edu [128.238.5.31] in
48 ;;; /pub/lisp/crypt++.el.gz
49 ;;;
50 ;;; via anonymous ftp to archive.cis.ohio-state.edu [128.146.8.52] in
51 ;;; /pub/gnu/emacs/elisp-archive/misc/crypt++.el.Z
52
53 ;;; BUG REPORTS
54 ;;;
55 ;;; Type M-x crypt-submit-report to generate a bug report template or put your
56 ;;; cursor at the end of this line and type C-x C-e: (crypt-submit-report)
57 ;;;
58 ;;; Please note that this bug-report facility (crypt-submit-report) uses Barry
59 ;;; Warsaw's reporter.el which is part of GNU Emacs v19 and bundled with many
60 ;;; other packages. If needed, you can obtain a copy of reporter.el at
61 ;;; /roebling.poly.edu:/pub/reporter.el or the elisp-archive. In fact,
62 ;;; crypt-submit-report will attempt to ange-ftp a copy for you from roebling
63 ;;; if you do not have one accessible.
64
65 ;;; Lawrence R. Dodd <dodd@roebling.poly.edu>
66 ;;; Polytechnic University
67 ;;; Brooklyn, New York USA
68
69 ;;; VERSION:
70 ;;;
71 ;;; Version: 2.82
72 ;;; Ident: crypt++.el,v 2.82 1994/03/31 12:30:17 dodd Exp
73 ;;; Date: 1994/03/31 12:30:17
74
75
76 ;;; INSTALLATION:
77 ;;;
78 ;;; To use this package, simply put it in a file called "crypt.el" in a Lisp
79 ;;; directory known to Emacs (see `load-path'), byte-compile it (you may get a
80 ;;; warning saying that the function reporter-submit-bug-report is not known
81 ;;; to be defined -- ignore it), and put the line:
82 ;;;
83 ;;; (require 'crypt)
84 ;;;
85 ;;; in your ~/.emacs file or in the file default.el in the ../lisp directory
86 ;;; of the Emacs distribution. Do not bother trying to autoload this file;
87 ;;; this package uses find-file and write-file hooks and thus should be loaded
88 ;;; the first time you visit any sort of file. Any package loaded after this
89 ;;; one that appends something to `write-file-hooks' will not be executed
90 ;;; because this package writes out the file. Other packages that append to
91 ;;; `write-file-hooks' should either be modified to prepend to that hook or be
92 ;;; loaded before this one (preferably the former).
93
94 ;;; NOTE: encryption users should set `crypt-encryption-type' to one of the
95 ;;; values in `crypt-encryption-alist' (see USAGE below).
96
97 ;;; SEE ALSO: /roebling.poly.edu:/pub/crypt++-fnf.el for file-not-found
98 ;;; support for GNU Emacs.
99
100 ;;; SPECIAL NOTES:
101 ;;;
102 ;;; If crypt is dumped with the emacs executable, or if it has already been
103 ;;; loaded in an emacs session, then modifying the variables used in building
104 ;;; the encryption and encoding tables will have no effect until these tables
105 ;;; are rebuilt. This may be done with `M-x crypt-rebuild-tables'. See USAGE
106 ;;; below to determine variables for which this is needed. For example,
107 ;;; post-load changes to `crypt-encryption-file-extension' or
108 ;;; `crypt-freeze-vs-fortran' can be incorporated into the encryption table
109 ;;; via `M-x crypt-rebuild-tables'. Similarly, post-load changes to
110 ;;; `crypt-bind-insert-file' are handled with `M-x crypt-bind-insert-file'.
111
112
113 ;;; USAGE:
114 ;;;
115 ;;; By default, intended to be transparent. User-defined variables
116 ;;;
117 ;;; controlling ENCRYPTION are
118 ;;;
119 ;;; crypt-encryption-type
120 ;;; crypt-encryption-file-extension
121 ;;; crypt-never-ever-decrypt
122 ;;; crypt-auto-write-buffer-encrypted
123 ;;; crypt-confirm-password
124 ;;; crypt-encrypted-disable-auto-save
125 ;;; crypt-encryption-alist
126 ;;;
127 ;;; controlling ENCODING are
128 ;;;
129 ;;; crypt-auto-decode-buffer
130 ;;; crypt-auto-write-buffer
131 ;;; crypt-query-if-interactive
132 ;;; crypt-no-extension-implies-plain
133 ;;; crypt-freeze-vs-fortran
134 ;;; crypt-compact-vs-C++
135 ;;; crypt-ignored-filenames
136 ;;; crypt-default-encoding
137 ;;; crypt-encoded-disable-auto-save
138 ;;; crypt-encoding-alist
139 ;;;
140 ;;; controlling file insertion are
141 ;;;
142 ;;; crypt-bind-insert-file
143 ;;; crypt-auto-decode-insert
144 ;;;
145 ;;; To find out more about these variables, load this file, put your cursor at
146 ;;; the end of any of the variable names, and hit C-h v [RET].
147 ;;;
148 ;;; NOTE: encryption users should set `crypt-encryption-type' to one of the
149 ;;; values in `crypt-encryption-alist'
150 ;;;
151 ;;; Although rarely needed, the following functions may be called interactively
152 ;;;
153 ;;; (crypt-encoded-mode)
154 ;;; (crypt-encode-region)
155 ;;; (crypt-encrypted-mode)
156 ;;; (crypt-encrypt-region)
157 ;;; (crypt-set-encryption-key)
158 ;;; (crypt-rebuild-tables)
159 ;;; (crypt-insert-file)
160 ;;; (crypt-bind-insert-file)
161 ;;; (crypt-submit-report)
162 ;;;
163 ;;; To find out more about these functions, load this file, put your cursor
164 ;;; inside any of the `()' of the above lines, and hit C-h f [RET].
165
166
167 ;;; NOTES ON INTERFACES WITH OTHER PROGRAMS AND PACKAGES:
168 ;;;
169 ;;; GZIP: the environment variable GZIP of gzip can cause an error if it
170 ;;; contains `--verbose' because standard output messages will be appended to
171 ;;; gzip'ed files. This corrupts the files. The cleanest solution is to pass
172 ;;; the `--quiet' switch in `crypt-encoding-alist' to override this. use gzip
173 ;;; version 1.0.4 or higher from prep.ai.mit.edu:/pub/gnu
174 ;;;
175 ;;; TAR-MODE: works properly with version 1.28 (or higher) with v19 emacs.
176
177
178 ;;; DESCRIPTION:
179 ;;;
180 ;;; The basic purpose of this package of Lisp functions is to recognize
181 ;;; automatically encrypted and encoded (i.e., compressed) files when they are
182 ;;; first visited or written. The BUFFER corresponding to the file is decoded
183 ;;; and/or decrypted before it is presented to the user. The file itself is
184 ;;; unchanged on the disk. When the buffer is subsequently saved to disk, a
185 ;;; hook function re-encodes the buffer before the actual disk write takes
186 ;;; place.
187 ;;;
188 ;;; This package recognizes all sorts of compressed files by a magic number at
189 ;;; the beginning of these files but uses a heuristic to detect encrypted
190 ;;; files. If you are asked for an encryption key for a file that is in fact
191 ;;; not encrypted, just hit RET and the file will be accepted as is, and the
192 ;;; crypt minor mode will not be entered.
193 ;;;
194 ;;; Other types of encoding programs may be added to this package by using the
195 ;;; variable `crypt-encoding-alist' which contains a table of encoding
196 ;;; programs such as compress, gzip (GNU zip), freeze, and compact.
197 ;;;
198 ;;; This new extended version of crypt now monitors the filename extensions of
199 ;;; buffers that are written out using write-file (C-x C-w). If the filename
200 ;;; extension matches one of the extensions listed in `crypt-encoding-alist,'
201 ;;; then this package will write the file out using the corresponding encoding
202 ;;; (compression) method. This is done whether or not the buffer originated
203 ;;; from a previously encoded (compressed) file.
204 ;;;
205 ;;; Thus, if the user is editing a file that may or may not have been encoded
206 ;;; originally (e.g., foobar.Z or foobar) and decides to write it to a
207 ;;; different file (e.g., barfoo or barfoo.z or barfoo.C). This package will
208 ;;; examine the filename extension and write the buffer in plain format or an
209 ;;; alternate encoding (compression) format by searching through the entries
210 ;;; in the table of encoding methods `crypt-encoding-alist.' This change in
211 ;;; encoding state is done automatically if the variable
212 ;;; `crypt-auto-write-buffer' is t otherwise the user is asked.
213
214
215 ;;; TO DO/KNOWN BUGS/HELP WANTED/APPLY WITHIN:
216 ;;;
217 ;;; All Users/hackers out there are strongly encouraged to pursue any of these
218 ;;; matters further (especially those that concern encryption and decryption!).
219 ;;; It is important to future programmers and modifiers of crypt++.el to know
220 ;;; about its perceived limitations. Since necessity drives invention, users
221 ;;; who find any of the following features of crypt++.el annoying are asked to
222 ;;; make suggestions and send patches (again, especially those that concern
223 ;;; encryption and decryption!).
224 ;;;
225 ;;; * currently crypt++ assumes that if a file is both encrypted and encoded
226 ;;; (i.e., compressed) that the order in which it was done was encryption
227 ;;; first _then_ compression. As has been pointed by many people compression
228 ;;; following encryption is useless since the encrypted file is basically
229 ;;; random. On the other hand, many agree that doing encryption _following_
230 ;;; compression is better since it makes it harder to crack the encryption.
231 ;;; We would like to make the ordering of these two user-configurable or if
232 ;;; nothing else change the order.
233 ;;;
234 ;;; Having read the above however, Francois Pinard <pinard@iro.umontreal.ca>
235 ;;; writes that encryption following compression may not be harder to crack
236 ;;; since "the fact that the first few uncrypted bytes are expected (the
237 ;;; compress signature) facilitates a serious attempt at uncrypting."
238 ;;; jwz agrees with Francois.
239 ;;;
240 ;;; * get write-region and append-to-file to handle encoded and encrypted
241 ;;; files. There is an interesting low-level encoding package by Jay Adams
242 ;;; <jka@ece.cmu.edu> called jka-compr.el that might address some of these
243 ;;; issues. We encourage hackers out there to come up with crypt++ versions
244 ;;; of write-region and append-to-file. The difficulty is creating versions
245 ;;; that mimic the originals as closely as possible.
246 ;;;
247 ;;; * instead of using call-process-region (which can fail badly if the region
248 ;;; is large and there's not much room in /tmp), write the region to a temp
249 ;;; file (with a customisable location) and use call-process directly.
250 ;;;
251 ;;; * users have mentioned trouble using crypt++ and hilit simultaneously since
252 ;;; the functions in write-file-hook for both write the file to disk and
253 ;;; return t. A possible solution is to have one of them write to a
254 ;;; scratch buffer instead of to disk and return nil and then allow the
255 ;;; other to do its work on the scratch buffer and write it to disk. Thanks
256 ;;; to Wayne Folta <folta@cs.UMD.EDU> and Amir J Katz <amir@matis.ingr.com>.
257 ;;; It would be nice to have another way in emacs to have an
258 ;;; after-write-file-hook and a before-write-file-hook of some sort.
259 ;;; Lucid Emacs has an after-write-file-hook. Recent versions of hilit19.el
260 ;;; do not automatically attach to `write-file-hooks' and return t.
261 ;;; However, the general problem of multiple packages returning t still
262 ;;; remains. dos-mode.el and crypt.el also conflict.
263 ;;;
264 ;;; * another possible source of trouble is with encryption (and encoding)
265 ;;; programs sticking verbose output into buffers prior to being written to
266 ;;; disk. This was definitely occurring with gzip because of --verbose in
267 ;;; the GZIP environment variable and is solved/hidden with the --quiet
268 ;;; switch. However, I suspect that some encryption problems out there are
269 ;;; capable of similar things so the user should be careful.
270 ;;;
271 ;;; * integrating crypt++ with a backgrounding package such as Olin Shivers'
272 ;;; `background.el' might be useful too. thanks to Mark Borges
273 ;;; <mdb@noaacrd.Colorado.EDU> for suggesting this.
274 ;;;
275 ;;; * Performing M-x crypt-encode-buffer or M-x crypt-encrypt-buffer and then
276 ;;; saving the file would possibly cause errors. It is better to toggle
277 ;;; `crypt-encoded-mode' (or `crypt-encrypted-mode') and simply save the
278 ;;; file. It is for this reason that `crypt-encode-buffer' and
279 ;;; `crypt-encrypt-buffer' are not interactive.
280 ;;;
281 ;;; * use plists instead of alists replacing calls to `nth' with `get'
282 ;;;
283 ;;; * merge encryption code completely into encoding code making encryption
284 ;;; just a special case of encoding.
285
286
287 ;;; Change log:
288 ;;;
289 ;;; 1.1 - original version of crypt.el
290 ;;; 1.2 -
291 ;;; jwz: works with tar-mode.el
292 ;;; jwz: applied patch from piet, merged with Lawrence Dodd's gzip version
293 ;;; 1.3 -
294 ;;; lrd: fixed compress-magic-regexp
295 ;;; 1.4, 1.5, 1.6 -
296 ;;; lrd: write-file compresses or gzips based on file extension
297 ;;; 2.1 -
298 ;;; lrd: merged with Rod Whitby's table-driven version (major upgrade)
299 ;;; 2.2 -
300 ;;; rjw: Changed file name to crypt++.el, so archie and lispdir can find it.
301 ;;; 2.3 -
302 ;;; rjw: Separated the hook additions and minor mode alist additions.
303 ;;; 2.4 -
304 ;;; rjw: Fixed the interactive form for crypt-buffer.
305 ;;; 2.5 -
306 ;;; lrd: doc mods, changed GNU free software notice (was out of date), added
307 ;;; anonymous ftp information
308 ;;; 2.6 -
309 ;;; lrd: added back in definition of `buffer' in defun crypt-buffer caused
310 ;;; an error when trying to read encrypted file; modified check for minor
311 ;;; mode alist addition; added gzip magic number warning
312 ;;; 2.7 - [posted to gnu.emacs.sources]
313 ;;; lrd: added `TO DO' and `KNOW BUGS' section to header
314 ;;; 2.8 -
315 ;;; lrd: added note about updating to v 1.24 of tar-mode.el
316 ;;; Thanks to Mark Borges <mdb@noaacrd.Colorado.EDU>
317 ;;; 2.9 -
318 ;;; lrd: moved query about `crypt-freeze-vs-fortran' out of defvar for
319 ;;; `crypt-encoding-alist,' an erroneous value of nil was being stuck into
320 ;;; alist when user set `crypt-freeze-vs-fortran' was nil, doc mod.
321 ;;; Thanks to Mark Borges <mdb@noaacrd.Colorado.EDU>
322 ;;; 2.10 -
323 ;;; rjw: moved query about `crypt-freeze-vs-fortran' back into defvar for
324 ;;; `crypt-encoding-alist,' - used append to ignore the erroneous nil.
325 ;;; 2.11 -
326 ;;; rjw: fixed a bug in my fix :-(
327 ;;; 2.12 -
328 ;;; rjw: Defvar crypt-magic-regexp and crypt-magic-regexp-inverse and
329 ;;; allow either a regexp or an elisp expression.
330 ;;; Suggested by Franc,ois Pinard <pinard@iro.umontreal.ca>.
331 ;;; 2.13 -
332 ;;; lrd: added in info on lispdir.el, doc mods and some puttering while
333 ;;; looking over rjw's v 2.12 mods.
334 ;;; 2.14 -
335 ;;; lrd: doc mod - trivial huh? switched `compact' and `gzip' in
336 ;;; `crypt-encoding-alist' - want gzip near top
337 ;;; 2.15 -
338 ;;; lrd: added in LCD Archive Entry and modified comments on tar-mode.el
339 ;;; since the version at the elisp-archive now works with crypt++.el
340 ;;; 2.16 -
341 ;;; lrd: provide `crypt' as well as `crypt++' allowing something like `ln -s
342 ;;; crypt++.el crypt.el' to be meaningful
343 ;;; Suggested (by|as) Per Abrahamsen <amanda@iesd.auc.dk>
344 ;;; 2.17 -
345 ;;; lrd: clarified bug report procedure, added fancy pseudo-graphics, added
346 ;;; to the `TO DO' list, put RCS tags in LCD Archive entry
347 ;;; 2.18 - [posted to gnu.emacs.sources]
348 ;;; lrd: included pointer to elisp archive in crypt-version description,
349 ;;; changed "Decode buffer %s? " to "Decode %s? " in crypt-find-file-hook
350 ;;; to be more general (mainly for crypt-insert-file)
351 ;;; 2.19 -
352 ;;; rjw: Added the crypt-compact-vs-C++ switch to distinguish compacted and
353 ;;; C++ files.
354 ;;; 2.20 -
355 ;;; lrd: (1) modified interactive form of crypt-buffer. (2) made search
356 ;;; case-insensitive in crypt-submit-report. (3) modified encoded-mode and
357 ;;; crypt-mode so that buffer-modified is not unconditionally set to nil
358 ;;; when the mode is not changed. Thanks to Gerd Hillebrand
359 ;;; <ggh@cs.brown.edu> for suggesting (2) and (3).
360 ;;; 2.21 -
361 ;;; rjw: Added an entry to the TODO list about the hazards of using
362 ;;; call-process-region on a large region and not much room in /tmp
363 ;;; (David Carlisle <carlisle@computer-science.manchester.ac.uk>).
364 ;;; 2.22 -
365 ;;; lrd: allow write-file-hooks to contain functions as well as lists.
366 ;;; Contributed by Ken Laprade <laprade@trantor.harris-atd.com>.
367 ;;; 2.23 -
368 ;;; lrd: made crypt-submit-report list values of more user-defined variables
369 ;;; 2.24 -
370 ;;; lrd: pass the -q switch to gzip to thwart the possibility of a --verbose
371 ;;; in the GZIP environment variable
372 ;;; 2.25 -
373 ;;; lrd: added some more to the TO DO list, clarified some things, also
374 ;;; untabified the entire file (I got tired of the control I's)
375 ;;; 2.26 -
376 ;;; lrd: use the long-named options for GNU zip (self-documenting)
377 ;;; 2.27 -
378 ;;; lrd: included observation by Francois Pinard <pinard@iro.umontreal.ca>
379 ;;; and worked on text in TO DO/KNOWN BUGS list
380 ;;; 2.28 -
381 ;;; lrd: added two new variables in (crypt-submit-report) to the list stuck
382 ;;; at the bottom of the mail message; changed the comments regarding the
383 ;;; user-defined variables. added in default values in user defined
384 ;;; variables. added to and removed stuff to the `TO DO' list.
385 ;;;
386 ;;; (encoded-mode):
387 ;;; added in code to remove any auto-save-files that may have been formed
388 ;;; before becoming an encoded buffer (for example a plain file saved to
389 ;;; disk encoded had orphan auto-save-files left behind). turning off
390 ;;; auto-save-mode disables the creation of auto-save-files, but it also
391 ;;; disables the possibility of these being removed when the buffer is
392 ;;; saved.
393 ;;;
394 ;;; (crypt-region):
395 ;;; now call the encryption and decryption program directly instead of
396 ;;; through the shell. this is more secure since the shell will expose the
397 ;;; password (key). thanks to Jon Cargille <jcargill@cs.wisc.edu>. defined
398 ;;; two new variables `crypt-decryption-args' and `crypt-encryption-args' to
399 ;;; take the arguments separately. removed (let ((opoint)...)) construct
400 ;;; this was a throw back to some old dead code and was not being used.
401 ;;; 2.29 -
402 ;;; lrd: added three new variables in (crypt-submit-report); added to the
403 ;;; `TO DO' list.
404 ;;;
405 ;;; (encode-region,encode-buffer,encoded-mode): fixed interactive forms -
406 ;;; the conversion to table version had eliminated some of the interactive
407 ;;; features of these. thanks to Kimball Collins <kpc@ptolemy.arc.nasa.gov>
408 ;;; for point this out. new interactive form uses functions
409 ;;; `crypt-get-encoding-type' and `crypt-symbol-alist-to-table' and variable
410 ;;; `crypt-default-encoding' to generate completion list of encoding types.
411 ;;;
412 ;;; (crypt-write-file-hook): two new user-defined variables
413 ;;; `crypt-query-if-interactive' and `crypt-no-extension-implies-plain' and
414 ;;; the buffer-local variable `buffer-interactive-mode' are used to help
415 ;;; determined whether or not plain output is really desired for files
416 ;;; without a compression file-name extension. the default behavior is the
417 ;;; same as before.
418 ;;; 2.30 -
419 ;;; lrd: added test for user-defined variable `crypt-never-ever-decrypt'
420 ;;; when finding a file. some users may never wish to decrypt files
421 ;;; and like to edit binary files. thanks to Nelson Minar
422 ;;; <nelson@reed.edu>. added to doc-strings of
423 ;;; `crypt-magic-regexp[-inverse]' -- these can be set to nil[t] and
424 ;;; accomplish the same thing as setting `crypt-never-ever-decrypt' to t
425 ;;; 2.31 -
426 ;;; rjw: Updated the comments in the encryption check section.
427 ;;; 2.32 - [posted to gnu.emacs.sources]
428 ;;; lrd: added warning about `crypt-(de|en)cryption-program'; doc mod.
429 ;;; 2.33 -
430 ;;; lrd: if `crypt-(de|en)cryption-args' are nil then don't pass any
431 ;;; arguments to (de|en)cryption program, nil is the default instead of
432 ;;; "". Thanks to Joe Ilacqua <spike@world.std.com>, David J. Schur
433 ;;; <djs@idm.com>, Peter Nuth <nuth@ai.mit.edu>, and Greg Larson
434 ;;; <glarson@bnr.ca>. `-q' exists in gzip 1.0.3 but not `--quiet' changed
435 ;;; GZIP NOTE. Thanks to Chris Moore <moore@src.bae.co.uk>.
436 ;;; 2.34 -
437 ;;; lrd: allow `crypt-(de|en)cryption-args' to be a list of strings -- more
438 ;;; robust. query for password (key), if none is set, when writing out file
439 ;;; for which `buffer-save-encrypted' is t. Thanks to John Interrante
440 ;;; <interran@uluru.Stanford.EDU>. (crypt-write-file-hook): check filename
441 ;;; extension against regexp `crypt-encryption-file-extension' and query for
442 ;;; encryption, unless `crypt-auto-write-buffer-encrypted' is t (don't
443 ;;; bother doing reverse check, encrypted to plain, not a common request).
444 ;;; (crypt-mode): delete auto-save files (cf., encoded-mode), may exist now.
445 ;;; (read-string-no-echo): applied patch from Piet van Oostrum
446 ;;; <piet@cs.ruu.nl> -- set `cursor-in-echo-area' _after_ setting buffer
447 ;;; (this was screwing up gnews).
448 ;;; 2.35 -
449 ;;; lrd: doc mod
450 ;;; 2.36 -
451 ;;; lrd: fixed typo, added RMAIL note.
452 ;;; 2.37 - [posted to gnu.emacs.sources]
453 ;;; lrd:
454 ;;; (crypt-write-file-hook): search user-defined list
455 ;;; `crypt-ignored-filenames' for possible match with `buffer-filename'
456 ;;; before attempting conversion from compressed to plain format; useful for
457 ;;; compressed incoming mail files (e.g., RMAIL, INBOX).
458 ;;;
459 ;;; (crypt-mode): query for key if not set already; need to switch order of
460 ;;; recovering key and toggling crypt-mode in crypt-find-file-hook (thanks
461 ;;; to Piet van Oostrum <piet@cs.ruu.nl>).
462 ;;;
463 ;;; (crypt-buffer) and (encode-buffer): remove interactive form; use
464 ;;; (crypt-mode) and (encoded-mode) instead so encryption and compression
465 ;;; are done at the very end; leave interactive form in (crypt-region) and
466 ;;; (encode-region) may still be used.
467 ;;;
468 ;;; (set-encryption-key): remove from `command-history' if called
469 ;;; interactively - thanks to George M. Georgiou
470 ;;; <georgiou@silicon.csci.csusb.edu>.
471 ;;; 2.38 -
472 ;;; lrd: added `crypt-' prefix to `(read-string-no-echo)' and `(save-point)'
473 ;;; changed file extension for gzip files to `.z' _or_ `.gz' (future release
474 ;;; of gzip with use later extension by default and so this should be
475 ;;; changed to just `.gz' someday).
476 ;;; 2.39 -
477 ;;; lrd: doc mod. added in patch from jwz - `(crypt-read-string-no-echo)' is
478 ;;; more secure, put property 'permanent-local on buffer-locals works for
479 ;;; Lucid Emacs and doesn't harm v18 emacs, change `buffer-interactive-mode'
480 ;;; to `buffer-interactive-encoded-mode.'
481 ;;; 2.40 -
482 ;;; lrd: put property 'preserved in case kill-fix.el is being used.
483 ;;; 2.41 -
484 ;;; lrd: all functions and variables now start with `crypt-', moved REVISION
485 ;;; HISTORY to bottom of header, interactive version of
486 ;;; `(crypt-encrypt-region)' clearer, `(crypt-read-string-no-echo)' now
487 ;;; echos `.'
488 ;;; 2.42 -
489 ;;; lrd: (crypt-check-extension-for-encoding): broke out of
490 ;;; `(crypt-write-file-hook)'. setting user variables
491 ;;; `crypt-compact-vs-C++' and `crypt-freeze-vs-fortran' to nil no longer
492 ;;; completely disables the reading compact'ed and frozen files but just
493 ;;; disables the use of the file-extension tricks of
494 ;;; `(crypt-check-extension-for-encoding).' (crypt-encode-region): allow
495 ;;; for a single line message from encoding program at top of region; if it
496 ;;; is there, then remove it; kludge for `compact' program.
497 ;;; 2.43 -
498 ;;; lrd: (crypt-encode-region): generalize the clean up procedure; add
499 ;;; element to `crypt-encoding-alist' and introduce new function
500 ;;; `(crypt-encoding-cleanup-regexp)' to extract a compression specific
501 ;;; regexp for erroneous message or lisp expression for cleanup.
502 ;;; 2.44 -
503 ;;; lrd: new element for `crypt-encoding-alist' handles whether or not
504 ;;; file-name extension tricks may be play with encoding method; compact and
505 ;;; freeze values default to `crypt-compact-vs-C++' and
506 ;;; `crypt-freeze-vs-fortran' (thanks to rjw);
507 ;;; (crypt-encoding-extension-tricks): new defun to handle this;
508 ;;; (crypt-check-extension-for-encoding): monitors "tricks" entry of
509 ;;; `crypt-encoding-alist' and adjust the bag of tricks it can apply.
510 ;;; 2.45 -
511 ;;; lrd: (crypt-encode-region): delete entire match of cleanup regexp by
512 ;;; requiring newlines in GARBAGE-REGEXP-OR-LISPEXP. (crypt-submit-report):
513 ;;; use Warsaw's reporter.el.
514 ;;; 2.46 -
515 ;;; lrd: (crypt-find-file-hook, crypt-write-file-hook): cleaned, documented,
516 ;;; and replaced occurrences of `(cond (C BODY))' with `(if C BODY)';
517 ;;; changed `crypt-magic-regexp' to `crypt-encryption-magic-regexp' and
518 ;;; `crypt-magic-regexp-inverse' to `crypt-encryption-magic-regexp-inverse'
519 ;;; for consistency with other variable names. new user-defined variable
520 ;;; `crypt-encryption-minor-mode-name' instead of always "Crypt". grouped
521 ;;; all encryption variables together.
522 ;;; 2.47 -
523 ;;; lrd: somewhat major change - put program-specific encryption variables
524 ;;; into a single table `crypt-encryption-alist' and let the variable
525 ;;; `crypt-encryption-type' define the appropriate entry to use; new
526 ;;; user-defined variable `crypt-confirm-password,' thanks to Jeff Clark
527 ;;; <jclark@src.honeywell.com>. (crypt-submit-report): improved error
528 ;;; handling, thanks to baw. (crypt-write-file-hook): fixed bug with
529 ;;; `crypt-encoding-extension-tricks'
530 ;;; 2.48 -
531 ;;; lrd: added dummy argument to `crypt-encoding-alist' and
532 ;;; `crypt-encryption-alist' and merged all defuns that work on their
533 ;;; elements into defuns that all start with `crypt-get-' and look through
534 ;;; both lists. simplifies some of code and closer to treating encryption
535 ;;; as a special case of encoding; crypt-minor-mode-alist: replaced (nth *)
536 ;;; with `(crypt-get-minor-mode)' call; (crypt-encode-region): allow
537 ;;; arguments to be list of strings; renamed (crypt-get-encoding-type) to
538 ;;; (crypt-read-encoding-type) for clarity.
539 ;;; 2.49 - [posted to gnu.emacs.sources]
540 ;;; lrd: (crypt-encode-region): ignore `args' if set to t
541 ;;; 2.50 -
542 ;;; lrd: (crypt-write-file-hook): in v19 we need to call `backup-buffer'
543 ;;; ourselves -- we write out the file and return t so `basic-save-buffer'
544 ;;; does not do it; also call `set-file-modes'
545 ;;; 2.51 -
546 ;;; lrd: some `defvar's are now `defconst's and tar-mode note was changed.
547 ;;; 2.52 -
548 ;;; lrd: make doc strings conform to GNU standards.
549 ;;; 2.53 -
550 ;;; lrd: made header conform to GNU Conventional Headers standard.
551 ;;; 2.54 -
552 ;;; lrd: `crypt-encryption-file-extension', `crypt-freeze-vs-fortran',
553 ;;; `crypt-compact-vs-C++', `crypt-encryption-magic-regexp', and
554 ;;; `crypt-encryption-magic-regexp-inverse' are used in defining the tables
555 ;;; `crypt-encoding-alist' and `crypt-encryption-alist' and so need to be set
556 ;;; _before_ loading crypt++. use `add-hook' if it is available.
557 ;;; 2.55 -
558 ;;; lrd: new interactive function `crypt-insert-file' mimics `insert-file'
559 ;;; but attempts to decode or decrypt before insertion; bound `C-x i' if
560 ;;; `crypt-bind-insert-file' is non-nil. comment out doc-strings from
561 ;;; internal subroutines, saves space.
562 ;;; 2.56 -
563 ;;; tfb: change the definitions of crypt-{encoding,encryption}-alist, to
564 ;;; call the functions crypt-make-{encoding,encryption}-alist resp.
565 ;;; Added crypt-reinit which regenerates these variables from their
566 ;;; functions, thus allowing this stuff to be preloaded even if people
567 ;;; set things in their init files.
568 ;;; Tim Bradshaw <tim.bradshaw@mid-heidelberg.de>
569 ;;; 2.57 -
570 ;;; lrd: untabify; remove duplicate entry in `crypt-make-encoding-alist';
571 ;;; change name of `crypt-make-*-alist' to `crypt-build-*-alist' and
572 ;;; `crypt-reinit' to `crypt-rebuild-tables'; (crypt-read-string-no-echo):
573 ;;; change local variable `form' to `help-form' so it is defined;
574 ;;; `crypt-encryption-alist' and `crypt-encoding-alist' must be defined with
575 ;;; `defconst' since we wish crypt++ to initialize these variables
576 ;;; unconditionally; modify INSTALLATION section to reflect these changes.
577 ;;; 2.58 -
578 ;;; lrd: doc mod.
579 ;;; 2.59 - [posted to gnu.emacs.sources]
580 ;;; lrd: (crypt-bind-insert-file): new function for changing "C-x i" in
581 ;;; initialization file or interactively.
582 ;;; 2.60 -
583 ;;; lrd: add `crypt-rebuild-tables' and `crypt-bind-insert-file' to
584 ;;; `after-init-hook' in GNU emacs v19 and to `term-setup-hook' in Lucid
585 ;;; emacs. Change INSTALLATION notes.
586 ;;; 2.61 - [posted to gnu.emacs.sources]
587 ;;; lrd: Doc mod. Clean up the installation of minor mode indicators.
588 ;;; 2.62 - [posted to gnu.emacs.sources]
589 ;;; lrd: installed patch from stig@hackvan.com to simplify crypt-get-* defuns
590 ;;; (now defmacros). Don't add to `term-setup-hook' unless no
591 ;;; `after-init-hook' _and_ definitely running v19, otherwise Rod gets an
592 ;;; error at home :-<. Don't assume C-x i had `insert-file' bound to it:
593 ;;; store old binding in `crypt-old-binding' before overwriting and use in
594 ;;; function `crypt-bind-insert-file.'
595 ;;; 2.63 -
596 ;;; lrd: (crypt-encode-buffer, crypt-encode-region, crypt-encrypt-buffer,
597 ;;; crypt-encrypt-region): changed argument list putting optional buffer
598 ;;; last and making default action to encode or encrypt. (crypt-encoded-p,
599 ;;; crypt-encrypted-p): new functions that do the actual testing of file
600 ;;; contents. (crypt-find-file): uses these new functions.
601 ;;; (crypt-rebuild-minor-modes-alist): new function to rebuild
602 ;;; `minor-mode-alist' called by function crypt-rebuild-tables.
603 ;;; (crypt-build-minor-mode-alist): new function called by
604 ;;; `crypt-minor-mode-alist' to create itself. `crypt-minor-mode-encrypted'
605 ;;; removed because defined in function crypt-build-minor-mode-alist.
606 ;;; 2.64 -
607 ;;; lrd: (crypt-find-file-hook): temporarily remove the encrytion file
608 ;;; extension to help determine the major mode, just like is done with the
609 ;;; encoding file extension. In order for this to work properly the file
610 ;;; extension in `crypt-encryption-file-extension' and
611 ;;; `crypt-encryption-alist' needs to be inside a pair of \\( \\).
612 ;;; 2.65 -
613 ;;; lrd: (crypt-find-file-hook): move determination of key, password, into
614 ;;; (crypt-encrypted-p).
615 ;;; 2.66 -
616 ;;; lrd: (crypt-set-encryption-key): improve prompt string for encryption
617 ;;; key.
618 ;;; 2.67 -
619 ;;; lrd: (crypt-write-file-hook): make check for encryption file-name
620 ;;; extension case-sensitive.
621 ;;; 2.68 -
622 ;;; lrd: fixed check for previous addition to `minor-mode-alist' -- was not
623 ;;; working. Check for an `add-hook' function; if one does not exist then
624 ;;; use a copy of one from GNU Emacs 19. When using `add-hook' to append to
625 ;;; the `write-file-hooks' make sure that the version accepts the optional
626 ;;; APPEND argument -- v19's does but the one in the elisp archive by Dan
627 ;;; LaLiberte <liberte@cs.uiuc.edu> does not append. This causes problems.
628 ;;; Thanks to Francesco Potorti` <pot@fly.CNUCE.CNR.IT> for pointing this
629 ;;; out.
630 ;;; 2.69 - [posted to gnu.emacs.sources]
631 ;;; lrd: doc mod with regards `after-init-hook' and Lucid Emacs. Add
632 ;;; pointer to crypt++-fnf.el for people who might be interested.
633 ;;; 2.70 -
634 ;;; lrd: narrow conditions under which crypt-encryption-magic-regexp
635 ;;; matches. Thanks to Philippe Michel <michel@thomson-lcr.fr> and Francois
636 ;;; Pinard <pinard@iro.umontreal.ca> for helping explain this with regards
637 ;;; to ISO/Latin-1.
638 ;;; 2.71 -
639 ;;; lrd: applied patches from Darrin Jewell <jewell@bdi.com> for DOS to UNIX
640 ;;; support. DOS entry added to crypt-build-encoding-alist.
641 ;;; (crypt-dos-to-unix-region, crypt-unix-to-dos-region): New
642 ;;; functions. (crypt-dos-has-ctrl-z): New buffer-local variable.
643 ;;; (crypt-encode-region): allow for encoding and decoding programs to be
644 ;;; elisp expressions. If they are then apply them directly to region.
645 ;;; Point out that crypt++.el conflicts with dos-mode.el.
646 ;;; 2.72 -
647 ;;; lrd: The limit for the regular expression search done by
648 ;;; `crypt-encrypted-p' is extended to 100 by default. The enlargement of
649 ;;; search field is needed because of previous reduction in size of regexp
650 ;;; being searched for. (crypt-magic-search-limit): New variable defining
651 ;;; this new limit. (crypt-encrypted-p): Uses it and cleaned up. Doc mod.
652 ;;; Thanks to Philippe Michel <michel@thomson-lcr.fr>, Francois Pinard
653 ;;; <pinard@iro.umontreal.ca>, and Dave Goldberg <dsg@blackbird.mitre.org>.
654 ;;; 2.73 - [posted to gnu.emacs.sources]
655 ;;; lrd: Apply patch from Kevin Rodgers <kevin@traffic.den.mmc.com> that
656 ;;; uses more verbose messages and capitals. Doc mod.
657 ;;; 2.74 -
658 ;;; lrd: Untabify. (crypt-encrypted-p): Check value of
659 ;;; `crypt-never-ever-decrypt' before anything else.
660 ;;; 2.75 -
661 ;;; lrd: (crypt-version): Remove call to `substring'.
662 ;;; 2.76 -
663 ;;; lrd: (crypt-encryption-magic-regexp-inverse): Add in regexp that will
664 ;;; match ksh `.sh_history' files so that they are not interpreted as
665 ;;; encrypted files. Thanks to Francesco Potorti` <pot@fly.CNUCE.CNR.IT>.
666 ;;; 2.77 - [posted to gnu.emacs.sources]
667 ;;; lrd: (crypt-bind-insert-file): Use substitute-key-definition to bind
668 ;;; crypt-insert-file to whatever key insert-file is bound to (not
669 ;;; necessarily C-x i). Call crypt-bind-insert-file directly in
670 ;;; file. Variable crypt-bind-insert-file: Doc mod. Remove
671 ;;; crypt-old-binding. Replace `M-x foobar' in doc strings with
672 ;;; `\\[foobar]'.
673 ;;; 2.78 -
674 ;;; lrd: (crypt-auto-write-answer-local): New internal variable. Holds
675 ;;; answer to query about file-extension tricks question per buffer. Thanks
676 ;;; to George Forman <forman@cs.washington.edu>. Remove Rod from list of
677 ;;; maintainers...he's busy enough. Merge multiple setq forms into single
678 ;;; setq forms.
679 ;;; 2.79 -
680 ;;; lrd: (crypt-y-or-n-p): New internal function for querying. Tests the
681 ;;; internal variable crypt-auto-write-answer-local to ensure single query.
682 ;;; (crypt-check-extension-for-encoding): Replace all occurrences of queries
683 ;;; involving y-or-no-p constructs with crypt-y-or-n-p.
684 ;;; 2.80 - [posted to gnu.emacs.sources]
685 ;;; lrd: (crypt-set-encryption-key): Shorten interactive prompt. Change
686 ;;; documentation.
687 ;;; 2.81 -
688 ;;; lrd: (crypt-variable-list): Add shell and path variables.
689 ;;; (crypt-confirm-password): Fix spelling error in doc.
690 ;;; 2.82 -
691 ;;; lrd: Applied patch from Noah Friedman <friedman@prep.ai.mit.edu>.
692 ;;; (crypt-encoded-disable-auto-save, crypt-encrypted-disable-auto-save):
693 ;;; New user-defined variables. (crypt-encoded-mode, crypt-encrypted-mode):
694 ;;; Use them.
695
696
697 ;;; Code:
698
699 ;;;; User definable variables.
700
701 (defvar crypt-encryption-type 'crypt
702 "*Method of encryption. Must be an element of `crypt-encryption-alist.'
703 If you change this after crypt++ is loaded then do \\[crypt-rebuild-tables].")
704
705 (defvar crypt-encryption-file-extension nil
706 "*Regexp for extension of files encrypted with `crypt-encryption-type.'
707 Should be of the form \"\\\\(\\\\.foo\\\\)$\". nil says use default values in
708 `crypt-encryption-alist.' If you change this after crypt++ is loaded then do
709 \\[crypt-rebuild-tables].")
710
711 (defvar crypt-never-ever-decrypt nil
712 "*t says never attempt to decrypt a buffer.")
713
714 (defvar crypt-auto-write-buffer-encrypted nil
715 "*t says files with `crypt-encryption-alist' file extension auto-encrypted.
716 nil says query. See `crypt-auto-write-buffer.'")
717
718 (defvar crypt-confirm-password nil
719 "*t says confirm new passwords and when writing a newly encrypted buffer.")
720
721 (defvar crypt-encoded-disable-auto-save t
722 "*If t, turn off auto-save-mode for buffers which are encoded.
723 If non-nil but not t, then no message is displayed.
724
725 The default is t is because there isn't any way to tell emacs to encode the
726 autosave file, so the autosave would be in a different format from the
727 original. The disadvantage of turning off autosaves is that any work you
728 do in that buffer will be completely lost if the changes are not explicitly
729 saved.
730
731 It is probably best to set this variable to nil and use buffer-local
732 variables in files for which you don't actually care about autosaves.
733 Unencoded recovery data is better than none at all.")
734
735 (defvar crypt-encrypted-disable-auto-save t
736 "*If t, turn off auto-save-mode for buffers which are encrypted.
737 If non-nil but not t, then no message is displayed.
738
739 The default is t is because there isn't any way to tell emacs to encrypt
740 the autosave file, so the autosave would be in cleartext form. The
741 disadvantage of turning off autosaves is that any work you do in that
742 buffer will be completely lost if the changes are not explicitly saved.
743
744 You might consider setting this variable to nil and use buffer-local
745 variables in files for which security is more important than data
746 recovery.")
747
748 ;;; ENCRYPTION
749
750 ;;; Encrypted files have no magic number, so we have to hack a way of
751 ;;; determining when a buffer should be decrypted. we do this only buffers
752 ;;; that match a MAGIC-REGEXP very close to beginning of buffer and that do
753 ;;; _NOT_ match a MAGIC-REGEXP-INVERSE.
754 ;;;
755 ;;; Currently MAGIC-REGEXP matches non-ASCII characters and
756 ;;; MAGIC-REGEXP-INVERSE will match Sun OS, 4.x BSD, and Ultrix executable
757 ;;; magic numbers, so binaries can still be edited (heh) without headaches.
758
759 (defconst crypt-encryption-magic-regexp "[\000\200-\237]"
760 "Regexp that must be found very close to beginning of encrypted buffer.
761 This is intended to be an internal variable \(not user-visible\). If you
762 change this after crypt++ is loaded then do \\[crypt-rebuild-tables].")
763
764 (defconst crypt-encryption-magic-regexp-inverse
765 "\\`\201\001\\|^\\(..\\)?\\([\007\010\013]\001\\|\001[\007\010\013]\\)"
766 "Regexp that must *not* be found very close to beginning of encrypted buffer.
767 This is intended to be an internal variable \(not user-visible\). If you
768 change this after crypt++ is loaded then do \\[crypt-rebuild-tables].")
769
770 (defconst crypt-magic-search-limit 100
771 "Limit of regular expression search used to recognize encrypted files.
772 Maximum position in file for presence of `crypt-encryption-magic-regexp' and
773 absence of `crypt-encryption-magic-regexp-inverse'.")
774
775 (defun crypt-build-encryption-alist ()
776 ;; Returns the encryption alist
777 (list
778 ;; crypt
779 (list 'crypt
780 crypt-encryption-magic-regexp crypt-encryption-magic-regexp-inverse
781 (or crypt-encryption-file-extension "\\(\\.e\\)$")
782 "crypt" "crypt"
783 nil
784 nil
785 "Crypt"
786 nil
787 t
788 )
789 ;; DES (Cipher Block Chaining - CBC) [DES' default]
790 (list 'des
791 crypt-encryption-magic-regexp crypt-encryption-magic-regexp-inverse
792 (or crypt-encryption-file-extension "\\(\\.des\\)$")
793 "des" "des"
794 '("-e" "-k")
795 '("-d" "-k")
796 "DES-CBC"
797 nil
798 t
799 )
800 ;; DES (Electronic Code Book - ECB)
801 (list 'des-ecb
802 crypt-encryption-magic-regexp crypt-encryption-magic-regexp-inverse
803 (or crypt-encryption-file-extension "\\(\\.des\\)$")
804 "des" "des"
805 '("-e" "-b" "-k")
806 '("-d" "-b" "-k")
807 "DES-ECB"
808 nil
809 t
810 )
811 ;; PGP
812 (list 'pgp
813 crypt-encryption-magic-regexp crypt-encryption-magic-regexp-inverse
814 (or crypt-encryption-file-extension "\\(\\.pgp\\)$")
815 "pgp" "pgp"
816 '("+batchmode" "+verbose=0" "-c" "-f" "-z")
817 '("+batchmode" "+verbose=0" "-f" "-z")
818 "PGP"
819 nil
820 t
821 )
822 ;; Add new elements here ...
823 ))
824
825 (defconst crypt-encryption-alist (crypt-build-encryption-alist)
826 "List of elements describing the encryption methods available.
827 each element looks like
828
829 \(ENCRYPTION-TYPE
830 MAGIC-REGEXP MAGIC-REGEXP-INVERSE
831 FILE-EXTENSION
832 ENCRYPT-PROGRAM DECRYPT-PROGRAM
833 ENCRYPT-ARGS
834 DECRYPT-ARGS
835 MINOR-MODE
836 GARBAGE-REGEXP-OR-LISPEXP
837 FILE-EXTENSION-TRICKS
838 \)
839
840 ENCRYPTION-TYPE is a symbol denoting the encryption type.
841
842 MAGIC-REGEXP regexp that must match very close to the beginning of an
843 encrypted buffer. This may also be some elisp expression to be evaluated at
844 \(point-min\) that will return t for an encrypted buffer. If this is set to
845 nil then crypt++ will never try to decrypt a buffer. Currently set to the
846 internal variable `crypt-encryption-magic-regexp' which will match non-ASCII
847 characters.
848
849 MAGIC-REGEXP-INVERSE regexp that must _NOT_ match very close to the beginning
850 of an encrypted buffer. This may also be some elisp expression to be
851 evaluated at \(point-min\) that will return t for a NON-encrypted buffer.
852 If this is set to t then crypt++ will never try to decrypt a buffer.
853 Currently set to the internal variable `crypt-encryption-magic-regexp-inverse'
854 which will match Sun OS, 4.x BSD, and Ultrix executable magic numbers, so
855 binaries can still be edited (heh) without headaches.
856
857 FILE-EXTENSION regexp denoting the file extension usually appended the
858 filename of files encrypted with ENCRYPT-PROGRAM. The variable
859 `crypt-encryption-file-extension' will over ride the default.
860
861 ENCRYPT-PROGRAM name of executable file to be used for encryption.
862
863 DECRYPT-PROGRAM name of executable file to be used for decryption.
864
865 ENCRYPT-ARGS arguments to be passed to ENCRYPT-PROGRAM may be a string or a
866 list of strings or nil.
867
868 DECRYPT-ARGS arguments to be passed to DECRYPT-PROGRAM may be a string or a
869 list of strings or nil.
870
871 MINOR-MODE string denoting the name for the encrypted minor mode as it will
872 appear in the mode line.
873
874 GARBAGE-REGEXP-OR-LISPEXP dummy variable for compatibility with encoding.
875
876 FILE-EXTENSION-TRICKS is t or nil depending on whether or not tricks
877 converting between different encryption types can be done based on
878 FILE-EXTENSION; typically t.
879 ")
880
881
882 ;;; ENCODING
883
884 (defvar crypt-auto-decode-buffer t
885 "*t says buffers visiting encoded files will be decoded automatically.
886 nil means to ask before doing the decoding.")
887
888 (defvar crypt-auto-write-buffer nil
889 "*t says save files with `crypt-encoding-alist' file extensions as encoded.
890 nil says to ask before doing this encoding. Similarly, buffers originating
891 from encoded files to be written to files not ending in `crypt-encoding-alist'
892 file extensions will be written in plain format automatically. nil says to
893 ask before doing this decoding.")
894
895 ;; This is an internal variable documented here and not in a DOCSTRING in
896 ;; order to save memory. If this variable's value has been changed from its
897 ;; default, then it contains the answer to the question "Write out buffer
898 ;; foobar using `compression-type'?". This question is asked only if *plain*
899 ;; buffer foobar is being written to disk *and* it has a provocative
900 ;; `compression-type' file-name extension (see DOCSTRING for variable
901 ;; crypt-auto-write-buffer). The variable is local to all buffers with a
902 ;; default value of 'ask so if the situation described above arises, then the
903 ;; question is asked at least once, unless the user-defined variable
904 ;; crypt-auto-write-buffer is non-nil.
905 (defvar crypt-auto-write-answer-local 'ask)
906 (make-variable-buffer-local 'crypt-auto-write-answer-local)
907 (setq-default crypt-auto-write-answer-local 'ask)
908 (put 'crypt-auto-write-answer-local 'permanent-local t) ; for v19 Emacs
909 (put 'crypt-auto-write-answer-local 'preserved t) ; for kill-fix.el
910
911 (defvar crypt-query-if-interactive t
912 "*t says ask when saving buffers where `crypt-encoded-mode' was toggled.
913 nil says that even if filename extension is plain (i.e., not listed in
914 `crypt-encoding-alist') buffer will be written in an encoded format without
915 asking.
916
917 This variable is designed for users that edit a plain file (with plain
918 extension) and then toggle `(crypt-encoded-mode)' and do not wish to be
919 queried every time that they save the buffer.
920
921 NOTE: if `(crypt-encoded-mode)' was not called interactively (the usual
922 scenario) then the value of this variable has no effect on how the buffer is
923 written to disk. In such a case `crypt-no-extension-implies-plain' is then
924 the relevant variable.")
925
926 (defvar crypt-no-extension-implies-plain t
927 "*t says file extensions not in `crypt-encoding-alist' may be written plain.
928 if `crypt-auto-write-buffer' is also t then any file ending in a plain
929 extension is written in plain format automatically, otherwise query user.
930
931 nil says user works with encoded (compressed) files without file extensions
932 and will not be queried each time they save these files.
933
934 NOTE: (1) this does not effect find-file (C-x C-f) since that works with a
935 magic regexp. (2) there is no way to distinguish between write-file and
936 save-buffer so nil will mean that neither will query.")
937
938 (defvar crypt-freeze-vs-fortran t
939 "*t says `.F' file extension denotes a frozen file not a Fortran file.
940 If you change this variable after crypt++ has been loaded then do
941 \\[crypt-rebuild-tables].")
942
943 (defvar crypt-compact-vs-C++ nil
944 "*t says `.C' file extension denotes a compacted file not a C++ file.
945 If you change this variable after crypt++ has been loaded then do
946 \\[crypt-rebuild-tables].")
947
948 (defvar crypt-ignored-filenames nil
949 "*List of regexp filenames for which encoded to plain conversion is not done.
950 A filename with a plain extension, in encoded format, that is matched by one of
951 these elements will be saved in encoded format without a query for conversion to
952 plain format.
953
954 This variable is provided for users that want to compress their incoming mail
955 for RMAIL and VM which look for files `RMAIL' and `INBOX,' respectively, to
956 store incoming mail. For example, the gzip extensions on `RMAIL.gz' and
957 `INBOX.gz' can be removed, this variable set to '\(\"INBOX$\" \"RMAIL$\"\) and
958 no query about conversion to plain format will be made.")
959
960 (defvar crypt-default-encoding "gzip"
961 "*Default encoding type as string used when `crypt-encoded-mode' is toggled.
962 Must match one of the elements of `crypt-encoding-alist'.")
963
964 (defvar crypt-dos-has-ctrl-z nil
965 "t if this buffer had a ctrl-z stripped from end, otherwise, nil.
966 Buffer local and set by `crypt-dos-to-unix-region'")
967 (make-variable-buffer-local 'crypt-dos-has-ctrl-z)
968 (setq-default crypt-dos-has-ctrl-z nil)
969 (put 'crypt-dos-has-ctrl-z 'permanent-local t) ; for v19 Emacs
970 (put 'crypt-dos-has-ctrl-z 'preserved t) ; for kill-fix.el
971
972 (defun crypt-build-encoding-alist ()
973 ;; Returns the encoding alist
974 (list
975 ;; compress
976 (list 'compress
977 "\037\235" nil
978 "\\(\\.Z\\)$"
979 "compress" "uncompress"
980 nil nil
981 "Compress"
982 nil
983 t)
984 ;; gzip (GNU zip)
985 (list 'gzip
986 "\037\213" nil
987 "\\(\\.g?z\\)$"
988 "gzip" "gzip"
989 "--quiet" "--decompress --quiet"
990 "Zip"
991 nil
992 t)
993 ;; freeze
994 (list 'freeze
995 "\037\236\\|\037\237" nil
996 "\\(\\.F\\)$"
997 "freeze" "freeze"
998 "" "-d"
999 "Freeze"
1000 nil
1001 crypt-freeze-vs-fortran)
1002 ;; compact
1003 (list 'compact
1004 "\377\037" nil
1005 "\\(\\.C\\)$"
1006 "compact" "uncompact"
1007 nil nil
1008 "Compact"
1009 "^Compression *:.*\n"
1010 crypt-compact-vs-C++)
1011 ;; DOS
1012 (list 'dos
1013 "[^\n\r]*\r$" nil
1014 "\\(\\.DOS\\)$"
1015 'crypt-unix-to-dos-region 'crypt-dos-to-unix-region
1016 nil nil
1017 "Dos"
1018 nil
1019 nil)
1020 ;; Add new elements here ...
1021 ))
1022
1023 (defconst crypt-encoding-alist (crypt-build-encoding-alist)
1024 "List of elements describing the encoding methods available.
1025 each element looks like
1026
1027 \(ENCODING-TYPE
1028 MAGIC-REGEXP MAGIC-REGEXP-INVERSE
1029 FILE-EXTENSION
1030 ENCODE-PROGRAM DECODE-PROGRAM
1031 ENCODE-ARGS DECODE-ARGS
1032 MINOR-MODE
1033 GARBAGE-REGEXP-OR-LISPEXP
1034 FILE-EXTENSION-TRICKS
1035 \)
1036
1037 ENCODING-TYPE is a symbol denoting the encoding type. Currently known
1038 encodings are (compress compact freeze gzip).
1039
1040 MAGIC-REGEXP is a regexp that matches the magic number at the
1041 beginning of files encoded with ENCODING-TYPE.
1042
1043 MAGIC-REGEXP-INVERSE dummy variable for compatibility with encryption.
1044
1045 FILE-EXTENSION is a string denoting the file extension usually
1046 appended the filename of files encoded with ENCODING-TYPE.
1047
1048 ENCODE-PROGRAM is a string denoting the name of the executable used to
1049 encode files.
1050
1051 DECODE-PROGRAM is a string denoting the name of the executable used to
1052 decode files.
1053
1054 ENCODE-ARGS arguments to be passed to ENCODE-PROGRAM may be a string or a
1055 list of strings or nil.
1056
1057 DECODE-ARGS arguments to be passed to DECODE-PROGRAM may be a string or a
1058 list of strings or nil.
1059
1060 MINOR-MODE is a string denoting the name for the encoded minor mode as
1061 it will appear in the mode line.
1062
1063 GARBAGE-REGEXP-OR-LISPEXP is (1) a regexp that matches any extraneous text
1064 that is produced by the ENCODE-COMMAND including any newlines and will be
1065 removed from the buffer before saving to disk; (2) a lisp expression that will
1066 clean up extraneous material in the buffer or nil. This is normally not
1067 needed but can be derived for any ENCODE-COMMAND by checking the standard
1068 error that results from `sh -c \"cat foo | ENCODE-COMMAND > bar\"'.
1069
1070 FILE-EXTENSION-TRICKS is t or nil depending on whether or not tricks
1071 converting between different encoding types can be done based on
1072 FILE-EXTENSION; typically t.
1073 ")
1074
1075
1076 ;;; This allows the user to alter contents of the encoding and encryption
1077 ;;; table variables without having to reload all of crypt++.
1078 (defun crypt-rebuild-tables ()
1079 "Rebuilds the encryption and encoding tables and `minor-mode-alist'.
1080 Allows user to alter variables used in building these tables. May be called
1081 interactively or in an initialization file. Part of `after-init-hook'."
1082 (interactive)
1083 (setq crypt-encryption-alist (crypt-build-encryption-alist)
1084 crypt-encoding-alist (crypt-build-encoding-alist))
1085 (crypt-rebuild-minor-modes-alist))
1086
1087
1088 ;;; Buffer locals.
1089
1090 (defvar crypt-buffer-save-encrypted nil
1091 "*non-nil says save buffer encrypted with `crypt-encryption-type.'
1092 local to all buffers.")
1093 (make-variable-buffer-local 'crypt-buffer-save-encrypted)
1094 (put 'crypt-buffer-save-encrypted 'permanent-local t) ; for v19 Emacs
1095 (put 'crypt-buffer-save-encrypted 'preserved t) ; for kill-fix.el
1096
1097 (defvar crypt-buffer-encryption-key nil
1098 "*Key used for encryption of current buffer. Local to all buffers.")
1099 (make-variable-buffer-local 'crypt-buffer-encryption-key)
1100 (put 'crypt-buffer-encryption-key 'permanent-local t) ; for v19 Emacs
1101 (put 'crypt-buffer-encryption-key 'preserved t) ; for kill-fix.el
1102
1103 (defvar crypt-buffer-save-encoded nil
1104 "*non-nil says buffer will be saved encoded. Local to all buffers.")
1105 (make-variable-buffer-local 'crypt-buffer-save-encoded)
1106 (put 'crypt-buffer-save-encoded 'permanent-local t) ; for v19 Emacs
1107 (put 'crypt-buffer-save-encoded 'preserved t) ; for kill-fix.el
1108
1109 (defvar crypt-buffer-encoding-type nil
1110 "*non-nil says buffer is encoded with ENCODING-TYPE. Local to all buffers.")
1111 (make-variable-buffer-local 'crypt-buffer-encoding-type)
1112 (put 'crypt-buffer-encoding-type 'permanent-local t) ; for v19 Emacs
1113 (put 'crypt-buffer-encoding-type 'preserved t) ; for kill-fix.el
1114
1115 (defvar crypt-buffer-interactive-encoded-mode nil
1116 "t says `crypt-encoded-mode' was toggled interactively, almost always nil.
1117 Local to all buffers.")
1118 (make-variable-buffer-local 'crypt-buffer-interactive-encoded-mode)
1119 (put 'crypt-buffer-interactive-encoded-mode 'permanent-local t) ; v19 Emacs
1120 (put 'crypt-buffer-interactive-encoded-mode 'preserved t) ; kill-fix.el
1121
1122
1123 ;;; Functions and macros that search `crypt-encryption-alist' and
1124 ;;; `crypt-encoding-alist'.
1125
1126 (defun crypt-get-alist-member (type n)
1127 ;; Returns TYPE's Nth element
1128 (nth n (or (assoc type crypt-encryption-alist)
1129 (assoc type crypt-encoding-alist))))
1130
1131 (defmacro crypt-get-magic-regexp (type)
1132 ;; Returns regexp found at top of files encoded/encrypted with TYPE.
1133 (list 'crypt-get-alist-member type 1))
1134
1135 (defmacro crypt-get-magic-regexp-inverse (type)
1136 ;; Returns regexp *not* found at top of files encoded/encrypted with TYPE.
1137 (list 'crypt-get-alist-member type 2))
1138
1139 (defmacro crypt-get-file-extension (type)
1140 ;; Returns regexp matching extension of files encoded/encrypted with TYPE.
1141 (list 'crypt-get-alist-member type 3))
1142
1143 (defmacro crypt-get-encoding-program (type)
1144 ;; Returns name of program, as string, used to encode/encrypt with TYPE.
1145 (list 'crypt-get-alist-member type 4))
1146
1147 (defmacro crypt-get-decoding-program (type)
1148 ;; Returns name of program, as string, used to decode/decrypt with TYPE.
1149 (list 'crypt-get-alist-member type 5))
1150
1151 (defmacro crypt-get-encoding-args (type)
1152 ;; Returns arguments passed to program used to encode/encrypt with TYPE.
1153 (list 'crypt-get-alist-member type 6))
1154
1155 (defmacro crypt-get-decoding-args (type)
1156 ;; Returns arguments passed to program used to decode/decrypt with TYPE.
1157 (list 'crypt-get-alist-member type 7))
1158
1159 (defmacro crypt-get-minor-mode-name (type)
1160 ;; Returns minor mode name, as string, for encoding/encrypting with TYPE.
1161 (list 'crypt-get-alist-member type 8))
1162
1163 (defmacro crypt-get-cleanup-regexp (type)
1164 ;; Returns regexp or lisp-exp for cleaning up encoding/encrypting with TYPE.
1165 (list 'crypt-get-alist-member type 9))
1166
1167 (defmacro crypt-get-extension-tricks (type)
1168 ;; Returns t if file extension tricks doable for encoding/encrypting with
1169 ;; TYPE.
1170 (list 'crypt-get-alist-member type 10))
1171
1172 (defun crypt-buffer-save-name (type)
1173 ;; Returns variable `crypt-buffer-save-TYPE', set to t if encoding with TYPE.
1174 ;; local to all buffers.
1175 (intern (concat "crypt-buffer-save-" (symbol-name type))))
1176
1177
1178 ;;; Create a buffer-local variable for each type of encoding.
1179 ;;; These variables are used to trigger the minor mode names.
1180
1181 (defun crypt-build-minor-mode-alist ()
1182 ;; Returns minor mode alist entries for encoded and encrypted buffers.
1183 (append
1184 ;; First the encrypted minor mode -- only one.
1185 (list (list 'crypt-buffer-save-encrypted
1186 (concat " " (crypt-get-minor-mode-name crypt-encryption-type))))
1187 ;; Now the encoding minor modes.
1188 (mapcar
1189 (function
1190 (lambda (element)
1191 (let ((variable (crypt-buffer-save-name (car element))))
1192 (make-variable-buffer-local variable)
1193 (put variable 'permanent-local t) ; for v19 Emacs
1194 (put variable 'preserved t) ; for kill-fix.el
1195 (list variable
1196 (concat " " (crypt-get-minor-mode-name (car element)))))))
1197 crypt-encoding-alist)))
1198
1199 (defconst crypt-minor-mode-alist (crypt-build-minor-mode-alist)
1200 "Alist containing encoded and encrypted minor modes.
1201 Derived from variable `crypt-encoding-alist' and function
1202 `crypt-build-minor-mode-encrypted'")
1203
1204 (defun crypt-rebuild-minor-modes-alist ()
1205 ;; Rebuilds the encryption and encoding minor modes and `minor-mode-alist.'
1206 ;; Allows user to alter variables used in building this alist. Called by
1207 ;; `crypt-rebuild-tables' and so part of `after-init-hook'."
1208
1209 ;; First remove old crypt minor mode entries from `minor-mode-alist'.
1210 (if (memq (car crypt-minor-mode-alist) minor-mode-alist)
1211 (let ((alist crypt-minor-mode-alist) elt)
1212 (while (and alist (setq elt (car alist)))
1213 (setq minor-mode-alist (delq elt minor-mode-alist)
1214 alist (cdr alist)))))
1215
1216 ;; Get new crypt minor mode entries and add to minor-mode-alist.
1217 (setq crypt-minor-mode-alist (crypt-build-minor-mode-alist)
1218 minor-mode-alist (append crypt-minor-mode-alist minor-mode-alist)))
1219
1220
1221 (defmacro crypt-save-point (&rest body)
1222 ;; Save value of point, evaluate FORMS, and restore value of point. If the
1223 ;; saved value of point is no longer valid go to (point-max). This macro
1224 ;; exists because, save-excursion loses track of point during some types of
1225 ;; deletions.
1226 (let ((var (make-symbol "saved-point")))
1227 (list 'let (list (list var '(point)))
1228 (list 'unwind-protect
1229 (cons 'progn body)
1230 (list 'goto-char var)))))
1231
1232
1233 (defun crypt-find-file-hook ()
1234
1235 ;; Hook run for decoding and/or decrypting the contents of a buffer. Meant
1236 ;; to be called as part of `find-file-hooks'
1237
1238 (let ((buffer-file-name buffer-file-name)
1239 (old-buffer-file-name buffer-file-name)
1240 (old-buffer-modified-p (buffer-modified-p))
1241 (case-fold-search nil) ; case-sensitive
1242 encrypted encoded buffer-read-only)
1243
1244 ;; DECODE AND/OR DECRYPT
1245 (crypt-save-point
1246
1247 ;; Do we have to DECODE? If not, then move on.
1248 (if (and (crypt-encoded-p)
1249 (or crypt-auto-decode-buffer
1250 (y-or-n-p (format "Decode %s? " (buffer-name)))))
1251
1252 ;; Decode, uncompress, the buffer.
1253 (progn
1254
1255 (if (and (not (null buffer-file-name))
1256 (string-match "\\.Z$" buffer-file-name))
1257 (set-visited-file-name
1258 (substring buffer-file-name 0 (match-beginning 0)))
1259 (if (and (not (null buffer-file-name))
1260 (string-match "\\.gz$" buffer-file-name))
1261 (set-visited-file-name
1262 (substring buffer-file-name 0 (match-beginning 0)))))
1263 (message "Decoding %s..." (buffer-name))
1264 (crypt-encode-buffer t)
1265
1266 ;; Store the encoding mode.
1267
1268 ;; We can not yet go into the minor modes because the major mode
1269 ;; may change later on and blow away all local variables (and thus
1270 ;; the minor modes). Only needed for vanilla v18. Our
1271 ;; buffer-locals defined 'permanent-local for v19 Emacs and
1272 ;; 'preserved for kill-fix.el.
1273
1274 (setq encoded crypt-buffer-encoding-type)
1275
1276 ;; Strip encoded file's extension so later we can set buffer's
1277 ;; major mode based on its file-name sans encoding extension.
1278 (if (string-match (crypt-get-file-extension
1279 crypt-buffer-encoding-type) buffer-file-name)
1280 (setq buffer-file-name
1281 (substring buffer-file-name 0 (match-beginning 1))))
1282
1283 ;; Decoding ends.
1284 (if (not (input-pending-p))
1285 (message "Decoding %s... done" (buffer-name)))))
1286
1287 ;; Do we have to DECRYPT? If not, then move on.
1288 (if (crypt-encrypted-p)
1289
1290 ;; Decrypt buffer.
1291 (progn
1292
1293 (message "Decrypting %s..." (buffer-name))
1294 (crypt-encrypt-buffer crypt-buffer-encryption-key t)
1295
1296 ;; Save key in case major mode blows all buffer-locals.
1297
1298 ;; Only needed for vanilla v18. Our buffer-locals defined
1299 ;; 'permanent-local for v19 Emacs and 'preserved for
1300 ;; kill-fix.el.
1301
1302 (setq encrypted crypt-buffer-encryption-key)
1303
1304 ;; Strip encrypted file's extension so later we can set buffer's
1305 ;; major mode based on its file-name sans encrypting extension.
1306 (if (and (crypt-get-extension-tricks crypt-encryption-type)
1307 (string-match (crypt-get-file-extension
1308 crypt-encryption-type) buffer-file-name))
1309 (setq buffer-file-name
1310 (substring buffer-file-name 0 (match-beginning 1))))
1311
1312 (if (not (input-pending-p))
1313 (message "Decrypting %s... done" (buffer-name))))))
1314
1315 ;; MAJOR AND MINOR MODES
1316
1317 ;; OK, if any changes have been made to the buffer we need to rerun the
1318 ;; code the does automatic selection of major mode.
1319
1320 (if (or encoded encrypted)
1321
1322 (progn
1323
1324 ;; Set the major mode.
1325 (set-auto-mode)
1326 (hack-local-variables)
1327
1328 ;; Now set our own minor mode(s).
1329 (if encoded
1330 ;; Recover encoding type, may have been smashed by major mode,
1331 ;; and toggle encoded mode.
1332 (progn (setq crypt-buffer-encoding-type encoded)
1333 (crypt-encoded-mode 1)))
1334
1335 (if encrypted
1336 ;; Recover encryption key, may have been smashed by major mode,
1337 ;; and toggle encrypted mode.
1338 (progn (setq crypt-buffer-encryption-key encrypted)
1339 (crypt-encrypted-mode 1)))
1340
1341 ;; Restore buffer file name now, so that lock file entry is removed
1342 ;; properly.
1343 (setq buffer-file-name old-buffer-file-name)
1344
1345 ;; Restore buffer modified flag to its previous value. Will also
1346 ;; remove lock file entry for buffer if previous value was nil.
1347 ;; This is why buffer-file-name had to be restored manually above.
1348 (set-buffer-modified-p old-buffer-modified-p)))))
1349
1350 (defun crypt-encoded-p (&optional buffer)
1351 ;; Returns t if current buffer, or optionally BUFFER, is encoded.
1352 ;; Sets `crypt-buffer-encoding-type' to encoding method.
1353 (save-excursion
1354 (and buffer (set-buffer buffer))
1355 (save-restriction
1356 (widen)
1357 (goto-char (point-min))
1358 (let ((alist crypt-encoding-alist) elt found)
1359 (while (and alist (setq elt (car alist)) (not found))
1360 (if (looking-at (nth 1 elt))
1361 (setq crypt-buffer-encoding-type (nth 0 elt)
1362 found t)
1363 ;; Decrement
1364 (setq alist (cdr alist))))
1365 found))))
1366
1367 (defun crypt-encrypted-p (&optional buffer)
1368 ;; Returns t if current buffer, or optionally BUFFER, is encrypted.
1369 ;; Look for MAGIC-REGEXP and absence of MAGIC-REGEXP-INVERSE. If so, then
1370 ;; assume it is an encrypted buffer.
1371 ;; Sets `crypt-buffer-encryption-key' to password if not set already.
1372
1373 ;; Do not try to decrypt buffer if not wanted.
1374 (if (not crypt-never-ever-decrypt)
1375
1376 (save-excursion
1377 (and buffer (set-buffer buffer))
1378
1379 (save-restriction
1380 (widen)
1381 (goto-char (point-min))
1382
1383 (let ((magic-regexp (crypt-get-magic-regexp crypt-encryption-type))
1384 (magic-regexp-inverse (crypt-get-magic-regexp-inverse
1385 crypt-encryption-type))
1386 (limit (min (point-max) crypt-magic-search-limit)))
1387
1388 ;; Check all encryption conditions. If any fail, then return nil
1389 ;; value of this if-form, else check for password.
1390 (if (and
1391
1392 ;; Check for existence of MAGIC-REGEXP.
1393 (if (stringp magic-regexp)
1394 ;; regular expression
1395 (re-search-forward magic-regexp limit t)
1396 ;; lisp expression
1397 (eval magic-regexp))
1398
1399 (goto-char (point-min))
1400
1401 ;; Check for absence of MAGIC-REGEXP-INVERSE.
1402 (not (if (stringp magic-regexp-inverse)
1403 ;; regular expression
1404 (re-search-forward magic-regexp-inverse limit t)
1405 ;; lisp expression
1406 (eval magic-regexp-inverse))))
1407
1408 (progn
1409
1410 ;; Get key, i.e., the password?
1411 (or crypt-buffer-encryption-key
1412 ;; Do not confirm on reading an encrypted file.
1413 (let ((crypt-confirm-password nil))
1414 (call-interactively 'crypt-set-encryption-key)))
1415
1416 ;; Do not turn on encryption mode if no key: may be a binary
1417 ;; file. Thanks to Paul Dworkin (paul@media-lab.media.mit.edu).
1418 (if (equal crypt-buffer-encryption-key "")
1419 ;; Return nil.
1420 (progn
1421 (message "No key given. Assumed normal.")
1422 nil)
1423 ;; Return t.
1424 t))))))))
1425
1426
1427 ;;;
1428
1429 (defun crypt-check-extension-for-encoding ()
1430
1431 ;; Checks file extensions for possible toggling of encoding modes. Used for
1432 ;; buffers to be written to disk and called by `crypt-write-file-hook'
1433
1434 ;; We try to flag a buffer to be written out in encoded form if the file
1435 ;; ends in one of the file-extensions in `crypt-encoding-alist' even if
1436 ;; `crypt-buffer-save-encoded' is nil. Conversely, we try to write out a
1437 ;; buffer as a plain file if it does _not_ end in one of these
1438 ;; file-extensions even if `crypt-buffer-save-encoded' is non-nil.
1439
1440 (let ((alist crypt-encoding-alist)
1441 (case-fold-search nil)
1442 found elt)
1443
1444 ;; Search through the file name extensions for a match.
1445 (while (and alist (setq elt (car alist)) (not found))
1446 (if (string-match (nth 3 elt) buffer-file-name)
1447 (setq found t)
1448 ;; Decrement.
1449 (setq alist (cdr alist))))
1450
1451 ;; Did we find a match?
1452 (if found
1453
1454 ;; File name ends in a very provocative extension.
1455
1456 ;; Check to see if already an encoded file.
1457 (if crypt-buffer-save-encoded
1458
1459 ;; Already encoded - do the methods of encoding match?
1460 (if (not (eq (nth 0 elt) crypt-buffer-encoding-type))
1461
1462 ;; A new encoding method is desired.
1463
1464 ;; Can we play some filename extension tricks with the
1465 ;; destination extension?
1466 (if (crypt-get-extension-tricks (nth 0 elt))
1467
1468 ;; Can play tricks.
1469 ;; Change the method of encoding?
1470 (if (crypt-y-or-n-p (format "Write %s using %s? "
1471 (buffer-name) (nth 4 elt)))
1472
1473 ;; Case one.
1474 ;; Turn off original encoding and turn on new encoding.
1475 (progn (crypt-encoded-mode -1)
1476 (setq crypt-buffer-encoding-type (nth 0 elt))
1477 (crypt-encoded-mode 1)))
1478
1479 ;; Can not play tricks - maybe wants a plain file?
1480 (if (crypt-y-or-n-p (format "Write %s a plain file? "
1481 (buffer-name)))
1482
1483 ;; Case three.
1484 ;; Turn off the minor mode and _then_ the flags.
1485 (progn
1486 (crypt-encoded-mode -1)
1487 (setq crypt-buffer-save-encoded nil
1488 crypt-buffer-encoding-type nil)))))
1489
1490 ;; Was a plain file.
1491 (if (and
1492 ;; Can we play some filename extension tricks?
1493 ;; If not then we must abort.
1494 (crypt-get-extension-tricks (nth 0 elt))
1495
1496 (crypt-y-or-n-p (format "Write %s using %s? "
1497 (buffer-name) (nth 4 elt))))
1498
1499 ;; Case two.
1500 ;; Turn on encoding flags and _then_ the minor mode.
1501 (progn
1502 (setq crypt-buffer-save-encoded t
1503 crypt-buffer-encoding-type (nth 0 elt))
1504 (crypt-encoded-mode 1))))
1505
1506 ;; No match - a plain-jane file extension - but if the encoded flag is
1507 ;; non-nil then the user may really want it written out in plain
1508 ;; format so we must override this flag.
1509 (if (and crypt-buffer-save-encoded
1510
1511 ;; Search the list of files to be ignored.
1512 ;; If `crypt-ignored-filenames' is nil then this let form
1513 ;; will return t. If a match is found this form will return
1514 ;; nil. Otherwise it will return t.
1515 (let ((tlist crypt-ignored-filenames)
1516 case-fold-search found elt)
1517
1518 ;; Search through the list of filenames for a match.
1519 (while (and tlist (setq elt (car tlist)) (not found))
1520 (if (string-match elt buffer-file-name)
1521 (setq found t)
1522 ;; Decrement.
1523 (setq tlist (cdr tlist))))
1524
1525 ;; Return t if we can _not_ find a match.
1526 (not found))
1527
1528 ;; If `(crypt-encoded-mode)' was called interactively, then
1529 ;; there is a high probability that no matter what the file
1530 ;; name extension the user wishes to write the file out in some
1531 ;; encoded format. Thanks to Kimball Collins
1532 ;; <kpc@ptolemy.arc.nasa.gov> for pointing out the need for
1533 ;; this. Unfortunately, still can not distinguish between
1534 ;; write-file and save-buffer. In the former the user may want
1535 ;; to write in plain format (or indeed some other format).
1536
1537 (if crypt-buffer-interactive-encoded-mode
1538 ;; Interactive
1539 crypt-query-if-interactive
1540 ;; Non-interactive but still may want encoded format.
1541 crypt-no-extension-implies-plain)
1542
1543 (crypt-y-or-n-p (format "Write %s as a plain file? "
1544 (buffer-name))))
1545
1546 ;; Case three.
1547 ;; Turn off the minor mode and _then_ the flags.
1548 (progn
1549 (crypt-encoded-mode -1)
1550 (setq crypt-buffer-save-encoded nil
1551 crypt-buffer-encoding-type nil))))))
1552
1553
1554 (defun crypt-y-or-n-p (prompt)
1555 ;; Queries user based on `crypt-auto-write-buffer' and internal buffer-local
1556 ;; variable `crypt-auto-write-answer-local'. Returns value of
1557 ;; `crypt-auto-write-answer-local', which is t or nil.
1558
1559 ;; Check if we need to ask user. Should be 'ask, nil, or t.
1560 (if (eq crypt-auto-write-answer-local 'ask) ; Default value.
1561 ;; We may need to ask.
1562 (or crypt-auto-write-buffer
1563 ;; Ask and store the answer.
1564 ;; Note: we only store if we asked.
1565 (setq crypt-auto-write-answer-local (y-or-n-p prompt)))
1566 ;; Use previous answer.
1567 crypt-auto-write-answer-local)) ; Will be nil or t.
1568
1569
1570 ;;; This function should be called ONLY as a write-file hook.
1571 ;;; Odd things will happen if it is called elsewhere.
1572
1573 (defun crypt-write-file-hook ()
1574
1575 ;; Hook for possibly writing out file, and backup file, in a non-plain
1576 ;; format. Terminates calls in `write-file-hooks' and should be at end of
1577 ;; list.
1578
1579 ;; Check file-extension for possible toggling of encoding modes.
1580 (crypt-check-extension-for-encoding)
1581
1582 ;; Check extension for encryption.
1583 (if (and
1584
1585 ;; Maybe file ends with provocative extension w.r.t. encryption?
1586 (stringp (crypt-get-file-extension crypt-encryption-type))
1587 (let ((case-fold-search nil)) ; Make case-sensitive.
1588 (string-match (crypt-get-file-extension crypt-encryption-type)
1589 buffer-file-name))
1590
1591 ;; Can we play tricks?
1592 (crypt-get-extension-tricks crypt-encryption-type)
1593
1594 ;; Match of filename extension - is file in plain format?
1595 (not crypt-buffer-save-encrypted)
1596
1597 ;; Query?
1598 (or crypt-auto-write-buffer-encrypted
1599 (y-or-n-p
1600 (format "Write %s as an encrypted file? " (buffer-name)))))
1601
1602 (progn
1603 ;; Set password and toggle `crypt-encrypted-mode'
1604 (call-interactively 'crypt-set-encryption-key)
1605 (crypt-encrypted-mode 1)))
1606
1607 ;; Now decide whether or not we need to continue with this defun. Does the
1608 ;; buffer need to be saved in a non-plain form? If not then writing is not
1609 ;; done here but later in the write-file-hooks - probably at the end.
1610
1611 (if (or crypt-buffer-save-encoded crypt-buffer-save-encrypted)
1612
1613 (save-excursion
1614 (save-restriction
1615
1616 (let
1617
1618 ;; BINDINGS
1619 ((copy-buffer (get-buffer-create " *crypt copy buffer*"))
1620 (selective-display selective-display)
1621 (buffer-read-only))
1622
1623 ;; FORMS
1624 (copy-to-buffer copy-buffer 1 (1+ (buffer-size)))
1625 (narrow-to-region (point) (point))
1626
1627 (unwind-protect
1628
1629 ;; BODYFORM
1630 (let (setmodes)
1631
1632 ;; As of v19, if one of functions of the `write-file-hooks'
1633 ;; returns a non-nil value, then `basic-save-buffer' no
1634 ;; longer creates a backup file. We must do it ourselves.
1635 ;; this should be a no-op in v18.
1636 (or buffer-backed-up
1637 (setq setmodes (backup-buffer)))
1638
1639 (insert-buffer-substring copy-buffer)
1640 (kill-buffer copy-buffer)
1641
1642 ;; "Who would cross the Bridge of Death
1643 ;; Must answer me
1644 ;; These questions three
1645 ;; Ere the other side he see."
1646 ;;
1647 ;; Bridgekeeper from Monty Python and the Holy Grail
1648
1649 ;; [1] selective-display non-nil means we must convert
1650 ;; carriage returns to newlines now, and set the variable
1651 ;; selective-display temporarily to nil.
1652 (if selective-display
1653 (progn
1654 (goto-char (point-min))
1655 (subst-char-in-region (point-min) (point-max) ?\r ?\n)
1656 (setq selective-display nil)))
1657
1658 ;; [2] encryption
1659 (if crypt-buffer-save-encrypted
1660 (progn
1661 ;; check for password
1662 (if (not crypt-buffer-encryption-key)
1663 (call-interactively 'crypt-set-encryption-key))
1664 (if (null crypt-buffer-encryption-key)
1665 (error "No encryption key set for buffer %s"
1666 (buffer-name)))
1667 (if (not (stringp crypt-buffer-encryption-key))
1668 (error "Encryption key is not a string"))
1669 (message "Encrypting %s..." (buffer-name))
1670 (crypt-encrypt-buffer crypt-buffer-encryption-key)))
1671
1672 ;; [3] encoding
1673 (if crypt-buffer-save-encoded
1674 (progn
1675 (message "Encoding %s..." (buffer-name))
1676 (crypt-encode-buffer)))
1677
1678 ;; Now write buffer/region to disk.
1679 (write-region (point-min) (point-max) buffer-file-name nil t)
1680 (delete-region (point-min) (point-max))
1681 (set-buffer-modified-p nil)
1682
1683 ;; Now that the file is written, set its modes.
1684 (if setmodes
1685 (condition-case ()
1686 (set-file-modes buffer-file-name setmodes)
1687 (error nil)))
1688
1689 ;; Return t so that `basic-save-buffer' will know that the
1690 ;; save has already been done.
1691
1692 ;; NOTE: this TERMINATES write-file-hooks so any hooks
1693 ;; following this one will not be executed.
1694
1695 t )
1696
1697 ;; UNWINDFORMS
1698 ;; unwind...sit back...take a load off...have a beer
1699
1700 ;; If the encoded and encrypted stuff has already been removed
1701 ;; then this is a no-op. This form is executed if BODYFORM
1702 ;; completes normally but the value of BODYFORM is returned -
1703 ;; i.e., t is returned.
1704
1705 (delete-region (point-min) (point-max))))))))
1706
1707
1708 ;;;; ENCRYPTION
1709
1710 (defun crypt-encrypt-region (start end key &optional decrypt)
1711 "Encrypt region START to END using KEY and `crypt-encryption-type'. When
1712 called interactively START and END default to point and mark \(START being the
1713 lesser of the two\), and KEY is prompted for. With optional DECRYPT non-nil,
1714 decryption is done."
1715
1716 (interactive
1717 (let (decrypt)
1718 (barf-if-buffer-read-only)
1719 (list (region-beginning)
1720 (region-end)
1721 (crypt-read-string-no-echo
1722 (concat (if (setq decrypt (y-or-n-p "Decrypt region? ")) "De" "En")
1723 "crypt buffer using key: ")
1724 ;; Do not confirm on decrypting region.
1725 (if (not decrypt) crypt-confirm-password))
1726 decrypt)))
1727
1728 (crypt-save-point
1729
1730 ;; We define the PROGRAM as the encryption program or decryption program
1731 ;; listed for `crypt-encryption-type' of `crypt-encryption-alist.' These
1732 ;; should be just the name of the executable and should _not_ contain any
1733 ;; arguments. `(call-process-region)' would be confused if we tried to
1734 ;; pass the arguments as part of the PROGRAM. The arguments are passed
1735 ;; through the encryption args or decryption args listed for
1736 ;; `crypt-encryption-type' of `crypt-encryption-alist.'
1737
1738 ;; Thanks to Joe Ilacqua <spike@world.std.com> and others for pointing out
1739 ;; an error that occurs with some encryption programs (e.g., the crypt from
1740 ;; Sun Microsystems, HPUX-8, and BSD) if `args' is `"".' This will allow
1741 ;; nil values and lists of strings for argument.
1742
1743 (let (prog args)
1744
1745 ;; Get the proper program and arguments.
1746 (if decrypt
1747 (setq prog (crypt-get-decoding-program crypt-encryption-type)
1748 args (crypt-get-decoding-args crypt-encryption-type))
1749 (setq prog (crypt-get-encoding-program crypt-encryption-type)
1750 args (crypt-get-encoding-args crypt-encryption-type)))
1751
1752 ;; Check arguments.
1753 (cond
1754
1755 ;; nil or "" args - don't pass.
1756 ((or (not args) (equal "" args))
1757 (call-process-region start end prog t t nil key))
1758
1759 ;; Check if the args are in the form of a list - must use apply.
1760 ((listp args)
1761 (apply 'call-process-region
1762 (append (list start end prog t t nil) args (list key))))
1763
1764 ;; Default - just a non-null string.
1765 (t
1766 (call-process-region start end prog t t nil args key))))))
1767
1768
1769 (defun crypt-encrypt-buffer (key &optional decrypt buffer)
1770
1771 ;; Use KEY to encrypt current buffer and with optional DECRYPT decrypt.
1772 ;; With optional BUFFER, encrypt or decrypt that buffer. Not meant to be
1773 ;; called interactively, toggle `crypt-encrypted-mode' to encrypt an entire
1774 ;; buffer.
1775
1776 (or buffer (setq buffer (current-buffer)))
1777 (save-excursion (set-buffer buffer)
1778 (crypt-encrypt-region (point-min) (point-max) key decrypt)))
1779
1780
1781 ;;;; ENCODING
1782
1783 (defun crypt-encode-region (start end &optional decode)
1784
1785 "Encode region START to END. When called interactively START and END
1786 default to point and mark \(START being the lesser of the two\). With
1787 optional DECODE non-nil, decoding is done.
1788
1789 If encoding is attempted, then checks for correct magic number at start of
1790 newly-encoded region. If not found, then searches and deletes a user-defined
1791 regexp, or executes a user-defined lisp expression, as defined in
1792 `crypt-encoding-alist,' and checks again for magic number."
1793
1794 (interactive "*r\nP")
1795
1796 ;; If called interactively then we may need to determine the encoding type.
1797 (if (and (interactive-p) (not crypt-buffer-encoding-type))
1798 (crypt-read-encoding-type))
1799
1800 (crypt-save-point
1801
1802 ;; We define the PROGRAM as `shell-file-name' and have it call the encoding
1803 ;; or decoding program with the arguments.
1804
1805 (let (prog args)
1806
1807 ;; Get the proper program and arguments.
1808 (if decode
1809 (setq prog (crypt-get-decoding-program crypt-buffer-encoding-type)
1810 args (crypt-get-decoding-args crypt-buffer-encoding-type))
1811 (setq prog (crypt-get-encoding-program crypt-buffer-encoding-type)
1812 args (crypt-get-encoding-args crypt-buffer-encoding-type)))
1813
1814 (cond
1815
1816 ;; prog is a string?
1817 ((stringp prog)
1818
1819 ;; Check arguments.
1820 (cond
1821
1822 ;; Check if the args are in the form of a list, will catch 'nil.
1823 ((listp args)
1824
1825 ;; Cat all the strings together.
1826 (while args
1827 (setq prog (concat prog " " (car args))
1828 args (cdr args))))
1829
1830 ;; Check if a non-null string.
1831 ((and (not (string= "" args))
1832 (not (eq args t))) ; just in case...
1833 (setq prog (concat prog " " args))))
1834
1835 (call-process-region start end shell-file-name t t nil "-c" prog))
1836
1837 ;; Otherwise try and eval it.
1838 (t
1839 (eval (if args
1840 (list prog start end args)
1841 (list prog start end))))))
1842
1843 ;; Encoding or decoding region?
1844 (if (not decode)
1845
1846 ;; Check if encoded region starts with magic number.
1847 (let ((magic (crypt-get-magic-regexp crypt-buffer-encoding-type))
1848 (clean (crypt-get-cleanup-regexp crypt-buffer-encoding-type))
1849 (case-fold-search nil))
1850
1851 ;; Top of region.
1852 (goto-char start)
1853
1854 ;; Check for magic number.
1855 (if (not (looking-at magic))
1856
1857 ;; Magic number not there.
1858
1859 ;; Some compression programs produce an (inane) standard error
1860 ;; message that gets piped into the buffer. For example, some
1861 ;; versions of compact output "Compression : 35.50%." There may
1862 ;; be some way to clean up buffer and check again.
1863
1864 (cond
1865
1866 ;; No mechanism to clean up - failed.
1867 ((eq clean nil)
1868 (error "Encoding failed!"))
1869
1870 ;; Cleanup a regexp string?
1871 ((stringp clean)
1872
1873 ;; Is regexp there?
1874 (if (looking-at clean)
1875
1876 (progn
1877 ;; Delete the match.
1878 (delete-region (match-beginning 0) (match-end 0))
1879
1880 ;; Check for magic again.
1881 (if (not (looking-at magic))
1882 (error "Encoding failed!")))))
1883
1884 ;; Default: evaluate a lisp expression and check again.
1885 (t (eval clean)
1886 (if (not (looking-at magic))
1887 (error "Encoding failed!")))))))))
1888
1889 (defun crypt-encode-buffer (&optional decode buffer)
1890
1891 ;; Encode current buffer. With optional DECODE non-nil decode and optional
1892 ;; BUFFER, encode or decode that buffer. Not meant to be called
1893 ;; interactively, toggle `crypt-encoded-mode' to encode an entire buffer.
1894
1895 (or buffer (setq buffer (current-buffer)))
1896 (save-excursion (set-buffer buffer)
1897 (crypt-encode-region (point-min) (point-max) decode)))
1898
1899
1900 ;;;; DOS <--> UNIX
1901 (defun crypt-dos-to-unix-region (start end)
1902 "Converts region from START to END, from dos to unix format.
1903 Replaces \"\\r\\n\" with \"\\n\" and, if exists, removes ^Z at end of file.
1904 Sets `crypt-dos-has-ctrl-z'."
1905 (save-excursion
1906 (save-restriction
1907 (let ((remove-ctrl-z (equal end (point-max))))
1908 (narrow-to-region start end)
1909 (goto-char (point-min))
1910 (while (search-forward "\r\n" nil t)
1911 (replace-match "\n" nil t))
1912 (if remove-ctrl-z
1913 (progn
1914 (goto-char (1- (point-max)))
1915 (setq crypt-dos-has-ctrl-z (looking-at "\C-z"))
1916 (if crypt-dos-has-ctrl-z (replace-match ""))))))))
1917
1918 (defun crypt-unix-to-dos-region (start end)
1919 "Converts region from START to END, from dos to unix format.
1920 Replaces \"\\n\" with \"\\r\\n\" and adds a ^Z at end of file if
1921 `crypt-dos-has-ctrl-z' is non-nil."
1922 (save-excursion
1923 (save-restriction
1924 (let ((add-ctrl-z (and crypt-dos-has-ctrl-z
1925 (equal end (point-max)))))
1926 (narrow-to-region start end)
1927 (goto-char (point-min))
1928 (while (search-forward "\n" nil t)
1929 (replace-match "\r\n" nil t))
1930 (if add-ctrl-z
1931 (progn
1932 (goto-char (point-max))
1933 (insert "\C-z")))))))
1934
1935
1936 ;;;; MODES
1937
1938 (defun crypt-encrypted-mode (&optional arg)
1939
1940 "Toggle encrypted mode. With ARG, turn on iff positive, otherwise turn off.
1941 minor mode in which buffers are automatically encrypted before being written.
1942 if toggled and a key has been set for the current buffer, then the current
1943 buffer is marked modified, since it needs to be rewritten with or without
1944 encryption.
1945
1946 Entering encrypted mode causes auto-saving to be turned off in the current
1947 buffer, as there is no way in Emacs Lisp to force auto save files to be
1948 encrypted."
1949
1950 (interactive "P")
1951 (let ((oldval crypt-buffer-save-encrypted))
1952 (setq crypt-buffer-save-encrypted
1953 (if arg (> arg 0) (not crypt-buffer-save-encrypted)))
1954
1955 (if crypt-buffer-save-encrypted
1956 ;; We are going to save as encrypted, we will turn off auto-saving.
1957 (progn
1958 ;; NEVER do this. Turning off auto-saving is one thing. But if there's
1959 ;; already an autosave for some other reason, what business does this
1960 ;; package have tampering with it?
1961 ; ;; If an auto-save file already exists, then delete it.
1962 ; (if (and (stringp buffer-auto-save-file-name)
1963 ; (file-exists-p buffer-auto-save-file-name))
1964 ; (delete-file buffer-auto-save-file-name))
1965 ;; If the key is not set then ask for it.
1966 (if (not crypt-buffer-encryption-key)
1967 (call-interactively 'crypt-set-encryption-key))
1968 ;; Turn-off auto-saving if crypt-encrypted-disable-auto-save non-nil.
1969 (and crypt-encrypted-disable-auto-save
1970 auto-save-default
1971 (progn
1972 (auto-save-mode 0)
1973 (if (eq crypt-encrypted-disable-auto-save t)
1974 (message "Auto-save off (in this buffer)")))))
1975
1976 ;; We are not going to save as encrypted, we will turn on auto-saving
1977 ;; but only if we are editing a file and the default says we should.
1978 (auto-save-mode (if (and auto-save-default buffer-file-name) 1 0)))
1979
1980 (if crypt-buffer-encryption-key
1981 ;; Set buffer-modified flag to t only if the mode has been changed,
1982 ;; old code set unconditionally to nil if mode was not changed .
1983 ;; Modification suggested by: Gerd Hillebrand <ggh@cs.brown.edu>
1984 (if (not (eq oldval crypt-buffer-save-encrypted))
1985 (set-buffer-modified-p t)))))
1986
1987
1988 ;;; Forgetting encryption keys (by jwz)
1989 ;;; This is really kind of bogus. Good behavior would be:
1990 ;;; - If a crypted buffer has not been "accessed" (edited? selected?
1991 ;;; viewed?) in N minutes, kill the buffer (since the plaintext is valuable.)
1992 ;;; - If a crypted buffer is modified, but "idle", just forget the password
1993 ;;; instead of killing the buffer (though the plaintext is valuable, it's
1994 ;;; also unsaved...)
1995 ;;; - The "idleness" of a modified buffer should be reset with every mod, so
1996 ;;; that an unsaved buffer that you have been constantly typing at for an
1997 ;;; hour doesn't lose its password.
1998 ;;; - But, if a password for a buffer has been discarded, and then an attempt
1999 ;;; is made to save that buffer, then we should confirm that the newly-
2000 ;;; typed password is the same as the password used in the file on disk.
2001 ;;; with PGP, we could check that by attempting to decrypt the file on
2002 ;;; disk into a scratch buffer and seeing if it contains the PGP error
2003 ;;; message.
2004 ;;; - BUG: if a password has been forgotten, and you save, and are prompted,
2005 ;;; the old file has already been renamed to a backup!! so if you ^G, the
2006 ;;; real file name no longer exists on disk - only as a ~ file.
2007
2008 (defun crypt-forget-encryption-key ()
2009 (cond (crypt-buffer-encryption-key
2010 (let ((inhibit-quit t))
2011 (fillarray crypt-buffer-encryption-key 0)
2012 (setq crypt-buffer-encryption-key nil))
2013 t)
2014 (t nil)))
2015
2016 (add-hook 'kill-buffer-hook 'crypt-forget-encryption-key)
2017
2018 (defvar crypt-forget-passwd-timeout (* 60 60)
2019 "*Do not retain passwords for encrypted buffers more than this many seconds.
2020 If nil, keep them indefinitely.")
2021
2022 (defun crypt-reset-passwd-timer ()
2023 (if (fboundp 'get-itimer) ; XEmacs, or anything with itimer.el loaded.
2024 (let ((name "crypt-forget-passwds"))
2025 (if (get-itimer name)
2026 (delete-itimer name))
2027 (if crypt-forget-passwd-timeout
2028 (start-itimer name
2029 'crypt-reset-passwds-timeout
2030 crypt-forget-passwd-timeout)))))
2031
2032 (defun crypt-reset-passwds-timeout ()
2033 ;; run by the timer code to forget all passwords
2034 (let ((buffers (buffer-list))
2035 (inhibit-quit t)
2036 (keep-going nil))
2037 (while buffers
2038 (save-excursion
2039 (set-buffer (car buffers))
2040 (cond ((and crypt-buffer-encryption-key
2041 (buffer-modified-p))
2042 ;; don't forget the password in modified buffers, but
2043 ;; do check again later (maybe it will be unmodified.)
2044 (setq keep-going t))
2045 (crypt-buffer-encryption-key
2046 ;; forget the password in unmodified buffers.
2047 (crypt-forget-encryption-key)
2048 ;; Mark the buffer read only so that it's not accidentally
2049 ;; edited; the smart thing to do is revert it, type the
2050 ;; encryption key (to make sure they same key is used)
2051 ;; and then edit it.
2052 (setq buffer-read-only t)
2053 (message "Password discarded in buffer %s"
2054 (buffer-name (car buffers))))
2055 ))
2056 (setq buffers (cdr buffers)))
2057 (if keep-going
2058 (crypt-reset-passwd-timer))
2059 nil))
2060
2061
2062 ;;; Originally `tek-symbol-alist-to-table' from tek-highlight.el.
2063 (defun crypt-symbol-alist-to-table (list)
2064 ;; Converts an alist of symbols to a table suitable for `completing-read.'
2065 ;; Called by `crypt-read-encoding-type'
2066 (mapcar (function (lambda (x) (list (symbol-name (car x)))))
2067 list))
2068
2069 (defun crypt-read-encoding-type ()
2070
2071 ;; Function called to query user for `crypt-buffer-encoding-type' uses
2072 ;; contents of `crypt-encoding-alist' and `crypt-default-encoding.'
2073
2074 ;; Use poor man's gmhist (i.e., we could have used gmhist's
2075 ;; `completing-read-with-history-in' instead).
2076 (let (
2077 ;; Find the encoding type desired by user.
2078 (type
2079 (completing-read
2080 (concat "encoding type (? for list): [" crypt-default-encoding "] ")
2081 (crypt-symbol-alist-to-table crypt-encoding-alist))))
2082
2083 ;; Test length of object returned by `completing-read'.
2084 (if (zerop (length type))
2085
2086 ;; Nothing there, i.e., user hit return -- use default.
2087 (setq crypt-buffer-encoding-type (intern crypt-default-encoding))
2088
2089 ;; Use the value from mini-buffer and update the default value.
2090 (setq crypt-buffer-encoding-type (intern type)
2091 crypt-default-encoding type))))
2092
2093 (defun crypt-encoded-mode (&optional arg)
2094
2095 "Toggle encoded mode. With ARG, turn on iff positive, otherwise turn off.
2096 minor mode in which buffers are automatically encoded before being written. if
2097 toggled then current buffer is marked modified, since it needs to be written
2098 with or without encoding.
2099
2100 Entering encoded mode causes auto-saving to be turned off in the current
2101 buffer, as there is no way in Emacs Lisp to force auto save files to be
2102 encoded."
2103
2104 (interactive "P")
2105
2106 ;; Set flag indicating whether or not `(crypt-encoded-mode)' was called
2107 ;; interactively.
2108 (setq crypt-buffer-interactive-encoded-mode (interactive-p))
2109
2110 ;; If called interactively then need to determine encoding type.
2111 (if (and crypt-buffer-interactive-encoded-mode
2112 (not crypt-buffer-encoding-type))
2113 (crypt-read-encoding-type))
2114
2115 ;; Save old value of `crypt-buffer-save-encoded'.
2116 (let ((oldval crypt-buffer-save-encoded))
2117
2118 ;; Set the variable `crypt-buffer-save-encoded' to t if the argument is
2119 ;; positive, otherwise toggle its current value.
2120 (setq crypt-buffer-save-encoded
2121 (if arg (> arg 0) (not crypt-buffer-save-encoded)))
2122
2123 ;; Set the variable generated by `(crypt-buffer-save-name)' to the value
2124 ;; stored in `crypt-buffer-save-encoded.'
2125 (set-variable (crypt-buffer-save-name crypt-buffer-encoding-type)
2126 crypt-buffer-save-encoded)
2127
2128 (if crypt-buffer-save-encoded
2129 ;; We are going to save as encoded, we might turn off auto-saving.
2130 (progn
2131 ;; NEVER do this. Turning off auto-saving is one thing. But if there's
2132 ;; already an autosave for some other reason, what business does this
2133 ;; package have tampering with it?
2134 ; ;; If an auto-save file already exists, then delete it.
2135 ; (if (and (stringp buffer-auto-save-file-name)
2136 ; (file-exists-p buffer-auto-save-file-name))
2137 ; (delete-file buffer-auto-save-file-name))
2138 ;; Turn-off auto-saving if crypt-encoded-disable-auto-save non-nil.
2139 (and crypt-encoded-disable-auto-save
2140 auto-save-default
2141 (progn
2142 (auto-save-mode 0)
2143 (if (eq crypt-encoded-disable-auto-save t)
2144 (message "Auto-save off (in this buffer)")))))
2145
2146 ;; We are not going to save as encoded, we will turn on auto-saving but
2147 ;; only if we are editing a file and the default says we should.
2148 (auto-save-mode (if (and auto-save-default buffer-file-name) 1 0)))
2149
2150 ;; Have we toggled the mode?
2151
2152 ;; If yes, then mark buffer as modified. If not, then leave
2153 ;; buffer-modified flag alone.
2154
2155 ;; The old code previously set the variable `set-buffer-modified-p' to a
2156 ;; value of t if there was a mode change and (unconditionally) to nil
2157 ;; if there was not a mode change.
2158
2159 ;; Modification suggested by: Gerd Hillebrand <ggh@cs.brown.edu>.
2160
2161 (if (not (eq oldval crypt-buffer-save-encoded))
2162 (set-buffer-modified-p t))))
2163
2164
2165 ;;;; Additional encryption functions
2166
2167 ;; For Emacs V18 compatibility
2168 (and (not (fboundp 'buffer-disable-undo))
2169 (fboundp 'buffer-flush-undo)
2170 (fset 'buffer-disable-undo 'buffer-flush-undo))
2171
2172 (fset 'crypt-read-string-no-echo 'read-passwd)
2173
2174 ;(defun crypt-read-string-no-echo (prompt &optional confirm)
2175 ;
2176 ; ;; Read a string from minibuffer, prompting with PROMPT, echoing periods.
2177 ; ;; Optional second argument CONFIRM non-nil means that the user will be
2178 ; ;; asked to type the string a second time for confirmation and if there is a
2179 ; ;; mismatch, the whole process is repeated.
2180 ; ;;
2181 ; ;; Line editing keys are --
2182 ; ;; C-h, DEL rubout
2183 ; ;; C-u, C-x line kill
2184 ; ;; C-q, C-v literal next
2185 ;
2186 ; (catch 'return-value
2187 ; (save-excursion
2188 ;
2189 ; (let ((input-buffer (get-buffer-create (make-temp-name " *password*")))
2190 ; char hold-password help-form kill-ring)
2191 ;
2192 ; (set-buffer input-buffer)
2193 ; ;; Don't add to undo ring.
2194 ; (buffer-disable-undo input-buffer)
2195 ;
2196 ; (let ((cursor-in-echo-area t)
2197 ; (echo-keystrokes 0))
2198 ;
2199 ; (unwind-protect
2200 ;
2201 ; ;; BODYFORM
2202 ; ;; Repeat until we get a `throw'.
2203 ; (while t
2204 ; (erase-buffer)
2205 ; (message prompt)
2206 ;
2207 ; ;; Read string.
2208 ; (while (not (memq (setq char (read-char)) '(?\C-m ?\C-j)))
2209 ; (if (setq help-form
2210 ; (cdr
2211 ; (assq char
2212 ; '((?\C-h . (delete-char -1))
2213 ; (?\C-? . (delete-char -1))
2214 ; (?\C-u . (delete-region 1 (point)))
2215 ; (?\C-x . (delete-region 1 (point)))
2216 ; (?\C-q . (quoted-insert 1))
2217 ; (?\C-v . (quoted-insert 1))))))
2218 ; (condition-case error-data
2219 ; (eval help-form)
2220 ; (error t))
2221 ; ;; Just a plain character - insert into password buffer.
2222 ; (insert char))
2223 ;
2224 ; ;; I think crypt-read-string-no-echo should echo asterisks.
2225 ; ;; -- Jamie. How about periods like in ange-ftp? -- lrd
2226 ; ;;
2227 ; (message "%s%s" prompt (make-string (buffer-size) ?.)))
2228 ;
2229 ; ;; Do we have to confirm password?
2230 ; (cond
2231 ;
2232 ; ;; No confirmation requested - terminate.
2233 ; ((not confirm)
2234 ; (throw 'return-value (buffer-string)))
2235 ;
2236 ; ;; Can we compare (confirm) password values yet?
2237 ; (hold-password
2238 ; (if (string= hold-password (buffer-string))
2239 ; ;; The two passwords match - terminate.
2240 ; (throw 'return-value hold-password)
2241 ;
2242 ; ;; Mismatch - start over.
2243 ; (progn
2244 ; (message (concat prompt "[Mismatch. Start over]"))
2245 ; (beep)
2246 ; (sit-for 2)
2247 ; (fillarray hold-password 0) ; destroy extra copy now
2248 ; (setq hold-password nil))))
2249 ;
2250 ; ;; Store password and read again.
2251 ; (t
2252 ; (setq hold-password (buffer-string))
2253 ; (message (concat prompt "[Retype to confirm]"))
2254 ; (sit-for 2))))
2255 ;
2256 ; ;; UNWINDFORMS
2257 ; ;; Clean up.
2258 ; (set-buffer input-buffer)
2259 ; (set-buffer-modified-p nil)
2260 ; (buffer-disable-undo input-buffer) ; redundant, but why not be safe.
2261 ; (widen)
2262 ; (goto-char (point-min))
2263 ; (while (not (eobp)) (delete-char 1) (insert "*")) ; destroy now
2264 ; (kill-buffer input-buffer)))))))
2265
2266 (defun crypt-set-encryption-key (key &optional buffer)
2267
2268 "Set the encryption KEY, a string, for current buffer or optionally BUFFER.
2269 If buffer is in encrypted mode, then it is also marked as modified, since it
2270 needs to be saved with the new key."
2271
2272 (interactive
2273 (progn
2274 (barf-if-buffer-read-only)
2275 (list (crypt-read-string-no-echo
2276 (format "Encryption key for %s? [RET to ignore]: " (buffer-name))
2277 crypt-confirm-password))))
2278
2279 ;; For security reasons we remove `(crypt-set-encryption-key "password")'
2280 ;; from the `command-history' list if called interactively.
2281 (if (interactive-p)
2282 (setq command-history (cdr command-history)))
2283
2284 (or buffer (setq buffer (current-buffer)))
2285
2286 (save-excursion
2287 (set-buffer buffer)
2288 (if (equal key crypt-buffer-encryption-key)
2289 (message "Key is identical to original, no change.")
2290
2291 (progn
2292 ;; jwz: destroy old string
2293 (if (and crypt-buffer-encryption-key
2294 (not (eq crypt-buffer-encryption-key key)))
2295 (fillarray crypt-buffer-encryption-key 0))
2296 (setq crypt-buffer-encryption-key key)
2297
2298 ;; Don't touch the modify flag unless we're in `(crypt-encrypted-mode)'.
2299 (if crypt-buffer-save-encrypted
2300 (set-buffer-modified-p t))
2301
2302 (crypt-reset-passwd-timer)
2303 ))))
2304
2305
2306 ;;;; Install hooks and mode indicators.
2307
2308 ;;; Check if mode indicators are not already installed and then prepend them.
2309 (and (not (assq 'crypt-buffer-save-encrypted minor-mode-alist))
2310 (setq minor-mode-alist (append crypt-minor-mode-alist minor-mode-alist)))
2311
2312 ;;; Install the hooks.
2313
2314 ;;; If add-hook isn't already defined overwrite it with our own.
2315 ;;; Note the `add-hook' function must take the optional APPEND argument.
2316 (if (not (fboundp 'add-hook))
2317 ;; No add-hook found.
2318 ;; Use `add-hook' from GNU Emacs v19.
2319 (defun add-hook (hook function &optional append)
2320 "Add to the value of HOOK the function FUNCTION.
2321 FUNCTION is not added if already present.
2322 FUNCTION is added (if necessary) at the beginning of the hook list
2323 unless the optional argument APPEND is non-nil, in which case
2324 FUNCTION is added at the end.
2325
2326 HOOK should be a symbol, and FUNCTION may be any valid function. If
2327 HOOK is void, it is first set to nil. If HOOK's value is a single
2328 function, it is changed to a list of functions."
2329 (or (boundp hook) (set hook nil))
2330 ;; If the hook value is a single function, turn it into a list.
2331 (let ((old (symbol-value hook)))
2332 (if (or (not (listp old)) (eq (car old) 'lambda))
2333 (set hook (list old))))
2334 (or (if (consp function)
2335 ;; Clever way to tell whether a given lambda-expression
2336 ;; is equal to anything in the hook.
2337 (let ((tail (assoc (cdr function) (symbol-value hook))))
2338 (equal function tail))
2339 (memq function (symbol-value hook)))
2340 (set hook
2341 (if append
2342 (nconc (symbol-value hook) (list function))
2343 (cons function (symbol-value hook)))))))
2344
2345 ;;; Attach ourselves to the find-file-hooks and find-file-not-found-hooks.
2346 (add-hook 'find-file-hooks 'crypt-find-file-hook)
2347 (add-hook 'find-file-not-found-hooks 'crypt-find-file-hook)
2348
2349 ;; Take care when appending to write-file-hook. User's version of add-hook
2350 ;; may not have APPEND option. If it fails then do it by hand. I wish
2351 ;; everyone would upgrade - lrd 8/31/93.
2352 (condition-case err
2353 (add-hook 'write-file-hooks 'crypt-write-file-hook t) ; *must* append this
2354 (error
2355 ;; Do it by hand. Not as robust as `add-hook'.
2356
2357 ;; Contributed by Ken Laprade <laprade@trantor.harris-atd.com>
2358 ;; Really should use some sort of add-hook - 16 Feb 93 - KCL
2359 (or (and (listp write-file-hooks) (not (eq (car write-file-hooks) 'lambda)))
2360 (setq write-file-hooks (list write-file-hooks)))
2361
2362 (cond
2363 ((not (memq 'crypt-write-file-hook write-file-hooks))
2364 ;; make this hook last on purpose
2365 (setq write-file-hooks (append write-file-hooks
2366 (list 'crypt-write-file-hook)))))))
2367
2368 ;; In order that the tables and key-binding correctly reflect user's
2369 ;; preferences we add ourselves to the `after-init-hook' GNU Emacs v19 and
2370 ;; Lucid Emacs v 19.8 (or later) or `term-setup-hook' in Lucid Emacs v 19.7
2371 ;; (or earlier). These are run *after* ~/.emacs and ../lisp/default.el are
2372 ;; loaded. Unfortunately, v18 does not have `after-init-hook' and
2373 ;; `term-setup-hook' is just a single function. It is a bit of a pain trying
2374 ;; to work our functions in properly without overwriting the user's value.
2375 ;; Therefore, we do nothing and hope they upgrade to v19 soon.
2376
2377 (cond ((boundp 'after-init-hook)
2378 ;; Must be running GNU Emacs v19 :->
2379 (add-hook 'after-init-hook 'crypt-rebuild-tables)
2380 (add-hook 'after-init-hook 'crypt-rebuild-minor-modes-alist)
2381 (add-hook 'after-init-hook 'crypt-bind-insert-file))
2382
2383 ((and (string-match "^19" emacs-version) t)
2384 ;; Probably running Lucid Emacs v19.7 (or earlier) since it,
2385 ;; unfortunately, does not have `after-init-hook'. Use
2386 ;; `term-setup-hook' instead and hope they upgrade to Lucid 19.8 or GNU
2387 ;; Emacs 19.
2388 (add-hook 'term-setup-hook 'crypt-rebuild-tables)
2389 (add-hook 'term-setup-hook 'crypt-rebuild-minor-modes-alist)
2390 (add-hook 'term-setup-hook 'crypt-bind-insert-file)))
2391
2392
2393 ;;; Code for conditionally decoding/decrypting an inserted file
2394
2395 (defvar crypt-bind-insert-file t
2396 "*t value means bind `crypt-insert-file' over `insert-file'.
2397 If you wish to change this variable after crypt++ has been loaded then do
2398 \\[crypt-bind-insert-file].")
2399
2400 (defvar crypt-auto-decode-insert nil
2401 "*t says decode/decrypt files that are inserted with `crypt-insert-file'.
2402 nil says to ask before doing this.")
2403
2404 ;;; Bind `crypt-insert-file' over wherever `insert-file' is bound?
2405 (defun crypt-bind-insert-file ()
2406
2407 "Bind `crypt-insert-file' in place of `insert-file' or reverse based on
2408 `crypt-bind-insert-file'. Part of `after-init-hook'."
2409
2410 (interactive)
2411
2412 (if (interactive-p)
2413 (setq crypt-bind-insert-file
2414 (y-or-n-p "Bind crypt-insert-file over insert-file? ")))
2415
2416 (if crypt-bind-insert-file
2417 (substitute-key-definition
2418 'insert-file 'crypt-insert-file (current-global-map))
2419 (substitute-key-definition
2420 'crypt-insert-file 'insert-file (current-global-map))))
2421
2422 ;;; Now call it.
2423 (crypt-bind-insert-file)
2424
2425 ;;; crypt++ replacement for `insert-file'
2426 (defun crypt-insert-file (filename)
2427 "Insert decoded/decrypted contents of file FILENAME into buffer after point.
2428 Set mark after the inserted text.
2429
2430 This function is meant for the user to run interactively.
2431 Don't call it from programs! Use `insert-file-contents' instead.
2432 \(Its calling sequence is different; see its documentation\).
2433
2434 This version will attempt to decrypt and/or decode file before inserting.
2435 see variable `crypt-auto-decode-insert'."
2436 (interactive "fInsert file: ")
2437 (if (file-directory-p filename)
2438 (signal 'file-error (list "Opening input file" "file is a directory"
2439 filename)))
2440 (let ((tem (crypt-insert-file-contents filename))) ; use crypt++ to insert
2441 (push-mark (+ (point) (car (cdr tem))))))
2442
2443 (defun crypt-insert-file-contents (file)
2444
2445 ;; Similar to `insert-file-contents' except decoding/decrypting of FILE
2446 ;; attempted. See `crypt-insert-file' and `crypt-auto-decode-insert'
2447
2448 (let (temp-buffer
2449 temp-list
2450 (crypt-auto-decode-buffer crypt-auto-decode-insert)
2451 (orig-buffer (current-buffer)))
2452
2453 ;; Create a temporary buffer and decode and decrypt it.
2454 (save-excursion
2455
2456 ;; Temporary buffer, use the same name as the file to be inserted.
2457 (setq temp-buffer (generate-new-buffer (file-name-nondirectory file)))
2458 (set-buffer temp-buffer)
2459
2460 ;; Original insert-file-contents - save list.
2461 (setq temp-list (insert-file-contents file nil))
2462
2463 ;; Make temp-buffer unmodified.
2464 (set-buffer-modified-p nil)
2465
2466 ;; Need to set buffer name to file name for crypt++.
2467 (setq buffer-file-name file)
2468
2469 ;; Decode and decrypt, if necessary.
2470 (crypt-find-file-hook)
2471
2472 ;; Find the length of the file to be inserted. `insert-file-contents'
2473 ;; returns it for the original encoded/encrypted file.
2474 (setcdr temp-list (cons (buffer-size) ()))
2475
2476 ;; Now insert temp-buffer into original buffer.
2477 (set-buffer orig-buffer)
2478 (insert-buffer temp-buffer)
2479
2480 ;; Kill the temporary buffer.
2481 (kill-buffer temp-buffer))
2482
2483 ;; Return modified list from `insert-file-contents'.
2484 temp-list))
2485
2486
2487 ;;;; BUG REPORTS
2488
2489 ;;; This section is provided for reports.
2490 ;;; Using Barry A. Warsaw's reporter.el
2491
2492 (defconst crypt-version "2.82"
2493 "Revision number of crypt++.el -- handles compressed and encrypted files.
2494 Type \\[crypt-submit-report] to send a bug report. Available via anonymous
2495 ftp in
2496
2497 /roebling.poly.edu:/pub/lisp/crypt++.el.gz
2498 /archive.cis.ohio-state.edu:/pub/gnu/emacs/elisp-archive/misc/crypt++.el.Z")
2499
2500 (defconst crypt-help-address
2501 "dodd@roebling.poly.edu"
2502 "Address(es) accepting submission of reports on crypt++.el.")
2503
2504 (defconst crypt-maintainer "Larry"
2505 "First name(s) of people accepting submission of reports on crypt++.el.")
2506
2507 (defconst crypt-file "crypt++.el"
2508 "Name of file containing emacs lisp code.")
2509
2510 (defconst crypt-variable-list
2511 (list 'shell-file-name ; These
2512 'load-path ; are
2513 'exec-path ; useful.
2514 'crypt-encryption-type
2515 'crypt-encryption-file-extension
2516 'crypt-never-ever-decrypt
2517 'crypt-auto-write-buffer-encrypted
2518 'crypt-confirm-password
2519 'crypt-encrypted-disable-auto-save
2520 'crypt-auto-decode-buffer
2521 'crypt-auto-write-buffer
2522 'crypt-query-if-interactive
2523 'crypt-no-extension-implies-plain
2524 'crypt-freeze-vs-fortran
2525 'crypt-compact-vs-C++
2526 'crypt-ignored-filenames
2527 'crypt-default-encoding
2528 'crypt-encoded-disable-auto-save
2529 'crypt-bind-insert-file
2530 'crypt-auto-decode-insert
2531 'crypt-encoding-alist
2532 'crypt-encryption-alist
2533 )
2534 "List of variables to be appended to reports sent by `crypt-submit-report.'")
2535
2536 (defun crypt-submit-report ()
2537 "Submit via reporter.el a bug report on program. Send report on `crypt-file'
2538 version `crypt-version,' to `crypt-maintainer' at address `crypt-help-address'
2539 listing variables `crypt-variable-list' in the message."
2540 (interactive)
2541
2542 ;; In case we can't find reporter...
2543 (condition-case err
2544 (progn
2545 ;; Get it if we can.
2546 (require 'reporter)
2547
2548 (reporter-submit-bug-report
2549 crypt-help-address ; address
2550 (concat crypt-file " " crypt-version) ; pkgname
2551 crypt-variable-list ; varlist
2552 nil nil ; pre-hooks and post-hooks
2553 (concat "Yo! " crypt-maintainer ","))) ; salutation
2554
2555 ;; ...fail gracefully.
2556 (error
2557 (beep)
2558
2559 ;; Do they have ange-ftp?
2560 (if (and (featurep 'ange-ftp)
2561 (y-or-n-p (concat "Sorry, reporter.el not found. "
2562 "Can I ange-ftp it for you? ")))
2563
2564 ;; Yes. Then Ange-ftp a copy from roebling.
2565 (let ((ange-ftp-generate-anonymous-password t))
2566 ;; Might want to use the elisp archive official site? But
2567 ;; then it would have to be uncompressed, etc. Ick!
2568 (find-file-other-window
2569 "/anonymous@roebling.poly.edu:/pub/reporter.el")
2570 (eval-current-buffer)
2571 (message (concat "Save reporter.el somewhere in `load-path' "
2572 "and try again.")))
2573
2574 ;; No ange-ftp.
2575 (message "Sorry, reporter.el not found.")
2576 (sit-for 3)
2577 (message (concat "Get it from archive.cis.ohio-state.edu "
2578 "or roebling.poly.edu"))))))
2579
2580 ;;; Provide this package as crypt++ as well as crypt.
2581 (provide 'crypt++)
2582 (provide 'crypt)
2583
2584 ;;; crypt++.el ends here.