home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / elisp / misc / crypt++.el < prev    next >
Encoding:
Text File  |  1993-06-14  |  82.3 KB  |  2,027 lines

  1. ;;; crypt++.el --- code for handling all sorts of compressed and encrypted files
  2.  
  3. ;;; Copyright (C) 1993 Rod Whitby and Lawrence R. Dodd
  4. ;;; Copyright (C) 1988, 1989, 1990 Kyle E. Jones
  5.  
  6. ;; Author: Rod Whitby <rwhitby@research.canon.oz.au>
  7. ;;    Lawrence R. Dodd <dodd@roebling.poly.edu>
  8. ;;    Kyle E. Jones <kyle@uunet.uu.net>
  9. ;; Maintainer: Lawrence R. Dodd <dodd@roebling.poly.edu>
  10. ;;    Rod Whitby <rwhitby@research.canon.oz.au>
  11. ;; Created: crypt.el in 1988, crypt++.el on 18 Jan 1993
  12. ;; Version: 2.53
  13. ;; Keywords: extensions
  14.  
  15. ;;; This program is free software; you can redistribute it and/or modify
  16. ;;; it under the terms of the GNU General Public License as published by
  17. ;;; the Free Software Foundation; either version 2 of the License, or
  18. ;;; (at your option) any later version.
  19. ;;;
  20. ;;; This program is distributed in the hope that it will be useful,
  21. ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23. ;;; GNU General Public License for more details.
  24. ;;;
  25. ;;; You should have received a copy of the GNU General Public License
  26. ;;; along with this program; if not, write to the Free Software
  27. ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  28.  
  29. ;;; Commentary:
  30.  
  31. (defconst crypt-version (substring "!Revision: 2.53 !" 11 -2)
  32.   "revision number of crypt++.el -- handles compressed and encrypted files.
  33. type M-x crypt-submit-report to send a bug report.  available via anonymous
  34. ftp in
  35.  
  36.    /roebling.poly.edu:/pub/crypt++.el
  37.    /archive.cis.ohio-state.edu:/pub/gnu/emacs/elisp-archive/misc/crypt++.el.Z")
  38.  
  39. ;;; LCD Archive Entry:
  40. ;;; crypt++|Rod Whitby and Lawrence R. Dodd|dodd@roebling.poly.edu|
  41. ;;; Code for handling all sorts of compressed and encrypted files.|
  42. ;;; 10-Jun-1993|2.53|~/misc/crypt++.el.Z|
  43.  
  44. ;;; AVAILABLE: 
  45. ;;; 
  46. ;;; via anonymous ftp to roebling.poly.edu [128.238.5.31] in /pub/crypt++.el
  47. ;;; (ange-ftp TAG: /roebling.poly.edu:/pub/crypt++.el)
  48. ;;; 
  49. ;;; via anonymous ftp to archive.cis.ohio-state.edu [128.146.8.52] in 
  50. ;;; /pub/gnu/emacs/elisp-archive/misc/crypt++.el.Z
  51.  
  52. ;;; BUG REPORTS
  53. ;;; 
  54. ;;; type M-x crypt-submit-report to generate a bug report template or put your
  55. ;;; cursor at the end of this line and type C-x C-e: (crypt-submit-report)
  56. ;;; 
  57. ;;; requires Barry Warsaw's reporter.el which can be obtained at
  58. ;;; /roebling.poly.edu:/pub/reporter.el and the elisp-archive.
  59.  
  60. ;;; please see notes on INSTALLATION and USAGE below
  61.  
  62. ;;; RESPONSIBLE PARTIES:
  63. ;;;
  64. ;;;   /Northern Hemisphere/
  65. ;;;  
  66. ;;;     Lawrence R. Dodd <dodd@roebling.poly.edu>   -  _    ,__o
  67. ;;;     Department of Chemical Engineering         -  _   , \_<,
  68. ;;;     Polymer Research Institute                  -    (*)/'(*)
  69. ;;;     Polytechnic University                     ~~~~~~~~~~~~~~~~~~ 
  70. ;;;     Six Metrotech
  71. ;;;     Brooklyn, New York, 11201 USA                        
  72. ;;;
  73. ;;;   /Southern Hemisphere/ 
  74. ;;;                                                   _--_|\  
  75. ;;;     Rod Whitby <rwhitby@research.canon.oz.au>    /      \ 
  76. ;;;     Canon Information Systems Research Australia \_.--._/ 
  77. ;;;     1 Thomas Holt Drive                                v 
  78. ;;;     North Ryde, N.S.W., 2113 Australia
  79. ;;; 
  80. ;;;   World-wide coverage!!  Bugs fixed while you sleep!!
  81.  
  82. ;;; VERSION:
  83. ;;;  
  84. ;;; !Id: crypt++.el,v 2.53 1993/06/10 21:45:45 dodd Exp !
  85. ;;; !Date: 1993/06/10 21:45:45 !
  86. ;;; !Revision: 2.53 !
  87.  
  88.  
  89. ;;; INSTALLATION:
  90. ;;;
  91. ;;; To use this package, simply put it in a file called "crypt++.el" in a Lisp
  92. ;;; directory known to Emacs, byte-compile it, and put the line:
  93. ;;;
  94. ;;;                      (require 'crypt++)
  95. ;;;
  96. ;;; in your ~/.emacs file or in the file default.el in the ../lisp directory
  97. ;;; of the Emacs distribution.  Do not bother trying to autoload this file;
  98. ;;; this package uses find-file and write-file hooks and thus should be loaded
  99. ;;; the first time you visit any sort of file.  Any package loaded after this
  100. ;;; one that appends something to `write-file-hooks' will not be executed
  101. ;;; because this package writes out the file.  Other packages that append to
  102. ;;; `write-file-hooks' should either be modified to prepend to that hook or be
  103. ;;; loaded before this one (preferably the former).  Requires Barry Warsaw's
  104. ;;; reporter.el for submitting bug reports, available from roebling.poly.edu.
  105.  
  106. ;;; An alternative is to stick 
  107. ;;; 
  108. ;;;                      (require 'crypt)
  109. ;;; 
  110. ;;; in your ~/.emacs, if it is not already there, and then make a (symbolic) 
  111. ;;; link from crypt++.el to crypt.el
  112. ;;; 
  113. ;;;                      ln -s crypt++.el crypt.el
  114. ;;; 
  115. ;;; this will make crypt++ act like a drop-in replacement for the original
  116. ;;; crypt since any package requiring crypt will find crypt++ instead.  Thanks
  117. ;;; to Per Abrahamsen <amanda@iesd.auc.dk> for this suggestion.
  118.  
  119.  
  120. ;;; USAGE:
  121. ;;; 
  122. ;;; By default, intended to be transparent.  User-defined variables 
  123. ;;; 
  124. ;;;     controlling ENCRYPTION are
  125. ;;;  
  126. ;;;        crypt-encryption-type
  127. ;;;        crypt-encryption-file-extension
  128. ;;;        crypt-never-ever-decrypt
  129. ;;;        crypt-auto-write-buffer-encrypted
  130. ;;;        crypt-confirm-password
  131. ;;;        crypt-encryption-alist
  132. ;;;  
  133. ;;;     controlling ENCODING are
  134. ;;;  
  135. ;;;        crypt-auto-decode-buffer
  136. ;;;        crypt-auto-write-buffer
  137. ;;;        crypt-query-if-interactive
  138. ;;;        crypt-no-extension-implies-plain
  139. ;;;        crypt-freeze-vs-fortran
  140. ;;;        crypt-compact-vs-C++
  141. ;;;        crypt-ignored-filenames
  142. ;;;        crypt-default-encoding
  143. ;;;        crypt-encoding-alist
  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-submit-report)
  159. ;;;
  160. ;;; to find out more about these functions, load this file, put your cursor
  161. ;;; inside any of the `()' of the above lines, and hit C-h f [RET].
  162.  
  163.  
  164. ;;; NOTES ON INTERFACES WITH OTHER PROGRAMS AND PACKAGES:
  165. ;;;
  166. ;;; GZIP: the environment variable GZIP of gzip can cause an error if it
  167. ;;; contains `--verbose' because standard output messages will be appended to
  168. ;;; gzip'ed files.  This corrupts the files.  The cleanest solution is to pass
  169. ;;; the `--quiet' switch in `crypt-encoding-alist' to override this.  use gzip
  170. ;;; version 1.0.4 or higher from prep.ai.mit.edu:/pub/gnu
  171. ;;; 
  172. ;;; TAR-MODE: works properly with version 1.28 (or higher) with v19 emacs.
  173. ;;;
  174. ;;; RMAIL and CHANGING MAJOR MODE (for v18 ONLY): in v18 emacs crypt++.el's
  175. ;;; buffer local variables are smashed whenever the major mode is changed of a
  176. ;;; buffer or whenever RMAIL is run on an encrypted and/or compressed file.
  177. ;;; This screws things up.  No smashing occurs with v19 Emacs.  for v18 emacs
  178. ;;; Joe Wells' "kill-fix.el" is needed to prevent this.  Get a copy of
  179. ;;; kill-fix.el from roebling.poly.edu:/pub or archive.cis.ohio-state.edu,
  180. ;;; store it where emacs can find it, stick a "(require 'kill-fix)" anywhere
  181. ;;; in your ~/.emacs, and the problem will be fixed.
  182. ;;; 
  183. ;;; LISPDIR: if you save this file as crypt++.el then the "(require 'crypt)"
  184. ;;; in lispdir.el needs to be replaced "(require 'crypt++)" or the symbolic
  185. ;;; link suggested above can be used.
  186.  
  187.  
  188. ;;; DESCRIPTION:
  189. ;;;
  190. ;;; The basic purpose of this package of Lisp functions is to recognize
  191. ;;; automatically encrypted and encoded (i.e., compressed) files when they are
  192. ;;; first visited or written.  The BUFFER corresponding to the file is decoded
  193. ;;; and/or decrypted before it is presented to the user.  The file itself is
  194. ;;; unchanged on the disk.  When the buffer is subsequently saved to disk, a
  195. ;;; hook function re-encodes the buffer before the actual disk write takes
  196. ;;; place.
  197. ;;;
  198. ;;; This package recognizes all sorts of compressed files by a magic number at
  199. ;;; the beginning of these files but uses a heuristic to detect encrypted
  200. ;;; files.  If you are asked for an encryption key for a file that is in fact
  201. ;;; not encrypted, just hit RET and the file will be accepted as is, and the
  202. ;;; crypt minor mode will not be entered.
  203. ;;;
  204. ;;; Other types of encoding programs may be added to this package by using the
  205. ;;; variable `crypt-encoding-alist' which contains a table of encoding
  206. ;;; programs such as compress, gzip (GNU zip), freeze, and compact.
  207. ;;;
  208. ;;; This new extended version of crypt now monitors the filename extensions of
  209. ;;; buffers that are written out using write-file (C-x C-w).  If the filename
  210. ;;; extension matches one of the extensions listed in `crypt-encoding-alist,'
  211. ;;; then this package will write the file out using the corresponding encoding
  212. ;;; (compression) method. This is done whether or not the buffer originated
  213. ;;; from a previously encoded (compressed) file.
  214. ;;;
  215. ;;; Thus, if the user is editing a file that may or may not have been encoded
  216. ;;; originally (e.g., foobar.Z or foobar) and decides to write it to a
  217. ;;; different file (e.g., barfoo or barfoo.z or barfoo.C).  This package will
  218. ;;; examine the filename extension and write the buffer in plain format or an
  219. ;;; alternate encoding (compression) format by searching through the entries
  220. ;;; in the table of encoding methods `crypt-encoding-alist.'  This change in
  221. ;;; encoding state is done automatically if the variable
  222. ;;; `crypt-auto-write-buffer' is t otherwise the user is asked.
  223.  
  224.  
  225. ;;; TO DO/KNOWN BUGS/HELP WANTED/APPLY WITHIN: 
  226. ;;; 
  227. ;;; All Users/hackers out there are strongly encouraged to pursue any of these
  228. ;;; matters further (especially those that concern encryption and decryption!).
  229. ;;; It is important to future programmers and modifiers of crypt++.el to know
  230. ;;; about its perceived limitations.  Since necessity drives invention, users
  231. ;;; who find any of the following features of crypt++.el annoying are asked to
  232. ;;; make suggestions and send patches (again, especially those that concern
  233. ;;; encryption and decryption!).
  234. ;;; 
  235. ;;; * currently crypt++ assumes that if a file is both encrypted and encoded
  236. ;;;   (i.e., compressed) that the order in which it was done was encryption
  237. ;;;   first _then_ compression.  As has been pointed by many people compression
  238. ;;;   following encryption is useless since the encrypted file is basically
  239. ;;;   random.  On the other hand, many agree that doing encryption _following_
  240. ;;;   compression is better since it makes it harder to crack the encryption.
  241. ;;;   We would like to make the ordering of these two user-configurable or if
  242. ;;;   nothing else change the order.
  243. ;;; 
  244. ;;;   Having read the above however, Francois Pinard <pinard@iro.umontreal.ca> 
  245. ;;;   writes that encryption following compression may not be harder to crack 
  246. ;;;   since "the fact that the first few uncrypted bytes are expected (the 
  247. ;;;   compress signature) facilitates a serious attempt at uncrypting." 
  248. ;;;   jwz agrees with Francois.
  249. ;;; 
  250. ;;; * get insert-file, write-region, and append-to-file to handle encoded and 
  251. ;;;   encrypted files.  There is a test version of crypt++-insert.el available
  252. ;;;   at roebling.poly.edu as well as an interesting low-level encoding package
  253. ;;;   by Jay Adams <jka@ece.cmu.edu> called jka-compr.el which might address
  254. ;;;   some of these issues.  crypt++-insert will ultimately be incorporated
  255. ;;;   into crypt++.  We encourage hackers out there to come up with crypt++
  256. ;;;   versions of write-region and append-to-file.  The difficulty is creating
  257. ;;;   versions that mimic the originals as closely as possible.
  258. ;;;
  259. ;;; * instead of using call-process-region (which can fail badly if the region 
  260. ;;;   is large and there's not much room in /tmp), write the region to a temp 
  261. ;;;   file (with a customisable location) and use call-process directly.
  262. ;;;
  263. ;;; * users have mentioned trouble using crypt++ and hilit simultaneously since 
  264. ;;;   the functions in write-file-hook for both write the file to disk and
  265. ;;;   return `t'.  A possible solution is to have one of them write to a
  266. ;;;   scratch buffer instead of to disk and return `nil' and then allow the
  267. ;;;   other to do its work on the scratch buffer and write it to disk.  Thanks
  268. ;;;   to Wayne Folta <folta@cs.UMD.EDU> and Amir J Katz <amir@matis.ingr.com>.
  269. ;;;   It would be nice to have another way in emacs to have an
  270. ;;;   after-write-file-hook and a before-write-file-hook of some sort.
  271. ;;;   Lucid Emacs has an after-write-file-hook.
  272. ;;;  
  273. ;;; * another possible source of trouble is with encryption (and encoding) 
  274. ;;;   programs sticking verbose output into buffers prior to being written to
  275. ;;;   disk.  This was definitely occurring with gzip because of --verbose in
  276. ;;;   the GZIP environment variable and is solved/hidden with the --quiet
  277. ;;;   switch.  However, I suspect that some encryption problems out there are
  278. ;;;   capable of similar things so the user should be careful.
  279. ;;; 
  280. ;;; * integrating crypt++ with a backgrounding package such as Olin Shivers' 
  281. ;;;   `background.el' might be useful too.  thanks to Mark Borges 
  282. ;;;   <mdb@noaacrd.Colorado.EDU> for suggesting this.
  283. ;;; 
  284. ;;; * performing `(crypt-encode-buffer)' or `(crypt-encrypt-buffer)' and then 
  285. ;;;   saving the file may cause errors.  it is better to toggle
  286. ;;;   `(crypt-encoded-mode)' (or `(crypt-encrypted-mode)') and simply save the
  287. ;;;   file.  it is for this reason that `(crypt-encode-buffer)' and
  288. ;;;   `(crypt-encrypt-buffer)' are not interactive.
  289. ;;; 
  290. ;;; * use plists instead of alists replacing calls to `nth' with `get' 
  291. ;;; 
  292. ;;; * merge encryption code completely into encoding code making encryption
  293. ;;;   just a special case of encoding.
  294.  
  295.  
  296. ;;; Change log:
  297. ;;;  
  298. ;;; 1.1 - original version of crypt.el
  299. ;;; 1.2 -
  300. ;;;   jwz: works with tar-mode.el
  301. ;;;   jwz: applied patch from piet, merged with Lawrence Dodd's gzip version
  302. ;;; 1.3 -
  303. ;;;   lrd: fixed compress-magic-regexp 
  304. ;;; 1.4, 1.5, 1.6 -
  305. ;;;   lrd: write-file compresses or gzips based on file extension
  306. ;;; 2.1 -
  307. ;;;   lrd: merged with Rod Whitby's table-driven version (major upgrade)
  308. ;;; 2.2 -
  309. ;;;   rjw: Changed file name to crypt++.el, so archie and lispdir can find it.
  310. ;;; 2.3 -
  311. ;;;   rjw: Separated the hook additions and minor mode alist additions.
  312. ;;; 2.4 -
  313. ;;;   rjw: Fixed the interactive form for crypt-buffer.
  314. ;;; 2.5 - 
  315. ;;;   lrd: doc mods, changed GNU free software notice (was out of date), added 
  316. ;;;   anonymous ftp information
  317. ;;; 2.6 - 
  318. ;;;   lrd: added back in definition of `buffer' in defun crypt-buffer caused 
  319. ;;;   an error when trying to read encrypted file; modified check for minor 
  320. ;;;   mode alist addition; added gzip magic number warning
  321. ;;; 2.7 - [posted to gnu.emacs.sources]
  322. ;;;   lrd: added `TO DO' and `KNOW BUGS' section to header 
  323. ;;; 2.8 - 
  324. ;;;   lrd: added note about updating to v 1.24 of tar-mode.el
  325. ;;;   Thanks to Mark Borges <mdb@noaacrd.Colorado.EDU>
  326. ;;; 2.9 -
  327. ;;;   lrd: moved query about `crypt-freeze-vs-fortran' out of defvar for
  328. ;;;   `crypt-encoding-alist,' an erroneous value of `nil' was being stuck into
  329. ;;;   alist when user set `crypt-freeze-vs-fortran' was nil, doc mod.
  330. ;;;   Thanks to Mark Borges <mdb@noaacrd.Colorado.EDU>
  331. ;;; 2.10 -
  332. ;;;   rjw: moved query about `crypt-freeze-vs-fortran' back into defvar for
  333. ;;;   `crypt-encoding-alist,' - used append to ignore the erroneous `nil'.
  334. ;;; 2.11 -
  335. ;;;   rjw: fixed a bug in my fix :-(
  336. ;;; 2.12 -
  337. ;;;   rjw: Defvar crypt-magic-regexp and crypt-magic-regexp-inverse and
  338. ;;;   allow either a regexp or an elisp expression.
  339. ;;;   Suggested by Franc,ois Pinard <pinard@iro.umontreal.ca>.
  340. ;;; 2.13 - 
  341. ;;;   lrd: added in info on lispdir.el, doc mods and some puttering while 
  342. ;;;   looking over rjw's v 2.12 mods.
  343. ;;; 2.14 - 
  344. ;;;   lrd: doc mod - trivial huh? switched `compact' and  `gzip' in 
  345. ;;;   `crypt-encoding-alist' - want gzip near top
  346. ;;; 2.15 - 
  347. ;;;   lrd: added in LCD Archive Entry and modified comments on tar-mode.el 
  348. ;;;   since the version at the elisp-archive now works with crypt++.el
  349. ;;; 2.16 - 
  350. ;;;   lrd: provide `crypt' as well as `crypt++' allowing something like `ln -s 
  351. ;;;   crypt++.el crypt.el' to be meaningful 
  352. ;;;   Suggested (by|as) Per Abrahamsen <amanda@iesd.auc.dk>
  353. ;;; 2.17 -
  354. ;;;   lrd: clarified bug report procedure, added fancy pseudo-graphics, added 
  355. ;;;   to the `TO DO' list, put RCS tags in LCD Archive entry
  356. ;;; 2.18 - [posted to gnu.emacs.sources]
  357. ;;;   lrd: included pointer to elisp archive in crypt-version description,
  358. ;;;   changed "Decode buffer %s? " to "Decode %s? " in crypt-find-file-hook 
  359. ;;;   to be more general (mainly for crypt-insert-file)
  360. ;;; 2.19 -
  361. ;;;   rjw: Added the crypt-compact-vs-C++ switch to distinguish compacted and
  362. ;;;   C++ files.
  363. ;;; 2.20 -
  364. ;;;   lrd: (1) modified interactive form of crypt-buffer. (2) made search 
  365. ;;;   case-insensitive in crypt-submit-report. (3) modified encoded-mode and 
  366. ;;;   crypt-mode so that buffer-modified is not unconditionally set to `nil' 
  367. ;;;   when the mode is not changed. Thanks to Gerd Hillebrand 
  368. ;;;   <ggh@cs.brown.edu> for suggesting (2) and (3).
  369. ;;; 2.21 -
  370. ;;;   rjw: Added an entry to the TODO list about the hazards of using
  371. ;;;   call-process-region on a large region and not much room in /tmp
  372. ;;;   (David Carlisle <carlisle@computer-science.manchester.ac.uk>).
  373. ;;; 2.22 - 
  374. ;;;   lrd: allow write-file-hooks to contain functions as well as lists. 
  375. ;;;   Contributed by Ken Laprade <laprade@trantor.harris-atd.com>.
  376. ;;; 2.23 - 
  377. ;;;   lrd: made crypt-submit-report list values of more user-defined variables
  378. ;;; 2.24 - 
  379. ;;;   lrd: pass the -q switch to gzip to thwart the possibility of a --verbose
  380. ;;;   in the GZIP environment variable
  381. ;;; 2.25 -
  382. ;;;   lrd: added some more to the TO DO list, clarified some things, also 
  383. ;;;   untabified the entire file (I got tired of the control I's) 
  384. ;;; 2.26 - 
  385. ;;;   lrd: use the long-named options for GNU zip (self-documenting)
  386. ;;; 2.27 - 
  387. ;;;   lrd: included observation by Francois Pinard <pinard@iro.umontreal.ca> 
  388. ;;;   and worked on text in TO DO/KNOWN BUGS list
  389. ;;; 2.28 - 
  390. ;;;   lrd: added two new variables in (crypt-submit-report) to the list stuck
  391. ;;;   at the bottom of the mail message; changed the comments regarding the 
  392. ;;;   user-defined variables.  added in default values in user defined 
  393. ;;;   variables.  added to and removed stuff to the `TO DO' list.
  394. ;;;
  395. ;;;   (encoded-mode): 
  396. ;;;   added in code to remove any auto-save-files that may have been formed
  397. ;;;   before becoming an encoded buffer (for example a plain file saved to
  398. ;;;   disk encoded had orphan auto-save-files left behind).  turning off
  399. ;;;   auto-save-mode disables the creation of auto-save-files, but it also 
  400. ;;;   disables the possibility of these being removed when the buffer is 
  401. ;;;   saved.
  402. ;;; 
  403. ;;;   (crypt-region): 
  404. ;;;   now call the encryption and decryption program directly instead of
  405. ;;;   through the shell.  this is more secure since the shell will expose the
  406. ;;;   password (key).  thanks to Jon Cargille <jcargill@cs.wisc.edu>.  defined
  407. ;;;   two new variables `crypt-decryption-args' and `crypt-encryption-args' to
  408. ;;;   take the arguments separately.  removed (let ((opoint)...)) construct 
  409. ;;;   this was a throw back to some old dead code and was not being used.
  410. ;;; 2.29 - 
  411. ;;;   lrd: added three new variables in (crypt-submit-report); added to the 
  412. ;;;   `TO DO' list.
  413. ;;;  
  414. ;;;   (encode-region,encode-buffer,encoded-mode): fixed interactive forms -
  415. ;;;   the conversion to table version had eliminated some of the interactive
  416. ;;;   features of these.  thanks to Kimball Collins <kpc@ptolemy.arc.nasa.gov>
  417. ;;;   for point this out.  new interactive form uses functions
  418. ;;;   `crypt-get-encoding-type' and `crypt-symbol-alist-to-table' and variable
  419. ;;;   `crypt-default-encoding' to generate completion list of encoding types.
  420. ;;; 
  421. ;;;   (crypt-write-file-hook): two new user-defined variables
  422. ;;;   `crypt-query-if-interactive' and `crypt-no-extension-implies-plain' and
  423. ;;;   the buffer-local variable `buffer-interactive-mode' are used to help
  424. ;;;   determined whether or not plain output is really desired for files
  425. ;;;   without a compression file-name extension.  the default behavior is the
  426. ;;;   same as before.
  427. ;;; 2.30 - 
  428. ;;;   lrd: added test for user-defined variable `crypt-never-ever-decrypt' 
  429. ;;;   when finding a file.  some users may never wish to decrypt files 
  430. ;;;   and like to edit binary files.  thanks to Nelson Minar 
  431. ;;;   <nelson@reed.edu>.  added to doc-strings of 
  432. ;;;   `crypt-magic-regexp[-inverse]' -- these can be set to `nil[t]' and 
  433. ;;;   accomplish the same thing as setting `crypt-never-ever-decrypt' to `t'
  434. ;;; 2.31 - 
  435. ;;;   rjw: Updated the comments in the encryption check section.
  436. ;;; 2.32 - [posted to gnu.emacs.sources]
  437. ;;;   lrd: added warning about `crypt-(de|en)cryption-program'; doc mod.
  438. ;;; 2.33 - 
  439. ;;;   lrd: if `crypt-(de|en)cryption-args' are `nil' then don't pass any
  440. ;;;   arguments to (de|en)cryption program, `nil' is the default instead of
  441. ;;;   "".  Thanks to Joe Ilacqua <spike@world.std.com>, David J. Schur
  442. ;;;   <djs@idm.com>, Peter Nuth <nuth@ai.mit.edu>, and Greg Larson 
  443. ;;;   <glarson@bnr.ca>.  `-q' exists in gzip 1.0.3 but not `--quiet' changed 
  444. ;;;   GZIP NOTE.  Thanks to Chris Moore <moore@src.bae.co.uk>.
  445. ;;; 2.34 - 
  446. ;;;   lrd: allow `crypt-(de|en)cryption-args' to be a list of strings -- more
  447. ;;;   robust.  query for password (key), if none is set, when writing out file
  448. ;;;   for which `buffer-save-encrypted' is `t.'  Thanks to John Interrante
  449. ;;;   <interran@uluru.Stanford.EDU>.  (crypt-write-file-hook): check filename
  450. ;;;   extension against regexp `crypt-encryption-file-extension' and query for
  451. ;;;   encryption, unless `crypt-auto-write-buffer-encrypted' is `t' (don't
  452. ;;;   bother doing reverse check, encrypted to plain, not a common request).
  453. ;;;   (crypt-mode): delete auto-save files (cf., encoded-mode), may exist now.
  454. ;;;   (read-string-no-echo): applied patch from Piet van Oostrum
  455. ;;;   <piet@cs.ruu.nl> -- set `cursor-in-echo-area' _after_ setting buffer
  456. ;;;   (this was screwing up gnews).
  457. ;;; 2.35 - 
  458. ;;;   lrd: doc mod
  459. ;;; 2.36 - 
  460. ;;;   lrd: fixed typo, added RMAIL note.
  461. ;;; 2.37 - [posted to gnu.emacs.sources]
  462. ;;;   lrd: 
  463. ;;;   (crypt-write-file-hook): search user-defined list
  464. ;;;   `crypt-ignored-filenames' for possible match with `buffer-filename'
  465. ;;;   before attempting conversion from compressed to plain format; useful for
  466. ;;;   compressed incoming mail files (e.g., RMAIL, INBOX).
  467. ;;;  
  468. ;;;   (crypt-mode): query for key if not set already; need to switch order of
  469. ;;;   recovering key and toggling crypt-mode in crypt-find-file-hook (thanks
  470. ;;;   to Piet van Oostrum <piet@cs.ruu.nl>).
  471. ;;;  
  472. ;;;   (crypt-buffer) and (encode-buffer): remove interactive form; use
  473. ;;;   (crypt-mode) and (encoded-mode) instead so encryption and compression
  474. ;;;   are done at the very end; leave interactive form in (crypt-region) and
  475. ;;;   (encode-region) may still be used.
  476. ;;;  
  477. ;;;   (set-encryption-key): remove from `command-history' if called
  478. ;;;   interactively - thanks to George M. Georgiou
  479. ;;;   <georgiou@silicon.csci.csusb.edu>.
  480. ;;; 2.38 - 
  481. ;;;   lrd: added `crypt-' prefix to `(read-string-no-echo)' and `(save-point)'
  482. ;;;   changed file extension for gzip files to `.z' _or_ `.gz' (future release
  483. ;;;   of gzip with use later extension by default and so this should be
  484. ;;;   changed to just `.gz' someday).
  485. ;;; 2.39 - 
  486. ;;;   lrd: doc mod. added in patch from jwz - `(crypt-read-string-no-echo)' is
  487. ;;;   more secure, put property 'permanent-local on buffer-locals works for
  488. ;;;   Lucid Emacs and doesn't harm v18 emacs, change `buffer-interactive-mode'
  489. ;;;   to `buffer-interactive-encoded-mode.'
  490. ;;; 2.40 - 
  491. ;;;   lrd: put property 'preserved in case kill-fix.el is being used.
  492. ;;; 2.41 - 
  493. ;;;   lrd: all functions and variables now start with `crypt-', moved REVISION
  494. ;;;   HISTORY to bottom of header, interactive version of
  495. ;;;   `(crypt-encrypt-region)' clearer, `(crypt-read-string-no-echo)' now
  496. ;;;   echos `.'
  497. ;;; 2.42 -
  498. ;;;   lrd: (crypt-check-extension-for-encoding): broke out of
  499. ;;;   `(crypt-write-file-hook)'.  setting user variables
  500. ;;;   `crypt-compact-vs-C++' and `crypt-freeze-vs-fortran' to `nil' no longer
  501. ;;;   completely disables the reading compact'ed and frozen files but just
  502. ;;;   disables the use of the file-extension tricks of
  503. ;;;   `(crypt-check-extension-for-encoding).'  (crypt-encode-region): allow
  504. ;;;   for a single line message from encoding program at top of region; if it
  505. ;;;   is there, then remove it; kludge for `compact' program.
  506. ;;; 2.43 - 
  507. ;;;   lrd: (crypt-encode-region): generalize the clean up procedure; add
  508. ;;;   element to `crypt-encoding-alist' and introduce new function
  509. ;;;   `(crypt-encoding-cleanup-regexp)' to extract a compression specific
  510. ;;;   regexp for erroneous message or lisp expression for cleanup.
  511. ;;; 2.44 - 
  512. ;;;   lrd: new element for `crypt-encoding-alist' handles whether or not
  513. ;;;   file-name extension tricks may be play with encoding method; compact and
  514. ;;;   freeze values default to `crypt-compact-vs-C++' and
  515. ;;;   `crypt-freeze-vs-fortran' (thanks to rjw);
  516. ;;;   (crypt-encoding-extension-tricks): new defun to handle this;
  517. ;;;   (crypt-check-extension-for-encoding): monitors "tricks" entry of
  518. ;;;   `crypt-encoding-alist' and adjust the bag of tricks it can apply.
  519. ;;; 2.45 - 
  520. ;;;   lrd: (crypt-encode-region): delete entire match of cleanup regexp by
  521. ;;;   requiring newlines in GARBAGE-REGEXP-OR-LISPEXP.  (crypt-submit-report):
  522. ;;;   use Warsaw's reporter.el.
  523. ;;; 2.46 -
  524. ;;;   lrd: (crypt-find-file-hook, crypt-write-file-hook): cleaned, documented,
  525. ;;;   and replaced occurrences of `(cond (C BODY))' with `(if C BODY)';
  526. ;;;   changed `crypt-magic-regexp' to `crypt-encryption-magic-regexp' and
  527. ;;;   `crypt-magic-regexp-inverse' to `crypt-encryption-magic-regexp-inverse'
  528. ;;;   for consistency with other variable names. new user-defined variable
  529. ;;;   `crypt-encryption-minor-mode-name' instead of always "Crypt".  grouped
  530. ;;;   all encryption variables together.
  531. ;;; 2.47 - 
  532. ;;;   lrd: somewhat major change - put program-specific encryption variables
  533. ;;;   into a single table `crypt-encryption-alist' and let the variable
  534. ;;;   `crypt-encryption-type' define the appropriate entry to use; new
  535. ;;;   user-defined variable `crypt-confirm-password,' thanks to Jeff Clark
  536. ;;;   <jclark@src.honeywell.com>. (crypt-submit-report): improved error 
  537. ;;;   handling, thanks to baw. (crypt-write-file-hook): fixed bug with 
  538. ;;;   `crypt-encoding-extension-tricks'
  539. ;;; 2.48 - 
  540. ;;;   lrd: added dummy argument to `crypt-encoding-alist' and
  541. ;;;   `crypt-encryption-alist' and merged all defuns that work on their
  542. ;;;   elements into defuns that all start with `crypt-get-' and look through
  543. ;;;   both lists.  simplifies some of code and closer to treating encryption
  544. ;;;   as a special case of encoding; crypt-minor-mode-alist: replaced (nth *)
  545. ;;;   with `(crypt-get-minor-mode)' call; (crypt-encode-region): allow
  546. ;;;   arguments to be list of strings; renamed (crypt-get-encoding-type) to
  547. ;;;   (crypt-read-encoding-type) for clarity.
  548. ;;; 2.49 - [posted to gnu.emacs.sources]
  549. ;;;   lrd: (crypt-encode-region): ignore `args' if set to `t'
  550. ;;; 2.50 - 
  551. ;;;   lrd: (crypt-write-file-hook): in v19 we need to call `backup-buffer'
  552. ;;;   ourselves -- we write out the file and return `t' so `basic-save-buffer'
  553. ;;;   does not do it; also call `set-file-modes'
  554. ;;; 2.51 -
  555. ;;;   lrd: some `defvar's are now `defconst's and tar-mode note was changed.
  556. ;;; 2.52 - 
  557. ;;;   lrd: make doc strings conform to GNU standards.
  558. ;;; 2.53 - 
  559. ;;;   lrd: made header conform to GNU Conventional Headers standard.
  560.  
  561.  
  562. ;;; Code:
  563.  
  564. ;;;; user definable variables
  565.  
  566. (defvar crypt-encryption-type 'crypt
  567.   "*method of encryption.  must be an element of `crypt-encryption-alist.'
  568. default: 'crypt")
  569.  
  570. (defvar crypt-encryption-file-extension nil
  571.   "*regexp for extension of files encrypted with `crypt-encryption-type.'
  572. nil says use default values in `crypt-encryption-alist.'  see
  573. `crypt-encryption-alist.'  default: nil")
  574.  
  575. (defvar crypt-never-ever-decrypt nil
  576.   "*t says never attempt to decrypt a buffer.  default: nil")
  577.  
  578. (defvar crypt-auto-write-buffer-encrypted nil
  579.   "*t says files with `crypt-encryption-alist' file extension auto-encrypted.
  580. nil says query.  see `crypt-auto-write-buffer.'  default: nil")
  581.  
  582. (defvar crypt-confirm-password nil
  583.   "*t says confirm news passwords and when writing a newly encrypted buffer.
  584. default: nil")
  585.  
  586. ;;; ENCRYPTION
  587.  
  588. ;;; Encrypted files have no magic number, so we have to hack a way of
  589. ;;; determining when a buffer should be decrypted.  we do this only buffers
  590. ;;; that match a MAGIC-REGEXP very close to beginning of buffer and that do
  591. ;;; _NOT_ match a MAGIC-REGEXP-INVERSE.
  592. ;;;  
  593. ;;; Currently MAGIC-REGEXP matches non-ASCII characters and
  594. ;;; MAGIC-REGEXP-INVERSE will match Sun OS, 4.x BSD, and Ultrix executable
  595. ;;; magic numbers, so binaries can still be edited (heh) without headaches.
  596.  
  597. (defconst crypt-encryption-magic-regexp "[\200-\377]"
  598.   "regexp that must be found very close to beginning of encrypted buffer.
  599. this is intended to be an internal variable (not user-visible).")
  600.  
  601. (defconst crypt-encryption-magic-regexp-inverse
  602.   "^\\(..\\)?\\([\007\010\013]\001\\|\001[\007\010\013]\\)"
  603.   "regexp that must *not* be found very close to beginning of encrypted buffer.
  604. this is intended to be an internal variable (not user-visible).")
  605.  
  606. (defconst crypt-encryption-alist
  607.   (list
  608.    ;; crypt
  609.    (list 'crypt
  610.          crypt-encryption-magic-regexp crypt-encryption-magic-regexp-inverse
  611.          (or crypt-encryption-file-extension "\\.e$")
  612.          "crypt" "crypt"
  613.          nil
  614.          nil
  615.          "Crypt"
  616.          nil
  617.          t
  618.          )
  619.    ;; DES (Cipher Block Chaining - CBC) [DES' default]
  620.    (list 'des
  621.          crypt-encryption-magic-regexp crypt-encryption-magic-regexp-inverse
  622.          (or crypt-encryption-file-extension "\\.des$")
  623.          "des" "des"
  624.          '("-e" "-k")
  625.          '("-d" "-k")
  626.          "DES-CBC"
  627.          nil
  628.          t
  629.          )
  630.    ;; DES (Electronic Code Book - ECB)
  631.    (list 'des-ecb
  632.          crypt-encryption-magic-regexp crypt-encryption-magic-regexp-inverse
  633.          (or crypt-encryption-file-extension "\\.des$")
  634.          "des" "des"
  635.          '("-e" "-b" "-k")
  636.          '("-d" "-b" "-k")
  637.          "DES-ECB"
  638.          nil
  639.          t
  640.          )
  641.    ;; PGP
  642.    (list 'pgp
  643.          crypt-encryption-magic-regexp crypt-encryption-magic-regexp-inverse
  644.          (or crypt-encryption-file-extension "\\.pgp$")
  645.          "pgp" "pgp"
  646.          '("+batchmode" "+verbose=0" "-c" "-f" "-z")
  647.          '("+batchmode" "+verbose=0" "-f" "-z")
  648.          "PGP"
  649.          nil
  650.          t
  651.          )
  652.    ;; Add new elements here ...
  653.    )
  654.  
  655.   "list of elements describing the encryption methods available.
  656. each element looks like
  657.  
  658.         \(ENCRYPTION-TYPE
  659.           MAGIC-REGEXP MAGIC-REGEXP-INVERSE
  660.           FILE-EXTENSION
  661.           ENCRYPT-PROGRAM DECRYPT-PROGRAM
  662.           ENCRYPT-ARGS
  663.           DECRYPT-ARGS
  664.           MINOR-MODE
  665.           GARBAGE-REGEXP-OR-LISPEXP
  666.           FILE-EXTENSION-TRICKS
  667.          \)
  668.  
  669. ENCRYPTION-TYPE is a symbol denoting the encryption type.
  670.  
  671. MAGIC-REGEXP regexp that must match very close to the beginning of an
  672. encrypted buffer.  This may also be some elisp expression to be evaluated at
  673. \(point-min\) that will return `t' for an encrypted buffer.  If this is set to
  674. `nil' then crypt++ will never try to decrypt a buffer.  Currently set to the
  675. internal variable `crypt-encryption-magic-regexp' which will match non-ASCII
  676. characters.
  677.  
  678. MAGIC-REGEXP-INVERSE regexp that must _NOT_ match very close to the beginning
  679. of an encrypted buffer.  This may also be some elisp expression to be
  680. evaluated at \(point-min\) that will return `t' for a NON-encrypted buffer.
  681. If this is set to `t' then crypt++ will never try to decrypt a buffer.
  682. Currently set to the internal variable `crypt-encryption-magic-regexp-inverse'
  683. which will match Sun OS, 4.x BSD, and Ultrix executable magic numbers, so
  684. binaries can still be edited (heh) without headaches.
  685.  
  686. FILE-EXTENSION regexp denoting the file extension usually appended the
  687. filename of files encrypted with ENCRYPT-PROGRAM.  The variable
  688. `crypt-encryption-file-extension' will over ride the default.
  689.  
  690. ENCRYPT-PROGRAM name of executable file to be used for encryption.
  691.  
  692. DECRYPT-PROGRAM name of executable file to be used for decryption.
  693.  
  694. ENCRYPT-ARGS arguments to be passed to ENCRYPT-PROGRAM may be a string or a
  695. list of strings or `nil.'
  696.  
  697. DECRYPT-ARGS arguments to be passed to DECRYPT-PROGRAM may be a string or a
  698. list of strings or `nil.'
  699.  
  700. MINOR-MODE string denoting the name for the encrypted minor mode as it will
  701. appear in the mode line.
  702.  
  703. GARBAGE-REGEXP-OR-LISPEXP dummy variable for compatibility with encoding.
  704.  
  705. FILE-EXTENSION-TRICKS is t or nil depending on whether or not tricks
  706. converting between different encryption types can be done based on
  707. FILE-EXTENSION; typically t.
  708. ")
  709.  
  710.  
  711. ;;; ENCODING 
  712.  
  713. (defvar crypt-auto-decode-buffer t
  714.   "*t says buffers visiting encoded files will be decoded automatically.
  715. nil means to ask before doing the decoding.  default: t")
  716.  
  717. (defvar crypt-auto-write-buffer nil
  718.   "*t says save files with `crypt-encoding-alist' file extensions as encoded.
  719. nil says to ask before doing this encoding.  similarly, buffers originating
  720. >from encoded files to be written to files not ending in `crypt-encoding-alist'
  721. file extensions will be written in plain format automatically.  nil says to
  722. ask before doing this decoding.  default: nil")
  723.  
  724. (defvar crypt-query-if-interactive t
  725.   "*t says ask when saving buffers where `crypt-encoded-mode' was toggled.
  726. nil says that even if filename extension is plain (i.e., not listed in
  727. `crypt-encoding-alist') buffer will be written in an encoded format without
  728. asking.  default: `t'
  729.  
  730. This variable is designed for users that edit a plain file (with plain
  731. extension) and then toggle `(crypt-encoded-mode)' and do not wish to be
  732. queried every time that they save the buffer.
  733.  
  734. NOTE: if `(crypt-encoded-mode)' was not called interactively (the usual
  735. scenario) then the value of this variable has no effect on how the buffer is
  736. written to disk.  In such a case `crypt-no-extension-implies-plain' is then
  737. the relevant variable.")
  738.  
  739. (defvar crypt-no-extension-implies-plain t
  740.   "*t says file extensions not in `crypt-encoding-alist' may be written plain.
  741. if `crypt-auto-write-buffer' is also t then any file ending in a plain
  742. extension is written in plain format automatically, otherwise query user.
  743. default: t
  744.  
  745. nil says user works with encoded (compressed) files without file extensions
  746. and will not be queried each time they save these files.
  747.  
  748. NOTE: (1) this does not effect find-file (C-x C-f) since that works with a
  749. magic regexp.  (2) there is no way to distinguish between write-file and
  750. save-buffer so nil will mean that neither will query.")
  751.  
  752. (defvar crypt-freeze-vs-fortran t
  753.   "*t says `.F' file extension denotes a frozen file not a Fortran file.
  754. default: t")
  755.  
  756. (defvar crypt-compact-vs-C++ nil
  757.   "*t says `.C' file extension denotes a compacted file not a C++ file.
  758. default: nil")
  759.  
  760. (defvar crypt-ignored-filenames nil
  761.   "*list of regexp filenames for which encoded to plain conversion is not done.
  762. a filename with a plain extension, in encoded format, that is matched by one of
  763. these elements will be saved in encoded format without a query for conversion to
  764. plain format.  default: nil
  765.  
  766. This variable is provided for users that want to compress their incoming mail
  767. for RMAIL and VM which look for files `RMAIL' and `INBOX,' respectively, to
  768. store incoming mail.  for example, the gzip extensions on `RMAIL.gz' and
  769. `INBOX.gz' can be removed, this variable set to '\(\"INBOX$\" \"RMAIL$\"\) and
  770. no query about conversion to plain format will be made.")
  771.  
  772. (defvar crypt-default-encoding "gzip"
  773.   "*default encoding type as string used when `crypt-encoded-mode' is toggled.
  774. must match one of the elements of `crypt-encoding-alist'  default: \"gzip\"")
  775.  
  776. (defconst crypt-encoding-alist
  777.   (list
  778.    ;; compress 
  779.    (list 'compress
  780.          "\037\235" nil
  781.          "\\(\\.Z\\)$"
  782.          "compress" "uncompress"
  783.          nil nil
  784.          "Compress"
  785.          nil
  786.          t)
  787.    ;; gzip (GNU zip)
  788.    (list 'gzip
  789.          "\037\213" nil
  790.          "\\(\\.g?z\\)$"
  791.          "gzip" "gzip"
  792.          "--quiet" "--decompress --quiet"
  793.          "Zip"
  794.          nil
  795.          t)
  796.    ;; freeze
  797.    (list 'freeze
  798.          "\037\236\\|\037\237" nil
  799.          "\\(\\.F\\)$"
  800.          "freeze" "freeze"
  801.          "" "-d"
  802.          "Freeze"
  803.          nil
  804.          crypt-freeze-vs-fortran)
  805.    ;; compact
  806.    (list 'compact
  807.          "\377\037" nil
  808.          "\\(\\.C\\)$"
  809.          "compact" "uncompact"
  810.          nil nil
  811.          "Compact"
  812.          "^Compression *:.*\n"
  813.          crypt-compact-vs-C++)
  814.    ;; Add new elements here ...
  815.    )
  816.  
  817.   "list of elements describing the encoding methods available.
  818. each element looks like
  819.  
  820.         \(ENCODING-TYPE
  821.           MAGIC-REGEXP MAGIC-REGEXP-INVERSE
  822.           FILE-EXTENSION
  823.           ENCODE-PROGRAM DECODE-PROGRAM
  824.           ENCODE-ARGS DECODE-ARGS
  825.           MINOR-MODE
  826.           GARBAGE-REGEXP-OR-LISPEXP
  827.           FILE-EXTENSION-TRICKS
  828.          \)
  829.  
  830. ENCODING-TYPE is a symbol denoting the encoding type.  Currently known
  831. encodings are (compress compact freeze gzip).
  832.  
  833. MAGIC-REGEXP is a regexp that matches the magic number at the
  834. beginning of files encoded with ENCODING-TYPE.
  835.  
  836. MAGIC-REGEXP-INVERSE dummy variable for compatibility with encryption.
  837.  
  838. FILE-EXTENSION is a string denoting the file extension usually
  839. appended the filename of files encoded with ENCODING-TYPE.
  840.  
  841. ENCODE-PROGRAM is a string denoting the name of the executable used to
  842. encode files.
  843.  
  844. DECODE-PROGRAM is a string denoting the name of the executable used to
  845. decode files.
  846.  
  847. ENCODE-ARGS arguments to be passed to ENCODE-PROGRAM may be a string or a
  848. list of strings or `nil.'
  849.  
  850. DECODE-ARGS arguments to be passed to DECODE-PROGRAM may be a string or a
  851. list of strings or `nil.'
  852.  
  853. MINOR-MODE is a string denoting the name for the encoded minor mode as 
  854. it will appear in the mode line.
  855.  
  856. GARBAGE-REGEXP-OR-LISPEXP is (1) a regexp that matches any extraneous text
  857. that is produced by the ENCODE-COMMAND including any newlines and will be
  858. removed from the buffer before saving to disk; (2) a lisp expression that will
  859. clean up extraneous material in the buffer or nil.  This is normally not
  860. needed but can be derived for any ENCODE-COMMAND by checking the standard
  861. error that results from `sh -c \"cat foo | ENCODE-COMMAND > bar\"'.
  862.  
  863. FILE-EXTENSION-TRICKS is t or nil depending on whether or not tricks
  864. converting between different encoding types can be done based on
  865. FILE-EXTENSION; typically t.
  866. ")
  867.  
  868.  
  869. ;;; buffer locals
  870.  
  871. (defvar crypt-buffer-save-encrypted nil
  872.   "*non-nil says save buffer encrypted with `crypt-encryption-type.'
  873. local to all buffers.")
  874. (make-variable-buffer-local 'crypt-buffer-save-encrypted)
  875. (put 'crypt-buffer-save-encrypted 'permanent-local t) ; for v19 Emacs
  876. (put 'crypt-buffer-save-encrypted 'preserved t)       ; for kill-fix.el
  877.  
  878. (defvar crypt-buffer-encryption-key nil
  879.   "*key used for encryption of current buffer.  local to all buffers.")
  880. (make-variable-buffer-local 'crypt-buffer-encryption-key)
  881. (put 'crypt-buffer-encryption-key 'permanent-local t) ; for v19 Emacs
  882. (put 'crypt-buffer-encryption-key 'preserved t)       ; for kill-fix.el
  883.  
  884. (defvar crypt-buffer-save-encoded nil
  885.   "*non-nil says buffer will be saved encoded.  local to all buffers.")
  886. (make-variable-buffer-local 'crypt-buffer-save-encoded)
  887. (put 'crypt-buffer-save-encoded 'permanent-local t)   ; for v19 Emacs
  888. (put 'crypt-buffer-save-encoded 'preserved t)         ; for kill-fix.el
  889.  
  890. (defvar crypt-buffer-encoding-type nil
  891.   "*non-nil says buffer is encoded with ENCODING-TYPE.  local to all buffers.")
  892. (make-variable-buffer-local 'crypt-buffer-encoding-type)
  893. (put 'crypt-buffer-encoding-type 'permanent-local t)  ; for v19 Emacs
  894. (put 'crypt-buffer-encoding-type 'preserved t)        ; for kill-fix.el
  895.  
  896. (defvar crypt-buffer-interactive-encoded-mode nil
  897.   "t says `crypt-encoded-mode' was toggled interactively, almost always nil.
  898. local to all buffers.")
  899. (make-variable-buffer-local 'crypt-buffer-interactive-encoded-mode)
  900. (put 'crypt-buffer-interactive-encoded-mode 'permanent-local t) ; v19 Emacs
  901. (put 'crypt-buffer-interactive-encoded-mode 'preserved t)       ; kill-fix.el
  902.  
  903.  
  904. ;;; defuns that work on `crypt-encryption-alist' and `crypt-encoding-alist'
  905.  
  906. (defun crypt-get-magic-regexp (type)
  907.   "returns regexp found at top of files encoded/encrypted with TYPE."
  908.   (let ((elt (or (assoc type crypt-encryption-alist)
  909.                  (assoc type crypt-encoding-alist))))
  910.     (and elt
  911.          (nth 1 elt))))
  912.  
  913. (defun crypt-get-magic-regexp-inverse (type)
  914.   "returns regexp *not* found at top of files encoded/encrypted with TYPE."
  915.   (let ((elt (or (assoc type crypt-encryption-alist)
  916.                  (assoc type crypt-encoding-alist))))
  917.     (and elt
  918.          (nth 2 elt))))
  919.  
  920. (defun crypt-get-file-extension (type)
  921.   "returns regexp matching extension of files encoded/encrypted with TYPE."
  922.   (let ((elt (or (assoc type crypt-encryption-alist)
  923.                  (assoc type crypt-encoding-alist))))
  924.     (and elt
  925.          (nth 3 elt))))
  926.  
  927. (defun crypt-get-encoding-program (type)
  928.   "returns name of program, as string, used to encode/encrypt with TYPE."
  929.   (let ((elt (or (assoc type crypt-encryption-alist)
  930.                  (assoc type crypt-encoding-alist))))
  931.     (and elt
  932.          (nth 4 elt))))
  933.  
  934. (defun crypt-get-decoding-program (type)
  935.   "returns name of program, as string, used to decode/decrypt with TYPE."
  936.   (let ((elt (or (assoc type crypt-encryption-alist)
  937.                  (assoc type crypt-encoding-alist))))
  938.     (and elt
  939.          (nth 5 elt))))
  940.  
  941. (defun crypt-get-encoding-args (type)
  942.   "returns arguments passed to program used to encode/encrypt with TYPE."
  943.   (let ((elt (or (assoc type crypt-encryption-alist)
  944.                  (assoc type crypt-encoding-alist))))
  945.     (and elt
  946.          (nth 6 elt))))
  947.  
  948. (defun crypt-get-decoding-args (type)
  949.   "returns arguments passed to program used to decode/decrypt with TYPE."
  950.   (let ((elt (or (assoc type crypt-encryption-alist)
  951.                  (assoc type crypt-encoding-alist))))
  952.     (and elt
  953.          (nth 7 elt))))
  954.  
  955. (defun crypt-get-minor-mode-name (type)
  956.   "returns minor mode name, as string, for encoding/encrypting with TYPE."
  957.   (let ((elt (or (assoc type crypt-encryption-alist)
  958.                  (assoc type crypt-encoding-alist))))
  959.     (and elt
  960.          (nth 8 elt))))
  961.  
  962. (defun crypt-get-cleanup-regexp (type)
  963.   "returns regexp or lisp-exp for cleaning up encoding/encrypting with TYPE."
  964.   (let ((elt (assoc type crypt-encoding-alist)))
  965.     (and elt
  966.          (nth 9 elt))))
  967.  
  968. (defun crypt-get-extension-tricks (type)
  969.   "returns t if file extension tricks doable for encoding/encrypting with TYPE."
  970.   (let ((elt (or (assoc type crypt-encryption-alist)
  971.                  (assoc type crypt-encoding-alist))))
  972.     (and elt
  973.          (nth 10 elt))))
  974.  
  975. (defun crypt-buffer-save-name (type)
  976.   "returns variable `crypt-buffer-save-TYPE', set to t if encoding with TYPE.
  977. local to all buffers."
  978.   (intern (concat "crypt-buffer-save-" (symbol-name type))))
  979.  
  980.  
  981. ;;; Create a buffer-local variable for each type of encoding.
  982. ;;; These variables are used to trigger the minor mode names.
  983.  
  984. (defvar crypt-minor-mode-encrypted
  985.   (list 'crypt-buffer-save-encrypted
  986.         (concat " " (crypt-get-minor-mode-name crypt-encryption-type)))
  987.   "simple minor mode alist entry for encrypted buffers.")
  988.  
  989. (defvar crypt-minor-mode-alist
  990.   (append
  991.    (list crypt-minor-mode-encrypted)
  992.    (mapcar
  993.     (function
  994.      (lambda (element)
  995.        (let ((variable (crypt-buffer-save-name (car element))))
  996.          (make-variable-buffer-local variable)
  997.          (put variable 'permanent-local t) ; for v19 Emacs
  998.          (put variable 'preserved t)       ; for kill-fix.el
  999.          (list variable
  1000.                (concat " " (crypt-get-minor-mode-name (car element)))))))
  1001.     crypt-encoding-alist))
  1002.   "alist containing encoded and encrypted minor modes.
  1003. derived from `crypt-encoding-alist' and `crypt-minor-mode-encrypted'")
  1004.  
  1005.  
  1006. (defmacro crypt-save-point (&rest body)
  1007.   "Save value of point, evaluate FORMS, and restore value of point.
  1008. If the saved value of point is no longer valid go to (point-max).
  1009. This macro exists because, save-excursion loses track of point during
  1010. some types of deletions."
  1011.   (let ((var (make-symbol "saved-point")))
  1012.     (list 'let (list (list var '(point)))
  1013.           (list 'unwind-protect
  1014.                 (cons 'progn body)
  1015.                 (list 'goto-char var)))))
  1016.  
  1017.  
  1018. (defun crypt-find-file-hook ()
  1019.  
  1020.   "Hook run for decoding and/or decrypting the contents of a buffer.
  1021. meant to be called as part of `find-file-hooks'"
  1022.  
  1023.   (let ((alist crypt-encoding-alist)
  1024.         (buffer-file-name buffer-file-name)
  1025.         (old-buffer-file-name buffer-file-name)
  1026.         (old-buffer-modified-p (buffer-modified-p))
  1027.         (case-fold-search nil)
  1028.         found elt regexp encrypted encoded buffer-read-only)
  1029.  
  1030.     ;; DECODE AND/OR DECRYPT
  1031.     (crypt-save-point
  1032.  
  1033.      (save-restriction
  1034.        (widen)
  1035.        (goto-char (point-min))
  1036.  
  1037.        ;; DECODE
  1038.  
  1039.        ;; We can reasonably assume that only one type of compression method
  1040.        ;; will be used
  1041.  
  1042.        ;; find the type of compression
  1043.  
  1044.        (while (and alist (setq elt (car alist)) (not found))
  1045.          (if (looking-at (nth 1 elt))
  1046.              (setq crypt-buffer-encoding-type (nth 0 elt)
  1047.                    found t)
  1048.            ;; decrement 
  1049.            (setq alist (cdr alist))))
  1050.  
  1051.        ;; do we have to decode? if not move on
  1052.        (if (and found 
  1053.                 (or crypt-auto-decode-buffer
  1054.                     (y-or-n-p (format "Decode %s? " (buffer-name)))))
  1055.  
  1056.            (progn
  1057.  
  1058.              ;; decode (uncompress) the buffer
  1059.              (message "Decoding %s..." (buffer-name))
  1060.              (crypt-encode-buffer (current-buffer) t)
  1061.  
  1062.              ;; We can not actually go into encoding minor mode yet because
  1063.              ;; the major mode may change later on and blow away all local
  1064.              ;; variables (and thus the minor modes).  So we make a note to go
  1065.              ;; into encoding mode later.
  1066.  
  1067.              ;; Note: this is only needed if using vanilla v18 since crypt++'s
  1068.              ;; buffer-locals are now 'permanent-local in v19 Emacs and 
  1069.              ;; 'preserved in v18 with kill-fix.el
  1070.  
  1071.              (setq encoded crypt-buffer-encoding-type)
  1072.  
  1073.              ;; here we strip the encoded file's extension so that later we
  1074.              ;; can set the buffer's major mode based on this modified name
  1075.              ;; instead of the name with the extension.
  1076.  
  1077.              (if (string-match
  1078.                   (crypt-get-file-extension crypt-buffer-encoding-type)
  1079.                   buffer-file-name)
  1080.                  (setq buffer-file-name
  1081.                        (substring buffer-file-name 0 (match-beginning 1))))
  1082.  
  1083.              ;; decoding ends
  1084.              (if (not (input-pending-p))
  1085.                  (message "Decoding %s... done" (buffer-name)))))
  1086.  
  1087.        ;; DECRYPTION 
  1088.  
  1089.        ;; Now peek at the file and see if it still looks like a binary file.
  1090.        ;; If so it may be encrypted still.  
  1091.  
  1092.        ;; look for MAGIC-REGEXP and the absence of MAGIC-REGEXP-INVERSE if
  1093.        ;; both return true then we assume that this is an encrypted buffer.
  1094.        
  1095.        (if (and
  1096.  
  1097.             (not (eobp))
  1098.             
  1099.             ;; Check for existence of MAGIC-REGEXP
  1100.             (let ((magic-regexp
  1101.                    (crypt-get-magic-regexp crypt-encryption-type)))
  1102.               (if (stringp magic-regexp)
  1103.                   ;; regular expression
  1104.                   (re-search-forward magic-regexp (min (point-max) 15) t)
  1105.                 ;; lisp expression
  1106.                 (eval magic-regexp)))
  1107.             
  1108.             (goto-char (point-min))
  1109.             
  1110.             ;; Check for absence of MAGIC-REGEXP-INVERSE
  1111.             (let ((magic-regexp-inverse
  1112.                    (crypt-get-magic-regexp-inverse crypt-encryption-type)))
  1113.               (not
  1114.                (if (stringp magic-regexp-inverse)
  1115.                    ;; regular expression
  1116.                    (re-search-forward magic-regexp-inverse
  1117.                                       (min (point-max) 15) t)
  1118.                  ;; lisp expression
  1119.                  (eval magic-regexp-inverse))))
  1120.             
  1121.             ;; shut off crypt mode if `crypt-never-ever-decrypt' is `t' -
  1122.             ;; thanks to Nelson Minar <nelson@reed.edu>.  this is equivalent
  1123.             ;; to user setting MAGIC-REGEXP to `nil' and/or
  1124.             ;; MAGIC-REGEXP-INVERSE to `t'
  1125.             
  1126.             (not crypt-never-ever-decrypt))
  1127.            
  1128.            ;; then it may be encrypted
  1129.            (progn
  1130.  
  1131.              ;; get key
  1132.              (if (not crypt-buffer-encryption-key)
  1133.                  ;; do not confirm on reading an encrypted file
  1134.                  (let ((crypt-confirm-password nil))
  1135.                    (call-interactively 'crypt-set-encryption-key)))
  1136.              
  1137.              ;; if user did not enter a key, turn off crypt mode.  good for
  1138.              ;; binaries that MAGIC-REGEXP-INVERSE doesn't recognize.  --
  1139.              ;; thanx to Paul Dworkin (paul@media-lab.media.mit.edu) can now
  1140.              ;; shut off entirely if `crypt-never-ever-decrypt' is `t' see
  1141.              ;; above - lrd.
  1142.              
  1143.              (if (equal crypt-buffer-encryption-key "")
  1144.                  
  1145.                  (message "No key given, buffer %s assumed normal."
  1146.                           (buffer-name))
  1147.                
  1148.                ;; decrypt the buffer
  1149.                (progn
  1150.                  
  1151.                  (message "Decrypting %s..." (buffer-name))
  1152.                  (crypt-encrypt-buffer crypt-buffer-encryption-key nil)
  1153.                  
  1154.                  ;; Tuck the key away for safe keeping since setting the
  1155.                  ;; major mode may well blow it away.  all buffer-locals are
  1156.                  ;; destroyed. 
  1157.  
  1158.                  ;; note: only needed if using vanilla v18 since crypt++'s
  1159.                  ;; buffer-locals are now 'permanent-local in v19 Emacs and
  1160.                  ;; 'preserved in v18 with kill-fix.el
  1161.                  
  1162.                  (setq encrypted crypt-buffer-encryption-key)
  1163.                  
  1164.                  (if (not (input-pending-p))
  1165.                      (message "Decrypting %s... done" (buffer-name)))))))))
  1166.  
  1167.     ;; MAJOR AND MINOR MODES
  1168.  
  1169.     ;; OK, if any changes have been made to the buffer we need to rerun the
  1170.     ;; code the does automatic selection of major mode.
  1171.  
  1172.     (if (or encoded encrypted)
  1173.  
  1174.         (progn
  1175.  
  1176.           ;; set the major mode
  1177.           (set-auto-mode)
  1178.           (hack-local-variables)
  1179.           
  1180.           ;; Now set our own minor mode(s).
  1181.           (if encoded
  1182.               ;; recover encoding type (may have been smashed by major mode)
  1183.               ;; and toggle encoded mode
  1184.               (progn (setq crypt-buffer-encoding-type encoded)
  1185.                      (crypt-encoded-mode 1)))
  1186.           
  1187.           (if encrypted
  1188.               ;; recover encryption key (may have been smashed by major mode)
  1189.               ;; and toggle crypt mode
  1190.               (progn (setq crypt-buffer-encryption-key encrypted)
  1191.                      (crypt-encrypted-mode 1)))
  1192.           
  1193.           ;; Restore buffer file name now, so that lock file entry is removed
  1194.           ;; properly.
  1195.           
  1196.           (setq buffer-file-name old-buffer-file-name)
  1197.           
  1198.           ;; Restore buffer modified flag to its previous value.  This will
  1199.           ;; also remove the lock file entry for the buffer if the previous
  1200.           ;; value was nil; this is why buffer-file-name had to be manually
  1201.           ;; restored above.
  1202.           
  1203.           (set-buffer-modified-p old-buffer-modified-p)))))
  1204.  
  1205. ;;; 
  1206.  
  1207. (defun crypt-check-extension-for-encoding ()
  1208.  
  1209.    "checks file extensions for possible toggling of encoding modes.
  1210. used for buffers to be written to disk and called by `crypt-write-file-hook.'"
  1211.  
  1212.   ;; We try to flag a buffer to be written out in encoded form if the file
  1213.   ;; ends in one of the file-extensions in `crypt-encoding-alist' even if
  1214.   ;; `crypt-buffer-save-encoded' is `nil'.  Conversely, we try to write out a
  1215.   ;; buffer as a plain file if it does _not_ end in one of these
  1216.   ;; file-extensions even if `crypt-buffer-save-encoded' is non-`nil'.
  1217.   
  1218.   (let ((alist crypt-encoding-alist)
  1219.         (case-fold-search nil)
  1220.         found elt)
  1221.  
  1222.     ;; search through the file name extensions for a match
  1223.     (while (and alist (setq elt (car alist)) (not found))
  1224.       (if (string-match (nth 3 elt) buffer-file-name)
  1225.           (setq found t)
  1226.         ;; decrement
  1227.         (setq alist (cdr alist))))
  1228.     
  1229.     ;; did we find a match? 
  1230.     (if found
  1231.         
  1232.         ;; file name ends in a very provocative extension
  1233.  
  1234.         ;; check to see if already an encoded file
  1235.         (if crypt-buffer-save-encoded
  1236.             
  1237.             ;; already encoded - do the methods of encoding match?
  1238.             (if (not (eq (nth 0 elt) crypt-buffer-encoding-type))
  1239.                  
  1240.                 ;; a new encoding method is desired
  1241.  
  1242.                 ;; can we play some filename extension tricks with the 
  1243.                 ;; destination extension?
  1244.                 (if (crypt-get-extension-tricks (nth 0 elt))
  1245.  
  1246.                     ;; can play tricks
  1247.                     ;; change the method of encoding?
  1248.                     (if (or crypt-auto-write-buffer
  1249.                             (y-or-n-p
  1250.                              (concat "write file using " (nth 4 elt) "? ")))
  1251.                 
  1252.                         ;; case one
  1253.                         ;; turn off original encoding and turn on new encoding
  1254.                         (progn (crypt-encoded-mode -1)
  1255.                                (setq crypt-buffer-encoding-type (nth 0 elt))
  1256.                                (crypt-encoded-mode 1)))
  1257.  
  1258.                   ;; can not play tricks - maybe wants a plain file?
  1259.                   (if (or crypt-auto-write-buffer
  1260.                           (y-or-n-p "write as a plain file? "))
  1261.  
  1262.                       ;; case three
  1263.                       ;; turn off the minor mode and _then_ the flags
  1264.                       (progn (crypt-encoded-mode -1)
  1265.                              (setq crypt-buffer-save-encoded nil)
  1266.                              (setq crypt-buffer-encoding-type nil)))))
  1267.           
  1268.           ;; was a plain file
  1269.           (if (and
  1270.                ;; can we play some filename extension tricks?
  1271.                ;; if not then we must abort
  1272.                (crypt-get-extension-tricks (nth 0 elt))
  1273.                (or crypt-auto-write-buffer
  1274.                    (y-or-n-p (concat "write file using " (nth 4 elt) "? "))))
  1275.               
  1276.               ;; case two
  1277.               ;; turn on encoding flags and _then_ the minor mode
  1278.               (progn (setq crypt-buffer-save-encoded t)
  1279.                      (setq crypt-buffer-encoding-type (nth 0 elt))
  1280.                      (crypt-encoded-mode 1))))
  1281.       
  1282.       ;; no match - a plain-jane file extension - but if the encoded flag is
  1283.       ;; non-`nil' then the user may really want it written out in plain
  1284.       ;; format so we must override this flag
  1285.       (if (and crypt-buffer-save-encoded
  1286.                
  1287.                ;; search the list of files to be ignored
  1288.                ;; if `crypt-ignored-filenames' is `nil' then this let form 
  1289.                ;; will return `t'.  if a match is found this form will return 
  1290.                ;; `nil'.  otherwise it will return `t'.
  1291.                (let ((tlist crypt-ignored-filenames)
  1292.                      case-fold-search found elt)
  1293.  
  1294.                  ;; search through the list of filenames for a match
  1295.                  (while (and tlist (setq elt (car tlist)) (not found))
  1296.                    (if (string-match elt buffer-file-name)
  1297.                        (setq found t)
  1298.                      ;; decrement
  1299.                      (setq tlist (cdr tlist))))
  1300.                  
  1301.                  ;; return `t' if we can _not_ find a match
  1302.                  (not found))
  1303.  
  1304.                ;; if `(crypt-encoded-mode)' was called interactively, then
  1305.                ;; there is a high probability that no matter what the file
  1306.                ;; name extension the user wishes to write the file out in some
  1307.                ;; encoded format thanks to Kimball Collins
  1308.                ;; <kpc@ptolemy.arc.nasa.gov> for pointing out the need for
  1309.                ;; this.  unfortunately, still can not distinguish between
  1310.                ;; write-file and save-buffer.  in the former the user may want
  1311.                ;; to write in plain format (or indeed some other format).
  1312.                
  1313.                (if crypt-buffer-interactive-encoded-mode
  1314.                    ;; interactive
  1315.                    crypt-query-if-interactive 
  1316.                  ;; non-interactive but still may want encoded format
  1317.                  crypt-no-extension-implies-plain)
  1318.  
  1319.                (or crypt-auto-write-buffer
  1320.                    (y-or-n-p "write as a plain file? ")))
  1321.  
  1322.           ;; case three
  1323.           ;; turn off the minor mode and _then_ the flags
  1324.           (progn (crypt-encoded-mode -1)
  1325.                  (setq crypt-buffer-save-encoded nil)
  1326.                  (setq crypt-buffer-encoding-type nil))))))
  1327.  
  1328.  
  1329. ;;; This function should be called ONLY as a write-file hook.
  1330. ;;; Odd things will happen if it is called elsewhere.
  1331.  
  1332. (defun crypt-write-file-hook ()
  1333.   
  1334.   "Hook for possibly writing out file, and backup file, in a non-plain format.
  1335. terminates calls in `write-file-hooks' and should be at end of list."
  1336.  
  1337.   ;; check file-extension for possible toggling of encoding modes
  1338.   (crypt-check-extension-for-encoding)
  1339.  
  1340.   ;; check extension for encryption
  1341.   (if (and
  1342.  
  1343.        ;; maybe file ends with provocative extension w.r.t. encryption?
  1344.        (stringp (crypt-get-file-extension crypt-encryption-type))
  1345.        (string-match (crypt-get-file-extension crypt-encryption-type)
  1346.                      buffer-file-name)
  1347.        
  1348.        ;; can we play tricks?
  1349.        (crypt-get-extension-tricks crypt-encryption-type)
  1350.  
  1351.        ;; match of filename extension - is file in plain format?
  1352.        (not crypt-buffer-save-encrypted)
  1353.        
  1354.        ;; query?
  1355.        (or crypt-auto-write-buffer-encrypted
  1356.            (y-or-n-p "write as an encrypted file? ")))
  1357.  
  1358.       (progn
  1359.         ;; set password and toggle `(crypt-encrypted-mode)'
  1360.         (call-interactively 'crypt-set-encryption-key)
  1361.         (crypt-encrypted-mode 1)))
  1362.  
  1363.   ;; Now decide whether or not we need to continue with this defun. Does the
  1364.   ;; buffer need to be saved in a non-plain form?  If not then writing is not
  1365.   ;; done here but later in the write-file-hooks - probably at the end.
  1366.  
  1367.   (if (or crypt-buffer-save-encoded crypt-buffer-save-encrypted)
  1368.       
  1369.       (save-excursion
  1370.         (save-restriction
  1371.  
  1372.           (let 
  1373.               
  1374.               ;; BINDINGS
  1375.               ((copy-buffer (get-buffer-create " *crypt copy buffer*"))
  1376.                (selective-display selective-display)
  1377.                (buffer-read-only))
  1378.             
  1379.             ;; FORMS
  1380.             (copy-to-buffer copy-buffer 1 (1+ (buffer-size)))
  1381.             (narrow-to-region (point) (point))
  1382.             
  1383.             (unwind-protect
  1384.                 
  1385.                 ;; BODYFORM
  1386.                 (let (setmodes)
  1387.  
  1388.                   ;; as of v19, if one of functions of the `write-file-hooks'
  1389.                   ;; returns a non-`nil' value, then `basic-save-buffer' no
  1390.                   ;; longer creates a backup file.  we must do it ourselves. 
  1391.                   ;; this should be a no-op in v18.
  1392.                   (or buffer-backed-up
  1393.                       (setq setmodes (backup-buffer)))
  1394.  
  1395.                   (insert-buffer-substring copy-buffer)
  1396.                   (kill-buffer copy-buffer)
  1397.                   
  1398.                   ;; "Who would cross the Bridge of Death
  1399.                   ;;  Must answer me
  1400.                   ;;  These questions three
  1401.                   ;;  Ere the other side he see."
  1402.                   ;;
  1403.                   ;; Bridgekeeper from Monty Python and the Holy Grail
  1404.                   
  1405.                   ;; [1] selective-display non-`nil' means we must convert
  1406.                   ;; carriage returns to newlines now, and set the variable
  1407.                   ;; selective-display temporarily to `nil.'
  1408.                   (if selective-display
  1409.                       (progn
  1410.                         (goto-char (point-min))
  1411.                         (subst-char-in-region (point-min) (point-max) ?\r ?\n)
  1412.                         (setq selective-display nil)))
  1413.                   
  1414.                   ;; [2] encryption
  1415.                   (if crypt-buffer-save-encrypted
  1416.                       (progn
  1417.                         ;; check for password
  1418.                         (if (not crypt-buffer-encryption-key)
  1419.                             (call-interactively 'crypt-set-encryption-key))
  1420.                         (if (null crypt-buffer-encryption-key)
  1421.                             (error "No encryption key set for buffer %s"
  1422.                                    (buffer-name)))
  1423.                         (if (not (stringp crypt-buffer-encryption-key))
  1424.                             (error "Encryption key is not a string"))
  1425.                         (message "Encrypting %s..." (buffer-name))
  1426.                         (crypt-encrypt-buffer crypt-buffer-encryption-key t)))
  1427.                   
  1428.                   ;; [3] encoding
  1429.                   (if crypt-buffer-save-encoded
  1430.                       (progn
  1431.                         (message "Encoding %s..." (buffer-name))
  1432.                         (crypt-encode-buffer)))
  1433.                   
  1434.                   ;; now write buffer/region to disk
  1435.                   (write-region (point-min) (point-max) buffer-file-name nil t)
  1436.                   (delete-region (point-min) (point-max))
  1437.                   (set-buffer-modified-p nil)
  1438.                   
  1439.                   ;; now that the file is written, set its modes
  1440.                   (if setmodes
  1441.                       (condition-case ()
  1442.                           (set-file-modes buffer-file-name setmodes)
  1443.                         (error nil)))
  1444.  
  1445.                   ;; return t so that `basic-save-buffer' will know that the
  1446.                   ;; save has already been done.
  1447.                   
  1448.                   ;; NOTE: this TERMINATES write-file-hooks so any hooks
  1449.                   ;; following this one will not be executed
  1450.                   
  1451.                   t )
  1452.  
  1453.               ;; UNWINDFORMS
  1454.               ;; unwind...sit back...take a load off...have a beer 
  1455.  
  1456.               ;; If the crypted stuff has already been removed then this is a
  1457.               ;; no-op.  this form is executed if BODYFORM completes normally 
  1458.               ;; but the value of BODYFORM is returned - i.e., t is returned.
  1459.  
  1460.               (delete-region (point-min) (point-max))))))))
  1461.  
  1462.               
  1463. ;;;; ENCRYPTION
  1464.  
  1465. (defun crypt-encrypt-region (start end encrypt key)
  1466.  
  1467.   "encrypt/decrypt the text in the region.  From a program, this function
  1468. takes four args: START, END, ENCRYPT and KEY.  When called interactively START
  1469. and END default to point and mark \(START being the lesser of the two\), KEY
  1470. is prompted for.  If ENCRYPT is t encryption is done otherwise decryption is
  1471. done using `crypt-encryption-type' of `crypt-encryption-alist.'"
  1472.  
  1473.   (interactive
  1474.    (let (encrypt)
  1475.      (barf-if-buffer-read-only)
  1476.      (list (region-beginning)
  1477.            (region-end)
  1478.            (setq encrypt (y-or-n-p "Encrypt region? "))
  1479.            (crypt-read-string-no-echo
  1480.             (concat (if encrypt "En" "De") "crypt buffer using key: ")
  1481.             ;; do not confirm on decrypting region
  1482.             (if encrypt crypt-confirm-password)))))
  1483.   
  1484.   (crypt-save-point
  1485.  
  1486.    ;; we define the PROGRAM as the encryption program or decryption program
  1487.    ;; listed for `crypt-encryption-type' of `crypt-encryption-alist.'  these
  1488.    ;; should be just the name of the executable and should _not_ contain any
  1489.    ;; arguments.  `(call-process-region)' would be confused if we tried to
  1490.    ;; pass the arguments as part of the PROGRAM.  the arguments are passed
  1491.    ;; through the encryption args or decryption args listed for
  1492.    ;; `crypt-encryption-type' of `crypt-encryption-alist.'
  1493.  
  1494.    ;; thanks to Joe Ilacqua <spike@world.std.com> and others for pointing out
  1495.    ;; an error that occurs with some encryption programs (e.g., the crypt from
  1496.    ;; Sun Microsystems, HPUX-8, and BSD) if `args' is `"".'  this will allow
  1497.    ;; `nil' values and lists of strings for argument.
  1498.  
  1499.    (let (prog args)
  1500.  
  1501.      ;; get the proper program and arguments
  1502.      (if encrypt
  1503.          (setq prog (crypt-get-encoding-program crypt-encryption-type)
  1504.                args (crypt-get-encoding-args crypt-encryption-type))
  1505.      
  1506.        (setq prog (crypt-get-decoding-program crypt-encryption-type)
  1507.              args (crypt-get-decoding-args crypt-encryption-type)))
  1508.      
  1509.      ;; check arguments
  1510.      (cond
  1511.  
  1512.       ;; nil or "" args - don't pass
  1513.       ((or (not args) (equal "" args))
  1514.        (call-process-region start end prog t t nil key))
  1515.        
  1516.       ;; check if the args are in the form of a list - must use apply
  1517.       ((listp args)
  1518.        (apply 'call-process-region
  1519.               (append (list start end prog t t nil) args (list key))))
  1520.        
  1521.       ;; default - just a non-null string
  1522.       (t
  1523.        (call-process-region start end prog t t nil args key))))))
  1524.    
  1525.      
  1526. (defun crypt-encrypt-buffer (key encrypt &optional buffer)
  1527.  
  1528.   "use KEY with ENCRYPT non-nil to encrypt current buffer, otherwise decrypt.
  1529. with optional argument BUFFER, encrypt or decrypt that buffer.  not meant to be
  1530. called interactively, use `crypt-encrypted-mode' to encrypt an entire buffer."
  1531.  
  1532.   (or buffer (setq buffer (current-buffer)))
  1533.   (save-excursion (set-buffer buffer)
  1534.                   (crypt-encrypt-region (point-min) (point-max) encrypt key)))
  1535.  
  1536.  
  1537. ;;;; ENCODING
  1538.  
  1539. (defun crypt-encode-region (start end &optional undo)
  1540.  
  1541.   "Encode the text in the region.  From a program, this function takes three
  1542. args: START, END and UNDO.  When called interactively START and END default to
  1543. point and mark \(START being the lesser of the two\).  Prefix arg \(or optional
  1544. second arg non-nil\) UNDO means decode.
  1545.  
  1546. If encoding is attempted will verify correct magic number at start of newly
  1547. encoded region.  If the magic number is not found will search and delete a
  1548. user-defined regexp, or execute a user-defined lisp expression, as defined in
  1549. `crypt-encoding-alist,' and check again for magic number."
  1550.  
  1551.   (interactive "*r\nP")
  1552.  
  1553.   ;; if called interactively then we may need to determine the encoding type
  1554.   (if (and (interactive-p) (not crypt-buffer-encoding-type))
  1555.       (crypt-read-encoding-type))
  1556.  
  1557.   (crypt-save-point
  1558.  
  1559.    ;; we define the PROGRAM as `shell-file-name' and have it call the encoding
  1560.    ;; or decoding program with the arguments.
  1561.  
  1562.    (let (prog args)
  1563.  
  1564.      ;; get the proper program and arguments
  1565.      (if undo
  1566.          (setq prog (crypt-get-decoding-program crypt-buffer-encoding-type)
  1567.                args (crypt-get-decoding-args crypt-buffer-encoding-type))
  1568.        (setq prog (crypt-get-encoding-program crypt-buffer-encoding-type)
  1569.              args (crypt-get-encoding-args crypt-buffer-encoding-type)))
  1570.      
  1571.      ;; check arguments
  1572.      (cond
  1573.  
  1574.       ;; check if the args are in the form of a list (will catch 'nil)
  1575.       ((listp args)
  1576.  
  1577.        ;; cat all the strings together
  1578.        (while args
  1579.          (setq prog (concat prog " " (car args))
  1580.                args (cdr args))))
  1581.  
  1582.       ;; check if a non-null string
  1583.       ((and (not (string= "" args))
  1584.             (not (eq args t))) ; just in case...
  1585.        (setq prog (concat prog " " args))))
  1586.  
  1587.      (call-process-region start end shell-file-name t t nil "-c" prog))
  1588.  
  1589.    ;; encoding or decoding region?
  1590.    (if (not undo)
  1591.  
  1592.        ;; check if encoded region starts with magic number
  1593.        (let ((magic (crypt-get-magic-regexp crypt-buffer-encoding-type))
  1594.              (clean (crypt-get-cleanup-regexp crypt-buffer-encoding-type))
  1595.              (case-fold-search nil))
  1596.          
  1597.          ;; top of region
  1598.          (goto-char start)
  1599.          
  1600.          ;; check for magic number
  1601.          (if (not (looking-at magic))
  1602.              
  1603.              ;; magic number not there. 
  1604.  
  1605.              ;; some compression programs produce an (inane) standard error
  1606.              ;; message that gets piped into the buffer.  for example, some
  1607.              ;; versions of compact output "Compression : 35.50%."  there may
  1608.              ;; be some way to clean up buffer and check again.
  1609.  
  1610.              (cond
  1611.  
  1612.               ;; no mechanism to clean up - failed
  1613.               ((eq clean nil)
  1614.                (error "Encoding failed!"))
  1615.  
  1616.               ;; cleanup a regexp string?
  1617.               ((stringp clean)
  1618.  
  1619.                ;; is regexp there?
  1620.                (if (looking-at clean)
  1621.  
  1622.                    (progn
  1623.                      ;; delete the match
  1624.                      (delete-region (match-beginning 0) (match-end 0))
  1625.  
  1626.                      ;; check for magic again
  1627.                      (if (not (looking-at magic))
  1628.                          (error "Encoding failed!")))))
  1629.                
  1630.               ;; default: evaluate a lisp expression and check again.
  1631.               (t (eval clean)
  1632.                  (if (not (looking-at magic))
  1633.                      (error "Encoding failed!")))))))))
  1634.  
  1635. (defun crypt-encode-buffer (&optional buffer undo)
  1636.  
  1637.   "encode BUFFER, defaults to current, optional non-nil UNDO means decode.  not
  1638. meant to be called interactively, use `crypt-encoded-mode' to encode an entire
  1639. buffer."
  1640.  
  1641.   (or buffer (setq buffer (current-buffer)))
  1642.   (save-excursion (set-buffer buffer)
  1643.                   (crypt-encode-region (point-min) (point-max) undo)))
  1644.  
  1645.  
  1646.  
  1647. ;;;; MODES
  1648.  
  1649. (defun crypt-encrypted-mode (&optional arg)
  1650.  
  1651.   "toggle encrypted mode.  With ARG, turn on iff positive, otherwise turn off.
  1652. minor mode in which buffers are automatically encrypted before being written.
  1653. if toggled and a key has been set for the current buffer, then the current
  1654. buffer is marked modified, since it needs to be rewritten with or without
  1655. encryption.
  1656.  
  1657. Entering encrypted mode causes auto-saving to be turned off in the current
  1658. buffer, as there is no way in Emacs Lisp to force auto save files to be
  1659. encrypted."
  1660.  
  1661.   (interactive "P")
  1662.   (let ((oldval crypt-buffer-save-encrypted))
  1663.     (setq crypt-buffer-save-encrypted
  1664.           (if arg (> arg 0) (not crypt-buffer-save-encrypted)))
  1665.  
  1666.     (if crypt-buffer-save-encrypted
  1667.         ;; we are going to save as encrypted, we will turn off auto-saving.
  1668.         (progn
  1669.           ;; if an auto-save file already exists, then delete it
  1670.           (if (and (stringp buffer-auto-save-file-name)
  1671.                    (file-exists-p buffer-auto-save-file-name))
  1672.               (delete-file buffer-auto-save-file-name))
  1673.           ;; if the key is not set then ask for it.
  1674.           (if (not crypt-buffer-encryption-key)
  1675.               (call-interactively 'crypt-set-encryption-key))
  1676.           ;; turn-off auto-saving
  1677.           (auto-save-mode 0))
  1678.  
  1679.       ;; we are not going to save as encrypted, we will turn on auto-saving
  1680.       ;; but only if we are editing a file and the default says we should.
  1681.       (auto-save-mode (if (and auto-save-default buffer-file-name) 1 0)))
  1682.  
  1683.     (if crypt-buffer-encryption-key
  1684.         ;; set buffer-modified flag to `t' only if the mode has been changed, 
  1685.         ;; old code set unconditionally to `nil' if mode was not changed 
  1686.         ;; modification suggested by: Gerd Hillebrand <ggh@cs.brown.edu>
  1687.         (if (not (eq oldval crypt-buffer-save-encrypted))
  1688.             (set-buffer-modified-p t)))))
  1689.  
  1690.  
  1691. ;;; originally `tek-symbol-alist-to-table' from tek-highlight.el
  1692. (defun crypt-symbol-alist-to-table (list)
  1693.   "Converts an alist of symbols to a table suitable for `completing-read.'
  1694. Called by `crypt-read-encoding-type.'"
  1695.   (mapcar (function (lambda (x) (list (symbol-name (car x)))))
  1696.           list))
  1697.  
  1698. (defun crypt-read-encoding-type ()
  1699.  
  1700.   "function called to query user for `crypt-buffer-encoding-type' if not set.
  1701. uses the contents of `crypt-encoding-alist' and `crypt-default-encoding.'"
  1702.  
  1703.   ;; use poor man's gmhist (i.e., we could have used gmhist's
  1704.   ;; `completing-read-with-history-in' instead)
  1705.   (let (
  1706.         ;; find the encoding type desired by user
  1707.         (type
  1708.          (completing-read
  1709.           (concat "encoding type (? for list): [" crypt-default-encoding "] ")
  1710.           (crypt-symbol-alist-to-table crypt-encoding-alist))))
  1711.     
  1712.     ;; test length of object returned by `completing-read'
  1713.     (if (zerop (length type))
  1714.         
  1715.         ;; nothing there, i.e., user hit return -- use default
  1716.         (setq crypt-buffer-encoding-type (intern crypt-default-encoding))
  1717.       
  1718.       ;; use the value from mini-buffer and update the default value
  1719.       (setq crypt-buffer-encoding-type (intern type)
  1720.             crypt-default-encoding type))))
  1721.  
  1722. (defun crypt-encoded-mode (&optional arg)
  1723.  
  1724.   "toggle encoded mode.  With ARG, turn on iff positive, otherwise turn off.
  1725. minor mode in which buffers are automatically encoded before being written.  if
  1726. toggled then current buffer is marked modified, since it needs to be written
  1727. with or without encoding.
  1728.  
  1729. Entering encoded mode causes auto-saving to be turned off in the current
  1730. buffer, as there is no way in Emacs Lisp to force auto save files to be
  1731. encoded."
  1732.  
  1733.   (interactive "P")
  1734.  
  1735.   ;; set flag indicating whether or not `(crypt-encoded-mode)' was called 
  1736.   ;; interactively
  1737.   (setq crypt-buffer-interactive-encoded-mode (interactive-p))
  1738.  
  1739.   ;; if called interactively then need to determine encoding type
  1740.   (if (and crypt-buffer-interactive-encoded-mode
  1741.            (not crypt-buffer-encoding-type))
  1742.       (crypt-read-encoding-type))
  1743.  
  1744.   ;; save old value of `crypt-buffer-save-encoded'
  1745.   (let ((oldval crypt-buffer-save-encoded))
  1746.  
  1747.     ;; set the variable `crypt-buffer-save-encoded' to `t' if the argument is 
  1748.     ;; positive, otherwise toggle its current value.
  1749.     (setq crypt-buffer-save-encoded
  1750.           (if arg (> arg 0) (not crypt-buffer-save-encoded)))
  1751.  
  1752.     ;; set the variable generated by `(crypt-buffer-save-name)' to the value
  1753.     ;; stored in `crypt-buffer-save-encoded.'
  1754.     (set-variable (crypt-buffer-save-name crypt-buffer-encoding-type)
  1755.                   crypt-buffer-save-encoded)
  1756.  
  1757.     (if crypt-buffer-save-encoded
  1758.         ;; we are going to save as encoded, we will turn off auto-saving.
  1759.         (progn
  1760.           ;; if an auto-save file already exists, then delete it
  1761.           (if (and (stringp buffer-auto-save-file-name)
  1762.                    (file-exists-p buffer-auto-save-file-name))
  1763.               (delete-file buffer-auto-save-file-name))
  1764.           ;; turn-off auto-saving
  1765.           (auto-save-mode 0))
  1766.  
  1767.       ;; we are not going to save as encoded, we will turn on auto-saving but
  1768.       ;; only if we are editing a file and the default says we should.
  1769.       (auto-save-mode (if (and auto-save-default buffer-file-name) 1 0)))
  1770.  
  1771.     ;; have we toggled the mode? 
  1772.  
  1773.     ;; if yes, then mark buffer as modified.  if not, then leave
  1774.     ;; buffer-modified flag alone.
  1775.  
  1776.     ;; the old code previously set the variable `set-buffer-modified-p' to a
  1777.     ;; value of `t' if there was a mode change and (unconditionally) to `nil'
  1778.     ;; if there was not a mode change.
  1779.  
  1780.     ;; modification suggested by: Gerd Hillebrand <ggh@cs.brown.edu>
  1781.  
  1782.     (if (not (eq oldval crypt-buffer-save-encoded))
  1783.         (set-buffer-modified-p t))))
  1784.  
  1785.  
  1786. ;;;; Additional encryption functions
  1787.  
  1788. (defun crypt-read-string-no-echo (prompt &optional confirm)
  1789.  
  1790.   "Read a string from the minibuffer, prompting with PROMPT, echoing periods.
  1791. Optional second argument CONFIRM non-nil means that the user will be asked to
  1792. type the string a second time for confirmation and if there is a mismatch, the
  1793. whole process is repeated.
  1794.  
  1795.            Line editing keys are --
  1796.              C-h, DEL      rubout
  1797.              C-u, C-x      line kill
  1798.              C-q, C-v      literal next"
  1799.   
  1800.   (catch 'return-value
  1801.     (save-excursion
  1802.  
  1803.       (let ((input-buffer (get-buffer-create (make-temp-name " *password*")))
  1804.             char hold-password help-form kill-ring)
  1805.  
  1806.         (set-buffer input-buffer)
  1807.         ;; don't add to undo ring
  1808.         (buffer-flush-undo input-buffer)
  1809.  
  1810.         (let ((cursor-in-echo-area t)
  1811.               (echo-keystrokes 0))
  1812.  
  1813.           (unwind-protect
  1814.  
  1815.               ;; BODYFORM 
  1816.               ;; repeat until we get a `throw'
  1817.               (while t
  1818.                 (erase-buffer)
  1819.                 (message prompt)
  1820.  
  1821.                 ;; read string
  1822.                 (while (not (memq (setq char (read-char)) '(?\C-m ?\C-j)))
  1823.                   (if (setq form
  1824.                             (cdr
  1825.                              (assq char
  1826.                                    '((?\C-h . (delete-char -1))
  1827.                                      (?\C-? . (delete-char -1))
  1828.                                      (?\C-u . (delete-region 1 (point)))
  1829.                                      (?\C-x . (delete-region 1 (point)))
  1830.                                      (?\C-q . (quoted-insert 1))
  1831.                                      (?\C-v . (quoted-insert 1))))))
  1832.                       (condition-case error-data
  1833.                           (eval form)
  1834.                         (error t))
  1835.                     ;; just a plain character - insert into password buffer
  1836.                     (insert char))
  1837.  
  1838.                   ;; I think crypt-read-string-no-echo should echo asterisks.
  1839.                   ;; -- Jamie. How about periods like in ange-ftp? -- lrd
  1840.                   ;;
  1841.                   (message "%s%s" prompt (make-string (buffer-size) ?.)))
  1842.                 
  1843.                 ;; do we have to confirm password?
  1844.                 (cond
  1845.  
  1846.                  ;; no confirmation requested - terminate
  1847.                  ((not confirm)
  1848.                   (throw 'return-value (buffer-string)))
  1849.                  
  1850.                  ;; can we compare (confirm) password values yet?
  1851.                  (hold-password
  1852.                   (if (string= hold-password (buffer-string))
  1853.                       ;; the two passwords match - terminate
  1854.                       (throw 'return-value hold-password)
  1855.  
  1856.                     ;; mismatch - start over
  1857.                     (progn
  1858.                       (message (concat prompt "[Mismatch. Start over]"))
  1859.                       (beep)
  1860.                       (sit-for 2)
  1861.                       (fillarray hold-password 0) ; destroy extra copy now
  1862.                       (setq hold-password nil))))
  1863.                  
  1864.                  ;; store password and read again
  1865.                  (t
  1866.                   (setq hold-password (buffer-string))
  1867.                   (message (concat prompt "[Retype to confirm]"))
  1868.                   (sit-for 2))))
  1869.             
  1870.             ;; UNWINDFORMS
  1871.             ;; clean up
  1872.             (set-buffer input-buffer)
  1873.             (set-buffer-modified-p nil)
  1874.             (buffer-flush-undo input-buffer) ; redundant, but why not be safe.
  1875.             (widen)
  1876.             (goto-char (point-min))
  1877.             (while (not (eobp)) (delete-char 1) (insert "*")) ; destroy now
  1878.             (kill-buffer input-buffer)))))))
  1879.  
  1880. (defun crypt-set-encryption-key (key &optional buffer)
  1881.  
  1882.   "set the encryption KEY for current buffer.  KEY a string.  optional BUFFER
  1883. argument should be a buffer.  if buffer is in encrypted mode, then it is also
  1884. marked as modified, since it needs to be saved with the new key."
  1885.  
  1886.   (interactive
  1887.    (progn
  1888.      (barf-if-buffer-read-only)
  1889.      (list (crypt-read-string-no-echo
  1890.             (format "Set encryption key for buffer %s: " (buffer-name))
  1891.             crypt-confirm-password))))
  1892.  
  1893.   ;; for security reasons we remove `(crypt-set-encryption-key "password")' 
  1894.   ;; from the `command-history' list if called interactively.
  1895.   (if (interactive-p)
  1896.       (setq command-history (cdr command-history)))
  1897.  
  1898.   (or buffer (setq buffer (current-buffer)))
  1899.  
  1900.   (save-excursion
  1901.     (set-buffer buffer)
  1902.     (if (equal key crypt-buffer-encryption-key)
  1903.         (message "Key is identical to original, no change.")
  1904.  
  1905.       (progn
  1906.         ;; #### Smash contents of old crypt-buffer-encryption-key string here?
  1907.         ;; That wouldn't be ok if some other buffer held a pointer to it.
  1908.         (setq crypt-buffer-encryption-key key)
  1909.         
  1910.         ;; don't touch the modify flag unless we're in `(crypt-encrypted-mode)'
  1911.         (if crypt-buffer-save-encrypted
  1912.             (set-buffer-modified-p t))))))
  1913.  
  1914.  
  1915. ;;;; Install the hooks, then add the mode indicators to the minor mode alist.
  1916.  
  1917. ;;; Check that the hooks are not already installed.
  1918.  
  1919. ;;; Contributed by Ken Laprade <laprade@trantor.harris-atd.com>
  1920. ;;; Really should use some sort of add-hook - 16 Feb 93 - KCL
  1921. (or (and (listp write-file-hooks) (not (eq (car write-file-hooks) 'lambda)))
  1922.     (setq write-file-hooks (list write-file-hooks)))
  1923.  
  1924. (cond
  1925.  ((not (memq 'crypt-write-file-hook write-file-hooks))
  1926.   ;; make this hook last on purpose
  1927.   (setq write-file-hooks (append write-file-hooks
  1928.                                  (list 'crypt-write-file-hook))
  1929.         find-file-hooks (cons 'crypt-find-file-hook find-file-hooks)
  1930.         find-file-not-found-hooks (cons 'crypt-find-file-hook
  1931.                                         find-file-not-found-hooks))))
  1932.  
  1933. ;;; Check that the mode indicators are not already installed.
  1934.  
  1935. (cond
  1936.  ((not (memq crypt-minor-mode-encrypted minor-mode-alist))
  1937.   ;; add the mode indicators
  1938.   (setq minor-mode-alist (append crypt-minor-mode-alist
  1939.                                  minor-mode-alist))))
  1940.  
  1941.  
  1942. ;;;; BUG REPORTS
  1943.  
  1944. ;;; this section is provided for reports.
  1945. ;;; using Barry A. Warsaw's reporter.el
  1946.  
  1947. (defconst crypt-help-address
  1948.   "dodd@roebling.poly.edu, rwhitby@research.canon.oz.au"
  1949.   "Address(es) accepting submission of reports on crypt++.el.")
  1950.  
  1951. (defconst crypt-maintainer "Larry and Rod"
  1952.   "First name(s) of people accepting submission of reports on crypt++.el.")
  1953.  
  1954. (defconst crypt-file "crypt++.el"
  1955.   "Name of file containing emacs lisp code.")
  1956.  
  1957. (defconst crypt-variable-list
  1958.   (list 'crypt-encryption-type 
  1959.         'crypt-encryption-file-extension
  1960.         'crypt-never-ever-decrypt
  1961.         'crypt-auto-write-buffer-encrypted
  1962.         'crypt-confirm-password
  1963.         'crypt-encryption-alist
  1964.         'crypt-auto-decode-buffer
  1965.         'crypt-auto-write-buffer
  1966.         'crypt-query-if-interactive
  1967.         'crypt-no-extension-implies-plain
  1968.         'crypt-freeze-vs-fortran
  1969.         'crypt-compact-vs-C++
  1970.         'crypt-ignored-filenames
  1971.         'crypt-default-encoding
  1972.         'crypt-encoding-alist)
  1973.   "list of variables to be appended to reports sent by `crypt-submit-report.'")
  1974.  
  1975. (defun crypt-submit-report ()
  1976.  
  1977.   "submit via reporter.el a bug report on program.  send report on `crypt-file'
  1978. version `crypt-version,' to `crypt-maintainer' at address `crypt-help-address'
  1979. listing variables `crypt-variable-list' in the message."
  1980.  
  1981.   (interactive)
  1982.  
  1983.   ;; in case we can't find it...
  1984.   (condition-case err
  1985.  
  1986.       (progn
  1987.         
  1988.         ;; get it if we can
  1989.         (require 'reporter)
  1990.  
  1991.         (reporter-submit-bug-report
  1992.          crypt-help-address                     ; address
  1993.          (concat crypt-file " " crypt-version)  ; pkgname
  1994.          crypt-variable-list                    ; varlist
  1995.          nil nil                                ; pre-hooks and post-hooks
  1996.          (concat "Yo! " crypt-maintainer ","))) ; salutation
  1997.  
  1998.     ;; fail gracefully
  1999.     (error 
  2000.      (beep)
  2001.  
  2002.      ;; do they have ange-ftp?
  2003.      (if (and (featurep 'ange-ftp)
  2004.               (y-or-n-p (concat "sorry reporter.el not found.  "
  2005.                                 "can I ange-ftp it for you? ")))
  2006.  
  2007.          ;; ange-ftp a copy
  2008.          (let ((ange-ftp-generate-anonymous-password t))
  2009.            ;; might want to use the elisp archive official site?  But
  2010.            ;; then it would be uncompressed, etc. Ick!
  2011.            (find-file-other-window
  2012.             "/anonymous@roebling.poly.edu:/pub/reporter.el")
  2013.            (eval-current-buffer)
  2014.            (message (concat "please save this file somewhere "
  2015.                             "emacs can find it and try again.")))
  2016.        
  2017.        ;; no ange-ftp
  2018.        (message (concat "sorry reporter.el not found. please get from "
  2019.                         "elisp-archive or roebling.poly.edu"))))))
  2020.   
  2021.  
  2022. ;;; provide this package as crypt++ as well as crypt
  2023. (provide 'crypt++)
  2024. (provide 'crypt)
  2025.  
  2026. ;;; crypt++.el ends here
  2027.