(nntp-wait-for-string): Supply a timeout for accept-process-output to ensure progress.
[gnus] / lisp / nnrss.el
index f28287f..8d8a40d 100644 (file)
@@ -1,32 +1,34 @@
 ;;; nnrss.el --- interfacing with RSS
 
-;; Copyright (C) 2001, 2002, 2003, 2004, 2005,
-;;   2006, 2007 Free Software Foundation, Inc.
+;; Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+;;   2008, 2009, 2010  Free Software Foundation, Inc.
 
 ;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
 ;; Keywords: RSS
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published
-;; by the Free Software Foundation; either version 2, or (at your
-;; option) any later version.
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
-;; GNU Emacs is distributed in the hope that it will be useful, but
-;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-;; General Public License for more details.
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
 ;;; Code:
 
+;; For Emacs < 22.2.
+(eval-and-compile
+  (unless (fboundp 'declare-function) (defmacro declare-function (&rest r))))
+
 (eval-when-compile (require 'cl))
 
 (require 'gnus)
 (defvoo nnrss-directory (nnheader-concat gnus-directory "rss/")
   "Where nnrss will save its files.")
 
+(defvoo nnrss-ignore-article-fields '(slash:comments)
+  "*List of fields that should be ignored when comparing RSS articles.
+Some RSS feeds update article fields during their lives, e.g. to
+indicate the number of comments or the number of times the
+articles have been seen.  However, if there is a difference
+between the local article and the distant one, the latter is
+considered to be new.  To avoid this and discard some fields, set
+this variable to the list of fields to be ignored.")
+
 ;; (group max rss-url)
 (defvoo nnrss-server-data nil)
 
@@ -83,7 +94,13 @@ 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.")
+  "*Coding system used when reading and writing files.
+If you run Gnus with various versions of Emacsen, the value of this
+variable should be the coding system that all those Emacsen support.
+Note that you have to regenerate all the nnrss groups if you change
+the value.  Moreover, you should be patient even if you are made to
+read the same articles twice, that arises for the difference of the
+versions of xml.el.")
 
 (defvar nnrss-compatible-encoding-alist
   (delq nil (mapcar (lambda (elem)
@@ -180,9 +197,8 @@ used to render text.  If it is nil, text will simply be folded.")
 (deffoo nnrss-close-group (group &optional server)
   t)
 
-(eval-when-compile
-  (defvar mm-text-html-renderer)
-  (defvar mm-text-html-washer-alist))
+(defvar mm-text-html-renderer)
+(defvar mm-text-html-washer-alist)
 
 (deffoo nnrss-request-article (article &optional group server buffer)
   (setq group (nnrss-decode-group-name group))
@@ -210,8 +226,6 @@ used to render text.  If it is nil, text will simply be folded.")
              (link (nth 2 e))
              (enclosure (nth 7 e))
              (comments (nth 8 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)
@@ -256,7 +270,7 @@ used to render text.  If it is nil, text will simply be folded.")
                      (replace-match "\n")
                    (replace-match "\n\n")))
                (unless (eobp)
-                 (let ((fill-column default-fill-column)
+                 (let ((fill-column (default-value 'fill-column))
                        (window (get-buffer-window nntp-server-buffer)))
                    (when window
                      (setq fill-column
@@ -294,7 +308,11 @@ used to render text.  If it is nil, text will simply be folded.")
                    "<#/part>\n"
                    "<#/multipart>\n"))
          (condition-case nil
-             (mml-to-mime)
+             ;; Allow `mml-to-mime' to generate MIME article without
+             ;; making inquiry to a user for unknown encoding.
+             (let ((mml-confirmation-set
+                    (cons 'unknown-encoding mml-confirmation-set)))
+               (mml-to-mime))
            (error
             (erase-buffer)
             (insert header
@@ -365,7 +383,8 @@ used to render text.  If it is nil, text will simply be folded.")
        (delq (assoc group nnrss-server-data) nnrss-server-data))
   (nnrss-save-server-data server)
   (ignore-errors
-   (delete-file (nnrss-make-filename group server)))
+    (let ((file-name-coding-system nnmail-pathname-coding-system))
+      (delete-file (nnrss-make-filename group server))))
   t)
 
 (deffoo nnrss-request-list-newsgroups (&optional server)
@@ -403,10 +422,12 @@ otherwise return nil."
                                         nnrss-compatible-encoding-alist)))))
     (mm-coding-system-p 'utf-8)))
 
+(declare-function w3-parse-buffer "ext:w3-parse" (&optional buff))
+
 (defun nnrss-fetch (url &optional local)
   "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
+    ;;some 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
@@ -472,15 +493,18 @@ nnrss: %s: Not valid XML %s and w3-parse doesn't work %s"
       (unless (assoc (car elem) nnrss-group-alist)
        (insert (prin1-to-string (car elem)) " 0 1 y\n")))))
 
-(eval-and-compile (autoload 'timezone-parse-date "timezone"))
+(autoload 'timezone-parse-date "timezone")
 
 (defun nnrss-normalize-date (date)
   "Return a date string of DATE in the RFC822 style.
 This function handles the ISO 8601 date format described in
-<URL:http://www.w3.org/TR/NOTE-datetime>, and also the RFC822 style
+URL `http://www.w3.org/TR/NOTE-datetime', and also the RFC822 style
 which RSS 2.0 allows."
-  (let (case-fold-search vector year month day time zone cts)
-    (cond ((null date))
+  (let (case-fold-search vector year month day time zone cts given)
+    (cond ((null date))                        ; do nothing for this case
+         ;; if the date is just digits (unix time stamp):
+         ((string-match "^[0-9]+$" date)
+          (setq given (seconds-to-time (string-to-number date))))
          ;; RFC822
          ((string-match " [0-9]+ " date)
           (setq vector (timezone-parse-date date)
@@ -538,19 +562,19 @@ which RSS 2.0 allows."
                  (if zone
                      (concat " " zone)
                    "")))
-      (message-make-date))))
+      (message-make-date given))))
 
 ;;; data functions
 
 (defun nnrss-read-server-data (server)
   (setq nnrss-server-data nil)
-  (let ((file (nnrss-make-filename "nnrss" server)))
+  (let ((file (nnrss-make-filename "nnrss" server))
+       (file-name-coding-system nnmail-pathname-coding-system))
     (when (file-exists-p file)
       ;; 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))
+       (let ((coding-system-for-read nnrss-file-coding-system))
          (insert-file-contents file)
          (eval-region (point-min) (point-max)))))))
 
@@ -573,13 +597,13 @@ which RSS 2.0 allows."
   (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 (nnrss-make-filename group server)))
+  (let ((file (nnrss-make-filename group server))
+       (file-name-coding-system nnmail-pathname-coding-system))
     (when (file-exists-p file)
       ;; 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))
+       (let ((coding-system-for-read nnrss-file-coding-system))
          (insert-file-contents file)
          (eval-region (point-min) (point-max))))
       (dolist (e nnrss-group-data)
@@ -658,10 +682,20 @@ which RSS 2.0 allows."
       (rfc2047-encode-region (point-min) (point-max)))
     (goto-char (point-min))
     (while (search-forward "\n" nil t)
-      (delete-backward-char 1))
+      (delete-char -1))
     (buffer-string)))
 
 ;;; Snarf functions
+(defun nnrss-make-hash-index (item)
+  (gnus-message 9 "nnrss: Making hash index of %s" (gnus-prin1-to-string item))
+  (setq item (gnus-remove-if
+             (lambda (field)
+               (when (listp field)
+                 (memq (car field) nnrss-ignore-article-fields)))
+             item))
+  (md5 (gnus-prin1-to-string item)
+       nil nil
+       nnrss-file-coding-system))
 
 (defun nnrss-check-group (group server)
   (let (file xml subject url extra changed author date feed-subject
@@ -698,7 +732,7 @@ which RSS 2.0 allows."
     (dolist (item (nreverse (nnrss-find-el (intern (concat rss-ns "item")) xml)))
       (when (and (listp item)
                 (string= (concat rss-ns "item") (car item))
-                (progn (setq hash-index (md5 (gnus-prin1-to-string item)))
+                (progn (setq hash-index (nnrss-make-hash-index item))
                        (not (gethash hash-index nnrss-group-hashtb))))
        (setq subject (nnrss-node-text rss-ns 'title item))
        (setq url (nnrss-decode-entities-string
@@ -759,6 +793,8 @@ which RSS 2.0 allows."
          (push (list group nnrss-group-max) nnrss-server-data)))
       (nnrss-save-server-data server))))
 
+(declare-function gnus-group-make-rss-group "gnus-group" (&optional url))
+
 (defun nnrss-opml-import (opml-file)
   "OPML subscriptions import.
 Read the file and attempt to subscribe to each Feed in the file."
@@ -976,7 +1012,7 @@ whether they are `offsite' or `onsite'."
 
 (defun nnrss-discover-feed (url)
   "Given a page, find an RSS feed using Mark Pilgrim's
-`ultra-liberal rss locator' (http://diveintomark.org/2002/08/15.html)."
+`ultra-liberal rss locator' (URL `http://diveintomark.org/2002/08/15.html')."
 
   (let ((parsed-page (nnrss-fetch url)))
 
@@ -1098,7 +1134,4 @@ prefix), return the prefix."
 
 (provide 'nnrss)
 
-
 ;;; nnrss.el ends here
-
-;;; arch-tag: 12910c07-0cdf-44fb-8d2c-416ded64c267