comparison lisp/vm/vm-misc.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children 49a24b4fd526
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 ;;; Miscellaneous functions for VM
2 ;;; Copyright (C) 1989, 1990, 1991, 1993, 1994 Kyle E. Jones
3 ;;;
4 ;;; This program is free software; you can redistribute it and/or modify
5 ;;; it under the terms of the GNU General Public License as published by
6 ;;; the Free Software Foundation; either version 1, or (at your option)
7 ;;; any later version.
8 ;;;
9 ;;; This program is distributed in the hope that it will be useful,
10 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ;;; GNU General Public License for more details.
13 ;;;
14 ;;; You should have received a copy of the GNU General Public License
15 ;;; along with this program; if not, write to the Free Software
16 ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 (provide 'vm-misc)
19
20 (defun vm-delete-non-matching-strings (regexp list &optional destructively)
21 "Delete strings matching REGEXP from LIST.
22 Optional third arg non-nil means to destructively alter LIST, instead of
23 working on a copy.
24
25 The new version of the list, minus the deleted strings, is returned."
26 (or destructively (setq list (copy-sequence list)))
27 (let ((curr list) (prev nil))
28 (while curr
29 (if (string-match regexp (car curr))
30 (setq prev curr
31 curr (cdr curr))
32 (if (null prev)
33 (setq list (cdr list)
34 curr list)
35 (setcdr prev (cdr curr))
36 (setq curr (cdr curr)))))
37 list ))
38
39 (defun vm-parse (string regexp &optional matchn)
40 (or matchn (setq matchn 1))
41 (let (list)
42 (store-match-data nil)
43 (while (string-match regexp string (match-end 0))
44 (setq list (cons (substring string (match-beginning matchn)
45 (match-end matchn)) list)))
46 (nreverse list)))
47
48 (defun vm-parse-addresses (string)
49 (if (null string)
50 ()
51 (let (work-buffer)
52 (save-excursion
53 (unwind-protect
54 (let (list start s char)
55 (setq work-buffer (generate-new-buffer "*vm-work*"))
56 (set-buffer work-buffer)
57 (insert string)
58 (goto-char (point-min))
59 (skip-chars-forward "\t\f\n\r ")
60 (setq start (point))
61 (while (not (eobp))
62 (skip-chars-forward "^\"\\,(")
63 (setq char (following-char))
64 (cond ((= char ?\\)
65 (forward-char 1)
66 (if (not (eobp))
67 (forward-char 1)))
68 ((= char ?,)
69 (setq s (buffer-substring start (point)))
70 (if (or (null (string-match "^[\t\f\n\r ]+$" s))
71 (not (string= s "")))
72 (setq list (cons s list)))
73 (forward-char 1)
74 (skip-chars-forward "\t\f\n\r ")
75 (setq start (point)))
76 ((= char ?\")
77 (forward-char 1)
78 (re-search-forward "[^\\]\"" nil 0))
79 ((= char ?\()
80 (let ((parens 1))
81 (forward-char 1)
82 (while (and (not (eobp)) (not (zerop parens)))
83 (re-search-forward "[^\\][()]" nil 0)
84 (cond ((eobp))
85 ((= (preceding-char) ?\()
86 (setq parens (1+ parens)))
87 ((= (preceding-char) ?\))
88 (setq parens (1- parens)))))))))
89 (setq s (buffer-substring start (point)))
90 (if (and (null (string-match "^[\t\f\n\r ]+$" s))
91 (not (string= s "")))
92 (setq list (cons s list)))
93 (nreverse list)) ; jwz: fixed order
94 (and work-buffer (kill-buffer work-buffer)))))))
95
96 (defun vm-write-string (where string)
97 (if (bufferp where)
98 (vm-save-buffer-excursion
99 (set-buffer where)
100 (goto-char (point-max))
101 (insert string))
102 (let ((temp-buffer nil))
103 (unwind-protect
104 (save-excursion
105 (setq temp-buffer (generate-new-buffer "*vm-work*"))
106 (set-buffer temp-buffer)
107 (insert string)
108 (write-region (point-min) (point-max) where t 'quiet))
109 (and temp-buffer (kill-buffer temp-buffer))))))
110
111 (defmacro vm-marker (pos &optional buffer)
112 (list 'set-marker '(make-marker) pos buffer))
113
114 (defmacro vm-increment (variable)
115 (list 'setq variable (list '1+ variable)))
116
117 (defmacro vm-decrement (variable)
118 (list 'setq variable (list '1- variable)))
119
120 (defmacro vm-select-folder-buffer ()
121 '(and vm-mail-buffer
122 (or (buffer-name vm-mail-buffer)
123 (error "Folder buffer has been killed."))
124 (set-buffer vm-mail-buffer)))
125
126 (defun vm-check-for-killed-summary ()
127 (and (bufferp vm-summary-buffer) (null (buffer-name vm-summary-buffer))
128 (let ((mp vm-message-list))
129 (setq vm-summary-buffer nil)
130 (while mp
131 (vm-set-su-start-of (car mp) nil)
132 (vm-set-su-end-of (car mp) nil)
133 (setq mp (cdr mp))))))
134
135 (defun vm-check-for-killed-folder ()
136 (and (bufferp vm-mail-buffer) (null (buffer-name vm-mail-buffer))
137 (setq vm-mail-buffer nil)))
138
139 (defmacro vm-error-if-folder-read-only ()
140 '(while vm-folder-read-only
141 (signal 'folder-read-only (list (current-buffer)))))
142
143 ;; XEmacs change
144 (define-error 'folder-read-only "Folder is read-only")
145
146 (defmacro vm-error-if-virtual-folder ()
147 '(and (eq major-mode 'vm-virtual-mode)
148 (error "%s cannot be applied to virtual folders." this-command)))
149
150 (defmacro vm-build-threads-if-unbuilt ()
151 '(if (null vm-thread-obarray)
152 (vm-build-threads nil)))
153
154 (defun vm-abs (n) (if (< n 0) (- n) n))
155
156 ;; save-restriction flubs restoring the clipping region if you
157 ;; (widen) and modify text outside the old region.
158 ;; This should do it right.
159 (defmacro vm-save-restriction (&rest forms)
160 (let ((vm-sr-clip (make-symbol "vm-sr-clip"))
161 (vm-sr-min (make-symbol "vm-sr-min"))
162 (vm-sr-max (make-symbol "vm-sr-max")))
163 (list 'let (list (list vm-sr-clip '(> (buffer-size)
164 (- (point-max) (point-min))))
165 ;; this shouldn't be necessary but the
166 ;; byte-compiler turns these into interned symbols
167 ;; which utterly defeats the purpose of the
168 ;; make-symbol calls above. Soooo, until the compiler
169 ;; is fixed, these must be made into (let ...)
170 ;; temporaries so that nested calls to this macros
171 ;; won't misbehave.
172 vm-sr-min vm-sr-max)
173 (list 'and vm-sr-clip
174 (list 'setq vm-sr-min '(set-marker (make-marker) (point-min)))
175 (list 'setq vm-sr-max '(set-marker (make-marker) (point-max))))
176 (list 'unwind-protect (cons 'progn forms)
177 '(widen)
178 (list 'and vm-sr-clip
179 (list 'progn
180 (list 'narrow-to-region vm-sr-min vm-sr-max)
181 (list 'set-marker vm-sr-min nil)
182 (list 'set-marker vm-sr-max nil)))))))
183
184 (defmacro vm-save-buffer-excursion (&rest forms)
185 (list 'let '((vm-sbe-buffer (current-buffer)))
186 (list 'unwind-protect
187 (cons 'progn forms)
188 '(and (not (eq vm-sbe-buffer (current-buffer)))
189 (buffer-name vm-sbe-buffer)
190 (set-buffer vm-sbe-buffer)))))
191
192 (defun vm-last (list) (while (cdr-safe list) (setq list (cdr list))) list)
193
194 (defun vm-vector-to-list (vector)
195 (let ((i (1- (length vector)))
196 list)
197 (while (>= i 0)
198 (setq list (cons (aref vector i) list))
199 (vm-decrement i))
200 list ))
201
202 (defun vm-extend-vector (vector length &optional fill)
203 (let ((vlength (length vector)))
204 (if (< vlength length)
205 (apply 'vector (nconc (vm-vector-to-list vector)
206 (make-list (- length vlength) fill)))
207 vector )))
208
209 (defun vm-obarray-to-string-list (obarray)
210 (let ((list nil))
211 (mapatoms (function (lambda (s) (setq list (cons (symbol-name s) list))))
212 obarray)
213 list ))
214
215 (defun vm-mapcar (function &rest lists)
216 (let (arglist result)
217 (while (car lists)
218 (setq arglist (mapcar 'car lists))
219 (setq result (cons (apply function arglist) result))
220 (setq lists (mapcar 'cdr lists)))
221 (nreverse result)))
222
223 (defun vm-mapc (function &rest lists)
224 (let (arglist)
225 (while (car lists)
226 (setq arglist (mapcar 'car lists))
227 (apply function arglist)
228 (setq lists (mapcar 'cdr lists)))))
229
230 (defun vm-delete (predicate list &optional reverse)
231 (let ((p list) (reverse (if reverse 'not 'identity)) prev)
232 (while p
233 (if (funcall reverse (funcall predicate (car p)))
234 (if (null prev)
235 (setq list (cdr list) p list)
236 (setcdr prev (cdr p))
237 (setq p (cdr p)))
238 (setq prev p p (cdr p))))
239 list ))
240
241 (defun vm-delete-duplicates (list &optional all hack-addresses)
242 "Delete duplicate equivalent strings from the list.
243 If ALL is t, then if there is more than one occurrence of a string in the list,
244 then all occurrences of it are removed instead of just the subsequent ones.
245 If HACK-ADDRESSES is t, then the strings are considered to be mail addresses,
246 and only the address part is compared (so that \"Name <foo>\" and \"foo\"
247 would be considered to be equivalent.)"
248 (let ((hashtable vm-delete-duplicates-obarray)
249 (new-list nil)
250 sym-string sym)
251 (fillarray hashtable 0)
252 (while list
253 (setq sym-string
254 (if hack-addresses
255 (nth 1 (funcall vm-chop-full-name-function (car list)))
256 (car list))
257 sym (intern sym-string hashtable))
258 (if (boundp sym)
259 (and all (setcar (symbol-value sym) nil))
260 (setq new-list (cons (car list) new-list))
261 (set sym new-list))
262 (setq list (cdr list)))
263 (delq nil (nreverse new-list))))
264
265 (defun vm-member-0 (thing list)
266 (catch 'done
267 (while list
268 (and (equal (car list) thing)
269 (throw 'done list))
270 (setq list (cdr list)))
271 nil ))
272
273 (fset 'vm-member (symbol-function (if (fboundp 'member) 'member 'vm-member-0)))
274
275 (defun vm-delqual (ob list)
276 (let ((prev nil)
277 (curr list))
278 (while curr
279 (if (not (equal ob (car curr)))
280 (setq prev curr
281 curr (cdr curr))
282 (if (null prev)
283 (setq list (cdr list)
284 curr list)
285 (setq curr (cdr curr))
286 (setcdr prev curr))))
287 list ))
288
289 (defun vm-copy-local-variables (buffer &rest variables)
290 (let ((values (mapcar 'symbol-value variables)))
291 (save-excursion
292 (set-buffer buffer)
293 (vm-mapc 'set variables values))))
294
295 ;; XEmacs change
296 (define-error 'folder-empty "Folder is empty")
297 (define-error 'unrecognized-folder-type "Unrecognized folder type")
298
299 (defun vm-error-if-folder-empty ()
300 (while (null vm-message-list)
301 (if vm-folder-type
302 (signal 'unrecognized-folder-type nil)
303 (signal 'folder-empty nil))))
304
305 (defun vm-copy (object)
306 (cond ((consp object)
307 (let (return-value cons)
308 (setq return-value (cons (vm-copy (car object)) nil)
309 cons return-value
310 object (cdr object))
311 (while (consp object)
312 (setcdr cons (cons (vm-copy (car object)) nil))
313 (setq cons (cdr cons)
314 object (cdr object)))
315 (setcdr cons object)
316 return-value ))
317 ((vectorp object) (apply 'vector (mapcar 'vm-copy object)))
318 ((stringp object) (copy-sequence object))
319 (t object)))
320
321 (defun vm-xemacs-p ()
322 (let ((case-fold-search nil))
323 (string-match "XEmacs" emacs-version)))
324
325 (defun vm-fsfemacs-19-p ()
326 (and (string-match "^19" emacs-version)
327 (not (string-match "XEmacs\\|Lucid" emacs-version))))
328
329 ;; make-frame might be defined and still not work. This would
330 ;; be true since the user could be running on a tty and using
331 ;; XEmacs 19.12, or using FSF Emacs 19.28 (or prior FSF Emacs versions).
332 ;;
333 ;; make-frame works on ttys in FSF Emacs 19.29, but other than
334 ;; looking at the version number I don't know a sane way to
335 ;; test for it without just running make-frame. I'll just
336 ;; let it not work for now... someone will complain eventually
337 ;; and I'll think of something.
338 (defun vm-multiple-frames-possible-p ()
339 (or (and (boundp 'window-system) (not (eq window-system nil)))
340 (and (fboundp 'device-type) (eq (device-type) 'x))))
341
342 (defun vm-mouse-support-possible-p ()
343 (vm-multiple-frames-possible-p))
344
345 (defun vm-menu-support-possible-p ()
346 (or (and (boundp 'window-system) (eq window-system 'x))
347 (and (fboundp 'device-type) (eq (device-type) 'x))))
348
349 (defun vm-toolbar-support-possible-p ()
350 (and (vm-xemacs-p)
351 (vm-multiple-frames-possible-p)
352 (featurep 'toolbar)))
353
354 (defun vm-run-message-hook (message &optional hook-variable)
355 (save-excursion
356 (set-buffer (vm-buffer-of message))
357 (vm-save-restriction
358 (widen)
359 (save-excursion
360 (narrow-to-region (vm-headers-of message) (vm-text-end-of message))
361 (run-hooks hook-variable)))))
362
363 (defun vm-error-free-call (function &rest args)
364 (condition-case nil
365 (apply function args)
366 (error nil)))
367
368 ;; XEmacs change
369 (define-error 'beginning-of-folder "Beginning of folder")
370 (define-error 'end-of-folder "End of folder")
371
372 (defun vm-trace (&rest args)
373 (save-excursion
374 (set-buffer (get-buffer-create "*vm-trace*"))
375 (apply 'insert args)))
376
377 (defun vm-timezone-make-date-sortable (string)
378 (or (cdr (assq string vm-sortable-date-alist))
379 (let ((vect (vm-parse-date string))
380 (date (vm-parse (current-time-string) " *\\([^ ]+\\)")))
381 ;; if specified date is incomplete fill in the holes
382 ;; with useful information, defaulting to the current
383 ;; date and timezone for everything except hh:mm:ss which
384 ;; defaults to midnight.
385 (if (equal (aref vect 1) "")
386 (aset vect 1 (nth 2 date)))
387 (if (equal (aref vect 2) "")
388 (aset vect 2 (nth 1 date)))
389 (if (equal (aref vect 3) "")
390 (aset vect 3 (nth 4 date)))
391 (if (equal (aref vect 4) "")
392 (aset vect 4 "00:00:00"))
393 (if (equal (aref vect 5) "")
394 (aset vect 5 (vm-current-time-zone)))
395 ;; save this work so we won't have to do it again
396 (setq vm-sortable-date-alist
397 (cons (cons string
398 (timezone-make-date-sortable
399 (format "%s %s %s %s %s"
400 (aref vect 1)
401 (aref vect 2)
402 (aref vect 3)
403 (aref vect 4)
404 (aref vect 5))))
405 vm-sortable-date-alist))
406 ;; return result
407 (cdr (car vm-sortable-date-alist)))))
408
409 (defun vm-current-time-zone ()
410 (or (condition-case nil
411 (let* ((zone (car (current-time-zone)))
412 (absmin (/ (vm-abs zone) 60)))
413 (format "%c%02d%02d" (if (< zone 0) ?- ?+)
414 (/ absmin 60) (% absmin 60)))
415 (error nil))
416 (let ((temp-buffer nil))
417 (condition-case nil
418 (unwind-protect
419 (save-excursion
420 (setq temp-buffer (generate-new-buffer "*vm-work*"))
421 (set-buffer temp-buffer)
422 (call-process "date" nil temp-buffer nil)
423 (nth 4 (vm-parse (vm-buffer-string-no-properties)
424 " *\\([^ ]+\\)")))
425 (and temp-buffer (kill-buffer temp-buffer)))
426 (error nil)))
427 ""))
428
429 (defun vm-should-generate-summary ()
430 (cond ((eq vm-startup-with-summary t) t)
431 ((integerp vm-startup-with-summary)
432 (let ((n vm-startup-with-summary))
433 (cond ((< n 0) (null (nth (vm-abs n) vm-message-list)))
434 (t (nth (1- n) vm-message-list)))))
435 (vm-startup-with-summary t)
436 (t nil)))
437
438 (defun vm-find-composition-buffer (&optional not-picky)
439 (let ((b-list (buffer-list)) choice alternate)
440 (save-excursion
441 (while b-list
442 (set-buffer (car b-list))
443 (if (eq major-mode 'mail-mode)
444 (if (buffer-modified-p)
445 (setq choice (current-buffer)
446 b-list nil)
447 (and not-picky (null alternate)
448 (setq alternate (current-buffer)))
449 (setq b-list (cdr b-list)))
450 (setq b-list (cdr b-list))))
451 (or choice alternate))))
452
453 (defun vm-get-file-buffer (file)
454 "Like get-file-buffer, but also checks buffers against FILE's truename"
455 (or (get-file-buffer file)
456 (and (fboundp 'file-truename)
457 (get-file-buffer (file-truename file)))))
458
459 (defun vm-set-region-face (start end face)
460 (cond ((fboundp 'make-overlay)
461 (let ((o (make-overlay start end)))
462 (overlay-put o 'face face)))
463 ((fboundp 'make-extent)
464 (let ((o (make-extent start end)))
465 (set-extent-property o 'face face)))))
466
467 (defun vm-unsaved-message (&rest args)
468 (let ((message-log-max nil))
469 (apply (function message) args)))
470
471 (defun vm-default-buffer-substring-no-properties (beg end &optional buffer)
472 (let ((s (if buffer
473 (save-excursion
474 (set-buffer buffer)
475 (buffer-substring beg end))
476 (buffer-substring beg end))))
477 (set-text-properties 0 (length s) nil s)
478 (copy-sequence s)))
479
480 (fset 'vm-buffer-substring-no-properties
481 (cond ((fboundp 'buffer-substring-no-properties)
482 (function buffer-substring-no-properties))
483 ((vm-xemacs-p)
484 (function buffer-substring))
485 (t (function vm-default-buffer-substring-no-properties))))
486
487 (defun vm-buffer-string-no-properties ()
488 (vm-buffer-substring-no-properties (point-min) (point-max)))