;;; nnheader.el --- header access macros for Gnus and its backends
-;; Copyright (C) 1987,88,89,90,93,94,95,96,97 Free Software Foundation, Inc.
+;; Copyright (C) 1987,88,89,90,93,94,95,96,97,98 Free Software Foundation, Inc.
;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
-;; Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
+;; Lars Magne Ingebrigtsen <larsi@gnus.org>
;; Keywords: news
;; This file is part of GNU Emacs.
;;; Code:
+(eval-when-compile (require 'cl))
+
(require 'mail-utils)
(defvar nnheader-max-head-length 4096
(autoload 'nnmail-message-id "nnmail")
(autoload 'mail-position-on-field "sendmail")
(autoload 'message-remove-header "message")
- (autoload 'cancel-function-timers "timers"))
+ (autoload 'cancel-function-timers "timers")
+ (autoload 'gnus-point-at-eol "gnus-util")
+ (autoload 'gnus-delete-line "gnus-util")
+ (autoload 'gnus-buffer-live-p "gnus-util")
+ (autoload 'gnus-encode-coding-string "gnus-ems"))
;;; Header access macros.
references chars lines xref)
"Create a new mail header structure initialized with the parameters given."
(vector number subject from date id references chars lines xref))
-
+
;; fake message-ids: generation and detection
(defvar nnheader-fake-message-id 1)
(let ((case-fold-search t)
(cur (current-buffer))
(buffer-read-only nil)
- in-reply-to lines p)
+ in-reply-to lines p ref)
(goto-char (point-min))
(when naked
(insert "\n"))
;; a case (which basically was the old function) is actually
;; about twice as fast, even though it looks messier. You
;; can't have everything, I guess. Speed and elegance
- ;; doesn't always go hand in hand.
+ ;; don't always go hand in hand.
(vector
;; Number.
(if naked
;; Message-ID.
(progn
(goto-char p)
- (if (search-forward "\nmessage-id: " nil t)
- (nnheader-header-value)
+ (if (search-forward "\nmessage-id:" nil t)
+ (buffer-substring
+ (1- (or (search-forward "<" (gnus-point-at-eol) t)
+ (point)))
+ (or (search-forward ">" (gnus-point-at-eol) t) (point)))
;; If there was no message-id, we just fake one to make
;; subsequent routines simpler.
(nnheader-generate-fake-message-id)))
(if (and (search-forward "\nin-reply-to: " nil t)
(setq in-reply-to (nnheader-header-value))
(string-match "<[^>]+>" in-reply-to))
- (substring in-reply-to (match-beginning 0)
- (match-end 0))
- "")))
+ (let (ref2)
+ (setq ref (substring in-reply-to (match-beginning 0)
+ (match-end 0)))
+ (while (string-match "<[^>]+>" in-reply-to (match-end 0))
+ (setq ref2 (substring in-reply-to (match-beginning 0)
+ (match-end 0)))
+ (when (> (length ref2) (length ref))
+ (setq ref ref2)))
+ ref)
+ nil)))
;; Chars.
0
;; Lines.
(defun nnheader-insert-nov (header)
(princ (mail-header-number header) (current-buffer))
- (insert
+ (insert
"\t"
(or (mail-header-subject header) "(none)") "\t"
(or (mail-header-from header) "(nobody)") "\t"
;; First we find the first wanted line.
(nnheader-find-nov-line beg)
(delete-region (point-min) (point))
- ;; Then we find the last wanted line.
+ ;; Then we find the last wanted line.
(when (nnheader-find-nov-line end)
(forward-line 1))
(delete-region (point) (point-max)))
(eobp))
(setq found t)
(setq prev (point))
- (cond ((> (setq num (read cur)) article)
+ (while (and (not (numberp (setq num (read cur))))
+ (not (eobp)))
+ (gnus-delete-line))
+ (cond ((> num article)
(setq max (point)))
((< num article)
(setq min (point)))
(defvar jka-compr-compression-info-list)
(defvar nnheader-numerical-files
(if (boundp 'jka-compr-compression-info-list)
- (concat "\\([0-9]+\\)\\("
+ (concat "\\([0-9]+\\)\\("
(mapconcat (lambda (i) (aref i 0))
jka-compr-compression-info-list "\\|")
"\\)?")
(defsubst nnheader-file-to-number (file)
"Take a file name and return the article number."
- (if (not (boundp 'jka-compr-compression-info-list))
+ (if (string= nnheader-numerical-short-files "^[0-9]+$")
(string-to-int file)
(string-match nnheader-numerical-short-files file)
(string-to-int (match-string 0 file))))
(defun nnheader-directory-files-safe (&rest args)
;; It has been reported numerous times that `directory-files'
;; fails with an alarming frequency on NFS mounted file systems.
- ;; This function executes that function twice and returns
+ ;; This function executes that function twice and returns
;; the longest result.
(let ((first (apply 'directory-files args))
(second (apply 'directory-files args)))
"Fold continuation lines in the current buffer."
(nnheader-replace-regexp "\\(\r?\n[ \t]+\\)+" " "))
-(defun nnheader-translate-file-chars (file)
+(defun nnheader-translate-file-chars (file &optional full)
+ "Translate FILE into something that can be a file name.
+If FULL, translate everything."
(if (null nnheader-file-name-translation-alist)
;; No translation is necessary.
- file
- ;; We translate -- but only the file name. We leave the directory
- ;; alone.
+ file
(let* ((i 0)
trans leaf path len)
- (if (string-match "/[^/]+\\'" file)
- ;; This is needed on NT's and stuff.
- (setq leaf (substring file (1+ (match-beginning 0)))
- path (substring file 0 (1+ (match-beginning 0))))
- ;; Fall back on this.
- (setq leaf (file-name-nondirectory file)
- path (file-name-directory file)))
+ (if full
+ ;; Do complete translation.
+ (setq leaf (copy-sequence file)
+ path "")
+ ;; We translate -- but only the file name. We leave the directory
+ ;; alone.
+ (if (string-match "/[^/]+\\'" file)
+ ;; This is needed on NT's and stuff.
+ (setq leaf (substring file (1+ (match-beginning 0)))
+ path (substring file 0 (1+ (match-beginning 0))))
+ ;; Fall back on this.
+ (setq leaf (file-name-nondirectory file)
+ path (file-name-directory file))))
(setq len (length leaf))
(while (< i len)
(when (setq trans (cdr (assq (aref leaf i)
(defun nnheader-get-report (backend)
"Get the most recent report from BACKEND."
(condition-case ()
- (message "%s" (symbol-value (intern (format "%s-status-string"
+ (nnheader-message 5 "%s" (symbol-value (intern (format "%s-status-string"
backend))))
- (error (message ""))))
+ (error (nnheader-message 5 ""))))
(defun nnheader-insert (format &rest args)
"Clear the communication buffer and insert FORMAT and ARGS into the buffer.
(apply 'insert format args))
t))
-(defun nnheader-mail-file-mbox-p (file)
- "Say whether FILE looks like an Unix mbox file."
- (when (and (file-exists-p file)
- (file-readable-p file)
- (file-regular-p file))
- (save-excursion
- (nnheader-set-temp-buffer " *mail-file-mbox-p*")
- (nnheader-insert-file-contents file)
- (goto-char (point-min))
- (prog1
- (looking-at message-unix-mail-delimiter)
- (kill-buffer (current-buffer))))))
-
(defun nnheader-replace-chars-in-string (string from to)
"Replace characters in STRING from FROM to TO."
(let ((string (substring string 0)) ;Copy string.
(defun nnheader-file-to-group (file &optional top)
"Return a group name based on FILE and TOP."
- (nnheader-replace-chars-in-string
+ (nnheader-replace-chars-in-string
(if (not top)
file
(condition-case ()
(substring (expand-file-name file)
- (length
+ (length
(expand-file-name
(file-name-as-directory top))))
(error "")))
(or (not (numberp gnus-verbose-backends))
(<= level gnus-verbose-backends)))
+(defvar nnheader-pathname-coding-system 'iso-8859-1
+ "*Coding system for pathname.")
+
(defun nnheader-group-pathname (group dir &optional file)
"Make pathname for GROUP."
(concat
(if (file-directory-p (concat dir group))
(concat dir group "/")
;; If not, we translate dots into slashes.
- (concat dir (nnheader-replace-chars-in-string group ?. ?/) "/")))
+ (concat dir
+ (gnus-encode-coding-string
+ (nnheader-replace-chars-in-string group ?. ?/)
+ nnheader-pathname-coding-system)
+ "/")))
(cond ((null file) "")
((numberp file) (int-to-string file))
(t file))))
(setq dir (concat
(file-name-directory
(directory-file-name (car path)))
- "etc/" package
+ "etc/" package
(if file "" "/"))))
(or file (file-directory-p dir)))
(setq result dir
(when (string-match (car ange-ftp-path-format) path)
(ange-ftp-re-read-dir path)))))
+(defvar nnheader-file-coding-system 'raw-text
+ "Coding system used in file backends of Gnus.")
+
(defun nnheader-insert-file-contents (filename &optional visit beg end replace)
"Like `insert-file-contents', q.v., but only reads in the file.
A buffer may be modified in several ways after reading into the buffer due
(let ((format-alist nil)
(auto-mode-alist (nnheader-auto-mode-alist))
(default-major-mode 'fundamental-mode)
- (after-insert-file-functions nil))
+ (enable-local-variables nil)
+ (after-insert-file-functions nil)
+ (find-file-hooks nil)
+ (coding-system-for-read nnheader-file-coding-system))
(insert-file-contents filename visit beg end replace)))
(defun nnheader-find-file-noselect (&rest args)
(auto-mode-alist (nnheader-auto-mode-alist))
(default-major-mode 'fundamental-mode)
(enable-local-variables nil)
- (after-insert-file-functions nil))
+ (after-insert-file-functions nil)
+ (find-file-hooks nil)
+ (coding-system-for-read nnheader-file-coding-system))
(apply 'find-file-noselect args)))
(defun nnheader-auto-mode-alist ()
(pop files))
(nreverse out)))
+(defun nnheader-directory-files (&rest args)
+ "Same as `directory-files', but prune \".\" and \"..\"."
+ (let ((files (apply 'directory-files args))
+ out)
+ (while files
+ (unless (member (file-name-nondirectory (car files)) '("." ".."))
+ (push (car files) out))
+ (pop files))
+ (nreverse out)))
+
(defmacro nnheader-skeleton-replace (from &optional to regexp)
`(let ((new (generate-new-buffer " *nnheader replace*"))
(cur (current-buffer))
(goto-char (point-min))
(while (,(if regexp 're-search-forward 'search-forward)
,from nil t)
- (insert-buffer-substring
+ (insert-buffer-substring
cur start (prog1 (match-beginning 0) (set-buffer new)))
(goto-char (point-max))
,(when to `(insert ,to))
(set-buffer cur)
(setq start (point)))
- (insert-buffer-substring
+ (insert-buffer-substring
cur start (prog1 (point-max) (set-buffer new)))
(copy-to-buffer cur (point-min) (point-max))
(kill-buffer (current-buffer))