Mercurial > emacs
comparison lisp/gnus/gnus-util.el @ 31716:9968f55ad26e
Update to emacs-21-branch of the Gnus CVS repository.
author | Gerd Moellmann <gerd@gnu.org> |
---|---|
date | Tue, 19 Sep 2000 13:37:09 +0000 |
parents | 15fc6acbae7a |
children | 51cea22fd2aa |
comparison
equal
deleted
inserted
replaced
31715:7c896543d225 | 31716:9968f55ad26e |
---|---|
1 ;;; gnus-util.el --- utility functions for Gnus | 1 ;;; gnus-util.el --- utility functions for Gnus |
2 ;; Copyright (C) 1996,97,98 Free Software Foundation, Inc. | 2 ;; Copyright (C) 1996, 1997, 1998, 1999, 2000 |
3 ;; Free Software Foundation, Inc. | |
3 | 4 |
4 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org> | 5 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org> |
5 ;; Keywords: news | 6 ;; Keywords: news |
6 | 7 |
7 ;; This file is part of GNU Emacs. | 8 ;; This file is part of GNU Emacs. |
31 ;;; Code: | 32 ;;; Code: |
32 | 33 |
33 (require 'custom) | 34 (require 'custom) |
34 (eval-when-compile (require 'cl)) | 35 (eval-when-compile (require 'cl)) |
35 (require 'nnheader) | 36 (require 'nnheader) |
36 (require 'timezone) | |
37 (require 'message) | 37 (require 'message) |
38 (eval-when-compile (require 'rmail)) | 38 (require 'time-date) |
39 | 39 |
40 (eval-and-compile | 40 (eval-and-compile |
41 (autoload 'nnmail-date-to-time "nnmail") | |
42 (autoload 'rmail-insert-rmail-file-header "rmail") | 41 (autoload 'rmail-insert-rmail-file-header "rmail") |
43 (autoload 'rmail-count-new-messages "rmail") | 42 (autoload 'rmail-count-new-messages "rmail") |
44 (autoload 'rmail-show-message "rmail")) | 43 (autoload 'rmail-show-message "rmail")) |
45 | 44 |
46 (defun gnus-boundp (variable) | 45 (defun gnus-boundp (variable) |
74 `(let ((symbol (intern ,string ,hashtable))) | 73 `(let ((symbol (intern ,string ,hashtable))) |
75 (or (boundp symbol) | 74 (or (boundp symbol) |
76 (set symbol nil)) | 75 (set symbol nil)) |
77 symbol)) | 76 symbol)) |
78 | 77 |
79 (defun gnus-truncate-string (str width) | |
80 (substring str 0 width)) | |
81 | |
82 ;; Added by Geoffrey T. Dairiki <dairiki@u.washington.edu>. A safe way | 78 ;; Added by Geoffrey T. Dairiki <dairiki@u.washington.edu>. A safe way |
83 ;; to limit the length of a string. This function is necessary since | 79 ;; to limit the length of a string. This function is necessary since |
84 ;; `(substr "abc" 0 30)' pukes with "Args out of range". | 80 ;; `(substr "abc" 0 30)' pukes with "Args out of range". |
85 (defsubst gnus-limit-string (str width) | 81 (defsubst gnus-limit-string (str width) |
86 (if (> (length str) width) | 82 (if (> (length str) width) |
105 (defmacro gnus-kill-buffer (buffer) | 101 (defmacro gnus-kill-buffer (buffer) |
106 `(let ((buf ,buffer)) | 102 `(let ((buf ,buffer)) |
107 (when (gnus-buffer-exists-p buf) | 103 (when (gnus-buffer-exists-p buf) |
108 (kill-buffer buf)))) | 104 (kill-buffer buf)))) |
109 | 105 |
110 (if (fboundp 'point-at-bol) | 106 (defalias 'gnus-point-at-bol |
111 (fset 'gnus-point-at-bol 'point-at-bol) | 107 (if (fboundp 'point-at-bol) |
112 (defun gnus-point-at-bol () | 108 'point-at-bol |
113 "Return point at the beginning of the line." | 109 'line-beginning-position)) |
114 (let ((p (point))) | 110 |
115 (beginning-of-line) | 111 (defalias 'gnus-point-at-eol |
116 (prog1 | 112 (if (fboundp 'point-at-eol) |
117 (point) | 113 'point-at-eol |
118 (goto-char p))))) | 114 'line-end-position)) |
119 | |
120 (if (fboundp 'point-at-eol) | |
121 (fset 'gnus-point-at-eol 'point-at-eol) | |
122 (defun gnus-point-at-eol () | |
123 "Return point at the end of the line." | |
124 (let ((p (point))) | |
125 (end-of-line) | |
126 (prog1 | |
127 (point) | |
128 (goto-char p))))) | |
129 | 115 |
130 (defun gnus-delete-first (elt list) | 116 (defun gnus-delete-first (elt list) |
131 "Delete by side effect the first occurrence of ELT as a member of LIST." | 117 "Delete by side effect the first occurrence of ELT as a member of LIST." |
132 (if (equal (car list) elt) | 118 (if (equal (car list) elt) |
133 (cdr list) | 119 (cdr list) |
177 (setq name address)) | 163 (setq name address)) |
178 ;; XOVER might not support folded From headers. | 164 ;; XOVER might not support folded From headers. |
179 (and (string-match "(.*" from) | 165 (and (string-match "(.*" from) |
180 (setq name (substring from (1+ (match-beginning 0)) | 166 (setq name (substring from (1+ (match-beginning 0)) |
181 (match-end 0))))) | 167 (match-end 0))))) |
182 ;; Fix by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>. | 168 (list (if (string= name "") nil name) (or address from)))) |
183 (list (or name from) (or address from)))) | 169 |
184 | 170 |
185 (defun gnus-fetch-field (field) | 171 (defun gnus-fetch-field (field) |
186 "Return the value of the header FIELD of current article." | 172 "Return the value of the header FIELD of current article." |
187 (save-excursion | 173 (save-excursion |
188 (save-restriction | 174 (save-restriction |
229 (defun gnus-string> (s1 s2) | 215 (defun gnus-string> (s1 s2) |
230 (not (or (string< s1 s2) | 216 (not (or (string< s1 s2) |
231 (string= s1 s2)))) | 217 (string= s1 s2)))) |
232 | 218 |
233 ;;; Time functions. | 219 ;;; Time functions. |
234 | |
235 (defun gnus-days-between (date1 date2) | |
236 ;; Return the number of days between date1 and date2. | |
237 (- (gnus-day-number date1) (gnus-day-number date2))) | |
238 | |
239 (defun gnus-day-number (date) | |
240 (let ((dat (mapcar (lambda (s) (and s (string-to-int s)) ) | |
241 (timezone-parse-date date)))) | |
242 (timezone-absolute-from-gregorian | |
243 (nth 1 dat) (nth 2 dat) (car dat)))) | |
244 | |
245 (defun gnus-time-to-day (time) | |
246 "Convert TIME to day number." | |
247 (let ((tim (decode-time time))) | |
248 (timezone-absolute-from-gregorian | |
249 (nth 4 tim) (nth 3 tim) (nth 5 tim)))) | |
250 | |
251 (defun gnus-encode-date (date) | |
252 "Convert DATE to internal time." | |
253 (let* ((parse (timezone-parse-date date)) | |
254 (date (mapcar (lambda (d) (and d (string-to-int d))) parse)) | |
255 (time (mapcar 'string-to-int (timezone-parse-time (aref parse 3))))) | |
256 (encode-time (caddr time) (cadr time) (car time) | |
257 (caddr date) (cadr date) (car date) | |
258 (* 60 (timezone-zone-to-minute (nth 4 date)))))) | |
259 | |
260 (defun gnus-time-minus (t1 t2) | |
261 "Subtract two internal times." | |
262 (let ((borrow (< (cadr t1) (cadr t2)))) | |
263 (list (- (car t1) (car t2) (if borrow 1 0)) | |
264 (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2))))) | |
265 | |
266 (defun gnus-time-less (t1 t2) | |
267 "Say whether time T1 is less than time T2." | |
268 (or (< (car t1) (car t2)) | |
269 (and (= (car t1) (car t2)) | |
270 (< (nth 1 t1) (nth 1 t2))))) | |
271 | 220 |
272 (defun gnus-file-newer-than (file date) | 221 (defun gnus-file-newer-than (file date) |
273 (let ((fdate (nth 5 (file-attributes file)))) | 222 (let ((fdate (nth 5 (file-attributes file)))) |
274 (or (> (car fdate) (car date)) | 223 (or (> (car fdate) (car date)) |
275 (and (= (car fdate) (car date)) | 224 (and (= (car fdate) (car date)) |
341 (yes-or-no-p prompt) | 290 (yes-or-no-p prompt) |
342 (message ""))) | 291 (message ""))) |
343 | 292 |
344 (defun gnus-dd-mmm (messy-date) | 293 (defun gnus-dd-mmm (messy-date) |
345 "Return a string like DD-MMM from a big messy string." | 294 "Return a string like DD-MMM from a big messy string." |
346 (let ((datevec (ignore-errors (timezone-parse-date messy-date)))) | 295 (condition-case () |
347 (if (or (not datevec) | 296 (format-time-string "%d-%b" (safe-date-to-time messy-date)) |
348 (string-equal "0" (aref datevec 1))) | 297 (error " - "))) |
349 "??-???" | |
350 (format "%2s-%s" | |
351 (condition-case () | |
352 ;; Make sure leading zeroes are stripped. | |
353 (number-to-string (string-to-number (aref datevec 2))) | |
354 (error "??")) | |
355 (capitalize | |
356 (or (car | |
357 (nth (1- (string-to-number (aref datevec 1))) | |
358 timezone-months-assoc)) | |
359 "???")))))) | |
360 | 298 |
361 (defmacro gnus-date-get-time (date) | 299 (defmacro gnus-date-get-time (date) |
362 "Convert DATE string to Emacs time. | 300 "Convert DATE string to Emacs time. |
363 Cache the result as a text property stored in DATE." | 301 Cache the result as a text property stored in DATE." |
364 ;; Either return the cached value... | 302 ;; Either return the cached value... |
365 `(let ((d ,date)) | 303 `(let ((d ,date)) |
366 (if (equal "" d) | 304 (if (equal "" d) |
367 '(0 0) | 305 '(0 0) |
368 (or (get-text-property 0 'gnus-time d) | 306 (or (get-text-property 0 'gnus-time d) |
369 ;; or compute the value... | 307 ;; or compute the value... |
370 (let ((time (nnmail-date-to-time d))) | 308 (let ((time (safe-date-to-time d))) |
371 ;; and store it back in the string. | 309 ;; and store it back in the string. |
372 (put-text-property 0 1 'gnus-time time d) | 310 (put-text-property 0 1 'gnus-time time d) |
373 time))))) | 311 time))))) |
374 | 312 |
375 (defsubst gnus-time-iso8601 (time) | 313 (defsubst gnus-time-iso8601 (time) |
449 (while (string-match "<[^>]+>" references beg) | 387 (while (string-match "<[^>]+>" references beg) |
450 (push (substring references (match-beginning 0) (setq beg (match-end 0))) | 388 (push (substring references (match-beginning 0) (setq beg (match-end 0))) |
451 ids)) | 389 ids)) |
452 (nreverse ids))) | 390 (nreverse ids))) |
453 | 391 |
454 (defun gnus-parent-id (references &optional n) | 392 (defsubst gnus-parent-id (references &optional n) |
455 "Return the last Message-ID in REFERENCES. | 393 "Return the last Message-ID in REFERENCES. |
456 If N, return the Nth ancestor instead." | 394 If N, return the Nth ancestor instead." |
457 (when references | 395 (when references |
458 (let ((ids (inline (gnus-split-references references)))) | 396 (let ((ids (inline (gnus-split-references references)))) |
459 (car (last ids (or n 1)))))) | 397 (while (nthcdr (or n 1) ids) |
398 (setq ids (cdr ids))) | |
399 (car ids)))) | |
460 | 400 |
461 (defsubst gnus-buffer-live-p (buffer) | 401 (defsubst gnus-buffer-live-p (buffer) |
462 "Say whether BUFFER is alive or not." | 402 "Say whether BUFFER is alive or not." |
463 (and buffer | 403 (and buffer |
464 (get-buffer buffer) | 404 (get-buffer buffer) |
494 (let ((event (read-event))) | 434 (let ((event (read-event))) |
495 ;; should be gnus-characterp, but this can't be called in XEmacs anyway | 435 ;; should be gnus-characterp, but this can't be called in XEmacs anyway |
496 (cons (and (numberp event) event) event))) | 436 (cons (and (numberp event) event) event))) |
497 | 437 |
498 (defun gnus-sortable-date (date) | 438 (defun gnus-sortable-date (date) |
499 "Make sortable string by string-lessp from DATE. | 439 "Make string suitable for sorting from DATE." |
500 Timezone package is used." | 440 (gnus-time-iso8601 (date-to-time date))) |
501 (condition-case () | |
502 (progn | |
503 (setq date (inline (timezone-fix-time | |
504 date nil | |
505 (aref (inline (timezone-parse-date date)) 4)))) | |
506 (inline | |
507 (timezone-make-sortable-date | |
508 (aref date 0) (aref date 1) (aref date 2) | |
509 (inline | |
510 (timezone-make-time-string | |
511 (aref date 3) (aref date 4) (aref date 5)))))) | |
512 (error ""))) | |
513 | 441 |
514 (defun gnus-copy-file (file &optional to) | 442 (defun gnus-copy-file (file &optional to) |
515 "Copy FILE to TO." | 443 "Copy FILE to TO." |
516 (interactive | 444 (interactive |
517 (list (read-file-name "Copy file: " default-directory) | 445 (list (read-file-name "Copy file: " default-directory) |
539 (progn | 467 (progn |
540 (set-buffer gnus-work-buffer) | 468 (set-buffer gnus-work-buffer) |
541 (erase-buffer)) | 469 (erase-buffer)) |
542 (set-buffer (gnus-get-buffer-create gnus-work-buffer)) | 470 (set-buffer (gnus-get-buffer-create gnus-work-buffer)) |
543 (kill-all-local-variables) | 471 (kill-all-local-variables) |
544 (buffer-disable-undo (current-buffer)))) | 472 (mm-enable-multibyte))) |
545 | 473 |
546 (defmacro gnus-group-real-name (group) | 474 (defmacro gnus-group-real-name (group) |
547 "Find the real name of a foreign newsgroup." | 475 "Find the real name of a foreign newsgroup." |
548 `(let ((gname ,group)) | 476 `(let ((gname ,group)) |
549 (if (string-match "^[^:]+:" gname) | 477 (if (string-match "^[^:]+:" gname) |
551 gname))) | 479 gname))) |
552 | 480 |
553 (defun gnus-make-sort-function (funs) | 481 (defun gnus-make-sort-function (funs) |
554 "Return a composite sort condition based on the functions in FUNC." | 482 "Return a composite sort condition based on the functions in FUNC." |
555 (cond | 483 (cond |
556 ((not (listp funs)) funs) | 484 ;; Just a simple function. |
485 ((gnus-functionp funs) funs) | |
486 ;; No functions at all. | |
557 ((null funs) funs) | 487 ((null funs) funs) |
558 ((cdr funs) | 488 ;; A list of functions. |
489 ((or (cdr funs) | |
490 (listp (car funs))) | |
559 `(lambda (t1 t2) | 491 `(lambda (t1 t2) |
560 ,(gnus-make-sort-function-1 (reverse funs)))) | 492 ,(gnus-make-sort-function-1 (reverse funs)))) |
493 ;; A list containing just one function. | |
561 (t | 494 (t |
562 (car funs)))) | 495 (car funs)))) |
563 | 496 |
564 (defun gnus-make-sort-function-1 (funs) | 497 (defun gnus-make-sort-function-1 (funs) |
565 "Return a composite sort condition based on the functions in FUNC." | 498 "Return a composite sort condition based on the functions in FUNC." |
566 (if (cdr funs) | 499 (let ((function (car funs)) |
567 `(or (,(car funs) t1 t2) | 500 (first 't1) |
568 (and (not (,(car funs) t2 t1)) | 501 (last 't2)) |
569 ,(gnus-make-sort-function-1 (cdr funs)))) | 502 (when (consp function) |
570 `(,(car funs) t1 t2))) | 503 (cond |
504 ;; Reversed spec. | |
505 ((eq (car function) 'not) | |
506 (setq function (cadr function) | |
507 first 't2 | |
508 last 't1)) | |
509 ((gnus-functionp function) | |
510 ;; Do nothing. | |
511 ) | |
512 (t | |
513 (error "Invalid sort spec: %s" function)))) | |
514 (if (cdr funs) | |
515 `(or (,function ,first ,last) | |
516 (and (not (,function ,last ,first)) | |
517 ,(gnus-make-sort-function-1 (cdr funs)))) | |
518 `(,function ,first ,last)))) | |
571 | 519 |
572 (defun gnus-turn-off-edit-menu (type) | 520 (defun gnus-turn-off-edit-menu (type) |
573 "Turn off edit menu in `gnus-TYPE-mode-map'." | 521 "Turn off edit menu in `gnus-TYPE-mode-map'." |
574 (define-key (symbol-value (intern (format "gnus-%s-mode-map" type))) | 522 (define-key (symbol-value (intern (format "gnus-%s-mode-map" type))) |
575 [menu-bar edit] 'undefined)) | 523 [menu-bar edit] 'undefined)) |
589 (print-readably t)) | 537 (print-readably t)) |
590 (prin1-to-string form))) | 538 (prin1-to-string form))) |
591 | 539 |
592 (defun gnus-make-directory (directory) | 540 (defun gnus-make-directory (directory) |
593 "Make DIRECTORY (and all its parents) if it doesn't exist." | 541 "Make DIRECTORY (and all its parents) if it doesn't exist." |
594 (when (and directory | 542 (let ((file-name-coding-system nnmail-pathname-coding-system)) |
595 (not (file-exists-p directory))) | 543 (when (and directory |
596 (make-directory directory t)) | 544 (not (file-exists-p directory))) |
545 (make-directory directory t))) | |
597 t) | 546 t) |
598 | 547 |
599 (defun gnus-write-buffer (file) | 548 (defun gnus-write-buffer (file) |
600 "Write the current buffer's contents to FILE." | 549 "Write the current buffer's contents to FILE." |
601 ;; Make sure the directory exists. | 550 ;; Make sure the directory exists. |
602 (gnus-make-directory (file-name-directory file)) | 551 (gnus-make-directory (file-name-directory file)) |
603 ;; Write the buffer. | 552 (let ((file-name-coding-system nnmail-pathname-coding-system)) |
604 (write-region (point-min) (point-max) file nil 'quietly)) | 553 ;; Write the buffer. |
554 (write-region (point-min) (point-max) file nil 'quietly))) | |
605 | 555 |
606 (defun gnus-delete-file (file) | 556 (defun gnus-delete-file (file) |
607 "Delete FILE if it exists." | 557 "Delete FILE if it exists." |
608 (when (file-exists-p file) | 558 (when (file-exists-p file) |
609 (delete-file file))) | 559 (delete-file file))) |
612 "Return STRING stripped of all whitespace." | 562 "Return STRING stripped of all whitespace." |
613 (while (string-match "[\r\n\t ]+" string) | 563 (while (string-match "[\r\n\t ]+" string) |
614 (setq string (replace-match "" t t string))) | 564 (setq string (replace-match "" t t string))) |
615 string) | 565 string) |
616 | 566 |
617 (defun gnus-put-text-property-excluding-newlines (beg end prop val) | 567 (defsubst gnus-put-text-property-excluding-newlines (beg end prop val) |
618 "The same as `put-text-property', but don't put this prop on any newlines in the region." | 568 "The same as `put-text-property', but don't put this prop on any newlines in the region." |
619 (save-match-data | 569 (save-match-data |
620 (save-excursion | 570 (save-excursion |
621 (save-restriction | 571 (save-restriction |
622 (goto-char beg) | 572 (goto-char beg) |
623 (while (re-search-forward "[ \t]*\n" end 'move) | 573 (while (re-search-forward gnus-emphasize-whitespace-regexp end 'move) |
624 (gnus-put-text-property beg (match-beginning 0) prop val) | 574 (gnus-put-text-property beg (match-beginning 0) prop val) |
625 (setq beg (point))) | 575 (setq beg (point))) |
626 (gnus-put-text-property beg (point) prop val))))) | 576 (gnus-put-text-property beg (point) prop val))))) |
627 | 577 |
628 (defun gnus-put-text-property-excluding-characters-with-faces (beg end | 578 (defun gnus-put-text-property-excluding-characters-with-faces (beg end |
731 (concat "\"" filename "\" does not exist, create it? "))) | 681 (concat "\"" filename "\" does not exist, create it? "))) |
732 (let ((file-buffer (create-file-buffer filename))) | 682 (let ((file-buffer (create-file-buffer filename))) |
733 (save-excursion | 683 (save-excursion |
734 (set-buffer file-buffer) | 684 (set-buffer file-buffer) |
735 (rmail-insert-rmail-file-header) | 685 (rmail-insert-rmail-file-header) |
736 (let ((require-final-newline nil)) | 686 (let ((require-final-newline nil) |
687 (coding-system-for-write mm-text-coding-system)) | |
737 (gnus-write-buffer filename))) | 688 (gnus-write-buffer filename))) |
738 (kill-buffer file-buffer)) | 689 (kill-buffer file-buffer)) |
739 (error "Output file does not exist"))) | 690 (error "Output file does not exist"))) |
740 (set-buffer tmpbuf) | 691 (set-buffer tmpbuf) |
741 (erase-buffer) | 692 (erase-buffer) |
742 (insert-buffer-substring artbuf) | 693 (insert-buffer-substring artbuf) |
743 (gnus-convert-article-to-rmail) | 694 (gnus-convert-article-to-rmail) |
744 ;; Decide whether to append to a file or to an Emacs buffer. | 695 ;; Decide whether to append to a file or to an Emacs buffer. |
745 (let ((outbuf (get-file-buffer filename))) | 696 (let ((outbuf (get-file-buffer filename))) |
746 (if (not outbuf) | 697 (if (not outbuf) |
747 (append-to-file (point-min) (point-max) filename) | 698 (mm-append-to-file (point-min) (point-max) filename) |
748 ;; File has been visited, in buffer OUTBUF. | 699 ;; File has been visited, in buffer OUTBUF. |
749 (set-buffer outbuf) | 700 (set-buffer outbuf) |
750 (let ((buffer-read-only nil) | 701 (let ((buffer-read-only nil) |
751 (msg (and (boundp 'rmail-current-message) | 702 (msg (and (boundp 'rmail-current-message) |
752 (symbol-value 'rmail-current-message)))) | 703 (symbol-value 'rmail-current-message)))) |
782 (gnus-y-or-n-p | 733 (gnus-y-or-n-p |
783 (concat "\"" filename "\" does not exist, create it? "))) | 734 (concat "\"" filename "\" does not exist, create it? "))) |
784 (let ((file-buffer (create-file-buffer filename))) | 735 (let ((file-buffer (create-file-buffer filename))) |
785 (save-excursion | 736 (save-excursion |
786 (set-buffer file-buffer) | 737 (set-buffer file-buffer) |
787 (let ((require-final-newline nil)) | 738 (let ((require-final-newline nil) |
739 (coding-system-for-write mm-text-coding-system)) | |
788 (gnus-write-buffer filename))) | 740 (gnus-write-buffer filename))) |
789 (kill-buffer file-buffer)) | 741 (kill-buffer file-buffer)) |
790 (error "Output file does not exist"))) | 742 (error "Output file does not exist"))) |
791 (set-buffer tmpbuf) | 743 (set-buffer tmpbuf) |
792 (erase-buffer) | 744 (erase-buffer) |
810 (goto-char (point-max)) | 762 (goto-char (point-max)) |
811 (unless (bolp) | 763 (unless (bolp) |
812 (insert "\n")) | 764 (insert "\n")) |
813 (insert "\n")) | 765 (insert "\n")) |
814 (goto-char (point-max)) | 766 (goto-char (point-max)) |
815 (append-to-file (point-min) (point-max) filename))) | 767 (mm-append-to-file (point-min) (point-max) filename))) |
816 ;; File has been visited, in buffer OUTBUF. | 768 ;; File has been visited, in buffer OUTBUF. |
817 (set-buffer outbuf) | 769 (set-buffer outbuf) |
818 (let ((buffer-read-only nil)) | 770 (let ((buffer-read-only nil)) |
819 (goto-char (point-max)) | 771 (goto-char (point-max)) |
820 (unless (eobp) | 772 (unless (eobp) |
851 | 803 |
852 ;;; | 804 ;;; |
853 ;;; .netrc and .authinforc parsing | 805 ;;; .netrc and .authinforc parsing |
854 ;;; | 806 ;;; |
855 | 807 |
856 (defvar gnus-netrc-syntax-table | |
857 (let ((table (copy-syntax-table text-mode-syntax-table))) | |
858 (modify-syntax-entry ?@ "w" table) | |
859 (modify-syntax-entry ?- "w" table) | |
860 (modify-syntax-entry ?_ "w" table) | |
861 (modify-syntax-entry ?! "w" table) | |
862 (modify-syntax-entry ?. "w" table) | |
863 (modify-syntax-entry ?, "w" table) | |
864 (modify-syntax-entry ?: "w" table) | |
865 (modify-syntax-entry ?\; "w" table) | |
866 (modify-syntax-entry ?% "w" table) | |
867 (modify-syntax-entry ?) "w" table) | |
868 (modify-syntax-entry ?( "w" table) | |
869 table) | |
870 "Syntax table when parsing .netrc files.") | |
871 | |
872 (defun gnus-parse-netrc (file) | 808 (defun gnus-parse-netrc (file) |
873 "Parse FILE and return an list of all entries in the file." | 809 "Parse FILE and return an list of all entries in the file." |
874 (if (not (file-exists-p file)) | 810 (when (file-exists-p file) |
875 () | 811 (with-temp-buffer |
876 (save-excursion | |
877 (let ((tokens '("machine" "default" "login" | 812 (let ((tokens '("machine" "default" "login" |
878 "password" "account" "macdef" "force")) | 813 "password" "account" "macdef" "force" |
814 "port")) | |
879 alist elem result pair) | 815 alist elem result pair) |
880 (nnheader-set-temp-buffer " *netrc*") | 816 (insert-file-contents file) |
881 (unwind-protect | 817 (goto-char (point-min)) |
882 (progn | 818 ;; Go through the file, line by line. |
883 (set-syntax-table gnus-netrc-syntax-table) | 819 (while (not (eobp)) |
884 (insert-file-contents file) | 820 (narrow-to-region (point) (gnus-point-at-eol)) |
885 (goto-char (point-min)) | 821 ;; For each line, get the tokens and values. |
886 ;; Go through the file, line by line. | 822 (while (not (eobp)) |
887 (while (not (eobp)) | 823 (skip-chars-forward "\t ") |
888 (narrow-to-region (point) (gnus-point-at-eol)) | 824 ;; Skip lines that begin with a "#". |
889 ;; For each line, get the tokens and values. | 825 (if (eq (char-after) ?#) |
890 (while (not (eobp)) | 826 (goto-char (point-max)) |
891 (skip-chars-forward "\t ") | 827 (unless (eobp) |
892 (unless (eobp) | 828 (setq elem |
893 (setq elem (buffer-substring | 829 (if (= (following-char) ?\") |
894 (point) (progn (forward-sexp 1) (point)))) | 830 (read (current-buffer)) |
895 (cond | 831 (buffer-substring |
896 ((equal elem "macdef") | 832 (point) (progn (skip-chars-forward "^\t ") |
897 ;; We skip past the macro definition. | 833 (point))))) |
898 (widen) | 834 (cond |
899 (while (and (zerop (forward-line 1)) | 835 ((equal elem "macdef") |
900 (looking-at "$"))) | 836 ;; We skip past the macro definition. |
901 (narrow-to-region (point) (point))) | 837 (widen) |
902 ((member elem tokens) | 838 (while (and (zerop (forward-line 1)) |
903 ;; Tokens that don't have a following value are ignored, | 839 (looking-at "$"))) |
904 ;; except "default". | 840 (narrow-to-region (point) (point))) |
905 (when (and pair (or (cdr pair) | 841 ((member elem tokens) |
906 (equal (car pair) "default"))) | 842 ;; Tokens that don't have a following value are ignored, |
907 (push pair alist)) | 843 ;; except "default". |
908 (setq pair (list elem))) | 844 (when (and pair (or (cdr pair) |
909 (t | 845 (equal (car pair) "default"))) |
910 ;; Values that haven't got a preceding token are ignored. | 846 (push pair alist)) |
911 (when pair | 847 (setq pair (list elem))) |
912 (setcdr pair elem) | 848 (t |
913 (push pair alist) | 849 ;; Values that haven't got a preceding token are ignored. |
914 (setq pair nil)))))) | 850 (when pair |
915 (if alist | 851 (setcdr pair elem) |
916 (push (nreverse alist) result)) | 852 (push pair alist) |
917 (setq alist nil | 853 (setq pair nil))))))) |
918 pair nil) | 854 (when alist |
919 (widen) | 855 (push (nreverse alist) result)) |
920 (forward-line 1)) | 856 (setq alist nil |
921 (nreverse result)) | 857 pair nil) |
922 (kill-buffer " *netrc*")))))) | 858 (widen) |
923 | 859 (forward-line 1)) |
924 (defun gnus-netrc-machine (list machine) | 860 (nreverse result))))) |
925 "Return the netrc values from LIST for MACHINE or for the default entry." | 861 |
926 (let ((rest list)) | 862 (defun gnus-netrc-machine (list machine &optional port defaultport) |
927 (while (and list | 863 "Return the netrc values from LIST for MACHINE or for the default entry. |
928 (not (equal (cdr (assoc "machine" (car list))) machine))) | 864 If PORT specified, only return entries with matching port tokens. |
865 Entries without port tokens default to DEFAULTPORT." | |
866 (let ((rest list) | |
867 result) | |
868 (while list | |
869 (when (equal (cdr (assoc "machine" (car list))) machine) | |
870 (push (car list) result)) | |
929 (pop list)) | 871 (pop list)) |
930 (car (or list | 872 (unless result |
931 (progn (while (and rest (not (assoc "default" (car rest)))) | 873 ;; No machine name matches, so we look for default entries. |
932 (pop rest)) | 874 (while rest |
933 rest))))) | 875 (when (assoc "default" (car rest)) |
876 (push (car rest) result)) | |
877 (pop rest))) | |
878 (when result | |
879 (setq result (nreverse result)) | |
880 (while (and result | |
881 (not (equal (or port defaultport "nntp") | |
882 (or (gnus-netrc-get (car result) "port") | |
883 defaultport "nntp")))) | |
884 (pop result)) | |
885 (car result)))) | |
934 | 886 |
935 (defun gnus-netrc-get (alist type) | 887 (defun gnus-netrc-get (alist type) |
936 "Return the value of token TYPE from ALIST." | 888 "Return the value of token TYPE from ALIST." |
937 (cdr (assoc type alist))) | 889 (cdr (assoc type alist))) |
938 | 890 |
939 ;;; Various | 891 ;;; Various |
940 | 892 |
941 (defvar gnus-group-buffer) ; Compiler directive | 893 (defvar gnus-group-buffer) ; Compiler directive |
942 (defun gnus-alive-p () | 894 (defun gnus-alive-p () |
943 "Say whether Gnus is running or not." | 895 "Say whether Gnus is running or not." |
944 (and (boundp 'gnus-group-buffer) | 896 (and (boundp 'gnus-group-buffer) |
945 (get-buffer gnus-group-buffer) | 897 (get-buffer gnus-group-buffer) |
946 (save-excursion | 898 (save-excursion |
969 (let (entry) | 921 (let (entry) |
970 (while (setq entry (assq key alist)) | 922 (while (setq entry (assq key alist)) |
971 (setq alist (delq entry alist))) | 923 (setq alist (delq entry alist))) |
972 alist)) | 924 alist)) |
973 | 925 |
974 (defmacro gnus-pull (key alist) | 926 (defmacro gnus-pull (key alist &optional assoc-p) |
975 "Modify ALIST to be without KEY." | 927 "Modify ALIST to be without KEY." |
976 (unless (symbolp alist) | 928 (unless (symbolp alist) |
977 (error "Not a symbol: %s" alist)) | 929 (error "Not a symbol: %s" alist)) |
978 `(setq ,alist (delq (assq ,key ,alist) ,alist))) | 930 (let ((fun (if assoc-p 'assoc 'assq))) |
931 `(setq ,alist (delq (,fun ,key ,alist) ,alist)))) | |
979 | 932 |
980 (defun gnus-globalify-regexp (re) | 933 (defun gnus-globalify-regexp (re) |
981 "Returns a regexp that matches a whole line, iff RE matches a part of it." | 934 "Returns a regexp that matches a whole line, iff RE matches a part of it." |
982 (concat (unless (string-match "^\\^" re) "^.*") | 935 (concat (unless (string-match "^\\^" re) "^.*") |
983 re | 936 re |
984 (unless (string-match "\\$$" re) ".*$"))) | 937 (unless (string-match "\\$$" re) ".*$"))) |
985 | 938 |
939 (defun gnus-set-window-start (&optional point) | |
940 "Set the window start to POINT, or (point) if nil." | |
941 (let ((win (get-buffer-window (current-buffer) t))) | |
942 (when win | |
943 (set-window-start win (or point (point)))))) | |
944 | |
945 (defun gnus-annotation-in-region-p (b e) | |
946 (if (= b e) | |
947 (eq (cadr (memq 'gnus-undeletable (text-properties-at b))) t) | |
948 (text-property-any b e 'gnus-undeletable t))) | |
949 | |
950 (defun gnus-or (&rest elems) | |
951 "Return non-nil if any of the elements are non-nil." | |
952 (catch 'found | |
953 (while elems | |
954 (when (pop elems) | |
955 (throw 'found t))))) | |
956 | |
957 (defun gnus-and (&rest elems) | |
958 "Return non-nil if all of the elements are non-nil." | |
959 (catch 'found | |
960 (while elems | |
961 (unless (pop elems) | |
962 (throw 'found nil))) | |
963 t)) | |
964 | |
965 (defun gnus-write-active-file (file hashtb &optional full-names) | |
966 (let ((coding-system-for-write nnmail-active-file-coding-system)) | |
967 (with-temp-file file | |
968 (mapatoms | |
969 (lambda (sym) | |
970 (when (and sym | |
971 (boundp sym) | |
972 (symbol-value sym)) | |
973 (insert (format "%S %d %d y\n" | |
974 (if full-names | |
975 sym | |
976 (intern (gnus-group-real-name (symbol-name sym)))) | |
977 (or (cdr (symbol-value sym)) | |
978 (car (symbol-value sym))) | |
979 (car (symbol-value sym)))))) | |
980 hashtb) | |
981 (goto-char (point-max)) | |
982 (while (search-backward "\\." nil t) | |
983 (delete-char 1))))) | |
984 | |
986 (provide 'gnus-util) | 985 (provide 'gnus-util) |
987 | 986 |
988 ;;; gnus-util.el ends here | 987 ;;; gnus-util.el ends here |