1 ;;; vm-ps-print.el --- PS-printing functions for VM
3 ;; Copyright (C) 1999 Robert Fenk
6 ;; Status: Tested with XEmacs 21.4.15 & VM 7.18
7 ;; Keywords: extensions, vm, ps-print
8 ;; X-URL: http://www.robf.de/Hacking/elisp
10 ;; This code is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 1, or (at your option)
15 ;; This program is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with this program; if not, write to the Free Software
22 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 ;; There are three new user functions for generating postscript output:
27 ;; vm-ps-print-message
28 ;; vm-ps-print-each-message
29 ;; vm-ps-print-message-preview
30 ;; The first one prints like vm-ps-print, but multiple messages are
31 ;; concatenated to one printout. In contrast to this the second
32 ;; function creates one print job for each message. Finally the the
33 ;; third one prints the current message as displayed in the
34 ;; presentation buffer -- the other two functions do their own MIME
35 ;; decoding therefore messages are always display in their default
38 ;; To use these functions you should put this file into your load-path
39 ;; and add the following lines to your .vm file:
41 ;; (require 'vm-ps-print)
43 ;; To redefine the default VM settings for the tool bar and menu add
44 ;; the following line. The default is to use `vm-ps-print-message',
45 ;; but if you use an optional non nil argument you will get
46 ;; `vm-ps-print-each-message' as print function.
48 ;; (vm-ps-print-message-infect-vm)
50 ;; This will refine the default VM settings and from now on you should
51 ;; be able to print to your postscript printer by using the usual VM
53 ;; Of course you still have to set `lpr-command' and `lpr-switches' or
54 ;; `ps-lpr-command' and `ps-lpr-switches' to reasonable values!
56 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
68 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
73 (defgroup vm-psprint nil
76 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
79 (defcustom vm-ps-print-message-function 'ps-print-buffer-with-faces
80 "*This should point to the function which is used for ps-printing.
81 The function should accept one optional argument which is a filename."
86 (defcustom vm-ps-print-message-separater "\n"
87 "*The separator between messages when printing multiple messages."
92 (defcustom vm-ps-print-message-font-size 10
93 "*The font size for the PS-output of the message text."
97 ;;----------------------------------------------------------------------------
100 (defcustom vm-ps-print-message-header-lines 2
101 "*See `ps-header-lines'."
106 (defcustom vm-ps-print-message-left-header
107 '(list (format "(Folder `%s')" folder-name)
108 (format "(%d message%s printed)" mcount (if (= mcount 1) "" "s")))
109 "*This variable should contain a command returning a valid `ps-left-header'."
114 (defcustom vm-ps-print-message-right-header
115 '(list"/pagenumberstring load" 'dd-mon-yyyy)
116 "*This variable should contain a command returning a valid `ps-right-header'.
117 The defaults to the number of pages and the date of the printout."
122 (defcustom vm-ps-print-message-summary-format
123 (concat "******************************************************************************\n"
124 (if (boundp 'vm-summary-format)
126 "%n %*%a %-17.17F %-3.3m %2d %4l/%-5c %I\"%s\"\n")
127 "******************************************************************************\n")
128 "*The summary line before a message.
129 See `vm-summary-format' for a description of the conversion specifiers."
133 ;;----------------------------------------------------------------------------
135 (defcustom vm-ps-print-each-message-header-lines 2
136 "*See `ps-header-lines'."
141 (defcustom vm-ps-print-each-message-left-header
142 '(list (format "(Folder `%s')" folder-name)
143 (format "(%s)" (vm-ps-print-tokenized-summary msg (vm-summary-sprintf vm-ps-print-each-message-summary-format msg t))))
144 "*This command should return a valid `ps-left-header'.
145 The default is to have the folder name and a summary according to the
146 variable `vm-ps-print-each-message-summary-format' in the left header."
151 (defcustom vm-ps-print-each-message-right-header
152 '(list "/pagenumberstring load" 'dd-mon-yyyy)
153 "*This variable should contain a command returning a valid `ps-right-header'.
154 The defaults to the number of pages and the date of the printout."
159 (defcustom vm-ps-print-each-message-summary-format
160 "Message# %n, Lines %l, Characters %c"
161 "*The summary line for the postscript header.
162 See `vm-summary-format' for a description of the conversion specifiers."
166 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
167 (defun vm-ps-print-message-internal (filename each folder-name mcount msg)
168 "This function does the actual call to the ps-printing function.
169 This is not a function to call interactively!
171 If the customization of headers is insufficient, then you may want
172 to modify this function. If FILENAME is a string, then the output is
173 written to that file. If EACH is t then create a new johb for each
174 message. FOLDER-NAME specifies the folder name which is displayed in
175 the header line and MCOUNT is the number of messages to print, while
176 MSG is a VM message pointer.
178 See: `vm-ps-print-message-function'"
179 (let* ((dd-mon-yyyy (format-time-string "%d %b %Y %T" (current-time)))
180 (ps-left-header (if each (eval vm-ps-print-each-message-left-header)
181 (eval vm-ps-print-message-left-header)))
182 (ps-right-header (if each (eval vm-ps-print-each-message-right-header)
183 (eval vm-ps-print-message-right-header)))
184 (ps-header-lines (if each vm-ps-print-each-message-header-lines
185 vm-ps-print-each-message-header-lines))
186 (ps-print-header-frame t)
187 (ps-font-size vm-ps-print-message-font-size))
188 ; (setq filename (expand-file-name "~/mail.ps"))
189 (funcall vm-ps-print-message-function filename)
192 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
193 (defun vm-ps-print-tokenized-summary (message tokens)
194 "Return the summary string for MESSAGE according to the format in TOKENS.
195 Like `vm-tokenized-summary-insert'."
200 (setq token (car tokens))
201 (cond ((stringp token)
202 (if vm-display-using-mime
203 (setq summary (concat summary
204 (vm-decode-mime-encoded-words-in-string token)))
205 (setq summary (concat summary token))))
207 (setq summary (concat summary (vm-padded-number-of message))))
209 (setq summary (concat summary (vm-su-mark message))))
210 ((eq token 'thread-indent)
211 (if (and vm-summary-show-threads
212 (natnump vm-summary-thread-indent-level))
213 (setq summary (concat summary
214 ?\ (* vm-summary-thread-indent-level
215 (vm-th-thread-indentation message)))))))
216 (setq tokens (cdr tokens)))
219 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
220 (defun vm-ps-print-message-folder-name ()
221 "Return a nice folder name, without complete path."
222 (let* ((folder-name (or (buffer-file-name) (buffer-name)))
224 (if (and vm-folder-directory
225 (string-match (concat (regexp-quote (expand-file-name
226 vm-folder-directory))
229 (substring folder-name (match-beginning 1) (match-end 2))
233 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
235 (defun vm-ps-print-message (&optional count filename each)
236 "PS-Print the current message.
238 A positive COUNT arg N means print the current message and the next
239 N-1 messages and a negative one print the current message and the
240 previous N-1 messages.
242 If FILENAME is specified then write PS into that file.
244 When printing a single message it acts like `vm-ps-print-each-message'.
245 When printing multiple messages it will insert a summary line according
246 to the variable `vm-ps-print-message-summary-format' and a separator
247 according to the variable `vm-ps-print-message-separater' between
248 messages. You might force the printing of one job per message, by
249 giving a t EACH argument.
251 See: `vm-ps-print-message-function'
252 `vm-ps-print-message-font-size'
253 `vm-ps-print-message-summary-format'
254 `vm-ps-print-message-separater'
255 `vm-ps-print-message-left-header'
256 `vm-ps-print-message-right-header'
257 for customization of the output."
259 (vm-follow-summary-cursor)
260 (vm-select-folder-buffer)
261 (vm-check-for-killed-summary)
262 (vm-error-if-folder-empty)
263 (or count (setq count 1))
265 (let* ((vm-summary-faces-mode nil)
266 (folder-name (vm-ps-print-message-folder-name))
269 (mlist (vm-select-marked-or-prefixed-messages count))
270 (mcount (length mlist))
271 (tmpbuf (get-buffer-create "*vm-ps-print*")))
274 (setq major-mode 'vm-mode)
276 (if (= mcount 1) (setq each 1))
279 (setq m (vm-real-message-of (car mlist)))
281 (vm-tokenized-summary-insert
282 m (vm-summary-sprintf vm-ps-print-message-summary-format m t)))
283 (setq mstart (point-max))
284 (vm-insert-region-from-buffer
285 (vm-buffer-of m) (vm-vheaders-of m) (vm-end-of m))
286 (vm-reorder-message-headers nil
288 vm-invisible-header-regexp)
289 (vm-decode-mime-encoded-words)
291 (re-search-forward "\n\n") ;; skip headers
292 (if (not (vm-mime-plain-message-p m))
293 (progn (vm-decode-mime-layout (vm-mm-layout m))
294 (delete-region (point) (point-max))))
295 (narrow-to-region mstart (point-max))
297 (vm-highlight-headers)
301 (progn (save-excursion
302 (vm-ps-print-message-internal filename t folder-name
306 (if (> (length mlist) 1) (insert vm-ps-print-message-separater)))
307 (setq mlist (cdr mlist)))
310 (vm-ps-print-message-internal filename nil folder-name mcount nil))
314 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
316 (defun vm-ps-print-each-message (&optional count filename)
317 "PS-Print the current message.
318 A positive COUNT arg N means print the current message and the next
319 N-1 messages and a negative one print the current message and the
320 previous N-1 messages.
322 If FILENAME is specified then write PS into that file.
324 This function acts like `vm-ps-print-message', but it will generate a
325 separate print job for each message and it does not generate the
326 summary lines between messages.
328 See: `vm-ps-print-message-function'
329 `vm-ps-print-message-font-size'
330 `vm-ps-print-each-message-separater'
331 `vm-ps-print-each-message-left-header'
332 `vm-ps-print-each-message-right-header'
333 `vm-ps-print-each-message-summary-format'
334 for customization of the output."
336 (vm-ps-print-message count filename t))
338 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
340 (defun vm-ps-print-message-presentation (&optional filename)
341 "PS-Print the currently presented message.
342 When called with a numeric prefix argument, prompts the user for the
343 name of a file to save the PostScript image in, instead of sending it
346 More specifically, the FILENAME argument is treated as follows: if it
347 is nil, send the image to the printer. If FILENAME is a string, save
348 the PostScript image in a file with that name. If FILENAME is a
349 number, prompt the user for the name of the file to save in.
351 See: `vm-ps-print-message-function'
352 `vm-ps-print-message-font-size'
353 `vm-ps-print-each-message-separater'
354 `vm-ps-print-each-message-left-header'
355 `vm-ps-print-each-message-right-header'
356 `vm-ps-print-each-message-summary-format'
357 for customization of the output."
358 (interactive (list (ps-print-preprint current-prefix-arg)))
360 (vm-follow-summary-cursor)
361 (vm-select-folder-buffer)
362 (vm-check-for-killed-summary)
363 (vm-error-if-folder-empty)
365 (let ((folder-name (vm-ps-print-message-folder-name))
367 (msg (car vm-message-pointer)))
369 (if (and (boundp 'vm-mail-buffer) (symbol-value 'vm-mail-buffer))
370 (set-buffer (symbol-value 'vm-mail-buffer)))
371 (if vm-presentation-buffer
372 (set-buffer vm-presentation-buffer))
373 (vm-ps-print-message-internal filename t folder-name mcount msg)
376 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
378 (defun vm-ps-print-message-fix-menu (menu each)
380 If EACH it t, then replace `vm-print-message' by
381 'vm-ps-print-each-message', otherwise by `vm-ps-print-message'."
382 (let ((tmpbuf (get-buffer-create "*vm-ps-print*")))
386 (insert (format "(setq %s '%S)" (symbol-name menu) (symbol-value menu)))
387 (if (re-search-backward "vm-\\(ps-\\)?print-\\(each-\\)?message"
389 (if each (replace-match "vm-print-each-message")
390 (replace-match "vm-ps-print-message")))
396 (defun vm-ps-print-message-infect-vm (&optional each)
397 "Call this function to hook the ps-printing functions into VM.
398 Arranges that the usual VM printing commands in menus and the
399 toolbar use `vm-ps-print-message' or `vm-ps-print-each-message'
400 (when EACH is t) instead of `vm-print-message'."
402 (if each (fset 'vm-toolbar-print-command 'vm-ps-print-each-message)
403 (fset 'vm-toolbar-print-command 'vm-ps-print-message))
404 (require 'vm-version)
406 (vm-ps-print-message-fix-menu 'vm-menu-dispose-menu each)
407 (vm-ps-print-message-fix-menu 'vm-menu-vm-menu each)
410 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
411 ;;; From: "Jeffrey J. Kosowsky" <jeff.kosowsky_ATsign_verizon_DOTsymbol_net>
413 (defun vm-ps-print-marked (&optional filename seperate nup color)
414 "Postscript print all marked emails in mail Summary. If no messages marked,
415 print just the current message.
416 Optionally write postscript output to FILENAME (default is to spool
418 Optionally force SEPERATE printing of each message by setting to 't'.
419 Optionally also print NUP pages per sheet.
420 Optionally also print in COLOR by setting to non-nil.
422 Note when run interactively setting a positive prefix number prints
423 NUP pages per sheet to the printer, while negative number prints NUP
424 pages per sheet to queried FILENAME. No prefix prints 1 page per sheet
425 to printer while prefix without numerical argument simply queries for
426 filename and formats 1 page per sheet. (JJK)"
428 (if (and (integerp current-prefix-arg) (plusp current-prefix-arg))
430 (list (ps-print-preprint current-prefix-arg))))
432 (ps-print-color-p color)
436 ((integerp current-prefix-arg) (abs current-prefix-arg))
437 (t 1))) ; default 1 page per sheet
439 (and (vm-marked-messages)
440 (setq last-command 'vm-next-command-uses-marks))
441 (vm-ps-print-message nil filename seperate)))
443 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
445 (provide 'vm-ps-print)
447 ;;; vm-ps-print.el ends here