# HG changeset patch # User Miles Bader # Date 1113106814 0 # Node ID ad05d91d35984744802f7b32fd89c646863ea17b # Parent f2d616f518a58cc5ef35605600c2531e77afc6d0 Revision: miles@gnu.org--gnu-2005/emacs--cvs-trunk--0--patch-243 Merge from gnus--rel--5.10 Patches applied: * gnus--rel--5.10 (patch 59) - Update from CVS 2005-04-06 Katsumi Yamaoka * lisp/calendar/time-date.el (time-to-seconds): Don't use the #xhhhh syntax which Emacs 20 doesn't support. (seconds-to-time, days-to-time, time-subtract, time-add): Ditto. 2005-04-06 Katsumi Yamaoka * lisp/gnus/mm-util.el (mm-coding-system-p): Don't return binary for the nil argument in XEmacs. * lisp/gnus/nnrss.el (nnrss-compatible-encoding-alist): New variable. (nnrss-request-group): Decode group name first. (nnrss-request-article): Make a text/plain article if mml-to-mime failed. (nnrss-get-encoding): Return a compatible encoding according to nnrss-compatible-encoding-alist. (nnrss-opml-export): Use dolist. (nnrss-find-el): Use consp instead of listp. (nnrss-order-hrefs): Use dolist. 2005-04-06 Arne J,Ax(Brgensen * lisp/gnus/nnrss.el (nnrss-verbose): Remove. (nnrss-request-group): Use `nnheader-message' instead. 2005-04-06 Mark Plaksin (tiny change) * lisp/gnus/nnrss.el (nnrss-verbose): New variable. (nnrss-request-group): Make it say nnrss is requesting a group. 2005-04-06 Katsumi Yamaoka * lisp/gnus/gnus-agent.el (gnus-agent-group-path): Decode group name. (gnus-agent-group-pathname): Ditto. * lisp/gnus/gnus-cache.el (gnus-cache-file-name): Decode group name. * lisp/gnus/gnus-group.el (gnus-group-line-format-alist): Use decoded group name for only %g and %c. (gnus-group-insert-group-line): Bind gnus-tmp-decoded-group instead of gnus-tmp-group to decoded group name. (gnus-group-make-group): Decode group name. (gnus-group-delete-group): Ditto. (gnus-group-make-rss-group): Exclude `/'s from group names; register the group data after opening the nnrss group; unify non-ASCII group names; encode group name. (gnus-group-catchup-current): Decode group name. (gnus-group-expire-articles-1): Ditto. (gnus-group-set-current-level): Ditto. (gnus-group-kill-group): Ditto. * lisp/gnus/gnus-spec.el (gnus-update-format-specifications): Flush the group format spec cache if it doesn't support decoded group names. * lisp/gnus/mm-url.el (mm-url-predefined-programs): Add --silent arg to curl. * lisp/gnus/nnrss.el: Require rfc2047 and mml. (nnrss-file-coding-system): New variable. (nnrss-format-string): Redefine it as an inline function. (nnrss-decode-group-name): New function. (nnrss-string-as-multibyte): Remove. (nnrss-retrieve-headers): Decode group name; don't use nnrss-format-string. (nnrss-request-group): Decode group name. (nnrss-request-article): Decode group name; allow a Message-ID as well as an article number; don't use nnrss-format-string; encode a Message-ID string which may contain non-ASCII characters; use mml-to-mime to compose a MIME article; use search-forward instead of re-search-forward. (nnrss-request-expire-articles): Decode group name. (nnrss-request-delete-group): Delete entries in nnrss-group-alist as well; decode group name. (nnrss-get-encoding): Fix regexp. (nnrss-fetch): Clarify error message. (nnrss-read-server-data): Use insert-file-contents instead of load; bind file-name-coding-system; use multibyte buffer. (nnrss-save-server-data): Insert newline; bind coding-system-for-write to the value of nnrss-file-coding-system; bind file-name-coding-system; add coding cookie. (nnrss-read-group-data): Use insert-file-contents instead of load; bind file-name-coding-system; use multibyte buffer. (nnrss-save-group-data): Bind coding-system-for-write to the value of nnrss-file-coding-system; bind file-name-coding-system. (nnrss-decode-entities-string): Rename from n-d-e-unibyte-string; make it work with non-ASCII text. (nnrss-opml-export): Use mm-set-buffer-file-coding-system instead of set-buffer-file-coding-system. (nnrss-find-el): Check carefully whether there's a list of string which old xml.el may return rather than a string; make it work with old xml.el as well. 2005-04-06 Tsuyoshi AKIHO * lisp/gnus/gnus-sum.el (gnus-summary-walk-group-buffer): Decode group name. * lisp/gnus/nnrss.el (nnrss-get-encoding): New function. (nnrss-fetch): Use unibyte buffer initially; bind coding-system-for-read while performing mm-url-insert; remove ^Ms; decode contents according to the encoding attribute. (nnrss-save-group-data): Add coding cookie. (nnrss-mime-encode-string): New function. (nnrss-check-group): Use it to encode subject and author. 2005-04-06 Maciek Pasternacki (tiny change) * lisp/gnus/nnrss.el (nnrss-fetch): Signal an error if w3-parse-buffer also failed. 2005-04-06 Jesper Harder * lisp/gnus/mm-util.el (mm-subst-char-in-string): Support inplace. * lisp/gnus/nnrss.el: Pedantic docstring and whitespace fixes (courtesy of checkdoc.el). (nnrss-request-article): Cleanup. (nnrss-request-delete-group): Use nnrss-make-filename. (nnrss-read-server-data): Use nnrss-make-filename; use load. (nnrss-save-server-data): Use nnrss-make-filename; use gnus-prin1. (nnrss-read-group-data): Fix off-by-one error. From Joakim Verona ; hash on description if link is missing; use nnrss-make-filename; use load. (nnrss-save-group-data): Use nnrss-make-filename; use gnus-prin1. (nnrss-make-filename): New function. (nnrss-close): New function. (nnrss-check-group): Hash on description if link is missing. (nnrss-get-namespace-prefix): Use string= to compare strings! Reported by David D. Smith . (nnrss-opml-export): Turn on sgml-mode. 2005-04-06 Mark A. Hershberger * lisp/gnus/nnrss.el (nnrss-opml-import, nnrss-opml-export): New functions. 2005-04-06 Katsumi Yamaoka * man/gnus.texi (RSS): Addition. diff -r f2d616f518a5 -r ad05d91d3598 lisp/ChangeLog --- a/lisp/ChangeLog Sun Apr 10 01:47:43 2005 +0000 +++ b/lisp/ChangeLog Sun Apr 10 04:20:14 2005 +0000 @@ -1,3 +1,9 @@ +2005-04-06 Katsumi Yamaoka + + * calendar/time-date.el (time-to-seconds): Don't use the #xhhhh + syntax which Emacs 20 doesn't support. + (seconds-to-time, days-to-time, time-subtract, time-add): Ditto. + 2005-04-09 Stefan Monnier * arc-mode.el (archive-mode-map): Move initialization into diff -r f2d616f518a5 -r ad05d91d3598 lisp/calendar/time-date.el --- a/lisp/calendar/time-date.el Sun Apr 10 01:47:43 2005 +0000 +++ b/lisp/calendar/time-date.el Sun Apr 10 04:20:14 2005 +0000 @@ -1,5 +1,6 @@ ;;; time-date.el --- Date and time handling functions -;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005 Free Software Foundation, Inc. +;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005 +;; Free Software Foundation, Inc. ;; Author: Lars Magne Ingebrigtsen ;; Masanobu Umeda @@ -112,15 +113,15 @@ "Convert time value TIME to a floating point number. You can use `float-time' instead." (with-decoded-time-value ((high low micro time)) - (+ (* 1.0 high #x10000) + (+ (* 1.0 high 65536) low (/ micro 1000000.0)))) ;;;###autoload (defun seconds-to-time (seconds) "Convert SECONDS (a floating point number) to a time value." - (list (floor seconds #x10000) - (floor (mod seconds #x10000)) + (list (floor seconds 65536) + (floor (mod seconds 65536)) (floor (* (- seconds (ffloor seconds)) 1000000)))) ;;;###autoload @@ -138,10 +139,10 @@ (defun days-to-time (days) "Convert DAYS into a time value." (let* ((seconds (* 1.0 days 60 60 24)) - (high (condition-case nil (floor (/ seconds #x10000)) + (high (condition-case nil (floor (/ seconds 65536)) (range-error most-positive-fixnum)))) - (list high (condition-case nil (floor (- seconds (* 1.0 high #x10000))) - (range-error #xffff))))) + (list high (condition-case nil (floor (- seconds (* 1.0 high 65536))) + (range-error 65535))))) ;;;###autoload (defun time-since (time) @@ -170,7 +171,7 @@ micro (+ micro 1000000))) (when (< low 0) (setq high (1- high) - low (+ low #x10000))) + low (+ low 65536))) (encode-time-value high low micro type))) ;;;###autoload @@ -185,9 +186,9 @@ (when (>= micro 1000000) (setq low (1+ low) micro (- micro 1000000))) - (when (>= low #x10000) + (when (>= low 65536) (setq high (1+ high) - low (- low #x10000))) + low (- low 65536))) (encode-time-value high low micro type))) ;;;###autoload diff -r f2d616f518a5 -r ad05d91d3598 lisp/gnus/ChangeLog --- a/lisp/gnus/ChangeLog Sun Apr 10 01:47:43 2005 +0000 +++ b/lisp/gnus/ChangeLog Sun Apr 10 04:20:14 2005 +0000 @@ -1,3 +1,131 @@ +2005-04-06 Katsumi Yamaoka + + * mm-util.el (mm-coding-system-p): Don't return binary for the nil + argument in XEmacs. + + * nnrss.el (nnrss-compatible-encoding-alist): New variable. + (nnrss-request-group): Decode group name first. + (nnrss-request-article): Make a text/plain article if mml-to-mime + failed. + (nnrss-get-encoding): Return a compatible encoding according to + nnrss-compatible-encoding-alist. + (nnrss-opml-export): Use dolist. + (nnrss-find-el): Use consp instead of listp. + (nnrss-order-hrefs): Use dolist. + +2005-04-06 Arne J,Ax(Brgensen + + * nnrss.el (nnrss-verbose): Remove. + (nnrss-request-group): Use `nnheader-message' instead. + +2005-04-06 Mark Plaksin (tiny change) + + * nnrss.el (nnrss-verbose): New variable. + (nnrss-request-group): Make it say nnrss is requesting a group. + +2005-04-06 Katsumi Yamaoka + + * gnus-agent.el (gnus-agent-group-path): Decode group name. + (gnus-agent-group-pathname): Ditto. + + * gnus-cache.el (gnus-cache-file-name): Decode group name. + + * gnus-group.el (gnus-group-line-format-alist): Use decoded group + name for only %g and %c. + (gnus-group-insert-group-line): Bind gnus-tmp-decoded-group + instead of gnus-tmp-group to decoded group name. + (gnus-group-make-group): Decode group name. + (gnus-group-delete-group): Ditto. + (gnus-group-make-rss-group): Exclude `/'s from group names; + register the group data after opening the nnrss group; unify + non-ASCII group names; encode group name. + (gnus-group-catchup-current): Decode group name. + (gnus-group-expire-articles-1): Ditto. + (gnus-group-set-current-level): Ditto. + (gnus-group-kill-group): Ditto. + + * gnus-spec.el (gnus-update-format-specifications): Flush the + group format spec cache if it doesn't support decoded group names. + + * mm-url.el (mm-url-predefined-programs): Add --silent arg to curl. + + * nnrss.el: Require rfc2047 and mml. + (nnrss-file-coding-system): New variable. + (nnrss-format-string): Redefine it as an inline function. + (nnrss-decode-group-name): New function. + (nnrss-string-as-multibyte): Remove. + (nnrss-retrieve-headers): Decode group name; don't use + nnrss-format-string. + (nnrss-request-group): Decode group name. + (nnrss-request-article): Decode group name; allow a Message-ID as + well as an article number; don't use nnrss-format-string; encode a + Message-ID string which may contain non-ASCII characters; use + mml-to-mime to compose a MIME article; use search-forward instead + of re-search-forward. + (nnrss-request-expire-articles): Decode group name. + (nnrss-request-delete-group): Delete entries in nnrss-group-alist + as well; decode group name. + (nnrss-get-encoding): Fix regexp. + (nnrss-fetch): Clarify error message. + (nnrss-read-server-data): Use insert-file-contents instead of load; + bind file-name-coding-system; use multibyte buffer. + (nnrss-save-server-data): Insert newline; bind + coding-system-for-write to the value of nnrss-file-coding-system; + bind file-name-coding-system; add coding cookie. + (nnrss-read-group-data): Use insert-file-contents instead of load; + bind file-name-coding-system; use multibyte buffer. + (nnrss-save-group-data): Bind coding-system-for-write to the + value of nnrss-file-coding-system; bind file-name-coding-system. + (nnrss-decode-entities-string): Rename from n-d-e-unibyte-string; + make it work with non-ASCII text. + (nnrss-opml-export): Use mm-set-buffer-file-coding-system instead + of set-buffer-file-coding-system. + (nnrss-find-el): Check carefully whether there's a list of string + which old xml.el may return rather than a string; make it work + with old xml.el as well. + +2005-04-06 Tsuyoshi AKIHO + + * gnus-sum.el (gnus-summary-walk-group-buffer): Decode group name. + + * nnrss.el (nnrss-get-encoding): New function. + (nnrss-fetch): Use unibyte buffer initially; bind + coding-system-for-read while performing mm-url-insert; remove ^Ms; + decode contents according to the encoding attribute. + (nnrss-save-group-data): Add coding cookie. + (nnrss-mime-encode-string): New function. + (nnrss-check-group): Use it to encode subject and author. + +2005-04-06 Maciek Pasternacki (tiny change) + + * nnrss.el (nnrss-fetch): Signal an error if w3-parse-buffer also + failed. + +2005-04-06 Jesper Harder + + * mm-util.el (mm-subst-char-in-string): Support inplace. + + * nnrss.el: Pedantic docstring and whitespace fixes (courtesy of + checkdoc.el). + (nnrss-request-article): Cleanup. + (nnrss-request-delete-group): Use nnrss-make-filename. + (nnrss-read-server-data): Use nnrss-make-filename; use load. + (nnrss-save-server-data): Use nnrss-make-filename; use gnus-prin1. + (nnrss-read-group-data): Fix off-by-one error. From Joakim Verona + ; hash on description if link is missing; use + nnrss-make-filename; use load. + (nnrss-save-group-data): Use nnrss-make-filename; use gnus-prin1. + (nnrss-make-filename): New function. + (nnrss-close): New function. + (nnrss-check-group): Hash on description if link is missing. + (nnrss-get-namespace-prefix): Use string= to compare strings! + Reported by David D. Smith . + (nnrss-opml-export): Turn on sgml-mode. + +2005-04-06 Mark A. Hershberger + + * nnrss.el (nnrss-opml-import, nnrss-opml-export): New functions. + 2005-04-04 Reiner Steib * message.el (message-make-date): Add defvars in order to silence diff -r f2d616f518a5 -r ad05d91d3598 lisp/gnus/gnus-agent.el --- a/lisp/gnus/gnus-agent.el Sun Apr 10 01:47:43 2005 +0000 +++ b/lisp/gnus/gnus-agent.el Sun Apr 10 04:20:14 2005 +0000 @@ -1,5 +1,5 @@ ;;; gnus-agent.el --- unplugged support for Gnus -;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 +;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 ;; Free Software Foundation, Inc. ;; Author: Lars Magne Ingebrigtsen @@ -1371,7 +1371,7 @@ (nnheader-translate-file-chars (nnheader-replace-duplicate-chars-in-string (nnheader-replace-chars-in-string - (gnus-group-real-name group) + (gnus-group-real-name (gnus-group-decoded-name group)) ?/ ?_) ?. ?_))) (if (or nnmail-use-long-file-names @@ -1387,8 +1387,10 @@ ;; unplugged. The agent must, therefore, use the same directory ;; while plugged. (let ((gnus-command-method (or gnus-command-method - (gnus-find-method-for-group group)))) - (nnmail-group-pathname (gnus-group-real-name group) (gnus-agent-directory)))) + (gnus-find-method-for-group group)))) + (nnmail-group-pathname (gnus-group-real-name + (gnus-group-decoded-name group)) + (gnus-agent-directory)))) (defun gnus-agent-get-function (method) (if (gnus-online method) diff -r f2d616f518a5 -r ad05d91d3598 lisp/gnus/gnus-cache.el --- a/lisp/gnus/gnus-cache.el Sun Apr 10 01:47:43 2005 +0000 +++ b/lisp/gnus/gnus-cache.el Sun Apr 10 04:20:14 2005 +0000 @@ -1,6 +1,6 @@ ;;; gnus-cache.el --- cache interface for Gnus -;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 -;; Free Software Foundation, Inc. +;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, +;; 2004, 2005 Free Software Foundation, Inc. ;; Author: Lars Magne Ingebrigtsen ;; Keywords: news @@ -421,6 +421,7 @@ (and (not unread) (not ticked) (not dormant) (memq 'read class)))) (defun gnus-cache-file-name (group article) + (setq group (gnus-group-decoded-name group)) (expand-file-name (if (stringp article) article (int-to-string article)) (file-name-as-directory diff -r f2d616f518a5 -r ad05d91d3598 lisp/gnus/gnus-group.el --- a/lisp/gnus/gnus-group.el Sun Apr 10 01:47:43 2005 +0000 +++ b/lisp/gnus/gnus-group.el Sun Apr 10 04:20:14 2005 +0000 @@ -482,9 +482,15 @@ (?T (gnus-range-length (cdr (assq 'tick gnus-tmp-marked))) ?d) (?i (+ (gnus-range-length (cdr (assq 'dormant gnus-tmp-marked))) (gnus-range-length (cdr (assq 'tick gnus-tmp-marked)))) ?d) - (?g gnus-tmp-group ?s) + (?g (if (boundp 'gnus-tmp-decoded-group) + gnus-tmp-decoded-group + gnus-tmp-group) + ?s) (?G gnus-tmp-qualified-group ?s) - (?c (gnus-short-group-name gnus-tmp-group) ?s) + (?c (gnus-short-group-name (if (boundp 'gnus-tmp-decoded-group) + gnus-tmp-decoded-group + gnus-tmp-group)) + ?s) (?C gnus-tmp-comment ?s) (?D gnus-tmp-newsgroup-description ?s) (?o gnus-tmp-moderated ?c) @@ -1441,8 +1447,8 @@ (point) (prog1 (1+ (point)) ;; Insert the text. - (let ((gnus-tmp-group (gnus-group-name-decode - gnus-tmp-group group-name-charset))) + (let ((gnus-tmp-decoded-group (gnus-group-name-decode + gnus-tmp-group group-name-charset))) (eval gnus-group-line-format-spec))) `(gnus-group ,(gnus-intern-safe gnus-tmp-group gnus-active-hashtb) gnus-unread ,(if (numberp number) @@ -2244,7 +2250,7 @@ (nname (if method (gnus-group-prefixed-name name meth) name)) backend info) (when (gnus-gethash nname gnus-newsrc-hashtb) - (error "Group %s already exists" nname)) + (error "Group %s already exists" (gnus-group-decoded-name nname))) ;; Subscribe to the new group. (gnus-group-change-level (setq info (list t nname gnus-level-default-subscribed nil nil meth)) @@ -2305,20 +2311,21 @@ (unless (gnus-check-backend-function 'request-delete-group group) (error "This back end does not support group deletion")) (prog1 - (if (and (not no-prompt) - (not (gnus-yes-or-no-p - (format - "Do you really want to delete %s%s? " - group (if force " and all its contents" ""))))) - () ; Whew! - (gnus-message 6 "Deleting group %s..." group) - (if (not (gnus-request-delete-group group force)) - (gnus-error 3 "Couldn't delete group %s" group) - (gnus-message 6 "Deleting group %s...done" group) - (gnus-group-goto-group group) - (gnus-group-kill-group 1 t) - (gnus-sethash group nil gnus-active-hashtb) - t)) + (let ((group-decoded (gnus-group-decoded-name group))) + (if (and (not no-prompt) + (not (gnus-yes-or-no-p + (format + "Do you really want to delete %s%s? " + group-decoded (if force " and all its contents" ""))))) + () ; Whew! + (gnus-message 6 "Deleting group %s..." group-decoded) + (if (not (gnus-request-delete-group group force)) + (gnus-error 3 "Couldn't delete group %s" group-decoded) + (gnus-message 6 "Deleting group %s...done" group-decoded) + (gnus-group-goto-group group) + (gnus-group-kill-group 1 t) + (gnus-sethash group nil gnus-active-hashtb) + t))) (gnus-group-position-point))) (defun gnus-group-rename-group (group new-name) @@ -2588,16 +2595,26 @@ (setq url (read-from-minibuffer "URL to Search for RSS: "))) (let ((feedinfo (nnrss-discover-feed url))) (if feedinfo - (let ((title (read-from-minibuffer "Title: " - (cdr (assoc 'title - feedinfo)))) + (let ((title (gnus-newsgroup-savable-name + (read-from-minibuffer "Title: " + (gnus-newsgroup-savable-name + (or (cdr (assoc 'title + feedinfo)) + ""))))) (desc (read-from-minibuffer "Description: " (cdr (assoc 'description feedinfo)))) - (href (cdr (assoc 'href feedinfo)))) - (push (list title href desc) - nnrss-group-alist) - (gnus-group-make-group title '(nnrss "")) + (href (cdr (assoc 'href feedinfo))) + (encodable (mm-coding-system-p 'utf-8))) + (when encodable + ;; Unify non-ASCII text. + (setq title (mm-decode-coding-string + (mm-encode-coding-string title 'utf-8) 'utf-8))) + (gnus-group-make-group (if encodable + (mm-encode-coding-string title 'utf-8) + title) + '(nnrss "")) + (push (list title href desc) nnrss-group-alist) (nnrss-save-server-data nil)) (error "No feeds found for %s" url)))) @@ -3101,7 +3118,7 @@ "Do you really want to mark all articles in %s as read? " "Mark all unread articles in %s as read? ") (if (= (length groups) 1) - (car groups) + (gnus-group-decoded-name (car groups)) (format "these %d groups" (length groups))))))) n (while (setq group (pop groups)) @@ -3179,7 +3196,8 @@ (defun gnus-group-expire-articles-1 (group) (when (gnus-check-backend-function 'request-expire-articles group) - (gnus-message 6 "Expiring articles in %s..." group) + (gnus-message 6 "Expiring articles in %s..." + (gnus-group-decoded-name group)) (let* ((info (gnus-get-info group)) (expirable (if (gnus-group-total-expirable-p group) (cons nil (gnus-list-of-read-articles group)) @@ -3204,7 +3222,8 @@ (gnus-request-expire-articles (gnus-uncompress-sequence (cdr expirable)) group)))) (gnus-close-group group)) - (gnus-message 6 "Expiring articles in %s...done" group) + (gnus-message 6 "Expiring articles in %s...done" + (gnus-group-decoded-name group)) ;; Return the list of un-expired articles. (cdr expirable)))) @@ -3243,7 +3262,8 @@ (while (setq group (pop groups)) (gnus-group-remove-mark group) (gnus-message 6 "Changed level of %s from %d to %d" - group (or (gnus-group-group-level) gnus-level-killed) + (gnus-group-decoded-name group) + (or (gnus-group-group-level) gnus-level-killed) level) (gnus-group-change-level group level (or (gnus-group-group-level) gnus-level-killed)) @@ -3392,7 +3412,7 @@ gnus-list-of-killed-groups)) (gnus-group-change-level (if entry entry group) gnus-level-killed (if entry nil level)) - (message "Killed group %s" group)) + (message "Killed group %s" (gnus-group-decoded-name group))) ;; If there are lots and lots of groups to be killed, we use ;; this thing instead. (dolist (group (nreverse groups)) diff -r f2d616f518a5 -r ad05d91d3598 lisp/gnus/gnus-spec.el --- a/lisp/gnus/gnus-spec.el Sun Apr 10 01:47:43 2005 +0000 +++ b/lisp/gnus/gnus-spec.el Sun Apr 10 04:20:14 2005 +0000 @@ -1,5 +1,5 @@ ;;; gnus-spec.el --- format spec functions for Gnus -;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 +;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 ;; Free Software Foundation, Inc. ;; Author: Lars Magne Ingebrigtsen @@ -196,6 +196,13 @@ (not (equal emacs-version (cdr (assq 'version gnus-format-specs))))) (setq gnus-format-specs nil)) + ;; Flush the group format spec cache if it doesn't support decoded + ;; group names. + (when (memq 'group types) + (let ((spec (assq 'group gnus-format-specs))) + (unless (string-match " gnus-tmp-decoded-group[ )]" + (gnus-prin1-to-string (nth 2 spec))) + (setq gnus-format-specs (delq spec gnus-format-specs))))) ;; Go through all the formats and see whether they need updating. (let (new-format entry type val updated) diff -r f2d616f518a5 -r ad05d91d3598 lisp/gnus/gnus-sum.el --- a/lisp/gnus/gnus-sum.el Sun Apr 10 01:47:43 2005 +0000 +++ b/lisp/gnus/gnus-sum.el Sun Apr 10 04:20:14 2005 +0000 @@ -7254,11 +7254,12 @@ (if (and group (not (gnus-ephemeral-group-p gnus-newsgroup-name))) (format " (Type %s for %s [%s])" - (single-key-description cmd) group + (single-key-description cmd) + (gnus-group-decoded-name group) (car (gnus-gethash group gnus-newsrc-hashtb))) (format " (Type %s to exit %s)" (single-key-description cmd) - gnus-newsgroup-name)))) + (gnus-group-decoded-name gnus-newsgroup-name))))) ;; Confirm auto selection. (setq key (car (setq keve (gnus-read-event-char prompt))) ended t) diff -r f2d616f518a5 -r ad05d91d3598 lisp/gnus/mm-url.el --- a/lisp/gnus/mm-url.el Sun Apr 10 01:47:43 2005 +0000 +++ b/lisp/gnus/mm-url.el Sun Apr 10 04:20:14 2005 +0000 @@ -59,7 +59,7 @@ '((wget "wget" "--user-agent=mm-url" "-q" "-O" "-") (w3m "w3m" "-dump_source") (lynx "lynx" "-source") - (curl "curl"))) + (curl "curl" "--silent"))) (defcustom mm-url-program (cond diff -r f2d616f518a5 -r ad05d91d3598 lisp/gnus/mm-util.el --- a/lisp/gnus/mm-util.el Sun Apr 10 01:47:43 2005 +0000 +++ b/lisp/gnus/mm-util.el Sun Apr 10 04:20:14 2005 +0000 @@ -57,9 +57,11 @@ mm-mime-mule-charset-alist) nil t)))) (subst-char-in-string - . (lambda (from to string) ;; stolen (and renamed) from nnheader.el - "Replace characters in STRING from FROM to TO." - (let ((string (substring string 0)) ;Copy string. + . (lambda (from to string &optional inplace) + ;; stolen (and renamed) from nnheader.el + "Replace characters in STRING from FROM to TO. + Unless optional argument INPLACE is non-nil, return a new string." + (let ((string (if inplace string (copy-sequence string))) (len (length string)) (idx 0)) ;; Replace all occurrences of FROM with TO. @@ -153,7 +155,7 @@ If CS is available, return CS itself in Emacs, and return a coding system object in XEmacs." (if (fboundp 'find-coding-system) - (find-coding-system cs) + (and cs (find-coding-system cs)) (if (fboundp 'coding-system-p) (when (coding-system-p cs) cs) diff -r f2d616f518a5 -r ad05d91d3598 lisp/gnus/nnrss.el --- a/lisp/gnus/nnrss.el Sun Apr 10 01:47:43 2005 +0000 +++ b/lisp/gnus/nnrss.el Sun Apr 10 04:20:14 2005 +0000 @@ -1,5 +1,5 @@ ;;; nnrss.el --- interfacing with RSS -;; Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. +;; Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. ;; Author: Shenghuo Zhu ;; Keywords: RSS @@ -36,9 +36,11 @@ (require 'time-date) (require 'rfc2231) (require 'mm-url) +(require 'rfc2047) +(require 'mml) (eval-when-compile (ignore-errors - (require 'xml))) + (require 'xml))) (eval '(require 'xml)) (nnoo-declare nnrss) @@ -75,20 +77,32 @@ (defvar nnrss-content-function nil "A function which is called in `nnrss-request-article'. The arguments are (ENTRY GROUP ARTICLE). -ENTRY is the record of the current headline. GROUP is the group name. +ENTRY is the record of the current headline. GROUP is the group name. ARTICLE is the article number of the current headline.") +(defvar nnrss-file-coding-system mm-universal-coding-system + "Coding system used when reading and writing files.") + +(defvar nnrss-compatible-encoding-alist '((iso-8859-1 . windows-1252)) + "Alist of encodings and those supersets. +The cdr of each element is used to decode data if it is available when +the car is what the data specify as the encoding. Or, the car is used +for decoding when the cdr that the data specify is not available.") + (nnoo-define-basics nnrss) ;;; Interface functions -(eval-when-compile - (defmacro nnrss-string-as-multibyte (string) - (if (featurep 'xemacs) - string - `(string-as-multibyte ,string)))) +(defsubst nnrss-format-string (string) + (gnus-replace-in-string string " *\n *" " ")) + +(defun nnrss-decode-group-name (group) + (if (and group (mm-coding-system-p 'utf-8)) + (setq group (mm-decode-coding-string group 'utf-8)) + group)) (deffoo nnrss-retrieve-headers (articles &optional group server fetch-old) + (setq group (nnrss-decode-group-name group)) (nnrss-possibly-change-group group server) (let (e) (save-excursion @@ -97,21 +111,26 @@ (dolist (article articles) (if (setq e (assq article nnrss-group-data)) (insert (number-to-string (car e)) "\t" ;; number - (if (nth 3 e) - (nnrss-format-string (nth 3 e)) "") - "\t" ;; subject - (if (nth 4 e) - (nnrss-format-string (nth 4 e)) - "(nobody)") - "\t" ;;from + ;; subject + (or (nth 3 e) "") + "\t" + ;; from + (or (nth 4 e) "(nobody)") + "\t" + ;; date (or (nth 5 e) "") - "\t" ;; date + "\t" + ;; id (format "<%d@%s.nnrss>" (car e) group) - "\t" ;; id - "\t" ;; refs - "-1" "\t" ;; chars - "-1" "\t" ;; lines - "" "\t" ;; Xref + "\t" + ;; refs + "\t" + ;; chars + "-1" "\t" + ;; lines + "-1" "\t" + ;; Xref + "" "\t" (if (and (nth 6 e) (memq nnrss-description-field nnmail-extra-headers)) @@ -132,69 +151,102 @@ 'nov) (deffoo nnrss-request-group (group &optional server dont-check) + (setq group (nnrss-decode-group-name group)) + (nnheader-message 6 "nnrss: Requesting %s..." group) (nnrss-possibly-change-group group server) - (if dont-check - t - (nnrss-check-group group server) - (nnheader-report 'nnrss "Opened group %s" group) - (nnheader-insert - "211 %d %d %d %s\n" nnrss-group-max nnrss-group-min nnrss-group-max - (prin1-to-string group) - t))) + (prog1 + (if dont-check + t + (nnrss-check-group group server) + (nnheader-report 'nnrss "Opened group %s" group) + (nnheader-insert + "211 %d %d %d %s\n" nnrss-group-max nnrss-group-min nnrss-group-max + (prin1-to-string group) + t)) + (nnheader-message 6 "nnrss: Requesting %s...done" group))) (deffoo nnrss-close-group (group &optional server) t) (deffoo nnrss-request-article (article &optional group server buffer) + (setq group (nnrss-decode-group-name group)) + (when (stringp article) + (setq article (if (string-match "\\`<\\([0-9]+\\)@" article) + (string-to-number (match-string 1 article)) + 0))) (nnrss-possibly-change-group group server) (let ((e (assq article nnrss-group-data)) - (boundary "=-=-=-=-=-=-=-=-=-") (nntp-server-buffer (or buffer nntp-server-buffer)) post err) (when e - (catch 'error - (with-current-buffer nntp-server-buffer - (erase-buffer) - (goto-char (point-min)) - (insert "Mime-Version: 1.0\nContent-Type: multipart/alternative; boundary=\"" boundary "\"\n") - (if group - (insert "Newsgroups: " group "\n")) - (if (nth 3 e) - (insert "Subject: " (nnrss-format-string (nth 3 e)) "\n")) - (if (nth 4 e) - (insert "From: " (nnrss-format-string (nth 4 e)) "\n")) - (if (nth 5 e) - (insert "Date: " (nnrss-format-string (nth 5 e)) "\n")) - (insert "Message-ID: " (format "<%d@%s.nnrss>" (car e) group) "\n") - (insert "\n") - (let ((text (if (nth 6 e) - (nnrss-string-as-multibyte (nth 6 e)))) - (link (if (nth 2 e) - (nth 2 e)))) - (insert "\n\n--" boundary "\nContent-Type: text/plain\n\n") - (let ((point (point))) - (if text - (progn (insert text) - (goto-char point) - (while (re-search-forward "\n" nil t) - (replace-match " ")) - (goto-char (point-max)) - (insert "\n\n"))) - (if link - (insert link))) - (insert "\n\n--" boundary "\nContent-Type: text/html\n\n") - (let ((point (point))) - (if text - (progn (insert "\n" text "\n") - (goto-char point) - (while (re-search-forward "\n" nil t) - (replace-match " ")) - (goto-char (point-max)) - (insert "\n\n"))) - (if link - (insert "

link

\n")))) - (if nnrss-content-function - (funcall nnrss-content-function e group article))))) + (with-current-buffer nntp-server-buffer + (erase-buffer) + (if group + (insert "Newsgroups: " group "\n")) + (if (nth 3 e) + (insert "Subject: " (nth 3 e) "\n")) + (if (nth 4 e) + (insert "From: " (nth 4 e) "\n")) + (if (nth 5 e) + (insert "Date: " (nnrss-format-string (nth 5 e)) "\n")) + (let ((header (buffer-string)) + (text (if (nth 6 e) + (mapconcat 'identity + (delete "" (split-string (nth 6 e) "\n+")) + " "))) + (link (nth 2 e)) + ;; Enable encoding of Newsgroups header in XEmacs. + (default-enable-multibyte-characters t) + (rfc2047-header-encoding-alist + (if (mm-coding-system-p 'utf-8) + (cons '("Newsgroups" . utf-8) + rfc2047-header-encoding-alist) + rfc2047-header-encoding-alist)) + rfc2047-encode-encoded-words body) + (when (or text link) + (insert "\n") + (insert "<#multipart type=alternative>\n" + "<#part type=\"text/plain\">\n") + (setq body (point)) + (if text + (progn + (insert text "\n") + (when link + (insert "\n" link "\n"))) + (when link + (insert link "\n"))) + (setq body (buffer-substring body (point))) + (insert "<#/part>\n" + "<#part type=\"text/html\">\n" + "\n") + (when text + (insert text "\n")) + (when link + (insert "

link

\n")) + (insert "\n" + "<#/part>\n" + "<#/multipart>\n")) + (condition-case nil + (mml-to-mime) + (error + (erase-buffer) + (insert header + "Content-Type: text/plain; charset=gnus-decoded\n" + "Content-Transfer-Encoding: 8bit\n\n" + body) + (nnheader-message + 3 "Warning - there might be invalid characters")))) + (goto-char (point-min)) + (search-forward "\n\n") + (forward-line -1) + (insert (format "Message-ID: <%d@%s.nnrss>\n" + (car e) + (let ((rfc2047-encoding-type 'mime) + rfc2047-encode-max-chars) + (rfc2047-encode-string + (gnus-replace-in-string group "[\t\n ]+" "_"))))) + (when nnrss-content-function + (funcall nnrss-content-function e group article)))) (cond (err (nnheader-report 'nnrss err)) @@ -217,6 +269,7 @@ (deffoo nnrss-request-expire-articles (articles group &optional server force) + (setq group (nnrss-decode-group-name group)) (nnrss-possibly-change-group group server) (let (e days not-expirable changed) (dolist (art articles) @@ -234,18 +287,18 @@ not-expirable)) (deffoo nnrss-request-delete-group (group &optional force server) + (setq group (nnrss-decode-group-name group)) (nnrss-possibly-change-group group server) + (let (elem) + ;; There may be two or more entries in `nnrss-group-alist' since + ;; this function didn't delete them formerly. + (while (setq elem (assoc group nnrss-group-alist)) + (setq nnrss-group-alist (delq elem nnrss-group-alist)))) (setq nnrss-server-data (delq (assoc group nnrss-server-data) nnrss-server-data)) (nnrss-save-server-data server) - (let ((file (expand-file-name - (nnrss-translate-file-chars - (concat group (and server - (not (equal server "")) - "-") - server ".el")) nnrss-directory))) - (ignore-errors - (delete-file file))) + (ignore-errors + (delete-file (nnrss-make-filename group server))) t) (deffoo nnrss-request-list-newsgroups (&optional server) @@ -262,34 +315,67 @@ ;;; Internal functions (eval-when-compile (defun xml-rpc-method-call (&rest args))) + +(defun nnrss-get-encoding () + "Return an encoding attribute specified in the current xml contents. +If `nnrss-compatible-encoding-alist' specifies the compatible encoding, +it is used instead. If the xml contents doesn't specify the encoding, +return `utf-8' which is the default encoding for xml if it is available, +otherwise return nil." + (goto-char (point-min)) + (if (re-search-forward + "<\\?[^>]*encoding=\\(\"\\([^\">]+\\)\"\\|'\\([^'>]+\\)'\\)" + nil t) + (let ((encoding (intern (downcase (or (match-string 2) + (match-string 3)))))) + (or + (mm-coding-system-p (cdr (assq encoding + nnrss-compatible-encoding-alist))) + (mm-coding-system-p encoding) + (mm-coding-system-p (car (rassq encoding + nnrss-compatible-encoding-alist))))) + (mm-coding-system-p 'utf-8))) + (defun nnrss-fetch (url &optional local) - "Fetch the url and put it in a the expected lisp structure." - (with-temp-buffer - ;some CVS versions of url.el need this to close the connection quickly - (let* (xmlform htmlform) + "Fetch URL and put it in a the expected Lisp structure." + (mm-with-unibyte-buffer + ;;some CVS versions of url.el need this to close the connection quickly + (let (cs xmlform htmlform) ;; bit o' work necessary for w3 pre-cvs and post-cvs (if local (let ((coding-system-for-read 'binary)) (insert-file-contents url)) - (mm-url-insert url)) - -;; Because xml-parse-region can't deal with anything that isn't -;; xml and w3-parse-buffer can't deal with some xml, we have to -;; parse with xml-parse-region first and, if that fails, parse -;; with w3-parse-buffer. Yuck. Eventually, someone should find out -;; why w3-parse-buffer fails to parse some well-formed xml and -;; fix it. + ;; FIXME: shouldn't binding `coding-system-for-read' be moved + ;; to `mm-url-insert'? + (let ((coding-system-for-read 'binary)) + (mm-url-insert url))) + (nnheader-remove-cr-followed-by-lf) + ;; Decode text according to the encoding attribute. + (when (setq cs (nnrss-get-encoding)) + (mm-decode-coding-region (point-min) (point-max) cs) + (mm-enable-multibyte)) + (goto-char (point-min)) - (condition-case err - (setq xmlform (xml-parse-region (point-min) (point-max))) - (error (if (fboundp 'w3-parse-buffer) - (setq htmlform (caddar (w3-parse-buffer - (current-buffer)))) - (message "nnrss: Not valid XML and w3 parse not available (%s)" - url)))) - (if htmlform - htmlform - xmlform)))) + ;; Because xml-parse-region can't deal with anything that isn't + ;; xml and w3-parse-buffer can't deal with some xml, we have to + ;; parse with xml-parse-region first and, if that fails, parse + ;; with w3-parse-buffer. Yuck. Eventually, someone should find out + ;; why w3-parse-buffer fails to parse some well-formed xml and + ;; fix it. + + (condition-case err1 + (setq xmlform (xml-parse-region (point-min) (point-max))) + (error + (condition-case err2 + (setq htmlform (caddar (w3-parse-buffer + (current-buffer)))) + (error + (message "\ +nnrss: %s: Not valid XML %s and w3-parse doesn't work %s" + url err1 err2))))) + (if htmlform + htmlform + xmlform)))) (defun nnrss-possibly-change-group (&optional group server) (when (and server @@ -302,9 +388,9 @@ (defvar nnrss-extra-categories '(nnrss-snarf-moreover-categories)) (defun nnrss-generate-active () - (if (y-or-n-p "fetch extra categories? ") - (dolist (func nnrss-extra-categories) - (funcall func))) + (when (y-or-n-p "Fetch extra categories? ") + (dolist (func nnrss-extra-categories) + (funcall func))) (save-excursion (set-buffer nntp-server-buffer) (erase-buffer) @@ -318,41 +404,26 @@ (defun nnrss-read-server-data (server) (setq nnrss-server-data nil) - (let ((file (expand-file-name - (nnrss-translate-file-chars - (concat "nnrss" (and server - (not (equal server "")) - "-") - server - ".el")) - nnrss-directory))) + (let ((file (nnrss-make-filename "nnrss" server))) (when (file-exists-p file) - (with-temp-buffer - (let ((coding-system-for-read 'binary) - emacs-lisp-mode-hook) + ;; In Emacs 21.3 and earlier, `load' doesn't support non-ASCII + ;; file names. So, we use `insert-file-contents' instead. + (mm-with-multibyte-buffer + (let ((coding-system-for-read nnrss-file-coding-system) + (file-name-coding-system nnmail-pathname-coding-system)) (insert-file-contents file) - (emacs-lisp-mode) - (goto-char (point-min)) - (eval-buffer)))))) + (eval-region (point-min) (point-max))))))) (defun nnrss-save-server-data (server) (gnus-make-directory nnrss-directory) - (let ((file (expand-file-name - (nnrss-translate-file-chars - (concat "nnrss" (and server - (not (equal server "")) - "-") - server ".el")) - nnrss-directory))) - (let ((coding-system-for-write 'binary) - print-level print-length) - (with-temp-file file - (insert "(setq nnrss-group-alist '" - (prin1-to-string nnrss-group-alist) - ")\n") - (insert "(setq nnrss-server-data '" - (prin1-to-string nnrss-server-data) - ")\n"))))) + (let ((coding-system-for-write nnrss-file-coding-system) + (file-name-coding-system nnmail-pathname-coding-system)) + (with-temp-file (nnrss-make-filename "nnrss" server) + (insert (format ";; -*- coding: %s; -*-\n" + nnrss-file-coding-system)) + (gnus-prin1 `(setq nnrss-group-alist ',nnrss-group-alist)) + (insert "\n") + (gnus-prin1 `(setq nnrss-server-data ',nnrss-server-data))))) (defun nnrss-read-group-data (group server) (setq nnrss-group-data nil) @@ -360,43 +431,50 @@ (let ((pair (assoc group nnrss-server-data))) (setq nnrss-group-max (or (cadr pair) 0)) (setq nnrss-group-min (+ nnrss-group-max 1))) - (let ((file (expand-file-name - (nnrss-translate-file-chars - (concat group (and server - (not (equal server "")) - "-") - server ".el")) - nnrss-directory))) + (let ((file (nnrss-make-filename group server))) (when (file-exists-p file) - (with-temp-buffer - (let ((coding-system-for-read 'binary) - emacs-lisp-mode-hook) + ;; In Emacs 21.3 and earlier, `load' doesn't support non-ASCII + ;; file names. So, we use `insert-file-contents' instead. + (mm-with-multibyte-buffer + (let ((coding-system-for-read nnrss-file-coding-system) + (file-name-coding-system nnmail-pathname-coding-system)) (insert-file-contents file) - (emacs-lisp-mode) - (goto-char (point-min)) - (eval-buffer))) + (eval-region (point-min) (point-max)))) (dolist (e nnrss-group-data) - (gnus-sethash (nth 2 e) e nnrss-group-hashtb) - (if (and (car e) (> nnrss-group-min (car e))) - (setq nnrss-group-min (car e))) - (if (and (car e) (< nnrss-group-max (car e))) - (setq nnrss-group-max (car e))))))) + (gnus-sethash (or (nth 2 e) (nth 6 e)) t nnrss-group-hashtb) + (when (and (car e) (> nnrss-group-min (car e))) + (setq nnrss-group-min (car e))) + (when (and (car e) (< nnrss-group-max (car e))) + (setq nnrss-group-max (car e))))))) (defun nnrss-save-group-data (group server) (gnus-make-directory nnrss-directory) - (let ((file (expand-file-name - (nnrss-translate-file-chars - (concat group (and server - (not (equal server "")) - "-") - server ".el")) - nnrss-directory))) - (let ((coding-system-for-write 'binary) - print-level print-length) - (with-temp-file file - (insert "(setq nnrss-group-data '" - (prin1-to-string nnrss-group-data) - ")\n"))))) + (let ((coding-system-for-write nnrss-file-coding-system) + (file-name-coding-system nnmail-pathname-coding-system)) + (with-temp-file (nnrss-make-filename group server) + (insert (format ";; -*- coding: %s; -*-\n" + nnrss-file-coding-system)) + (gnus-prin1 `(setq nnrss-group-data ',nnrss-group-data))))) + +(defun nnrss-make-filename (name server) + (expand-file-name + (nnrss-translate-file-chars + (concat name + (and server + (not (equal server "")) + "-") + server + ".el")) + nnrss-directory)) + +(gnus-add-shutdown 'nnrss-close 'gnus) + +(defun nnrss-close () + "Clear internal nnrss variables." + (setq nnrss-group-data nil + nnrss-server-data nil + nnrss-group-hashtb nil + nnrss-group-alist nil)) ;;; URL interface @@ -407,15 +485,36 @@ (mm-with-unibyte-current-buffer (mm-url-insert url))) -(defun nnrss-decode-entities-unibyte-string (string) +(defun nnrss-decode-entities-string (string) (if string - (mm-with-unibyte-buffer + (mm-with-multibyte-buffer (insert string) (mm-url-decode-entities-nbsp) (buffer-string)))) (defalias 'nnrss-insert 'nnrss-insert-w3) +(defun nnrss-mime-encode-string (string) + (mm-with-multibyte-buffer + (insert string) + (mm-url-decode-entities-nbsp) + (goto-char (point-min)) + (while (re-search-forward "[\t\n ]+" nil t) + (replace-match " ")) + (goto-char (point-min)) + (skip-chars-forward " ") + (delete-region (point-min) (point)) + (goto-char (point-max)) + (skip-chars-forward " ") + (delete-region (point) (point-max)) + (let ((rfc2047-encoding-type 'mime) + rfc2047-encode-max-chars) + (rfc2047-encode-region (point-min) (point-max))) + (goto-char (point-min)) + (while (search-forward "\n" nil t) + (delete-backward-char 1)) + (buffer-string))) + ;;; Snarf functions (defun nnrss-check-group (group server) @@ -431,11 +530,11 @@ (second (assoc group nnrss-group-alist)))) (unless url (setq url - (cdr - (assoc 'href - (nnrss-discover-feed - (read-string - (format "URL to search for %s: " group) "http://"))))) + (cdr + (assoc 'href + (nnrss-discover-feed + (read-string + (format "URL to search for %s: " group) "http://"))))) (let ((pair (assoc group nnrss-server-data))) (if pair (setcdr (cdr pair) (list url)) @@ -451,12 +550,16 @@ content-ns (nnrss-get-namespace-prefix xml "http://purl.org/rss/1.0/modules/content/")) (dolist (item (nreverse (nnrss-find-el (intern (concat rss-ns "item")) xml))) (when (and (listp item) - (eq (intern (concat rss-ns "item")) (car item)) - (setq url (nnrss-decode-entities-unibyte-string - (nnrss-node-text rss-ns 'link (cddr item)))) - (not (gnus-gethash url nnrss-group-hashtb))) + (string= (concat rss-ns "item") (car item)) + (if (setq url (nnrss-decode-entities-string + (nnrss-node-text rss-ns 'link (cddr item)))) + (not (gnus-gethash url nnrss-group-hashtb)) + (setq extra (or (nnrss-node-text content-ns 'encoded item) + (nnrss-node-text rss-ns 'description item))) + (not (gnus-gethash extra nnrss-group-hashtb)))) (setq subject (nnrss-node-text rss-ns 'title item)) - (setq extra (or (nnrss-node-text content-ns 'encoded item) + (setq extra (or extra + (nnrss-node-text content-ns 'encoded item) (nnrss-node-text rss-ns 'description item))) (setq author (or (nnrss-node-text rss-ns 'author item) (nnrss-node-text dc-ns 'creator item) @@ -469,13 +572,14 @@ (incf nnrss-group-max) (current-time) url - (and subject (nnrss-decode-entities-unibyte-string subject)) - (and author (nnrss-decode-entities-unibyte-string author)) + (and subject (nnrss-mime-encode-string subject)) + (and author (nnrss-mime-encode-string author)) date - (and extra (nnrss-decode-entities-unibyte-string extra))) + (and extra (nnrss-decode-entities-string extra))) nnrss-group-data) - (gnus-sethash url (car nnrss-group-data) nnrss-group-hashtb) - (setq changed t))) + (gnus-sethash (or url extra) t nnrss-group-hashtb) + (setq changed t)) + (setq extra nil)) (when changed (nnrss-save-group-data group server) (let ((pair (assoc group nnrss-server-data))) @@ -484,6 +588,45 @@ (push (list group nnrss-group-max) nnrss-server-data))) (nnrss-save-server-data server)))) +(defun nnrss-opml-import (opml-file) + "OPML subscriptions import. +Read the file and attempt to subscribe to each Feed in the file." + (interactive "fImport file: ") + (mapcar + (lambda (node) (gnus-group-make-rss-group + (cdr (assq 'xmlUrl (cadr node))))) + (nnrss-find-el 'outline + (progn + (find-file opml-file) + (xml-parse-region (point-min) + (point-max)))))) + +(defun nnrss-opml-export () + "OPML subscription export. +Export subscriptions to a buffer in OPML Format." + (interactive) + (with-current-buffer (get-buffer-create "*OPML Export*") + (mm-set-buffer-file-coding-system 'utf-8) + (insert "\n" + "\n" + "\n" + " \n" + " mySubscriptions\n" + " " (format-time-string "%a, %d %b %Y %T %z") + "\n" + " " user-mail-address "\n" + " " (user-full-name) "\n" + " \n" + " \n") + (dolist (sub nnrss-group-alist) + (insert " \n")) + (insert " \n" + "\n")) + (pop-to-buffer "*OPML Export*") + (when (fboundp 'sgml-mode) + (sgml-mode))) + (defun nnrss-generate-download-script () "Generate a download script in the current buffer. It is useful when `(setq nnrss-use-local t)'." @@ -530,9 +673,6 @@ (if changed (nnrss-save-server-data "")))) -(defun nnrss-format-string (string) - (gnus-replace-in-string (nnrss-string-as-multibyte string) " *\n *" " ")) - (defun nnrss-node-text (namespace local-name element) (let* ((node (assq (intern (concat namespace (symbol-name local-name))) element)) @@ -551,56 +691,59 @@ node)) (defun nnrss-find-el (tag data &optional found-list) - "Find the all matching elements in the data. Careful with this on -large documents!" - (if (listp data) - (mapcar (lambda (bit) - (if (car-safe bit) - (progn (if (equal tag (car bit)) - (setq found-list - (append found-list - (list bit)))) - (if (and (listp (car-safe (caddr bit))) - (not (stringp (caddr bit)))) - (setq found-list - (append found-list - (nnrss-find-el - tag (caddr bit)))) - (setq found-list - (append found-list - (nnrss-find-el - tag (cddr bit)))))))) - data)) + "Find the all matching elements in the data. +Careful with this on large documents!" + (when (consp data) + (dolist (bit data) + (when (car-safe bit) + (when (equal tag (car bit)) + ;; Old xml.el may return a list of string. + (when (and (consp (caddr bit)) + (stringp (caaddr bit))) + (setcar (cddr bit) (caaddr bit))) + (setq found-list + (append found-list + (list bit)))) + (if (and (consp (car-safe (caddr bit))) + (not (stringp (caddr bit)))) + (setq found-list + (append found-list + (nnrss-find-el + tag (caddr bit)))) + (setq found-list + (append found-list + (nnrss-find-el + tag (cddr bit)))))))) found-list) (defun nnrss-rsslink-p (el) "Test if the element we are handed is an RSS autodiscovery link." (and (eq (car-safe el) 'link) (string-equal (cdr (assoc 'rel (cadr el))) "alternate") - (or (string-equal (cdr (assoc 'type (cadr el))) + (or (string-equal (cdr (assoc 'type (cadr el))) "application/rss+xml") (string-equal (cdr (assoc 'type (cadr el))) "text/xml")))) (defun nnrss-get-rsslinks (data) "Extract the elements that are links to RSS from the parsed data." - (delq nil (mapcar + (delq nil (mapcar (lambda (el) (if (nnrss-rsslink-p el) el)) (nnrss-find-el 'link data)))) (defun nnrss-extract-hrefs (data) - "Recursively extract hrefs from a page's source. DATA should be -the output of xml-parse-region or w3-parse-buffer." + "Recursively extract hrefs from a page's source. +DATA should be the output of `xml-parse-region' or +`w3-parse-buffer'." (mapcar (lambda (ahref) (cdr (assoc 'href (cadr ahref)))) (nnrss-find-el 'a data))) -(defmacro nnrss-match-macro (base-uri item - onsite-list offsite-list) +(defmacro nnrss-match-macro (base-uri item onsite-list offsite-list) `(cond ((or (string-match (concat "^" ,base-uri) ,item) - (not (string-match "://" ,item))) - (setq ,onsite-list (append ,onsite-list (list ,item)))) - (t (setq ,offsite-list (append ,offsite-list (list ,item)))))) + (not (string-match "://" ,item))) + (setq ,onsite-list (append ,onsite-list (list ,item)))) + (t (setq ,offsite-list (append ,offsite-list (list ,item)))))) (defun nnrss-order-hrefs (base-uri hrefs) "Given a list of hrefs, sort them using the following priorities: @@ -615,29 +758,28 @@ (let (rss-onsite-end rdf-onsite-end xml-onsite-end rss-onsite-in rdf-onsite-in xml-onsite-in rss-offsite-end rdf-offsite-end xml-offsite-end - rss-offsite-in rdf-offsite-in xml-offsite-in) - (mapcar (lambda (href) - (if (not (null href)) - (cond ((string-match "\\.rss$" href) - (nnrss-match-macro - base-uri href rss-onsite-end rss-offsite-end)) - ((string-match "\\.rdf$" href) - (nnrss-match-macro - base-uri href rdf-onsite-end rdf-offsite-end)) - ((string-match "\\.xml$" href) - (nnrss-match-macro - base-uri href xml-onsite-end xml-offsite-end)) - ((string-match "rss" href) - (nnrss-match-macro - base-uri href rss-onsite-in rss-offsite-in)) - ((string-match "rdf" href) - (nnrss-match-macro - base-uri href rdf-onsite-in rdf-offsite-in)) - ((string-match "xml" href) - (nnrss-match-macro - base-uri href xml-onsite-in xml-offsite-in))))) - hrefs) - (append + rss-offsite-in rdf-offsite-in xml-offsite-in) + (dolist (href hrefs) + (cond ((null href)) + ((string-match "\\.rss$" href) + (nnrss-match-macro + base-uri href rss-onsite-end rss-offsite-end)) + ((string-match "\\.rdf$" href) + (nnrss-match-macro + base-uri href rdf-onsite-end rdf-offsite-end)) + ((string-match "\\.xml$" href) + (nnrss-match-macro + base-uri href xml-onsite-end xml-offsite-end)) + ((string-match "rss" href) + (nnrss-match-macro + base-uri href rss-onsite-in rss-offsite-in)) + ((string-match "rdf" href) + (nnrss-match-macro + base-uri href rdf-onsite-in rdf-offsite-in)) + ((string-match "xml" href) + (nnrss-match-macro + base-uri href xml-onsite-in xml-offsite-in)))) + (append rss-onsite-end rdf-onsite-end xml-onsite-end rss-onsite-in rdf-onsite-in xml-onsite-in rss-offsite-end rdf-offsite-end xml-offsite-end @@ -670,23 +812,23 @@ ;; - offsite links containing any of the above (let* ((base-uri (progn (string-match ".*://[^/]+/?" url) (match-string 0 url))) - (hrefs (nnrss-order-hrefs + (hrefs (nnrss-order-hrefs base-uri (nnrss-extract-hrefs parsed-page))) (rss-link nil)) - (while (and (eq rss-link nil) (not (eq hrefs nil))) - (let ((href-data (nnrss-fetch (car hrefs)))) - (if (nnrss-rss-p href-data) - (let* ((rss-ns (nnrss-get-namespace-prefix href-data "http://purl.org/rss/1.0/"))) - (setq rss-link (nnrss-rss-title-description - rss-ns href-data (car hrefs)))) - (setq hrefs (cdr hrefs))))) - (if rss-link rss-link + (while (and (eq rss-link nil) (not (eq hrefs nil))) + (let ((href-data (nnrss-fetch (car hrefs)))) + (if (nnrss-rss-p href-data) + (let* ((rss-ns (nnrss-get-namespace-prefix href-data "http://purl.org/rss/1.0/"))) + (setq rss-link (nnrss-rss-title-description + rss-ns href-data (car hrefs)))) + (setq hrefs (cdr hrefs))))) + (if rss-link rss-link ;; 4. check syndic8 - (nnrss-find-rss-via-syndic8 url)))))))) + (nnrss-find-rss-via-syndic8 url)))))))) (defun nnrss-find-rss-via-syndic8 (url) - "query syndic8 for the rss feeds it has for the url." + "Query syndic8 for the rss feeds it has for URL." (if (not (locate-library "xml-rpc")) (progn (message "XML-RPC is not available... not checking Syndic8.") @@ -697,22 +839,22 @@ 'syndic8.FindSites url))) (when feedid - (let* ((feedinfo (xml-rpc-method-call + (let* ((feedinfo (xml-rpc-method-call "http://www.syndic8.com/xmlrpc.php" 'syndic8.GetFeedInfo feedid)) (urllist - (delq nil + (delq nil (mapcar (lambda (listinfo) - (if (string-equal + (if (string-equal (cdr (assoc "status" listinfo)) "Syndicated") (cons (cdr (assoc "sitename" listinfo)) (list (cons 'title - (cdr (assoc + (cdr (assoc "sitename" listinfo))) (cons 'href (cdr (assoc @@ -721,20 +863,20 @@ (if (not (> (length urllist) 1)) (cdar urllist) (let ((completion-ignore-case t) - (selection + (selection (mapcar (lambda (listinfo) - (cons (cdr (assoc "sitename" listinfo)) - (string-to-int + (cons (cdr (assoc "sitename" listinfo)) + (string-to-int (cdr (assoc "feedid" listinfo))))) feedinfo))) - (cdr (assoc + (cdr (assoc (completing-read "Multiple feeds found. Select one: " selection nil t) urllist))))))))) (defun nnrss-rss-p (data) - "Test if data is an RSS feed. Simply ensures that the first -element is rss or rdf." + "Test if DATA is an RSS feed. +Simply ensures that the first element is rss or rdf." (or (eq (caar data) 'rss) (eq (caar data) 'rdf:RDF))) @@ -755,13 +897,13 @@ that gives the URI for which you want to retrieve the namespace prefix), return the prefix." (let* ((prefix (car (rassoc uri (cadar el)))) - (nslist (if prefix + (nslist (if prefix (split-string (symbol-name prefix) ":"))) (ns (cond ((eq (length nslist) 1) ; no prefix given "") ((eq (length nslist) 2) ; extract prefix (cadr nslist))))) - (if (and ns (not (eq ns ""))) + (if (and ns (not (string= ns ""))) (concat ns ":") ns))) diff -r f2d616f518a5 -r ad05d91d3598 man/ChangeLog --- a/man/ChangeLog Sun Apr 10 01:47:43 2005 +0000 +++ b/man/ChangeLog Sun Apr 10 04:20:14 2005 +0000 @@ -1,3 +1,7 @@ +2005-04-06 Katsumi Yamaoka + + * gnus.texi (RSS): Addition. + 2005-04-09 Luc Teirlinck * display.texi (Useless Whitespace): `indicate-unused-lines' is diff -r f2d616f518a5 -r ad05d91d3598 man/gnus.texi --- a/man/gnus.texi Sun Apr 10 01:47:43 2005 +0000 +++ b/man/gnus.texi Sun Apr 10 04:20:14 2005 +0000 @@ -15873,14 +15873,45 @@ @acronym{RSS} has a quite regular and nice interface, and it's possible to get the information Gnus needs to keep groups updated. +Note: you had better use Emacs which supports the @code{utf-8} coding +system because @acronym{RSS} uses UTF-8 for encoding non-@acronym{ASCII} +text by default. It is also used by default for non-@acronym{ASCII} +group names. + @kindex G R (Summary) -Use @kbd{G R} from the summary buffer to subscribe to a feed---you -will be prompted for the location of the feed. +Use @kbd{G R} from the summary buffer to subscribe to a feed---you will +be prompted for the location, the title and the description of the feed. +The title, which allows any characters, will be used for the group name +and the name of the group data file. The description can be omitted. An easy way to get started with @code{nnrss} is to say something like the following in the group buffer: @kbd{B nnrss RET RET y}, then subscribe to groups. +The @code{nnrss} back end saves the group data file in +@code{nnrss-directory} (see below) for each @code{nnrss} group. File +names containing non-@acronym{ASCII} characters will be encoded by the +coding system specified with the @code{nnmail-pathname-coding-system} +variable. If it is @code{nil}, in Emacs the coding system defaults to +the value of @code{default-file-name-coding-system}. If you are using +XEmacs and want to use non-@acronym{ASCII} group names, you should set +the value for the @code{nnmail-pathname-coding-system} variable properly. + +@cindex OPML +You can also use the following commands to import and export your +subscriptions from a file in @acronym{OPML} format (Outline Processor +Markup Language). + +@defun nnrss-opml-import file +Prompt for an @acronym{OPML} file, and subscribe to each feed in the +file. +@end defun + +@defun nnrss-opml-export +Write your current @acronym{RSS} subscriptions to a buffer in +@acronym{OPML} format. +@end defun + The following @code{nnrss} variables can be altered: @table @code @@ -15889,6 +15920,13 @@ The directory where @code{nnrss} stores its files. The default is @file{~/News/rss/}. +@item nnrss-file-coding-system +@vindex nnrss-file-coding-system +The coding system used when reading and writing the @code{nnrss} groups +data files. The default is the value of +@code{mm-universal-coding-system} (which defaults to @code{emacs-mule} +in Emacs or @code{escape-quoted} in XEmacs). + @item nnrss-use-local @vindex nnrss-use-local @findex nnrss-generate-download-script