;;; nnheader.el --- header access macros for Semi-gnus and its backends
;; Copyright (C) 1987, 1988, 1989, 1990, 1993, 1994, 1995, 1996,
-;; 1997, 1998, 2000, 2001, 2002, 2003
+;; 1997, 1998, 2000, 2001, 2002, 2003, 2004
;; Free Software Foundation, Inc.
;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
;;(eval-when-compile (require 'gnus-util))
(require 'mail-utils)
+(require 'gnus-util)
;; Reduce the required value of `recursive-load-depth-limit' for Emacs 21.
(require 'pces)
:group 'gnus-server
:type 'boolean)
-(defvar nnheader-max-head-length 4096
+(defvar nnheader-max-head-length 8192
"*Max length of the head of articles.
Value is an integer, nil, or t. nil means read in chunks of a file
(defvar nnheader-read-timeout
(if (string-match "windows-nt\\|os/2\\|emx\\|cygwin"
(symbol-name system-type))
+ ;; http://thread.gmane.org/v9655t3pjo.fsf@marauder.physik.uni-ulm.de
+ ;;
+ ;; IIRC, values lower than 1.0 didn't/don't work on Windows/DOS.
+ ;;
+ ;; There should probably be a runtime test to determine the timing
+ ;; resolution, or a primitive to report it. I don't know off-hand
+ ;; what's possible. Perhaps better, maybe the Windows/DOS primitive
+ ;; could round up non-zero timeouts to a minimum of 1.0?
1.0
0.1)
"How long nntp should wait between checking for the end of output.
-Shorter values mean quicker response, but is more CPU intensive.")
+Shorter values mean quicker response, but are more CPU intensive.")
(defvar nnheader-file-name-translation-alist
(let ((case-fold-search t))
(defvar nnheader-auto-save-coding-system
(cond
- ((boundp 'MULE) '*junet*)
((not (fboundp 'find-coding-system)) nil)
((find-coding-system 'emacs-mule)
(if (memq system-type '(windows-nt ms-dos ms-windows))
(autoload 'nnmail-message-id "nnmail")
(autoload 'mail-position-on-field "sendmail")
(autoload 'message-remove-header "message")
- (autoload 'gnus-point-at-eol "gnus-util")
(autoload 'gnus-buffer-live-p "gnus-util"))
;; mm-util stuff.
(defalias 'mm-image-load-path 'nnheader-image-load-path)
;; Should keep track of `mm-read-coding-system' in mm-util.el.
- (defalias 'mm-read-coding-system
- (if (or (and (featurep 'xemacs)
- (<= (string-to-number emacs-version) 21.1))
- (boundp 'MULE))
- (lambda (prompt &optional default-coding-system)
- (read-coding-system prompt))
- 'read-coding-system))
+ (defalias 'mm-read-coding-system 'read-coding-system)
;; Should keep track of `mm-%s' in mm-util.el.
(defalias 'mm-multibyte-string-p
;; Should keep track of `mm-detect-coding-region' in mm-util.el.
(defun nnheader-detect-coding-region (start end)
"Like 'detect-coding-region' except returning the best one."
- (let ((coding-systems
- (static-if (boundp 'MULE)
- (code-detect-region (point) (point-max))
- (detect-coding-region (point) (point-max)))))
+ (let ((coding-systems (detect-coding-region (point) (point-max))))
(or (car-safe coding-systems)
coding-systems)))
(defalias 'mm-detect-coding-region 'nnheader-detect-coding-region)
(defmacro nnheader-with-unibyte-buffer (&rest forms)
"Create a temporary buffer, and evaluate FORMS there like `progn'.
Use unibyte mode for this."
- `(let (default-enable-multibyte-characters default-mc-flag)
+ `(let (default-enable-multibyte-characters)
(with-temp-buffer ,@forms)))
(put 'nnheader-with-unibyte-buffer 'lisp-indent-function 0)
(put 'nnheader-with-unibyte-buffer 'edebug-form-spec '(body))
(cond ((featurep 'xemacs)
`(let (default-enable-multibyte-characters)
,@forms))
- ((boundp 'MULE)
- `(let ((,multibyte mc-flag)
- (,buffer (current-buffer)))
- (unwind-protect
- (let (default-enable-multibyte-characters default-mc-flag)
- (setq mc-flag nil)
- ,@forms)
- (set-buffer ,buffer)
- (setq mc-flag ,multibyte))))
(t
`(let ((,multibyte enable-multibyte-characters)
(,buffer (current-buffer)))
(lambda nil t))
((featurep 'xemacs)
(lambda nil nil))
- ((boundp 'MULE)
- (lambda nil mc-flag))
(t
(lambda nil enable-multibyte-characters))))
"Return non-nil if SYM is a coding system."
(or (and (fboundp 'find-coding-system) (find-coding-system sym))
(and (fboundp 'coding-system-p) (coding-system-p sym))))
- (defalias 'mm-coding-system-p 'nnheader-coding-system-p))
+ (defalias 'mm-coding-system-p 'nnheader-coding-system-p)
+
+ (defalias 'mm-disable-multibyte
+ (static-if (featurep 'xemacs)
+ 'ignore
+ (lambda nil (set-buffer-multibyte nil))))
+ (defalias 'mm-enable-multibyte
+ (static-if (featurep 'xemacs)
+ 'ignore
+ ;; Why isn't it t but `to'? See mm-util.el.
+ (lambda nil (set-buffer-multibyte 'to))))
+
+ (defalias 'mm-encode-coding-region 'encode-coding-region)
+
+ (defalias 'mm-string-make-unibyte
+ (if (fboundp 'string-make-unibyte)
+ 'string-make-unibyte
+ 'identity)))
;; mail-parse stuff.
(unless (featurep 'mail-parse)
- ;; Should keep track of `rfc2047-narrow-to-field' in rfc2047.el.
- (defun-maybe std11-narrow-to-field ()
- "Narrow the buffer to the header on the current line."
- (forward-line 0)
- (narrow-to-region (point)
- (progn
- (std11-field-end)
- (when (eolp) (forward-line 1))
- (point)))
- (goto-char (point-min)))
+ (unless (fboundp 'std11-narrow-to-field)
+ (defalias 'std11-narrow-to-field
+ ;; Should keep track of `rfc2047-narrow-to-field' in rfc2047.el.
+ (lambda ()
+ "Narrow the buffer to the header on the current line."
+ (forward-line 0)
+ (narrow-to-region (point)
+ (progn
+ (std11-field-end)
+ (when (eolp) (forward-line 1))
+ (point)))
+ (goto-char (point-min)))))
(defalias 'mail-header-narrow-to-field 'std11-narrow-to-field)
;; Should keep track of `ietf-drums-narrow-to-header' in ietf-drums.el.
(point-max)))
(goto-char (point-min)))
- ;; Should keep track of `rfc2047-fold-region' in rfc2047.el.
- (defun-maybe std11-fold-region (b e)
- "Fold long lines in region B to E."
- (save-restriction
- (narrow-to-region b e)
- (goto-char (point-min))
- (let ((break nil)
- (qword-break nil)
- (first t)
- (bol (save-restriction
- (widen)
- (gnus-point-at-bol))))
- (while (not (eobp))
- (when (and (or break qword-break)
- (> (- (point) bol) 76))
- (goto-char (or break qword-break))
- (setq break nil
- qword-break nil)
- (if (looking-at "[ \t]")
- (insert "\n")
- (insert "\n "))
- (setq bol (1- (point)))
- ;; Don't break before the first non-LWSP characters.
- (skip-chars-forward " \t")
- (unless (eobp)
- (forward-char 1)))
- (cond
- ((eq (char-after) ?\n)
- (forward-char 1)
- (setq bol (point)
- break nil
- qword-break nil)
- (skip-chars-forward " \t")
- (unless (or (eobp) (eq (char-after) ?\n))
- (forward-char 1)))
- ((eq (char-after) ?\r)
- (forward-char 1))
- ((memq (char-after) '(? ?\t))
- (skip-chars-forward " \t")
- (if first
- ;; Don't break just after the header name.
- (setq first nil)
- (setq break (1- (point)))))
- ((not break)
- (if (not (looking-at "=\\?[^=]"))
- (if (eq (char-after) ?=)
- (forward-char 1)
- (skip-chars-forward "^ \t\n\r="))
- (setq qword-break (point))
- (skip-chars-forward "^ \t\n\r")))
- (t
- (skip-chars-forward "^ \t\n\r"))))
- (when (and (or break qword-break)
- (> (- (point) bol) 76))
- (goto-char (or break qword-break))
- (setq break nil
- qword-break nil)
- (if (looking-at "[ \t]")
- (insert "\n")
- (insert "\n "))
- (setq bol (1- (point)))
- ;; Don't break before the first non-LWSP characters.
- (skip-chars-forward " \t")
- (unless (eobp)
- (forward-char 1))))))
-
- ;; Should keep track of `rfc2047-fold-field' in rfc2047.el.
- (defun-maybe std11-fold-field ()
- "Fold the current line."
- (save-excursion
- (save-restriction
- (std11-narrow-to-field)
- (std11-fold-region (point-min) (point-max)))))
-
+ (unless (fboundp 'std11-fold-region)
+ (defalias 'std11-fold-region
+ ;; Should keep track of `rfc2047-fold-region' in rfc2047.el.
+ (lambda (b e)
+ "Fold long lines in region B to E."
+ (save-restriction
+ (narrow-to-region b e)
+ (goto-char (point-min))
+ (let ((break nil)
+ (qword-break nil)
+ (first t)
+ (bol (save-restriction
+ (widen)
+ (point-at-bol))))
+ (while (not (eobp))
+ (when (and (or break qword-break)
+ (> (- (point) bol) 76))
+ (goto-char (or break qword-break))
+ (setq break nil
+ qword-break nil)
+ (if (looking-at "[ \t]")
+ (insert "\n")
+ (insert "\n "))
+ (setq bol (1- (point)))
+ ;; Don't break before the first non-LWSP characters.
+ (skip-chars-forward " \t")
+ (unless (eobp)
+ (forward-char 1)))
+ (cond
+ ((eq (char-after) ?\n)
+ (forward-char 1)
+ (setq bol (point)
+ break nil
+ qword-break nil)
+ (skip-chars-forward " \t")
+ (unless (or (eobp) (eq (char-after) ?\n))
+ (forward-char 1)))
+ ((eq (char-after) ?\r)
+ (forward-char 1))
+ ((memq (char-after) '(? ?\t))
+ (skip-chars-forward " \t")
+ (if first
+ ;; Don't break just after the header name.
+ (setq first nil)
+ (setq break (1- (point)))))
+ ((not break)
+ (if (not (looking-at "=\\?[^=]"))
+ (if (eq (char-after) ?=)
+ (forward-char 1)
+ (skip-chars-forward "^ \t\n\r="))
+ (setq qword-break (point))
+ (skip-chars-forward "^ \t\n\r")))
+ (t
+ (skip-chars-forward "^ \t\n\r"))))
+ (when (and (or break qword-break)
+ (> (- (point) bol) 76))
+ (goto-char (or break qword-break))
+ (setq break nil
+ qword-break nil)
+ (if (looking-at "[ \t]")
+ (insert "\n")
+ (insert "\n "))
+ (setq bol (1- (point)))
+ ;; Don't break before the first non-LWSP characters.
+ (skip-chars-forward " \t")
+ (unless (eobp)
+ (forward-char 1))))))))
+
+ (unless (fboundp 'std11-fold-field)
+ (defalias 'std11-fold-field
+ ;; Should keep track of `rfc2047-fold-field' in rfc2047.el.
+ (lambda ()
+ "Fold the current line."
+ (save-excursion
+ (save-restriction
+ (std11-narrow-to-field)
+ (std11-fold-region (point-min) (point-max)))))))
(defalias 'mail-header-fold-field 'std11-fold-field)
- ;; Should keep track of `rfc2047-unfold-region' in rfc2047.el.
- (defun-maybe std11-unfold-region (b e)
- "Unfold lines in region B to E."
- (save-restriction
- (narrow-to-region b e)
- (goto-char (point-min))
- (let ((bol (save-restriction
- (widen)
- (gnus-point-at-bol)))
- (eol (gnus-point-at-eol)))
- (forward-line 1)
- (while (not (eobp))
- (if (and (looking-at "[ \t]")
- (< (- (gnus-point-at-eol) bol) 76))
- (delete-region eol (progn
- (goto-char eol)
- (skip-chars-forward "\r\n")
- (point)))
- (setq bol (gnus-point-at-bol)))
- (setq eol (gnus-point-at-eol))
- (forward-line 1)))))
-
- ;; Should keep track of `rfc2047-unfold-field' in rfc2047.el.
- (defun-maybe std11-unfold-field ()
- "Fold the current line."
- (save-excursion
- (save-restriction
- (std11-narrow-to-field)
- (std11-unfold-region (point-min) (point-max)))))
-
+ (unless (fboundp 'std11-unfold-region)
+ (defalias 'std11-unfold-region
+ ;; Should keep track of `rfc2047-unfold-region' in rfc2047.el.
+ (lambda (b e)
+ "Unfold lines in region B to E."
+ (save-restriction
+ (narrow-to-region b e)
+ (goto-char (point-min))
+ (let ((bol (save-restriction
+ (widen)
+ (point-at-bol)))
+ (eol (point-at-eol)))
+ (forward-line 1)
+ (while (not (eobp))
+ (if (and (looking-at "[ \t]")
+ (< (- (point-at-eol) bol) 76))
+ (delete-region eol (progn
+ (goto-char eol)
+ (skip-chars-forward "\r\n")
+ (point)))
+ (setq bol (point-at-bol)))
+ (setq eol (point-at-eol))
+ (forward-line 1)))))))
+
+ (unless (fboundp 'std11-unfold-field)
+ (defalias 'std11-unfold-field
+ ;; Should keep track of `rfc2047-unfold-field' in rfc2047.el.
+ (lambda ()
+ "Fold the current line."
+ (save-excursion
+ (save-restriction
+ (std11-narrow-to-field)
+ (std11-unfold-region (point-min) (point-max)))))))
(defalias 'mail-header-unfold-field 'std11-unfold-field)
- ;; This is the original function in T-gnus.
- (defun-maybe std11-extract-addresses-components (string)
- "Extract a list of full name and canonical address from STRING. Each
+ (unless (fboundp 'std11-extract-addresses-components)
+ (defalias 'std11-extract-addresses-components
+ ;; This is the original function in T-gnus.
+ (lambda (string)
+ "Extract a list of full name and canonical address from STRING. Each
element looks like a list of the form (FULL-NAME CANONICAL-ADDRESS).
If no name can be extracted, FULL-NAME will be nil."
- (when string
- (let (addresses)
- (dolist (structure (std11-parse-addresses-string
- (std11-unfold-string string))
- addresses)
- (push (list (std11-full-name-string structure)
- (std11-address-string structure))
- addresses))
- (nreverse addresses))))
+ (when string
+ (let (addresses)
+ (dolist (structure (std11-parse-addresses-string
+ (std11-unfold-string string))
+ addresses)
+ (push (list (std11-full-name-string structure)
+ (std11-address-string structure))
+ addresses))
+ (nreverse addresses))))))
;; Should keep track of `ietf-drums-parse-addresses' in ietf-drums.el.
(defun mail-header-parse-addresses (string)
(setq value (buffer-substring start (point)))))
(goto-char begin)
value))
-
(defalias 'mail-header-field-value 'std11-field-value))
;; ietf-drums stuff.
(defvar nnheader-fake-message-id 1)
-(defsubst nnheader-generate-fake-message-id ()
- (concat "fake+none+" (int-to-string (incf nnheader-fake-message-id))))
+(defsubst nnheader-generate-fake-message-id (&optional number)
+ (if (numberp number)
+ (format "fake+none+%s+%d" gnus-newsgroup-name number)
+ (format "fake+none+%s+%s"
+ gnus-newsgroup-name
+ (int-to-string (incf nnheader-fake-message-id)))))
(defsubst nnheader-fake-message-id-p (id)
(save-match-data ; regular message-id's are <.*>
- (string-match "\\`fake\\+none\\+[0-9]+\\'" id)))
+ (string-match "\\`fake\\+none\\+.*\\+[0-9]+\\'" id)))
;; Parsing headers and NOV lines.
(goto-char p)
(if (search-forward "\nmessage-id:" nil t)
(buffer-substring
- (1- (or (search-forward "<" (gnus-point-at-eol) t)
+ (1- (or (search-forward "<" (point-at-eol) t)
(point)))
- (or (search-forward ">" (gnus-point-at-eol) t) (point)))
+ (or (search-forward ">" (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)))
+ (nnheader-generate-fake-message-id number)))
;; References.
(progn
(goto-char p)
out)))
out))
-(defmacro nnheader-nov-read-message-id ()
- '(let ((id (nnheader-nov-field)))
+(defvar nnheader-uniquify-message-id nil)
+
+(defmacro nnheader-nov-read-message-id (&optional number)
+ `(let ((id (nnheader-nov-field)))
(if (string-match "^<[^>]+>$" id)
- id
- (nnheader-generate-fake-message-id))))
+ ,(if nnheader-uniquify-message-id
+ `(if (string-match "__[^@]+@" id)
+ (concat (substring id 0 (match-beginning 0))
+ (substring id (1- (match-end 0))))
+ id)
+ 'id)
+ (nnheader-generate-fake-message-id ,number))))
(defun nnheader-parse-nov ()
- (let ((eol (gnus-point-at-eol)))
+ (let* ((eol (point-at-eol))
+ (number (nnheader-nov-read-integer)))
(make-full-mail-header
- (nnheader-nov-read-integer) ; number
+ number ; number
(nnheader-nov-field) ; subject
(nnheader-nov-field) ; from
(nnheader-nov-field) ; date
- (nnheader-nov-read-message-id) ; id
+ (nnheader-nov-read-message-id number) ; id
(nnheader-nov-field) ; refs
(nnheader-nov-read-integer) ; chars
(nnheader-nov-read-integer) ; lines
(number (length articles))
(count 0)
(file-name-coding-system 'binary)
- (pathname-coding-system 'binary)
(case-fold-search t)
(cur (current-buffer))
article
;; This is invalid, but not all articles have Message-IDs.
()
(mail-position-on-field "References")
- (let ((begin (gnus-point-at-bol))
+ (let ((begin (point-at-bol))
(fill-column 78)
(fill-prefix "\t"))
(when references
(point-max)))
(goto-char (point-min)))
+(defun nnheader-get-lines-and-char ()
+ "Return the number of lines and chars in the article body."
+ (goto-char (point-min))
+ (if (not (re-search-forward "\n\r?\n" nil t))
+ (list 0 0)
+ (list (count-lines (point) (point-max))
+ (- (point-max) (point)))))
+
(defun nnheader-remove-body ()
"Remove the body from an article in this current buffer."
(goto-char (point-min))
(defvar nnheader-directory-files-is-safe
(or (eq system-type 'windows-nt)
- (and (not (featurep 'xemacs))
- (> emacs-major-version 20)))
+ (not (featurep 'xemacs)))
"If non-nil, Gnus believes `directory-files' is safe.
It has been reported numerous times that `directory-files' fails with
an alarming frequency on NFS mounted file systems. If it is nil,
((numberp file) (int-to-string file))
(t file))))
-(defun nnheader-functionp (form)
- "Return non-nil if FORM is funcallable."
- (or (and (symbolp form) (fboundp form))
- (and (listp form) (eq (car form) 'lambda))))
-
(defun nnheader-concat (dir &rest files)
"Concat DIR as directory to FILES."
(apply 'concat (file-name-as-directory dir) files))
"Return the file size of FILE or 0."
(or (nth 7 (file-attributes file)) 0))
-(defun nnheader-find-etc-directory (package &optional file)
+(defun nnheader-find-etc-directory (package &optional file first)
"Go through `load-path' and find the \"../etc/PACKAGE\" directory.
This function will look in the parent directory of each `load-path'
entry, and look for the \"etc\" directory there.
-If FILE, find the \".../etc/PACKAGE\" file instead."
+If FILE, find the \".../etc/PACKAGE\" file instead.
+If FIRST is non-nil, return the directory or the file found at the
+first. Otherwise, find the newest one, though it may take a time."
(let ((path load-path)
- dir result)
+ dir results)
;; We try to find the dir by looking at the load path,
;; stripping away the last component and adding "etc/".
(while path
"etc/" package
(if file "" "/"))))
(or file (file-directory-p dir)))
- (setq result dir
- path nil)
+ (progn
+ (or (member dir results)
+ (push dir results))
+ (setq path (if first nil (cdr path))))
(setq path (cdr path))))
- result))
+ (if (or first (not (cdr results)))
+ (car results)
+ (car (sort results 'file-newer-than-file-p)))))
(eval-when-compile
(defvar ange-ftp-path-format)
"Strip all \r's from the current buffer."
(nnheader-skeleton-replace "\r"))
-(defalias 'nnheader-run-at-time 'run-at-time)
(defalias 'nnheader-cancel-timer 'cancel-timer)
(defalias 'nnheader-cancel-function-timers 'cancel-function-timers)
(defalias 'nnheader-string-as-multibyte 'string-as-multibyte)