Revision: miles@gnu.org--gnu-2005/emacs--cvs-trunk--0--patch-243
authorMiles Bader <miles@gnu.org>
Sun, 10 Apr 2005 04:20:14 +0000 (04:20 +0000)
committerMiles Bader <miles@gnu.org>
Sun, 10 Apr 2005 04:20:14 +0000 (04:20 +0000)
Merge from gnus--rel--5.10

Patches applied:

 * gnus--rel--5.10  (patch 59)

   - Update from CVS

2005-04-06  Katsumi Yamaoka  <yamaoka@jpl.org>

   * 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  <yamaoka@jpl.org>

   * 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\e,Ax\e(Brgensen  <arne@arnested.dk>

   * lisp/gnus/nnrss.el (nnrss-verbose): Remove.
   (nnrss-request-group): Use `nnheader-message' instead.

2005-04-06  Mark Plaksin  <happy@usg.edu>  (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  <yamaoka@jpl.org>

   * 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  <akiho@kawachi.zaq.ne.jp>

   * 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  <maciekp@japhy.fnord.org>  (tiny change)

   * lisp/gnus/nnrss.el (nnrss-fetch): Signal an error if w3-parse-buffer also
   failed.

2005-04-06  Jesper Harder  <harder@ifa.au.dk>

   * 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
   <joakim@verona.se>; 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 <davidsmith@acm.org>.
   (nnrss-opml-export): Turn on sgml-mode.

2005-04-06  Mark A. Hershberger  <mah@everybody.org>

   * lisp/gnus/nnrss.el (nnrss-opml-import, nnrss-opml-export): New functions.

2005-04-06  Katsumi Yamaoka  <yamaoka@jpl.org>

   * man/gnus.texi (RSS): Addition.

13 files changed:
lisp/ChangeLog
lisp/calendar/time-date.el
lisp/gnus/ChangeLog
lisp/gnus/gnus-agent.el
lisp/gnus/gnus-cache.el
lisp/gnus/gnus-group.el
lisp/gnus/gnus-spec.el
lisp/gnus/gnus-sum.el
lisp/gnus/mm-url.el
lisp/gnus/mm-util.el
lisp/gnus/nnrss.el
man/ChangeLog
man/gnus.texi

index 724de4f..078fe15 100644 (file)
@@ -1,3 +1,9 @@
+2005-04-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * 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  <monnier@iro.umontreal.ca>
 
        * arc-mode.el (archive-mode-map): Move initialization into
index 7160d26..ddeb33b 100644 (file)
@@ -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 <larsi@gnus.org>
 ;;     Masanobu Umeda <umerin@mse.kyutech.ac.jp>
@@ -112,15 +113,15 @@ and type 3 is the list (HIGH LOW MICRO)."
   "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 @@ You can use `float-time' instead."
 (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 @@ Return the difference in the format of a time value."
            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 @@ Return the difference in the format of a time value."
     (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
index d8e1065..7eb877a 100644 (file)
@@ -1,3 +1,131 @@
+2005-04-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * 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\e,Ax\e(Brgensen  <arne@arnested.dk>
+
+       * nnrss.el (nnrss-verbose): Remove.
+       (nnrss-request-group): Use `nnheader-message' instead.
+
+2005-04-06  Mark Plaksin  <happy@usg.edu>  (tiny change)
+
+       * nnrss.el (nnrss-verbose): New variable.
+       (nnrss-request-group): Make it say nnrss is requesting a group.
+
+2005-04-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * 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  <akiho@kawachi.zaq.ne.jp>
+
+       * 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  <maciekp@japhy.fnord.org>  (tiny change)
+
+       * nnrss.el (nnrss-fetch): Signal an error if w3-parse-buffer also
+       failed.
+
+2005-04-06  Jesper Harder  <harder@ifa.au.dk>
+
+       * 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
+       <joakim@verona.se>; 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 <davidsmith@acm.org>.
+       (nnrss-opml-export): Turn on sgml-mode.
+
+2005-04-06  Mark A. Hershberger  <mah@everybody.org>
+
+       * nnrss.el (nnrss-opml-import, nnrss-opml-export): New functions.
+
 2005-04-04  Reiner Steib  <Reiner.Steib@gmx.de>
 
        * message.el (message-make-date): Add defvars in order to silence
index 9a02f5b..4236c79 100644 (file)
@@ -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 <larsi@gnus.org>
@@ -1371,7 +1371,7 @@ downloaded into the agent."
         (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 @@ downloaded into the agent."
   ;; 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)
index 8f2b491..657ade9 100644 (file)
@@ -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 <larsi@gnus.org>
 ;; Keywords: news
@@ -421,6 +421,7 @@ Returns the list of articles removed."
       (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
index 6d38626..30b7fe6 100644 (file)
@@ -482,9 +482,15 @@ simple manner.")
     (?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 @@ if it is a string, only list groups matching REGEXP."
      (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 @@ ADDRESS."
         (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 @@ be removed from the server, even when it's empty."
   (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 @@ If there is, use Gnus to create an nnrss group"
       (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 @@ up is returned."
                   "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 @@ Uses the process/prefix convention."
 
 (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 @@ Uses the process/prefix convention."
            (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 @@ Uses the process/prefix convention."
     (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 @@ of groups killed."
                  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))
index ff92413..ef1c431 100644 (file)
@@ -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 <larsi@gnus.org>
@@ -196,6 +196,13 @@ Return a list of updated types."
            (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)
index 8d6a5f9..17cb1ea 100644 (file)
@@ -7254,11 +7254,12 @@ If BACKWARD, the previous article is selected instead of the next."
             (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)
index a66c039..ff7608e 100644 (file)
@@ -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
index 3be6444..b8a739e 100644 (file)
                    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 @@ In XEmacs, also return non-nil if CS is a coding system object.
 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)
index 6ff2b46..006e309 100644 (file)
@@ -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 <zsh@cs.rochester.edu>
 ;; Keywords: RSS
 (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 @@ To use the description in headers, put this name into `nnmail-extra-headers'.")
 (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 @@ ARTICLE is the article number of the current headline.")
       (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 @@ ARTICLE is the article number of the current headline.")
   '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 "<html><head></head><body>\n" text "\n</body></html>")
-                        (goto-char point)
-                        (while (re-search-forward "\n" nil t)
-                          (replace-match " "))
-                        (goto-char (point-max))
-                        (insert "\n\n")))
-             (if link
-                 (insert "<p><a href=\"" link "\">link</a></p>\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"
+                   "<html><head></head><body>\n")
+           (when text
+             (insert text "\n"))
+           (when link
+             (insert "<p><a href=\"" link "\">link</a></p>\n"))
+           (insert "</body></html>\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 @@ ARTICLE is the article number of the current headline.")
 
 (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 @@ ARTICLE is the article number of the current headline.")
     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 @@ ARTICLE is the article number of the current headline.")
 
 ;;; 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.
-
-    (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))))
+       ;; 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))
+
+      ;; 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 @@ ARTICLE is the article number of the current headline.")
 (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 @@ ARTICLE is the article number of the current headline.")
 
 (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 @@ ARTICLE is the article number of the current headline.")
   (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 @@ ARTICLE is the article number of the current headline.")
   (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 @@ ARTICLE is the article number of the current headline.")
                    (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 @@ ARTICLE is the article number of the current headline.")
          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 @@ ARTICLE is the article number of the current headline.")
          (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 @@ ARTICLE is the article number of the current headline.")
          (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 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+           "<!-- OPML generated by Emacs Gnus' nnrss.el -->\n"
+           "<opml version=\"1.1\">\n"
+           "  <head>\n"
+           "    <title>mySubscriptions</title>\n"
+           "    <dateCreated>" (format-time-string "%a, %d %b %Y %T %z")
+           "</dateCreated>\n"
+           "    <ownerEmail>" user-mail-address "</ownerEmail>\n"
+           "    <ownerName>" (user-full-name) "</ownerName>\n"
+           "  </head>\n"
+           "  <body>\n")
+    (dolist (sub nnrss-group-alist)
+      (insert "    <outline text=\"" (car sub)
+             "\" xmlUrl=\"" (cadr sub) "\"/>\n"))
+    (insert "  </body>\n"
+           "</opml>\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 @@ It is useful when `(setq nnrss-use-local t)'."
     (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 @@ It is useful when `(setq nnrss-use-local t)'."
     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 <link> 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 @@ whether they are `offsite' or `onsite'."
   (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 @@ whether they are `offsite' or `onsite'."
 ;;       - 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 @@ whether they are `offsite' or `onsite'."
                   '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 @@ whether they are `offsite' or `onsite'."
          (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 @@ element is rss or rdf."
 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)))
 
index f5fac83..bd8aa59 100644 (file)
@@ -1,3 +1,7 @@
+2005-04-06  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (RSS): Addition.
+
 2005-04-09  Luc Teirlinck  <teirllm@auburn.edu>
 
        * display.texi (Useless Whitespace): `indicate-unused-lines' is
index c670da1..6345cc2 100644 (file)
@@ -15873,14 +15873,45 @@ changes to a wiki (e.g. @url{http://cliki.net/recent-changes.rdf}).
 @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 following @code{nnrss} variables can be altered:
 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