Mercurial > emacs
comparison lisp/net/newsticker.el @ 90261:7beb78bc1f8e
Revision: miles@gnu.org--gnu-2005/emacs--unicode--0--patch-97
Merge from emacs--cvs-trunk--0
Patches applied:
* emacs--cvs-trunk--0 (patch 616-696)
- Add lisp/mh-e/.arch-inventory
- Update from CVS
- Merge from gnus--rel--5.10
- Update from CVS: lisp/smerge-mode.el: Add 'tools' to file keywords.
- lisp/gnus/ChangeLog: Remove duplicate entry
* gnus--rel--5.10 (patch 147-181)
- Update from CVS
- Merge from emacs--cvs-trunk--0
- Update from CVS: lisp/mml.el (mml-preview): Doc fix.
- Update from CVS: texi/message.texi: Fix default values.
- Update from CVS: texi/gnus.texi (RSS): Addition.
author | Miles Bader <miles@gnu.org> |
---|---|
date | Mon, 16 Jan 2006 08:37:27 +0000 |
parents | 5e2d3828e89f b42dfcb5e692 |
children | d6f8fe3307c8 |
comparison
equal
deleted
inserted
replaced
90260:0ca0d9181b5e | 90261:7beb78bc1f8e |
---|---|
1 ;;; newsticker.el --- A news-ticker for Emacs. | 1 ;;; newsticker.el --- A Newsticker for Emacs. |
2 | 2 |
3 ;; Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. | 3 ;; Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. |
4 | 4 |
5 ;; This file is part of GNU Emacs. | 5 ;; This file is part of GNU Emacs. |
6 | 6 |
7 ;; Author: Ulf Jasper <ulf.jasper@web.de> | 7 ;; Author: Ulf Jasper <ulf.jasper@web.de> |
8 ;; Filename: newsticker.el | 8 ;; Filename: newsticker.el |
9 ;; URL: http://www.nongnu.org/newsticker | 9 ;; URL: http://www.nongnu.org/newsticker |
10 ;; Created: 17. June 2003 | 10 ;; Created: 17. June 2003 |
11 ;; Keywords: News, RSS | 11 ;; Keywords: News, RSS, Atom |
12 ;; Time-stamp: "1. November 2005, 21:16:53 (ulf)" | |
13 | |
14 ;; ====================================================================== | |
12 | 15 |
13 ;; This program is free software; you can redistribute it and/or modify | 16 ;; This program is free software; you can redistribute it and/or modify |
14 ;; it under the terms of the GNU General Public License as published by | 17 ;; it under the terms of the GNU General Public License as published by |
15 ;; the Free Software Foundation; either version 2 of the License, or (at | 18 ;; the Free Software Foundation; either version 2 of the License, or (at |
16 ;; your option) any later version. | 19 ;; your option) any later version. |
22 | 25 |
23 ;; You should have received a copy of the GNU General Public License | 26 ;; You should have received a copy of the GNU General Public License |
24 ;; along with this program; if not, write to the Free Software Foundation, | 27 ;; along with this program; if not, write to the Free Software Foundation, |
25 ;; Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 28 ;; Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
26 | 29 |
27 (defconst newsticker-version "1.8" "Version number of newsticker.el.") | 30 (defconst newsticker-version "1.9" "Version number of newsticker.el.") |
28 | 31 |
29 ;; ====================================================================== | 32 ;; ====================================================================== |
30 | |
31 ;;; Commentary: | 33 ;;; Commentary: |
32 | 34 |
33 ;; Overview | 35 ;; Overview |
34 ;; -------- | 36 ;; -------- |
35 | 37 |
36 ;; Newsticker provides a newsticker for Emacs. A newsticker is a thing that | 38 ;; Newsticker provides a newsticker for Emacs. A newsticker is a thing |
37 ;; asynchronously retrieves headlines from a list of news sites, prepares | 39 ;; that asynchronously retrieves headlines from a list of news sites, |
38 ;; these headlines for reading, and allows for loading the corresponding | 40 ;; prepares these headlines for reading, and allows for loading the |
39 ;; articles in a web browser. | 41 ;; corresponding articles in a web browser. |
40 | 42 |
41 ;; Headlines consist of a title and (possibly) a small description. They | 43 ;; Headlines consist of a title and (possibly) a small description. They |
42 ;; are contained in RSS (RDF Site Summary) files. Newsticker should work | 44 ;; are contained in "RSS" (RDF Site Summary) or "Atom" files. Newsticker |
43 ;; with all RSS files that follow the RDF Rich Site Summary 1.0 | 45 ;; should work with the following RSS formats: |
44 ;; specification. It should also work with version 2.0 as well as | 46 ;; * RSS 0.91 |
45 ;; other/older/alternative RSS formats (like 0.9<something> or such). In | 47 ;; (see http://backend.userland.com/rss091 or |
46 ;; other words: Newsticker is a "RSS reader" or "RSS aggregator". | 48 ;; http://my.netscape.com/publish/formats/rss-spec-0.91.html) |
49 ;; * RSS 0.92 | |
50 ;; (see http://backend.userland.com/rss092) | |
51 ;; * RSS 1.0 | |
52 ;; (see http://purl.org/rss/1.0/spec) | |
53 ;; * RSS 2.0 | |
54 ;; (see http://blogs.law.harvard.edu/tech/rss) | |
55 ;; as well as the following Atom formats: | |
56 ;; * Atom 0.3 | |
57 ;; * Atom 1.0 | |
58 ;; (see http://www.ietf.org/internet-drafts/draft-ietf-atompub-format-11.txt) | |
59 ;; That makes Newsticker.el an "Atom aggregator, "RSS reader", "RSS | |
60 ;; aggregator", and "Feed Reader". | |
47 | 61 |
48 ;; Newsticker provides several commands for reading headlines, navigating | 62 ;; Newsticker provides several commands for reading headlines, navigating |
49 ;; through them, marking them as read/unread, hiding old headlines | 63 ;; through them, marking them as read/unread, hiding old headlines |
50 ;; etc. Headlines can be displayed as plain text or as rendered HTML. | 64 ;; etc. Headlines can be displayed as plain text or as rendered HTML. |
51 | 65 |
52 ;; Headlines can be displayed in the echo area, either scrolling like | 66 ;; Headlines can be displayed in the echo area, either scrolling like |
53 ;; messages in a stock-quote ticker, or just changing. | 67 ;; messages in a stock-quote ticker, or just changing. |
54 | 68 |
55 ;; Newsticker allows for automatic processing of headlines by providing | 69 ;; Newsticker allows for automatic processing of headlines by providing |
56 ;; hooks and (sample) functions for automatically downloading images and | 70 ;; hooks and (sample) functions for automatically downloading images and |
57 ;; enclosed files (as delivered by podcasts, e.g.). | 71 ;; enclosed files (as delivered by podcasts, e.g.). |
58 | 72 |
59 | |
60 | |
61 ;; Requirements | 73 ;; Requirements |
62 ;; ------------ | 74 ;; ------------ |
63 ;; Newsticker can be used with Emacs version 21.1 or later as well as | 75 ;; Newsticker can be used with GNU Emacs version 21.1 or later as well as |
64 ;; XEmacs. It requires an XML-parser (`xml.el') which is part of | 76 ;; XEmacs. It requires an XML-parser (`xml.el') which is part of GNU |
65 ;; Emacs. If you are using XEmacs you want to get the `net-utils' package | 77 ;; Emacs. If you are using XEmacs you want to get the `net-utils' package |
66 ;; which contains `xml.el' for XEmacs. | 78 ;; which contains `xml.el' for XEmacs. |
67 | 79 |
68 ;; Newsticker requires a program which can retrieve files via http and | 80 ;; Newsticker requires a program which can retrieve files via http and |
69 ;; prints them to stdout. By default Newsticker will use wget for this | 81 ;; prints them to stdout. By default Newsticker will use wget for this |
70 ;; task. | 82 ;; task. |
83 | |
84 ;; Installation | |
85 ;; ------------ | |
86 | |
87 ;; If you are using Newsticker as part of GNU Emacs there is no need to | |
88 ;; perform any installation steps in order to use Newsticker. Otherwise | |
89 ;; place Newsticker in a directory where Emacs can find it. Add the | |
90 ;; following line to your Emacs startup file (`~/.emacs'). | |
91 ;; (add-to-list 'load-path "/path/to/newsticker/") | |
92 ;; (autoload 'newsticker-start "newsticker" "Emacs Newsticker" t) | |
93 ;; (autoload 'newsticker-show-news "newsticker" "Emacs Newsticker" t) | |
94 | |
95 ;; If you are using `imenu', which allows for navigating with the help of a | |
96 ;; menu, you should add the following to your Emacs startup file | |
97 ;; (`~/.emacs'). | |
98 ;; (add-hook 'newsticker-mode-hook 'imenu-add-menubar-index) | |
99 | |
100 ;; That's it. | |
71 | 101 |
72 ;; Usage | 102 ;; Usage |
73 ;; ----- | 103 ;; ----- |
74 ;; The command newsticker-show-news will display all available headlines in | 104 ;; The command newsticker-show-news will display all available headlines in |
75 ;; a special buffer, called `*newsticker*'. It will also start the | 105 ;; a special buffer, called `*newsticker*'. It will also start the |
76 ;; asynchronous download of headlines. The modeline in the `*newsticker*' | 106 ;; asynchronous download of headlines. The modeline in the `*newsticker*' |
77 ;; buffer informs whenever new headlines have arrived. Clicking | 107 ;; buffer informs whenever new headlines have arrived. Clicking |
78 ;; mouse-button 2 or pressing RET in this buffer on a headline will call | 108 ;; mouse-button 2 or pressing RET in this buffer on a headline will call |
79 ;; browse-url to load the corresponding news story in your favourite web | 109 ;; browse-url to load the corresponding news story in your favourite web |
80 ;; browser. | 110 ;; browser. |
81 | 111 |
82 ;; The scrolling, or flashing of headlines in the echo area, can be started | 112 ;; The scrolling, or flashing of headlines in the echo area, can be started |
83 ;; with the command newsticker-start-ticker. It can be stopped with | 113 ;; with the command newsticker-start-ticker. It can be stopped with |
84 ;; newsticker-stop-ticker. | 114 ;; newsticker-stop-ticker. |
85 | 115 |
86 ;; If you just want to start the periodic download of headlines use the | 116 ;; If you just want to start the periodic download of headlines use the |
87 ;; command newsticker-start. Calling newsticker-stop will stop the periodic | 117 ;; command newsticker-start. Calling newsticker-stop will stop the |
88 ;; download, but will call newsticker-stop-ticker as well. | 118 ;; periodic download, but will call newsticker-stop-ticker as well. |
89 | 119 |
90 ;; Configuration | 120 ;; Configuration |
91 ;; ------------- | 121 ;; ------------- |
92 ;; All Newsticker options are customizable, i.e. they can be changed with | 122 ;; All Newsticker options are customizable, i.e. they can be changed with |
93 ;; Emacs customization methods: Call the command customize-group and enter | 123 ;; Emacs customization methods: Call the command customize-group and enter |
108 ;; * newsticker-headline-processing contains options that define how the | 138 ;; * newsticker-headline-processing contains options that define how the |
109 ;; retrieved headlines are processed. | 139 ;; retrieved headlines are processed. |
110 ;; o newsticker-keep-obsolete-items decides whether unread headlines that | 140 ;; o newsticker-keep-obsolete-items decides whether unread headlines that |
111 ;; have been removed from the feed are kept in the Newsticker cache. | 141 ;; have been removed from the feed are kept in the Newsticker cache. |
112 ;; * newsticker-layout contains options that define how the buffer for | 142 ;; * newsticker-layout contains options that define how the buffer for |
113 ;; reading RSS headlines is formatted. | 143 ;; reading news headlines is formatted. |
114 ;; o newsticker-item-format defines how the title of a headline is | 144 ;; o newsticker-item-format defines how the title of a headline is |
115 ;; formatted. | 145 ;; formatted. |
116 ;; * newsticker-ticker contains options that define how headlines are shown | 146 ;; * newsticker-ticker contains options that define how headlines are shown |
117 ;; in the echo area. | 147 ;; in the echo area. |
118 ;; o newsticker-display-interval and newsticker-scroll-smoothly define | 148 ;; o newsticker-display-interval and newsticker-scroll-smoothly define |
119 ;; how headlines are shown in the echo area. | 149 ;; how headlines are shown in the echo area. |
120 ;; * newsticker-hooks contains options for hooking other Emacs commands to | 150 ;; * newsticker-hooks contains options for hooking other Emacs commands to |
121 ;; newsticker functions. | 151 ;; newsticker functions. |
122 ;; o newsticker-new-item-functions allows for automatic processing of | 152 ;; o newsticker-new-item-functions allows for automatic processing of |
123 ;; headlines. See `newsticker-download-images', and | 153 ;; headlines. See `newsticker-download-images', and |
124 ;; `newsticker-download-enclosures' for sample functions. | 154 ;; `newsticker-download-enclosures' for sample functions. |
125 ;; * newsticker-miscellaneous contains other Newsticker options. | 155 ;; * newsticker-miscellaneous contains other Newsticker options. |
126 | 156 |
127 ;; Please have a look at the customization buffers for the complete list of | 157 ;; Please have a look at the customization buffers for the complete list of |
128 ;; options. | 158 ;; options. |
132 ;; This newsticker is designed do its job silently in the background | 162 ;; This newsticker is designed do its job silently in the background |
133 ;; without disturbing you. However, it is probably impossible to prevent | 163 ;; without disturbing you. However, it is probably impossible to prevent |
134 ;; such a tool from slightly attenuating your Editor's responsiveness every | 164 ;; such a tool from slightly attenuating your Editor's responsiveness every |
135 ;; once in a while. | 165 ;; once in a while. |
136 | 166 |
137 ;; Newsticker-mode supports imenu. It allows for navigating with the help | 167 ;; Byte-compiling newsticker.el is recommended. |
138 ;; of a menu. In order to use this feature you should also add the | |
139 ;; following. | |
140 ;; (add-hook 'newsticker-mode-hook 'imenu-add-menubar-index) | |
141 | 168 |
142 ;; ====================================================================== | 169 ;; ====================================================================== |
143 ;;; History: | 170 ;;; History: |
171 | |
172 ;; 1.9 (2005-11-01) | |
173 ;; * Rewrote feed parsing part. Newsticker now supports RSS 0.91, | |
174 ;; 0.92, 1.0, 2.0 as well as Atom 0.3 and 1.0 -- thanks to Thien-Thi | |
175 ;; Nguyen. | |
176 ;; * Changed auto-marking mechanism: Replaced variable | |
177 ;; `newsticker-auto-mark-filter' with new variable | |
178 ;; `newsticker-auto-mark-filter-list', which allows for looking not | |
179 ;; only at the title but also at the description of a headline. | |
180 ;; * Call `newsticker--ticker-text-setup' only after all pending | |
181 ;; downloads processes have finished. | |
182 ;; * Improved handling of coding systems. | |
183 ;; * Added magic autoload comments. | |
184 ;; * Bugfixes: | |
185 ;; - `hide-entry' was hiding too much when called for the last | |
186 ;; headline, | |
187 ;; - update mode-line and menu-bar when necessary, | |
188 ;; - repaired `newsticker--imenu-goto', | |
189 ;; - other minor things. | |
144 | 190 |
145 ;; 1.8 (2005-08-26) | 191 ;; 1.8 (2005-08-26) |
146 ;; * Added commands `newsticker-show-extra' and `newsticker-hide-extra' | 192 ;; * Added commands `newsticker-show-extra' and `newsticker-hide-extra' |
147 ;; to show and hide extra RSS elements, bound to "sx" and "hx" | 193 ;; to show and hide extra RSS elements, bound to "sx" and "hx" |
148 ;; resp. Changed default value of `newsticker-show-all-rss-elements' | 194 ;; resp. Changed default value of `newsticker-show-all-rss-elements' |
154 | 200 |
155 ;; 1.7 (2005-06-25) | 201 ;; 1.7 (2005-06-25) |
156 ;; * Tool-bar support: most important commands can be called from | 202 ;; * Tool-bar support: most important commands can be called from |
157 ;; tool-bar buttons. | 203 ;; tool-bar buttons. |
158 ;; * Auto-Narrowing introduced: *newsticker* buffer can be narrowed to | 204 ;; * Auto-Narrowing introduced: *newsticker* buffer can be narrowed to |
159 ;; a single item (bound to key `xi') or a single feed (bound to `xf'). | 205 ;; a single item (bound to key `xi') or a single feed (bound to |
206 ;; `xf'). | |
160 ;; * Enclosure support: enclosed items are shown (see | 207 ;; * Enclosure support: enclosed items are shown (see |
161 ;; `newsticker-enclosure-face') and can be (automatically) downloaded | 208 ;; `newsticker-enclosure-face') and can be (automatically) downloaded |
162 ;; (see below). For those of you who read "podcasts". | 209 ;; (see below). For those of you who read "podcasts". |
163 ;; * Added variable `newsticker-auto-mark-filter' for automatically | 210 ;; * Added variable `newsticker-auto-mark-filter' for automatically |
164 ;; marking items as immortal or old. | 211 ;; marking items as immortal or old. |
177 ;; arbitrary programs for URLs, bound to `C-RET'. | 224 ;; arbitrary programs for URLs, bound to `C-RET'. |
178 ;; * URLs in extra elements are clickable. | 225 ;; * URLs in extra elements are clickable. |
179 ;; * Better support for w3, added command | 226 ;; * Better support for w3, added command |
180 ;; `newsticker-w3m-show-inline-images' for displaying all inline | 227 ;; `newsticker-w3m-show-inline-images' for displaying all inline |
181 ;; images. | 228 ;; images. |
182 ;; * Insert an artificial headline which notifies about failed retrievals. | 229 ;; * Insert an artificial headline which notifies about failed |
230 ;; retrievals. | |
183 ;; * Use pubDate element (RSS 2.0) instead of retrieval time when | 231 ;; * Use pubDate element (RSS 2.0) instead of retrieval time when |
184 ;; available. | 232 ;; available. |
185 ;; * Customizable options grouped. | 233 ;; * Customizable options grouped. |
186 ;; * Bugfixes: `newsticker--imenu-create-index'; strip whitespace | 234 ;; * Bugfixes: `newsticker--imenu-create-index'; strip whitespace |
187 ;; from links; apply coding-system to extra-elements; time-comparison | 235 ;; from links; apply coding-system to extra-elements; time-comparison |
188 ;; for obsolete items; and others which I have forgotten. | 236 ;; for obsolete items; and others which I have forgotten. |
189 ;; * Workaround for another bug in xml-parse-region -- thanks to anonymous | 237 ;; * Workaround for another bug in xml-parse-region -- thanks to |
190 ;; for sending patch. | 238 ;; anonymous for sending patch. |
191 ;; * Renamed invisible buffers ` *wget-newsticker-<feed>*' to | 239 ;; * Renamed invisible buffers ` *wget-newsticker-<feed>*' to |
192 ;; ` *newsticker-wget-<feed>*'. | 240 ;; ` *newsticker-wget-<feed>*'. |
193 ;; * Tested with Emacs versions 21.3 and 22.0 and XEmacs 21.something. | 241 ;; * Tested with GNU Emacs versions 21.3 and 22.0 and XEmacs |
242 ;; 21.something. | |
194 | 243 |
195 ;; 1.6 * Support for (some) optional RSS elements: guid, dc:date. See | 244 ;; 1.6 * Support for (some) optional RSS elements: guid, dc:date. See |
196 ;; `newsticker-show-all-rss-elements' `newsticker-extra-face'. | 245 ;; `newsticker-show-all-rss-elements' `newsticker-extra-face'. |
197 ;; * Better support for w3m -- `newsticker-default-face' is obsolete | 246 ;; * Better support for w3m -- `newsticker-default-face' is obsolete |
198 ;; now, removed `newsticker-w3m-toggle-inline-image'. | 247 ;; now, removed `newsticker-w3m-toggle-inline-image'. |
199 ;; * Added `newsticker-desc-comp-max' -- comparison of item descriptions | 248 ;; * Added `newsticker-desc-comp-max' -- comparison of item |
200 ;; can take quite some time. | 249 ;; descriptions can take quite some time. |
201 ;; * Added `newsticker--buffer-make-item-completely-visible' to | 250 ;; * Added `newsticker--buffer-make-item-completely-visible' to |
202 ;; ensure that the current item is fully visible. | 251 ;; ensure that the current item is fully visible. |
203 ;; * Allow for non-positive retrieval-interval, which make newsticker | 252 ;; * Allow for non-positive retrieval-interval, which make newsticker |
204 ;; get news only once. | 253 ;; get news only once. |
205 ;; * Use :set for customizable variables. | 254 ;; * Use :set for customizable variables. |
341 (defvar tool-bar-map) | 390 (defvar tool-bar-map) |
342 (defvar w3-mode-map) | 391 (defvar w3-mode-map) |
343 (defvar w3m-minor-mode-map) | 392 (defvar w3m-minor-mode-map) |
344 | 393 |
345 ;; ====================================================================== | 394 ;; ====================================================================== |
395 ;;; Newsticker status | |
396 ;; ====================================================================== | |
397 | |
398 (defvar newsticker--retrieval-timer-list nil | |
399 "List of timers for news retrieval. | |
400 This is an alist, each element consisting of (feed-name . timer)") | |
401 | |
402 (defvar newsticker--display-timer nil | |
403 "Timer for newsticker display.") | |
404 | |
405 ;;;###autoload | |
406 (defun newsticker-running-p () | |
407 "Check whether newsticker is running. | |
408 Return t if newsticker is running, nil otherwise. Newsticker is | |
409 considered to be running if the newsticker timer list is not empty." | |
410 (> (length newsticker--retrieval-timer-list) 0)) | |
411 | |
412 ;;;###autoload | |
413 (defun newsticker-ticker-running-p () | |
414 "Check whether newsticker's actual ticker is running. | |
415 Return t if ticker is running, nil otherwise. Newsticker is | |
416 considered to be running if the newsticker timer list is not | |
417 empty." | |
418 (timerp newsticker--display-timer)) | |
419 | |
420 ;; ====================================================================== | |
346 ;;; Customizables | 421 ;;; Customizables |
347 ;; ====================================================================== | 422 ;; ====================================================================== |
348 (defgroup newsticker nil | 423 (defgroup newsticker nil |
349 "RSS aggregator." | 424 "Aggregator for RSS and Atom feeds." |
350 :group 'applications) | 425 :group 'applications) |
351 | 426 |
352 (defconst newsticker--raw-url-list-defaults | 427 (defconst newsticker--raw-url-list-defaults |
353 '(("CNET News.com" | 428 '(("CNET News.com" |
354 "http://export.cnet.com/export/feeds/news/rss/1,11176,,00.xml") | 429 "http://export.cnet.com/export/feeds/news/rss/1,11176,,00.xml") |
474 (t | 549 (t |
475 (error "Ooops %s" symbol))))) | 550 (error "Ooops %s" symbol))))) |
476 | 551 |
477 ;; customization group feed | 552 ;; customization group feed |
478 (defgroup newsticker-feed nil | 553 (defgroup newsticker-feed nil |
479 "Settings for the RSS feeds." | 554 "Settings for news feeds." |
480 :group 'newsticker) | 555 :group 'newsticker) |
481 | 556 |
482 (defcustom newsticker-url-list-defaults | 557 (defcustom newsticker-url-list-defaults |
483 '(("Emacs Wiki" | 558 '(("Emacs Wiki" |
484 "http://www.emacswiki.org/cgi-bin/wiki.pl?action=rss" | 559 "http://www.emacswiki.org/cgi-bin/wiki.pl?action=rss" |
504 optionally followed by a START-TIME, INTERVAL specifier and WGET-ARGUMENTS. | 579 optionally followed by a START-TIME, INTERVAL specifier and WGET-ARGUMENTS. |
505 | 580 |
506 The LABEL gives the name of the news feed. It can be an arbitrary string. | 581 The LABEL gives the name of the news feed. It can be an arbitrary string. |
507 | 582 |
508 The URL gives the location of the news feed. It must point to a valid | 583 The URL gives the location of the news feed. It must point to a valid |
509 RSS file. The RSS file is retrieved by calling wget, or whatever you | 584 RSS or Atom file. The file is retrieved by calling wget, or whatever you |
510 specify as `newsticker-wget-name'. | 585 specify as `newsticker-wget-name'. |
511 | 586 |
512 The START-TIME can be either a string, or nil. If it is a string it | 587 The START-TIME can be either a string, or nil. If it is a string it |
513 specifies a fixed time at which this feed shall be retrieved for the | 588 specifies a fixed time at which this feed shall be retrieved for the |
514 first time. (Examples: \"11:00pm\", \"23:00\"). If it is nil (or | 589 first time. (Examples: \"11:00pm\", \"23:00\"). If it is nil (or |
533 (string :tag "Fixed Time")) | 608 (string :tag "Fixed Time")) |
534 (choice :tag "Interval" | 609 (choice :tag "Interval" |
535 (const :tag "Default" nil) | 610 (const :tag "Default" nil) |
536 (const :tag "Hourly" 3600) | 611 (const :tag "Hourly" 3600) |
537 (const :tag "Daily" 86400) | 612 (const :tag "Daily" 86400) |
613 (const :tag "Weekly" 604800) | |
538 (integer :tag "Interval")) | 614 (integer :tag "Interval")) |
539 (choice :tag "Wget Arguments" | 615 (choice :tag "Wget Arguments" |
540 (const :tag "Default arguments" nil) | 616 (const :tag "Default arguments" nil) |
541 (repeat :tag "Special arguments" string)))) | 617 (repeat :tag "Special arguments" string)))) |
542 :set 'newsticker--set-customvar | 618 :set 'newsticker--set-customvar |
567 make it less than 1800 seconds (30 minutes)!" | 643 make it less than 1800 seconds (30 minutes)!" |
568 :type '(choice :tag "Interval" | 644 :type '(choice :tag "Interval" |
569 (const :tag "No automatic retrieval" 0) | 645 (const :tag "No automatic retrieval" 0) |
570 (const :tag "Hourly" 3600) | 646 (const :tag "Hourly" 3600) |
571 (const :tag "Daily" 86400) | 647 (const :tag "Daily" 86400) |
648 (const :tag "Weekly" 604800) | |
572 (integer :tag "Interval")) | 649 (integer :tag "Interval")) |
573 :set 'newsticker--set-customvar | 650 :set 'newsticker--set-customvar |
574 :group 'newsticker-feed) | 651 :group 'newsticker-feed) |
575 | 652 |
576 (defcustom newsticker-desc-comp-max | 653 (defcustom newsticker-desc-comp-max |
582 :type 'integer | 659 :type 'integer |
583 :group 'newsticker-feed) | 660 :group 'newsticker-feed) |
584 | 661 |
585 ;; customization group behaviour | 662 ;; customization group behaviour |
586 (defgroup newsticker-headline-processing nil | 663 (defgroup newsticker-headline-processing nil |
587 "Settings for the automatic processing of RSS headlines." | 664 "Settings for the automatic processing of headlines." |
588 :group 'newsticker) | 665 :group 'newsticker) |
589 | 666 |
590 (defcustom newsticker-automatically-mark-items-as-old | 667 (defcustom newsticker-automatically-mark-items-as-old |
591 t | 668 t |
592 "Decides whether to automatically mark items as old. | 669 "Decides whether to automatically mark items as old. |
621 Obsolete items which are older than this value will be silently | 698 Obsolete items which are older than this value will be silently |
622 deleted at the next retrieval." | 699 deleted at the next retrieval." |
623 :type 'integer | 700 :type 'integer |
624 :group 'newsticker-headline-processing) | 701 :group 'newsticker-headline-processing) |
625 | 702 |
626 (defcustom newsticker-auto-mark-filter | 703 (defcustom newsticker-auto-mark-filter-list |
627 nil | 704 nil |
628 "A filter for automatically marking headlines. | 705 "A list of filters for automatically marking headlines. |
629 | 706 |
630 This is an alist of the form (FEED-NAME OLD-LIST IMMORTAL-LIST). I.e. each | 707 This is an alist of the form (FEED-NAME PATTERN-LIST). I.e. each |
631 element consists of a FEED-NAME and two lists. Each list consists a set of | 708 element consists of a FEED-NAME a PATTERN-LIST. Each element of |
632 regular expressions. The first list contains patterns of headlines which | 709 the pattern-list has the form (AGE TITLE-OR-DESCRIPTION REGEXP). |
633 will be marked as old. The second list contains patterns of headlines which | 710 AGE must be one of the symbols 'old or 'immortal. |
634 will be marked as immortal. | 711 TITLE-OR-DESCRIPTION must be on of the symbols 'title, |
635 | 712 'description, or 'all. REGEXP is a regular expression, i.e. a |
636 This filter is checked after a new headline has been retrieved. If | 713 string. |
637 FEED-NAME matches the name of the corresponding news feed, both sublists | 714 |
638 are checked: If the title of the headline matches any of the regular | 715 This filter is checked after a new headline has been retrieved. |
639 expressions in OLD-LIST, this headline is marked as old, if it matches any | 716 If FEED-NAME matches the name of the corresponding news feed, the |
640 of the expressions in IMMORTAL-LIST it is marked as immortal. | 717 pattern-list is checked: The new headline will be marked as AGE |
641 | 718 if REGEXP matches the headline's TITLE-OR-DESCRIPTION. |
642 If, for example, `newsticker-auto-mark-filter' looks like | 719 |
643 \((slashdot (\"^Forget me!$\") (\"^Read me$\" \"important\"))) | 720 If, for example, `newsticker-auto-mark-filter-list' looks like |
644 then all articles from slashdot are marked as old if they have the title | 721 \((slashdot ('old 'title \"^Forget me!$\") ('immortal 'title \"Read me\") |
645 \"Forget me!\". All articles which have the title \"Read me\" and all | 722 \('immortal 'all \"important\")))) |
646 articles which contain the string \"important\" in their title are marked | 723 |
647 as immortal." | 724 then all articles from slashdot are marked as old if they have |
648 :type '(repeat (list :tag "Feed filter rule" | 725 the title \"Forget me!\". All articles with a title containing |
726 the string \"Read me\" are marked as immortal. All articles which | |
727 contain the string \"important\" in their title or their | |
728 description are marked as immortal." | |
729 :type '(repeat (list :tag "Auto mark filter" | |
649 (string :tag "Feed name") | 730 (string :tag "Feed name") |
650 ;;(choice ,@(mapcar (lambda (i) | 731 (repeat |
651 ;; (list :tag (car i) (car i))) | 732 (list :tag "Filter element" |
652 ;; newsticker-url-list)) | 733 (choice |
653 (repeat :tag "Mark as old" string) | 734 :tag "Auto-assigned age" |
654 (repeat :tag "Mark as immortal" string))) | 735 (const :tag "Old" old) |
736 (const :tag "Immortal" immortal)) | |
737 (choice | |
738 :tag "Title/Description" | |
739 (const :tag "Title" title) | |
740 (const :tag "Description" description) | |
741 (const :tag "All" all)) | |
742 (string :tag "Regexp"))))) | |
655 :group 'newsticker-headline-processing) | 743 :group 'newsticker-headline-processing) |
656 | 744 |
657 ;; customization group layout | 745 ;; customization group layout |
658 (defgroup newsticker-layout nil | 746 (defgroup newsticker-layout nil |
659 "Settings for layout of the RSS reader." | 747 "Settings for layout of the feed reader." |
660 :group 'newsticker) | 748 :group 'newsticker) |
661 | 749 |
662 (defcustom newsticker-sort-method | 750 (defcustom newsticker-sort-method |
663 'sort-by-original-order | 751 'sort-by-original-order |
664 "Sort method for news items. | 752 "Sort method for news items. |
665 The following sort methods are available: | 753 The following sort methods are available: |
666 * `sort-by-original-order' keeps the order in which the items | 754 * `sort-by-original-order' keeps the order in which the items |
667 appear in the RSS file (please note that for immortal items, | 755 appear in the headline file (please note that for immortal items, |
668 which have been removed from the news feed, there is no original | 756 which have been removed from the news feed, there is no original |
669 order), | 757 order), |
670 * `sort-by-time' looks at the time at which an item has been seen | 758 * `sort-by-time' looks at the time at which an item has been seen |
671 the first time. The most recent item is put at top, | 759 the first time. The most recent item is put at top, |
672 * `sort-by-title' will put the items in an alphabetical order." | 760 * `sort-by-title' will put the items in an alphabetical order." |
678 :group 'newsticker-layout) | 766 :group 'newsticker-layout) |
679 | 767 |
680 (defcustom newsticker-hide-old-items-in-newsticker-buffer | 768 (defcustom newsticker-hide-old-items-in-newsticker-buffer |
681 nil | 769 nil |
682 "Decides whether to automatically hide old items in the *newsticker* buffer. | 770 "Decides whether to automatically hide old items in the *newsticker* buffer. |
683 If set to t old items will be completely folded and only new items | 771 If set to t old items will be completely folded and only new |
684 will show up in the *newsticker* buffer. Otherwise old as well as new | 772 items will show up in the *newsticker* buffer. Otherwise old as |
685 items will be visible." | 773 well as new items will be visible." |
686 :type 'boolean | 774 :type 'boolean |
687 :set 'newsticker--set-customvar | 775 :set 'newsticker--set-customvar |
688 :group 'newsticker-layout) | 776 :group 'newsticker-layout) |
689 | 777 |
690 (defcustom newsticker-show-descriptions-of-new-items | 778 (defcustom newsticker-show-descriptions-of-new-items |
700 "%l | 788 "%l |
701 %t %d %s" | 789 %t %d %s" |
702 "Format string for feed headings. | 790 "Format string for feed headings. |
703 The following printf-like specifiers can be used: | 791 The following printf-like specifiers can be used: |
704 %d The date the feed was retrieved. See `newsticker-date-format'. | 792 %d The date the feed was retrieved. See `newsticker-date-format'. |
705 %l The logo (image) of the feed. Most RSS feeds provide a small | 793 %l The logo (image) of the feed. Most news feeds provide a small |
706 image as logo. Newsticker can display them, if Emacs can -- | 794 image as logo. Newsticker can display them, if Emacs can -- |
707 see `image-types' for a list of supported image types. | 795 see `image-types' for a list of supported image types. |
708 %L The logo (image) of the feed. If the logo is not available | 796 %L The logo (image) of the feed. If the logo is not available |
709 the title of the feed is used. | 797 the title of the feed is used. |
710 %s The statistical data of the feed. See `newsticker-statistics-format'. | 798 %s The statistical data of the feed. See `newsticker-statistics-format'. |
716 (defcustom newsticker-item-format | 804 (defcustom newsticker-item-format |
717 "%t %d" | 805 "%t %d" |
718 "Format string for news item headlines. | 806 "Format string for news item headlines. |
719 The following printf-like specifiers can be used: | 807 The following printf-like specifiers can be used: |
720 %d The date the item was (first) retrieved. See `newsticker-date-format'. | 808 %d The date the item was (first) retrieved. See `newsticker-date-format'. |
721 %l The logo (image) of the feed. Most RSS feeds provide a small | 809 %l The logo (image) of the feed. Most news feeds provide a small |
722 image as logo. Newsticker can display them, if Emacs can -- | 810 image as logo. Newsticker can display them, if Emacs can -- |
723 see `image-types' for a list of supported image types. | 811 see `image-types' for a list of supported image types. |
724 %L The logo (image) of the feed. If the logo is not available | 812 %L The logo (image) of the feed. If the logo is not available |
725 the title of the feed is used. | 813 the title of the feed is used. |
726 %t The title of the item." | 814 %t The title of the item." |
731 (defcustom newsticker-desc-format | 819 (defcustom newsticker-desc-format |
732 "%d %c" | 820 "%d %c" |
733 "Format string for news descriptions (contents). | 821 "Format string for news descriptions (contents). |
734 The following printf-like specifiers can be used: | 822 The following printf-like specifiers can be used: |
735 %c The contents (description) of the item. | 823 %c The contents (description) of the item. |
736 %d The date the item was (first) retrieved. See `newsticker-date-format'." | 824 %d The date the item was (first) retrieved. See |
825 `newsticker-date-format'." | |
737 :type 'string | 826 :type 'string |
738 :set 'newsticker--set-customvar | 827 :set 'newsticker--set-customvar |
739 :group 'newsticker-layout) | 828 :group 'newsticker-layout) |
740 | 829 |
741 (defcustom newsticker-date-format | 830 (defcustom newsticker-date-format |
757 %O The number of obsolete items in the feed." | 846 %O The number of obsolete items in the feed." |
758 :type 'string | 847 :type 'string |
759 :set 'newsticker--set-customvar | 848 :set 'newsticker--set-customvar |
760 :group 'newsticker-layout) | 849 :group 'newsticker-layout) |
761 | 850 |
762 (defcustom newsticker-show-all-rss-elements | 851 (defcustom newsticker-show-all-news-elements |
763 nil | 852 nil |
764 "Show all RSS elements." | 853 "Show all news elements." |
765 :type 'boolean | 854 :type 'boolean |
766 ;;:set 'newsticker--set-customvar | 855 ;;:set 'newsticker--set-customvar |
767 :group 'newsticker-layout) | 856 :group 'newsticker-layout) |
768 | 857 |
769 ;; image related things | 858 ;; image related things |
833 :group 'newsticker-layout) | 922 :group 'newsticker-layout) |
834 | 923 |
835 | 924 |
836 ;; faces | 925 ;; faces |
837 (defgroup newsticker-faces nil | 926 (defgroup newsticker-faces nil |
838 "Settings for the faces of the RSS reader." | 927 "Settings for the faces of the feed reader." |
839 :group 'newsticker-layout) | 928 :group 'newsticker-layout) |
840 | 929 |
841 (defface newsticker-feed-face | 930 (defface newsticker-feed-face |
842 '((((class color) (background dark)) | 931 '((((class color) (background dark)) |
843 (:family "helvetica" :bold t :height 1.2 :foreground "misty rose")) | 932 (:family "helvetica" :bold t :height 1.2 :foreground "misty rose")) |
920 ;; :group 'newsticker-faces) | 1009 ;; :group 'newsticker-faces) |
921 | 1010 |
922 | 1011 |
923 ;; customization group ticker | 1012 ;; customization group ticker |
924 (defgroup newsticker-ticker nil | 1013 (defgroup newsticker-ticker nil |
925 "Settings for the RSS ticker." | 1014 "Settings for the headline ticker." |
926 :group 'newsticker) | 1015 :group 'newsticker) |
927 | 1016 |
928 (defcustom newsticker-display-interval | 1017 (defcustom newsticker-display-interval |
929 0.3 | 1018 0.3 |
930 "Time interval for displaying news items in the echo area (seconds). | 1019 "Time interval for displaying news items in the echo area (seconds). |
1117 ;; copied from subr.el | 1206 ;; copied from subr.el |
1118 (unless (fboundp 'remove-from-invisibility-spec) | 1207 (unless (fboundp 'remove-from-invisibility-spec) |
1119 (defun remove-from-invisibility-spec (arg) | 1208 (defun remove-from-invisibility-spec (arg) |
1120 "Remove elements from `buffer-invisibility-spec'." | 1209 "Remove elements from `buffer-invisibility-spec'." |
1121 (if (consp buffer-invisibility-spec) | 1210 (if (consp buffer-invisibility-spec) |
1122 (setq buffer-invisibility-spec (delete arg buffer-invisibility-spec))))) | 1211 (setq buffer-invisibility-spec |
1212 (delete arg buffer-invisibility-spec))))) | |
1123 | 1213 |
1124 ;; ====================================================================== | 1214 ;; ====================================================================== |
1125 ;;; Internal variables | 1215 ;;; Internal variables |
1126 ;; ====================================================================== | 1216 ;; ====================================================================== |
1127 (defvar newsticker--display-timer nil | |
1128 "Timer for newsticker display.") | |
1129 (defvar newsticker--retrieval-timer-list nil | |
1130 "List of timers for news retrieval. | |
1131 This is an alist, each element consisting of (feed-name . timer)") | |
1132 (defvar newsticker--item-list nil | 1217 (defvar newsticker--item-list nil |
1133 "List of newsticker items.") | 1218 "List of newsticker items.") |
1134 (defvar newsticker--item-position 0 | 1219 (defvar newsticker--item-position 0 |
1135 "Actual position in list of newsticker items.") | 1220 "Actual position in list of newsticker items.") |
1136 (defvar newsticker--prev-message "There was no previous message yet!" | 1221 (defvar newsticker--prev-message "There was no previous message yet!" |
1139 "The text which is scrolled smoothly in the echo area.") | 1224 "The text which is scrolled smoothly in the echo area.") |
1140 (defvar newsticker--buffer-uptodate-p nil | 1225 (defvar newsticker--buffer-uptodate-p nil |
1141 "Tells whether the newsticker buffer is up to date.") | 1226 "Tells whether the newsticker buffer is up to date.") |
1142 (defvar newsticker--latest-update-time (current-time) | 1227 (defvar newsticker--latest-update-time (current-time) |
1143 "The time at which the latest news arrived.") | 1228 "The time at which the latest news arrived.") |
1229 (defvar newsticker--process-ids nil | |
1230 "List of PIDs of active newsticker processes.") | |
1144 | 1231 |
1145 (defvar newsticker--cache nil "Cached newsticker data. | 1232 (defvar newsticker--cache nil "Cached newsticker data. |
1146 This is a list of the form | 1233 This is a list of the form |
1147 | 1234 |
1148 ((label1 | 1235 ((label1 |
2117 ;;; Newsticker mode | 2204 ;;; Newsticker mode |
2118 ;; ====================================================================== | 2205 ;; ====================================================================== |
2119 | 2206 |
2120 (define-derived-mode newsticker-mode fundamental-mode | 2207 (define-derived-mode newsticker-mode fundamental-mode |
2121 "NewsTicker" | 2208 "NewsTicker" |
2122 "Viewing RSS news feeds in Emacs." | 2209 "Viewing news feeds in Emacs." |
2123 (set (make-local-variable 'tool-bar-map) newsticker-tool-bar-map) | 2210 (set (make-local-variable 'tool-bar-map) newsticker-tool-bar-map) |
2124 (set (make-local-variable 'imenu-sort-function) nil) | 2211 (set (make-local-variable 'imenu-sort-function) nil) |
2125 (set (make-local-variable 'scroll-conservatively) 999) | 2212 (set (make-local-variable 'scroll-conservatively) 999) |
2126 (setq imenu-create-index-function 'newsticker--imenu-create-index) | 2213 (setq imenu-create-index-function 'newsticker--imenu-create-index) |
2127 (setq imenu-default-goto-function 'newsticker--imenu-goto) | 2214 (setq imenu-default-goto-function 'newsticker--imenu-goto) |
2137 'mode-line-frame-identification | 2224 'mode-line-frame-identification |
2138 " Newsticker (" | 2225 " Newsticker (" |
2139 '(newsticker--buffer-uptodate-p | 2226 '(newsticker--buffer-uptodate-p |
2140 "up to date" | 2227 "up to date" |
2141 "NEED UPDATE") | 2228 "NEED UPDATE") |
2142 ") -- " | 2229 ") " |
2230 '(:eval (format "[%d]" (length newsticker--process-ids))) | |
2231 " -- " | |
2143 '(:eval (newsticker--buffer-get-feed-title-at-point)) | 2232 '(:eval (newsticker--buffer-get-feed-title-at-point)) |
2144 ": " | 2233 ": " |
2145 '(:eval (newsticker--buffer-get-item-title-at-point)) | 2234 '(:eval (newsticker--buffer-get-item-title-at-point)) |
2146 " %-")) | 2235 " %-")) |
2147 (unless newsticker-show-all-rss-elements | 2236 (unless newsticker-show-all-news-elements |
2148 (add-to-invisibility-spec 'extra)) | 2237 (add-to-invisibility-spec 'extra)) |
2149 (newsticker--buffer-set-uptodate nil)) | 2238 (newsticker--buffer-set-uptodate nil)) |
2150 | 2239 |
2151 ;; refine its mode-map | 2240 ;; refine its mode-map |
2152 (define-key newsticker-mode-map "sO" 'newsticker-show-old-items) | 2241 (define-key newsticker-mode-map "sO" 'newsticker-show-old-items) |
2174 (define-key newsticker-mode-map "N" 'newsticker-next-new-item) | 2263 (define-key newsticker-mode-map "N" 'newsticker-next-new-item) |
2175 (define-key newsticker-mode-map "f" 'newsticker-next-feed) | 2264 (define-key newsticker-mode-map "f" 'newsticker-next-feed) |
2176 (define-key newsticker-mode-map "M" 'newsticker-mark-all-items-as-read) | 2265 (define-key newsticker-mode-map "M" 'newsticker-mark-all-items-as-read) |
2177 (define-key newsticker-mode-map "m" | 2266 (define-key newsticker-mode-map "m" |
2178 'newsticker-mark-all-items-at-point-as-read) | 2267 'newsticker-mark-all-items-at-point-as-read) |
2179 (define-key newsticker-mode-map "o" 'newsticker-mark-item-at-point-as-read) | 2268 (define-key newsticker-mode-map "o" |
2269 'newsticker-mark-item-at-point-as-read) | |
2180 (define-key newsticker-mode-map "G" 'newsticker-get-all-news) | 2270 (define-key newsticker-mode-map "G" 'newsticker-get-all-news) |
2181 (define-key newsticker-mode-map "g" 'newsticker-get-news-at-point) | 2271 (define-key newsticker-mode-map "g" 'newsticker-get-news-at-point) |
2182 (define-key newsticker-mode-map "u" 'newsticker-buffer-update) | 2272 (define-key newsticker-mode-map "u" 'newsticker-buffer-update) |
2183 (define-key newsticker-mode-map "U" 'newsticker-buffer-force-update) | 2273 (define-key newsticker-mode-map "U" 'newsticker-buffer-force-update) |
2184 (define-key newsticker-mode-map "a" 'newsticker-add-url) | 2274 (define-key newsticker-mode-map "a" 'newsticker-add-url) |
2185 | 2275 |
2186 (define-key newsticker-mode-map "i" | 2276 (define-key newsticker-mode-map "i" |
2187 'newsticker-mark-item-at-point-as-immortal) | 2277 'newsticker-mark-item-at-point-as-immortal) |
2188 | 2278 |
2189 (define-key newsticker-mode-map "xf" 'newsticker-toggle-auto-narrow-to-feed) | 2279 (define-key newsticker-mode-map "xf" |
2190 (define-key newsticker-mode-map "xi" 'newsticker-toggle-auto-narrow-to-item) | 2280 'newsticker-toggle-auto-narrow-to-feed) |
2281 (define-key newsticker-mode-map "xi" | |
2282 'newsticker-toggle-auto-narrow-to-item) | |
2191 | 2283 |
2192 ;; maps for the clickable portions | 2284 ;; maps for the clickable portions |
2193 (defvar newsticker--url-keymap (make-sparse-keymap) | 2285 (defvar newsticker--url-keymap (make-sparse-keymap) |
2194 "Key map for click-able headings in the newsticker buffer.") | 2286 "Key map for click-able headings in the newsticker buffer.") |
2195 (define-key newsticker--url-keymap [mouse-2] | 2287 (define-key newsticker--url-keymap [mouse-2] |
2334 (setq interval nil)) | 2426 (setq interval nil)) |
2335 ;; Suddenly XEmacs doesn't like start-time 0 | 2427 ;; Suddenly XEmacs doesn't like start-time 0 |
2336 (if (or (not start-time) | 2428 (if (or (not start-time) |
2337 (and (numberp start-time) (= start-time 0))) | 2429 (and (numberp start-time) (= start-time 0))) |
2338 (setq start-time 1)) | 2430 (setq start-time 1)) |
2339 (message "start-time %s" start-time) | 2431 ;; (message "start-time %s" start-time) |
2340 (setq timer (run-at-time start-time interval | 2432 (setq timer (run-at-time start-time interval |
2341 'newsticker-get-news feed-name)) | 2433 'newsticker-get-news feed-name)) |
2342 (if interval | 2434 (if interval |
2343 (add-to-list 'newsticker--retrieval-timer-list | 2435 (add-to-list 'newsticker--retrieval-timer-list |
2344 (cons feed-name timer)))))) | 2436 (cons feed-name timer)))))) |
2345 (append newsticker-url-list-defaults newsticker-url-list)) | 2437 (append newsticker-url-list-defaults newsticker-url-list)) |
2346 (unless running | 2438 (unless running |
2347 (run-hooks 'newsticker-start-hook) | 2439 (run-hooks 'newsticker-start-hook) |
2348 (message "Newsticker started!")))) | 2440 (message "Newsticker started!")))) |
2349 | 2441 |
2442 ;;;###autoload | |
2350 (defun newsticker-start-ticker () | 2443 (defun newsticker-start-ticker () |
2351 "Start newsticker's ticker (but not the news retrieval. | 2444 "Start newsticker's ticker (but not the news retrieval). |
2352 Start display timer for the actual ticker if wanted and not | 2445 Start display timer for the actual ticker if wanted and not |
2353 running already." | 2446 running already." |
2354 (interactive) | 2447 (interactive) |
2355 (if (and (> newsticker-display-interval 0) | 2448 (if (and (> newsticker-display-interval 0) |
2356 (not newsticker--display-timer)) | 2449 (not newsticker--display-timer)) |
2504 (setq pos (next-single-property-change pos 'w3m-image)) | 2597 (setq pos (next-single-property-change pos 'w3m-image)) |
2505 (when pos | 2598 (when pos |
2506 (goto-char pos) | 2599 (goto-char pos) |
2507 (when (get-text-property pos 'w3m-image) | 2600 (when (get-text-property pos 'w3m-image) |
2508 (let ((invis (newsticker--lists-intersect-p | 2601 (let ((invis (newsticker--lists-intersect-p |
2509 (get-text-property (1- (point)) 'invisible) | 2602 (get-text-property (1- (point)) |
2603 'invisible) | |
2510 buffer-invisibility-spec))) | 2604 buffer-invisibility-spec))) |
2511 (if invis | 2605 (if invis |
2512 (w3m-remove-image | 2606 (w3m-remove-image |
2513 pos (next-single-property-change pos 'w3m-image)) | 2607 pos (next-single-property-change pos |
2608 'w3m-image)) | |
2514 (w3m-toggle-inline-image t)))))))))))) | 2609 (w3m-toggle-inline-image t)))))))))))) |
2515 | 2610 |
2516 ;; ====================================================================== | 2611 ;; ====================================================================== |
2517 ;;; keymap stuff | 2612 ;;; keymap stuff |
2518 ;; ====================================================================== | 2613 ;; ====================================================================== |
2586 (unless (newsticker--lists-intersect-p | 2681 (unless (newsticker--lists-intersect-p |
2587 (get-text-property (point) 'invisible) | 2682 (get-text-property (point) 'invisible) |
2588 buffer-invisibility-spec) | 2683 buffer-invisibility-spec) |
2589 (setq go-ahead nil)))) | 2684 (setq go-ahead nil)))) |
2590 (run-hooks 'newsticker-select-item-hook) | 2685 (run-hooks 'newsticker-select-item-hook) |
2686 (force-mode-line-update) | |
2591 (point)) | 2687 (point)) |
2592 | 2688 |
2593 (defun newsticker-previous-item (&optional do-not-wrap-at-bob) | 2689 (defun newsticker-previous-item (&optional do-not-wrap-at-bob) |
2594 "Go to previous news item. | 2690 "Go to previous news item. |
2595 Return new buffer position. | 2691 Return new buffer position. |
2612 buffer-invisibility-spec) | 2708 buffer-invisibility-spec) |
2613 (setq go-ahead nil)) | 2709 (setq go-ahead nil)) |
2614 (goto-char (point-min)) | 2710 (goto-char (point-min)) |
2615 (setq go-ahead nil)))) | 2711 (setq go-ahead nil)))) |
2616 (run-hooks 'newsticker-select-item-hook) | 2712 (run-hooks 'newsticker-select-item-hook) |
2713 (force-mode-line-update) | |
2617 (point)) | 2714 (point)) |
2618 | 2715 |
2619 (defun newsticker-next-feed () | 2716 (defun newsticker-next-feed () |
2620 "Go to next news feed. | 2717 "Go to next news feed. |
2621 Return new buffer position." | 2718 Return new buffer position." |
2622 (interactive) | 2719 (interactive) |
2623 (widen) | 2720 (widen) |
2624 (newsticker--buffer-goto '(feed)) | 2721 (newsticker--buffer-goto '(feed)) |
2625 (run-hooks 'newsticker-select-feed-hook) | 2722 (run-hooks 'newsticker-select-feed-hook) |
2723 (force-mode-line-update) | |
2626 (point)) | 2724 (point)) |
2627 | 2725 |
2628 (defun newsticker-previous-feed () | 2726 (defun newsticker-previous-feed () |
2629 "Go to previous news feed. | 2727 "Go to previous news feed. |
2630 Return new buffer position." | 2728 Return new buffer position." |
2631 (interactive) | 2729 (interactive) |
2632 (widen) | 2730 (widen) |
2633 (newsticker--buffer-goto '(feed) nil t) | 2731 (newsticker--buffer-goto '(feed) nil t) |
2634 (run-hooks 'newsticker-select-feed-hook) | 2732 (run-hooks 'newsticker-select-feed-hook) |
2733 (force-mode-line-update) | |
2635 (point)) | 2734 (point)) |
2636 | 2735 |
2637 (defun newsticker-mark-all-items-at-point-as-read () | 2736 (defun newsticker-mark-all-items-at-point-as-read () |
2638 "Mark all items as read and clear ticker contents." | 2737 "Mark all items as read and clear ticker contents." |
2639 (interactive) | 2738 (interactive) |
2643 (let ((feed (get-text-property (point) 'feed)) | 2742 (let ((feed (get-text-property (point) 'feed)) |
2644 (pos (point))) | 2743 (pos (point))) |
2645 (when feed | 2744 (when feed |
2646 (message "Marking all items as read for %s" (symbol-name feed)) | 2745 (message "Marking all items as read for %s" (symbol-name feed)) |
2647 (newsticker--cache-replace-age newsticker--cache feed 'new 'old) | 2746 (newsticker--cache-replace-age newsticker--cache feed 'new 'old) |
2648 (newsticker--cache-replace-age newsticker--cache feed 'obsolete 'old) | 2747 (newsticker--cache-replace-age newsticker--cache feed 'obsolete |
2748 'old) | |
2649 (newsticker--cache-update) | 2749 (newsticker--cache-update) |
2650 (newsticker--buffer-set-uptodate nil) | 2750 (newsticker--buffer-set-uptodate nil) |
2651 (newsticker--ticker-text-setup) | 2751 (newsticker--ticker-text-setup) |
2652 (newsticker-buffer-update) | 2752 (newsticker-buffer-update) |
2653 ;; go back to where we came frome | 2753 ;; go back to where we came frome |
2844 (newsticker--buffer-redraw)) | 2944 (newsticker--buffer-redraw)) |
2845 | 2945 |
2846 (defun newsticker-show-old-items () | 2946 (defun newsticker-show-old-items () |
2847 "Show old items." | 2947 "Show old items." |
2848 (interactive) | 2948 (interactive) |
2849 (newsticker--buffer-hideshow 'desc-old t) | |
2850 (newsticker--buffer-hideshow 'item-old t) | 2949 (newsticker--buffer-hideshow 'item-old t) |
2851 (newsticker--buffer-redraw)) | 2950 (newsticker--buffer-redraw)) |
2852 | 2951 |
2853 (defun newsticker-hide-entry () | 2952 (defun newsticker-hide-entry () |
2854 "Hide description of entry at point." | 2953 "Hide description of entry at point." |
2859 inv-prop org-inv-prop | 2958 inv-prop org-inv-prop |
2860 is-invisible) | 2959 is-invisible) |
2861 (newsticker--buffer-beginning-of-item) | 2960 (newsticker--buffer-beginning-of-item) |
2862 (newsticker--buffer-goto '(desc)) | 2961 (newsticker--buffer-goto '(desc)) |
2863 (setq pos1 (max (point-min) (1- (point)))) | 2962 (setq pos1 (max (point-min) (1- (point)))) |
2864 (newsticker--buffer-goto '(extra feed item)) | 2963 (newsticker--buffer-goto '(extra feed item nil)) |
2865 (setq pos2 (max (point-min) (1- (point)))) | 2964 (setq pos2 (max (point-min) (1- (point)))) |
2866 (setq inv-prop (get-text-property pos1 'invisible)) | 2965 (setq inv-prop (get-text-property pos1 'invisible)) |
2867 (setq org-inv-prop (get-text-property pos1 'org-invisible)) | 2966 (setq org-inv-prop (get-text-property pos1 'org-invisible)) |
2868 (cond ((eq inv-prop t) | 2967 (cond ((eq inv-prop t) |
2869 ;; do nothing | 2968 ;; do nothing |
2870 ) | 2969 ) |
2871 ((eq org-inv-prop nil) | 2970 ((eq org-inv-prop nil) |
2872 (add-text-properties pos1 pos2 (list 'invisible t | 2971 (add-text-properties pos1 pos2 |
2873 'org-invisible inv-prop))) | 2972 (list 'invisible t |
2973 'org-invisible inv-prop))) | |
2874 (t | 2974 (t |
2875 ;; toggle | 2975 ;; toggle |
2876 (add-text-properties pos1 pos2 (list 'invisible org-inv-prop)) | 2976 (add-text-properties pos1 pos2 |
2977 (list 'invisible org-inv-prop)) | |
2877 (remove-text-properties pos1 pos2 '(org-invisible)))))) | 2978 (remove-text-properties pos1 pos2 '(org-invisible)))))) |
2878 (newsticker--buffer-redraw)) | 2979 (newsticker--buffer-redraw)) |
2879 | 2980 |
2880 (defun newsticker-show-entry () | 2981 (defun newsticker-show-entry () |
2881 "Show description of entry at point." | 2982 "Show description of entry at point." |
2891 (newsticker--buffer-goto '(extra feed item)) | 2992 (newsticker--buffer-goto '(extra feed item)) |
2892 (setq pos2 (max (point-min) (1- (point)))) | 2993 (setq pos2 (max (point-min) (1- (point)))) |
2893 (setq inv-prop (get-text-property pos1 'invisible)) | 2994 (setq inv-prop (get-text-property pos1 'invisible)) |
2894 (setq org-inv-prop (get-text-property pos1 'org-invisible)) | 2995 (setq org-inv-prop (get-text-property pos1 'org-invisible)) |
2895 (cond ((eq org-inv-prop nil) | 2996 (cond ((eq org-inv-prop nil) |
2896 (add-text-properties pos1 pos2 (list 'invisible nil | 2997 (add-text-properties pos1 pos2 |
2897 'org-invisible inv-prop))) | 2998 (list 'invisible nil |
2999 'org-invisible inv-prop))) | |
2898 (t | 3000 (t |
2899 ;; toggle | 3001 ;; toggle |
2900 (add-text-properties pos1 pos2 (list 'invisible org-inv-prop)) | 3002 (add-text-properties pos1 pos2 |
3003 (list 'invisible org-inv-prop)) | |
2901 (remove-text-properties pos1 pos2 '(org-invisible)))))) | 3004 (remove-text-properties pos1 pos2 '(org-invisible)))))) |
2902 (newsticker--buffer-redraw)) | 3005 (newsticker--buffer-redraw)) |
2903 | 3006 |
2904 (defun newsticker-toggle-auto-narrow-to-feed () | 3007 (defun newsticker-toggle-auto-narrow-to-feed () |
2905 "Toggle narrowing to current news feed. | 3008 "Toggle narrowing to current news feed. |
2906 If auto-narrowing is active, only news item of the current feed | 3009 If auto-narrowing is active, only news item of the current feed |
2907 are visible." | 3010 are visible." |
2908 (interactive) | 3011 (interactive) |
2909 (newsticker-set-auto-narrow-to-feed (not newsticker--auto-narrow-to-feed))) | 3012 (newsticker-set-auto-narrow-to-feed |
3013 (not newsticker--auto-narrow-to-feed))) | |
2910 | 3014 |
2911 (defun newsticker-set-auto-narrow-to-feed (value) | 3015 (defun newsticker-set-auto-narrow-to-feed (value) |
2912 "Turn narrowing to current news feed on or off. | 3016 "Turn narrowing to current news feed on or off. |
2913 If VALUE is nil, auto-narrowing is turned off, otherwise it is turned on." | 3017 If VALUE is nil, auto-narrowing is turned off, otherwise it is turned on." |
2914 (interactive) | 3018 (interactive) |
2915 (setq newsticker--auto-narrow-to-item nil) | 3019 (setq newsticker--auto-narrow-to-item nil) |
2916 (setq newsticker--auto-narrow-to-feed value) | 3020 (setq newsticker--auto-narrow-to-feed value) |
2917 (widen) | 3021 (widen) |
3022 (newsticker--buffer-make-item-completely-visible) | |
2918 (run-hooks 'newsticker-narrow-hook)) | 3023 (run-hooks 'newsticker-narrow-hook)) |
2919 | 3024 |
2920 (defun newsticker-toggle-auto-narrow-to-item () | 3025 (defun newsticker-toggle-auto-narrow-to-item () |
2921 "Toggle narrowing to current news item. | 3026 "Toggle narrowing to current news item. |
2922 If auto-narrowing is active, only one item of the current feed | 3027 If auto-narrowing is active, only one item of the current feed |
2923 is visible." | 3028 is visible." |
2924 (interactive) | 3029 (interactive) |
2925 (newsticker-set-auto-narrow-to-item (not newsticker--auto-narrow-to-item))) | 3030 (newsticker-set-auto-narrow-to-item |
3031 (not newsticker--auto-narrow-to-item))) | |
2926 | 3032 |
2927 (defun newsticker-set-auto-narrow-to-item (value) | 3033 (defun newsticker-set-auto-narrow-to-item (value) |
2928 "Turn narrowing to current news item on or off. | 3034 "Turn narrowing to current news item on or off. |
2929 If VALUE is nil, auto-narrowing is turned off, otherwise it is turned on." | 3035 If VALUE is nil, auto-narrowing is turned off, otherwise it is turned on." |
2930 (interactive) | 3036 (interactive) |
2931 (setq newsticker--auto-narrow-to-feed nil) | 3037 (setq newsticker--auto-narrow-to-feed nil) |
2932 (setq newsticker--auto-narrow-to-item value) | 3038 (setq newsticker--auto-narrow-to-item value) |
2933 (widen) | 3039 (widen) |
3040 (newsticker--buffer-make-item-completely-visible) | |
2934 (run-hooks 'newsticker-narrow-hook)) | 3041 (run-hooks 'newsticker-narrow-hook)) |
2935 | 3042 |
2936 (defun newsticker-customize () | 3043 (defun newsticker-customize () |
2937 "Open the newsticker customization group." | 3044 "Open the newsticker customization group." |
2938 (interactive) | 3045 (interactive) |
2989 (when (get-text-property (point) 'feed) | 3096 (when (get-text-property (point) 'feed) |
2990 (save-excursion | 3097 (save-excursion |
2991 (newsticker--buffer-beginning-of-item) | 3098 (newsticker--buffer-beginning-of-item) |
2992 (let ((age (get-text-property (point) 'nt-age))) | 3099 (let ((age (get-text-property (point) 'nt-age))) |
2993 (and (memq age '(new old obsolete)) t))))) | 3100 (and (memq age '(new old obsolete)) t))))) |
2994 | |
2995 ;; ====================================================================== | |
2996 ;;; local stuff | |
2997 ;; ====================================================================== | |
2998 (defun newsticker-running-p () | |
2999 "Check whether newsticker is running. | |
3000 Return t if newsticker is running, nil otherwise. Newsticker is | |
3001 considered to be running if the newsticker timer list is not empty." | |
3002 (> (length newsticker--retrieval-timer-list) 0)) | |
3003 | |
3004 (defun newsticker-ticker-running-p () | |
3005 "Check whether newsticker's actual ticker is running. | |
3006 Return t if ticker is running, nil otherwise. Newsticker is | |
3007 considered to be running if the newsticker timer list is not | |
3008 empty." | |
3009 (timerp newsticker--display-timer)) | |
3010 | 3101 |
3011 ;; ====================================================================== | 3102 ;; ====================================================================== |
3012 ;;; local stuff | 3103 ;;; local stuff |
3013 ;; ====================================================================== | 3104 ;; ====================================================================== |
3014 (defun newsticker-get-news (feed-name) | 3105 (defun newsticker-get-news (feed-name) |
3036 ;; start wget | 3127 ;; start wget |
3037 (let* ((args (append wget-arguments (list url))) | 3128 (let* ((args (append wget-arguments (list url))) |
3038 (proc (apply 'start-process feed-name buffername | 3129 (proc (apply 'start-process feed-name buffername |
3039 newsticker-wget-name args))) | 3130 newsticker-wget-name args))) |
3040 (set-process-coding-system proc 'no-conversion 'no-conversion) | 3131 (set-process-coding-system proc 'no-conversion 'no-conversion) |
3041 (set-process-sentinel proc 'newsticker--sentinel))))) | 3132 (set-process-sentinel proc 'newsticker--sentinel) |
3042 | 3133 (setq newsticker--process-ids (cons (process-id proc) |
3134 newsticker--process-ids)) | |
3135 (force-mode-line-update))))) | |
3043 | 3136 |
3044 (defun newsticker-mouse-browse-url (event) | 3137 (defun newsticker-mouse-browse-url (event) |
3045 "Call `browse-url' for the link of the item at which the EVENT occurred." | 3138 "Call `browse-url' for the link of the item at which the EVENT occurred." |
3046 (interactive "e") | 3139 (interactive "e") |
3047 (save-excursion | 3140 (save-excursion |
3113 0 nil)) | 3206 0 nil)) |
3114 (message "%s: Error while retrieving news from %s" | 3207 (message "%s: Error while retrieving news from %s" |
3115 (format-time-string "%A, %H:%M" (current-time)) | 3208 (format-time-string "%A, %H:%M" (current-time)) |
3116 (process-name process)) | 3209 (process-name process)) |
3117 (throw 'oops nil)) | 3210 (throw 'oops nil)) |
3118 (let* ((coding-system nil) | 3211 (let* ((coding-system 'utf-8) |
3119 (node-list | 3212 (node-list |
3120 (save-current-buffer | 3213 (save-current-buffer |
3121 (set-buffer (process-buffer process)) | 3214 (set-buffer (process-buffer process)) |
3122 ;; a very very dirty workaround to overcome the | 3215 ;; a very very dirty workaround to overcome the |
3123 ;; problems with the newest (20030621) xml.el: | 3216 ;; problems with the newest (20030621) xml.el: |
3158 "<description>\\(<img.*?\\)</description>" nil t) | 3251 "<description>\\(<img.*?\\)</description>" nil t) |
3159 (replace-match | 3252 (replace-match |
3160 "<description><![CDATA[ \\1 ]]></description>")) | 3253 "<description><![CDATA[ \\1 ]]></description>")) |
3161 ;; | 3254 ;; |
3162 (set-buffer-modified-p nil) | 3255 (set-buffer-modified-p nil) |
3256 ;; check coding system | |
3163 (goto-char (point-min)) | 3257 (goto-char (point-min)) |
3164 (if (re-search-forward "encoding=\"\\([^\"]+\\)\"" | 3258 (if (re-search-forward "encoding=\"\\([^\"]+\\)\"" |
3165 nil t) | 3259 nil t) |
3166 (setq coding-system (intern | 3260 (setq coding-system (intern (downcase (match-string 1)))) |
3167 (downcase(match-string 1))))) | 3261 (setq coding-system |
3262 (condition-case nil | |
3263 (check-coding-system coding-system) | |
3264 (coding-system-error | |
3265 (message | |
3266 "newsticker.el: ignoring coding system %s for %s" | |
3267 coding-system name) | |
3268 nil)))) | |
3269 ;; Decode if possible | |
3270 (when coding-system | |
3271 (decode-coding-region (point-min) (point-max) | |
3272 coding-system)) | |
3168 (condition-case errordata | 3273 (condition-case errordata |
3169 ;; The xml parser might fail | 3274 ;; The xml parser might fail |
3170 ;; or the xml might be bugged | 3275 ;; or the xml might be bugged |
3171 (xml-parse-region (point-min) (point-max)) | 3276 (xml-parse-region (point-min) (point-max)) |
3172 (error (message "Could not parse %s: %s" | 3277 (error (message "Could not parse %s: %s" |
3173 (buffer-name) (cadr errordata)) | 3278 (buffer-name) (cadr errordata)) |
3174 (throw 'oops nil))))) | 3279 (throw 'oops nil))))) |
3175 (topnode (car node-list)) | 3280 (topnode (car node-list)) |
3176 (channelnode (car (xml-get-children topnode 'channel))) | 3281 (channelnode (car (xml-get-children topnode 'channel))) |
3177 (imageurl nil) | 3282 (imageurl nil)) |
3178 (position 0)) | |
3179 ;; mark all items as obsolete | 3283 ;; mark all items as obsolete |
3180 (newsticker--cache-replace-age newsticker--cache | 3284 (newsticker--cache-replace-age newsticker--cache |
3181 name-symbol | 3285 name-symbol |
3182 'new 'obsolete-new) | 3286 'new 'obsolete-new) |
3183 (newsticker--cache-replace-age newsticker--cache | 3287 (newsticker--cache-replace-age newsticker--cache |
3184 name-symbol | 3288 name-symbol |
3185 'old 'obsolete-old) | 3289 'old 'obsolete-old) |
3186 (newsticker--cache-replace-age newsticker--cache | 3290 (newsticker--cache-replace-age newsticker--cache |
3187 name-symbol | 3291 name-symbol |
3188 'feed 'obsolete-old) | 3292 'feed 'obsolete-old) |
3189 ;; gather the news | 3293 |
3190 (if (eq (xml-node-name topnode) 'rss) | 3294 ;; check Atom/RSS version and call corresponding parser |
3191 ;; this is RSS 0.91 or something similar | 3295 (condition-case error-data |
3192 ;; all items are inside the channel node | 3296 (if (cond |
3193 (setq topnode channelnode)) | 3297 ;; RSS 0.91 |
3194 (setq imageurl | 3298 ((and (eq 'rss (xml-node-name topnode)) |
3195 (car (xml-node-children | 3299 (string= "0.91" (xml-get-attribute topnode 'version))) |
3196 (car (xml-get-children | 3300 (setq imageurl (newsticker--get-logo-url-rss-0.91 topnode)) |
3197 (car (xml-get-children | 3301 (newsticker--parse-rss-0.91 name time topnode)) |
3198 topnode | 3302 ;; RSS 0.92 |
3199 'image)) | 3303 ((and (eq 'rss (xml-node-name topnode)) |
3200 'url))))) | 3304 (string= "0.92" (xml-get-attribute topnode 'version))) |
3201 (let ((title (or (car (xml-node-children (car (xml-get-children | 3305 (setq imageurl (newsticker--get-logo-url-rss-0.92 topnode)) |
3202 channelnode 'title)))) | 3306 (newsticker--parse-rss-0.92 name time topnode)) |
3203 "[untitled]")) | 3307 ;; RSS 1.0 |
3204 (link (or (car (xml-node-children (car (xml-get-children | 3308 ((eq 'rdf:RDF (xml-node-name topnode)) |
3205 channelnode 'link)))) | 3309 (setq imageurl (newsticker--get-logo-url-rss-1.0 topnode)) |
3206 "")) | 3310 (newsticker--parse-rss-1.0 name time topnode)) |
3207 (desc (or (car (xml-node-children (car (xml-get-children | 3311 ;; RSS 2.0 |
3208 channelnode | 3312 ((and (eq 'rss (xml-node-name topnode)) |
3209 'content:encoded)))) | 3313 (string= "2.0" (xml-get-attribute topnode 'version))) |
3210 (car (xml-node-children (car (xml-get-children | 3314 (setq imageurl (newsticker--get-logo-url-rss-2.0 topnode)) |
3211 channelnode | 3315 (newsticker--parse-rss-2.0 name time topnode)) |
3212 'description)))) | 3316 ;; Atom 0.3 |
3213 "[No description available]")) | 3317 ((and (eq 'feed (xml-node-name topnode)) |
3214 (old-item nil)) | 3318 (string= "http://purl.org/atom/ns#" |
3215 ;; check coding system | 3319 (xml-get-attribute topnode 'xmlns))) |
3216 (setq coding-system | 3320 (setq imageurl (newsticker--get-logo-url-atom-0.3 topnode)) |
3217 (condition-case nil | 3321 (newsticker--parse-atom-0.3 name time topnode)) |
3218 (check-coding-system coding-system) | 3322 ;; Atom 1.0 |
3219 (coding-system-error | 3323 ((and (eq 'feed (xml-node-name topnode)) |
3220 (message "newsticker.el: %s %s %s %s" | 3324 (string= "http://www.w3.org/2005/Atom" |
3221 "ignoring coding system " | 3325 (xml-get-attribute topnode 'xmlns))) |
3222 coding-system | 3326 (setq imageurl (newsticker--get-logo-url-atom-1.0 topnode)) |
3223 " for " | 3327 (newsticker--parse-atom-1.0 name time topnode)) |
3224 name) | 3328 ;; unknown feed type |
3225 nil))) | 3329 (t |
3226 ;; apply coding system | 3330 (newsticker--debug-msg "Feed type unknown: %s: %s" |
3227 (when coding-system | 3331 (xml-node-name topnode) name) |
3228 (setq title (newsticker--decode-coding-string title coding-system)) | 3332 nil)) |
3229 (if desc | 3333 (setq something-was-added t)) |
3230 (setq desc (newsticker--decode-coding-string desc | 3334 (xerror (message "sentinelerror in %s: %s" name error-data))) |
3231 coding-system))) | 3335 |
3232 (setq link (newsticker--decode-coding-string link coding-system))) | |
3233 ;; decode numeric entities | |
3234 (setq title (newsticker--decode-numeric-entities title)) | |
3235 (setq desc (newsticker--decode-numeric-entities desc)) | |
3236 (setq link (newsticker--decode-numeric-entities link)) | |
3237 ;; remove whitespace from title, desc, and link | |
3238 (setq title (newsticker--remove-whitespace title)) | |
3239 (setq desc (newsticker--remove-whitespace desc)) | |
3240 (setq link (newsticker--remove-whitespace link)) | |
3241 | |
3242 ;; handle the feed itself | |
3243 (unless (newsticker--cache-contains newsticker--cache | |
3244 name-symbol title | |
3245 desc link 'feed) | |
3246 (setq something-was-added t)) | |
3247 (setq newsticker--cache | |
3248 (newsticker--cache-add | |
3249 newsticker--cache name-symbol | |
3250 title desc link time 'feed position | |
3251 (xml-node-children channelnode) | |
3252 'feed time)) | |
3253 ;; gather all items for this feed | |
3254 (mapc (lambda (node) | |
3255 (when (eq (xml-node-name node) 'item) | |
3256 (setq position (1+ position)) | |
3257 (setq title (or (car (xml-node-children | |
3258 (car (xml-get-children | |
3259 node 'title)))) | |
3260 "[untitled]")) | |
3261 (setq link (or (car (xml-node-children | |
3262 (car (xml-get-children | |
3263 node 'link)))) | |
3264 "")) | |
3265 (setq desc (or | |
3266 (car (xml-node-children | |
3267 (car (xml-get-children | |
3268 node 'content:encoded)))) | |
3269 (car (xml-node-children | |
3270 (car (xml-get-children | |
3271 node 'description)))))) | |
3272 ;; use pubDate value if present | |
3273 (setq time (or (newsticker--decode-rfc822-date | |
3274 (car (xml-node-children | |
3275 (car (xml-get-children | |
3276 node 'pubDate))))) | |
3277 time)) | |
3278 ;; use dc:date value if present | |
3279 (setq time (or (newsticker--decode-iso8601-date | |
3280 (car (xml-node-children | |
3281 (car (xml-get-children | |
3282 node 'dc:date))))) | |
3283 time)) | |
3284 ;; It happened that the title or description | |
3285 ;; contained evil HTML code that confused the | |
3286 ;; xml parser. Therefore: | |
3287 (unless (stringp title) | |
3288 (setq title (prin1-to-string title))) | |
3289 (unless (or (stringp desc) (not desc)) | |
3290 (setq desc (prin1-to-string desc))) | |
3291 ;; ignore items with empty title AND empty desc | |
3292 (when (or (> (length title) 0) | |
3293 (> (length desc) 0)) | |
3294 ;; apply coding system | |
3295 (when coding-system | |
3296 (setq title (newsticker--decode-coding-string | |
3297 title coding-system)) | |
3298 (if desc | |
3299 (setq desc (newsticker--decode-coding-string desc | |
3300 coding-system))) | |
3301 (setq link (newsticker--decode-coding-string | |
3302 link coding-system))) | |
3303 ;; decode numeric entities | |
3304 (setq title (newsticker--decode-numeric-entities title)) | |
3305 (when desc | |
3306 (setq desc (newsticker--decode-numeric-entities desc))) | |
3307 (setq link (newsticker--decode-numeric-entities link)) | |
3308 ;; remove whitespace from title, desc, and link | |
3309 (setq title (newsticker--remove-whitespace title)) | |
3310 (setq desc (newsticker--remove-whitespace desc)) | |
3311 (setq link (newsticker--remove-whitespace link)) | |
3312 ;; add data to cache | |
3313 ;; do we have this item already? | |
3314 (let* ((tguid (assoc 'guid (xml-node-children node))) | |
3315 (guid (if (stringp tguid) | |
3316 tguid | |
3317 (car (xml-node-children tguid))))) | |
3318 ;;(message "guid=%s" guid) | |
3319 (setq old-item | |
3320 (newsticker--cache-contains newsticker--cache | |
3321 name-symbol title | |
3322 desc link nil guid))) | |
3323 ;; add this item, or mark it as old, or do nothing | |
3324 (let ((age1 'new) | |
3325 (age2 'old) | |
3326 (item-new-p nil)) | |
3327 (if old-item | |
3328 (let ((prev-age (newsticker--age old-item))) | |
3329 (unless | |
3330 newsticker-automatically-mark-items-as-old | |
3331 (if (eq prev-age 'obsolete-old) | |
3332 (setq age2 'old) | |
3333 (setq age2 'new))) | |
3334 (if (eq prev-age 'immortal) | |
3335 (setq age2 'immortal))) | |
3336 ;; item was not there | |
3337 (setq item-new-p t) | |
3338 (setq something-was-added t)) | |
3339 (setq newsticker--cache | |
3340 (newsticker--cache-add | |
3341 newsticker--cache name-symbol title desc link | |
3342 time age1 position (xml-node-children node) | |
3343 age2)) | |
3344 (when item-new-p | |
3345 (let ((item (newsticker--cache-contains | |
3346 newsticker--cache | |
3347 name-symbol title | |
3348 desc link nil))) | |
3349 (if newsticker-auto-mark-filter | |
3350 (newsticker--run-auto-mark-filter name item)) | |
3351 (run-hook-with-args | |
3352 'newsticker-new-item-functions name item))))))) | |
3353 (xml-get-children topnode 'item))) | |
3354 ;; Remove those old items from cache which have been removed from | 3336 ;; Remove those old items from cache which have been removed from |
3355 ;; the feed | 3337 ;; the feed |
3356 (newsticker--cache-replace-age newsticker--cache | 3338 (newsticker--cache-replace-age newsticker--cache |
3357 name-symbol 'obsolete-old 'deleteme) | 3339 name-symbol 'obsolete-old 'deleteme) |
3358 (newsticker--cache-remove newsticker--cache name-symbol | 3340 (newsticker--cache-remove newsticker--cache name-symbol |
3369 (newsticker--cache-remove newsticker--cache | 3351 (newsticker--cache-remove newsticker--cache |
3370 name-symbol 'obsolete-expired) | 3352 name-symbol 'obsolete-expired) |
3371 (newsticker--cache-replace-age newsticker--cache | 3353 (newsticker--cache-replace-age newsticker--cache |
3372 name-symbol 'obsolete-new | 3354 name-symbol 'obsolete-new |
3373 'obsolete)) | 3355 'obsolete)) |
3374 ;; bring cache data into proper order.... | 3356 (newsticker--update-process-ids) |
3375 ;; (newsticker--cache-sort) | |
3376 ;; setup scrollable text | 3357 ;; setup scrollable text |
3377 (newsticker--ticker-text-setup) | 3358 (when (= 0 (length newsticker--process-ids)) |
3359 (newsticker--ticker-text-setup)) | |
3378 (setq newsticker--latest-update-time (current-time)) | 3360 (setq newsticker--latest-update-time (current-time)) |
3379 (when something-was-added | 3361 (when something-was-added |
3380 ;; FIXME: should we care about removed items as well? | 3362 ;; FIXME: should we care about removed items as well? |
3381 (newsticker--cache-update) | 3363 (newsticker--cache-update) |
3382 (newsticker--buffer-set-uptodate nil)) | 3364 (newsticker--buffer-set-uptodate nil)) |
3385 (kill-buffer (process-buffer process))) | 3367 (kill-buffer (process-buffer process))) |
3386 ;; launch retrieval of image | 3368 ;; launch retrieval of image |
3387 (when (and imageurl | 3369 (when (and imageurl |
3388 (string-match "%l" newsticker-heading-format)) | 3370 (string-match "%l" newsticker-heading-format)) |
3389 (newsticker--image-get name imageurl)))))) | 3371 (newsticker--image-get name imageurl)))))) |
3372 | |
3373 (defun newsticker--get-logo-url-atom-1.0 (node) | |
3374 "Return logo URL from atom 1.0 data in NODE." | |
3375 (car (xml-node-children | |
3376 (car (xml-get-children node 'logo))))) | |
3377 | |
3378 (defun newsticker--get-logo-url-atom-0.3 (node) | |
3379 "Return logo URL from atom 0.3 data in NODE." | |
3380 (car (xml-node-children | |
3381 (car (xml-get-children (car (xml-get-children node 'image)) 'url))))) | |
3382 | |
3383 (defun newsticker--get-logo-url-rss-2.0 (node) | |
3384 "Return logo URL from RSS 2.0 data in NODE." | |
3385 (car (xml-node-children | |
3386 (car (xml-get-children | |
3387 (car (xml-get-children | |
3388 (car (xml-get-children node 'channel)) 'image)) 'url))))) | |
3389 | |
3390 (defun newsticker--get-logo-url-rss-1.0 (node) | |
3391 "Return logo URL from RSS 1.0 data in NODE." | |
3392 (car (xml-node-children | |
3393 (car (xml-get-children (car (xml-get-children node 'image)) 'url))))) | |
3394 | |
3395 (defun newsticker--get-logo-url-rss-0.92 (node) | |
3396 "Return logo URL from RSS 0.92 data in NODE." | |
3397 (car (xml-node-children | |
3398 (car (xml-get-children (car (xml-get-children node 'image)) 'url))))) | |
3399 | |
3400 (defun newsticker--get-logo-url-rss-0.91 (node) | |
3401 "Return logo URL from RSS 0.91 data in NODE." | |
3402 (car (xml-node-children | |
3403 (car (xml-get-children (car (xml-get-children node 'image)) 'url))))) | |
3404 | |
3405 (defun newsticker--parse-atom-0.3 (name time topnode) | |
3406 "Parse Atom 0.3 data. | |
3407 Return value as well as arguments NAME, TIME, and TOPNODE are the | |
3408 same as in `newsticker--parse-generic-rss'." | |
3409 (newsticker--debug-msg "Parsing Atom 0.3 feed %s" name) | |
3410 (let (new-feed new-item) | |
3411 (setq new-feed (newsticker--parse-generic-feed | |
3412 name time | |
3413 ;; title | |
3414 (car (xml-node-children | |
3415 (car (xml-get-children topnode 'title)))) | |
3416 ;; desc | |
3417 (car (xml-node-children | |
3418 (car (xml-get-children topnode 'content)))) | |
3419 ;; link | |
3420 (xml-get-attribute | |
3421 (car (xml-get-children topnode 'link)) 'href) | |
3422 ;; extra-elements | |
3423 (xml-node-children topnode))) | |
3424 (setq new-item (newsticker--parse-generic-items | |
3425 name time (xml-get-children topnode 'entry) | |
3426 ;; title-fn | |
3427 (lambda (node) | |
3428 (car (xml-node-children | |
3429 (car (xml-get-children node 'title))))) | |
3430 ;; desc-fn | |
3431 (lambda (node) | |
3432 (or (car (xml-node-children | |
3433 (car (xml-get-children node 'content)))) | |
3434 (car (xml-node-children | |
3435 (car (xml-get-children node 'summary)))))) | |
3436 ;; link-fn | |
3437 (lambda (node) | |
3438 (xml-get-attribute | |
3439 (car (xml-get-children node 'link)) 'href)) | |
3440 ;; time-fn | |
3441 (lambda (node) | |
3442 (newsticker--decode-rfc822-date | |
3443 (car (xml-node-children | |
3444 (car (xml-get-children node 'modified)))))) | |
3445 ;; guid-fn | |
3446 (lambda (node) | |
3447 (let ((tguid (assoc 'guid (xml-node-children node)))) | |
3448 (if (stringp tguid) | |
3449 tguid | |
3450 (car (xml-node-children tguid))))) | |
3451 ;; extra-fn | |
3452 (lambda (node) | |
3453 (xml-node-children node)))) | |
3454 (or new-item new-feed))) | |
3455 | |
3456 (defun newsticker--parse-atom-1.0 (name time topnode) | |
3457 "Parse Atom 1.0 data. | |
3458 Argument NAME gives the name of a news feed. TIME gives the | |
3459 system time at which the data have been retrieved. TOPNODE | |
3460 contains the feed data as returned by the xml parser. | |
3461 | |
3462 For the Atom 1.0 specification see | |
3463 http://www.atompub.org/2005/08/17/draft-ietf-atompub-format-11.html" | |
3464 (newsticker--debug-msg "Parsing Atom 1.0 feed %s" name) | |
3465 (let (new-feed new-item) | |
3466 (setq new-feed (newsticker--parse-generic-feed | |
3467 name time | |
3468 ;; title | |
3469 (car (xml-node-children | |
3470 (car (xml-get-children topnode 'title)))) | |
3471 ;; desc | |
3472 (car (xml-node-children | |
3473 (car (xml-get-children topnode 'subtitle)))) | |
3474 ;; link | |
3475 (car (xml-node-children | |
3476 (car (xml-get-children topnode 'link)))) | |
3477 ;; extra-elements | |
3478 (xml-node-children topnode))) | |
3479 (setq new-item (newsticker--parse-generic-items | |
3480 name time (xml-get-children topnode 'entry) | |
3481 ;; title-fn | |
3482 (lambda (node) | |
3483 (car (xml-node-children | |
3484 (car (xml-get-children node 'title))))) | |
3485 ;; desc-fn | |
3486 (lambda (node) | |
3487 (or (car (xml-node-children | |
3488 (car (xml-get-children node 'content)))) | |
3489 (car (xml-node-children | |
3490 (car (xml-get-children node 'summary)))))) | |
3491 ;; link-fn | |
3492 (lambda (node) | |
3493 (car (xml-node-children | |
3494 (car (xml-get-children node 'link))))) | |
3495 ;; time-fn | |
3496 (lambda (node) | |
3497 (newsticker--decode-iso8601-date | |
3498 (or (car (xml-node-children | |
3499 (car (xml-get-children node 'updated)))) | |
3500 (car (xml-node-children | |
3501 (car (xml-get-children node 'published))))))) | |
3502 ;; guid-fn | |
3503 (lambda (node) | |
3504 (car (xml-node-children | |
3505 (car (xml-get-children node 'id))))) | |
3506 ;; extra-fn | |
3507 (lambda (node) | |
3508 (xml-node-children node)))) | |
3509 (or new-item new-feed))) | |
3510 | |
3511 (defun newsticker--parse-rss-0.91 (name time topnode) | |
3512 "Parse RSS 0.91 data. | |
3513 Return value as well as arguments NAME, TIME, and TOPNODE are the | |
3514 same as in `newsticker--parse-atom-1.0'. | |
3515 | |
3516 For the RSS 0.91 specification see http://backend.userland.com/rss091 or | |
3517 http://my.netscape.com/publish/formats/rss-spec-0.91.html." | |
3518 (newsticker--debug-msg "Parsing RSS 0.91 feed %s" name) | |
3519 (let* ((channelnode (car (xml-get-children topnode 'channel))) | |
3520 (pub-date (newsticker--decode-rfc822-date | |
3521 (car (xml-node-children | |
3522 (car (xml-get-children channelnode 'pubDate)))))) | |
3523 is-new-feed has-new-items) | |
3524 (setq is-new-feed (newsticker--parse-generic-feed | |
3525 name time | |
3526 ;; title | |
3527 (car (xml-node-children | |
3528 (car (xml-get-children channelnode 'title)))) | |
3529 ;; desc | |
3530 (car (xml-node-children | |
3531 (car (xml-get-children channelnode | |
3532 'description)))) | |
3533 ;; link | |
3534 (car (xml-node-children | |
3535 (car (xml-get-children channelnode 'link)))) | |
3536 ;; extra-elements | |
3537 (xml-node-children channelnode))) | |
3538 (setq has-new-items (newsticker--parse-generic-items | |
3539 name time (xml-get-children channelnode 'item) | |
3540 ;; title-fn | |
3541 (lambda (node) | |
3542 (car (xml-node-children | |
3543 (car (xml-get-children node 'title))))) | |
3544 ;; desc-fn | |
3545 (lambda (node) | |
3546 (car (xml-node-children | |
3547 (car (xml-get-children node 'description))))) | |
3548 ;; link-fn | |
3549 (lambda (node) | |
3550 (car (xml-node-children | |
3551 (car (xml-get-children node 'link))))) | |
3552 ;; time-fn | |
3553 (lambda (node) | |
3554 pub-date) | |
3555 ;; guid-fn | |
3556 (lambda (node) | |
3557 nil) | |
3558 ;; extra-fn | |
3559 (lambda (node) | |
3560 (xml-node-children node)))) | |
3561 (or has-new-items is-new-feed))) | |
3562 | |
3563 (defun newsticker--parse-rss-0.92 (name time topnode) | |
3564 "Parse RSS 0.92 data. | |
3565 Return value as well as arguments NAME, TIME, and TOPNODE are the | |
3566 same as in `newsticker--parse-atom-1.0'. | |
3567 | |
3568 For the RSS 0.92 specification see http://backend.userland.com/rss092." | |
3569 (newsticker--debug-msg "Parsing RSS 0.92 feed %s" name) | |
3570 (let* ((channelnode (car (xml-get-children topnode 'channel))) | |
3571 (pub-date (newsticker--decode-rfc822-date | |
3572 (car (xml-node-children | |
3573 (car (xml-get-children channelnode 'pubDate)))))) | |
3574 is-new-feed has-new-items) | |
3575 (setq is-new-feed (newsticker--parse-generic-feed | |
3576 name time | |
3577 ;; title | |
3578 (car (xml-node-children | |
3579 (car (xml-get-children channelnode 'title)))) | |
3580 ;; desc | |
3581 (car (xml-node-children | |
3582 (car (xml-get-children channelnode | |
3583 'description)))) | |
3584 ;; link | |
3585 (car (xml-node-children | |
3586 (car (xml-get-children channelnode 'link)))) | |
3587 ;; extra-elements | |
3588 (xml-node-children channelnode))) | |
3589 (setq has-new-items (newsticker--parse-generic-items | |
3590 name time (xml-get-children channelnode 'item) | |
3591 ;; title-fn | |
3592 (lambda (node) | |
3593 (car (xml-node-children | |
3594 (car (xml-get-children node 'title))))) | |
3595 ;; desc-fn | |
3596 (lambda (node) | |
3597 (car (xml-node-children | |
3598 (car (xml-get-children node 'description))))) | |
3599 ;; link-fn | |
3600 (lambda (node) | |
3601 (car (xml-node-children | |
3602 (car (xml-get-children node 'link))))) | |
3603 ;; time-fn | |
3604 (lambda (node) | |
3605 pub-date) | |
3606 ;; guid-fn | |
3607 (lambda (node) | |
3608 nil) | |
3609 ;; extra-fn | |
3610 (lambda (node) | |
3611 (xml-node-children node)))) | |
3612 (or has-new-items is-new-feed))) | |
3613 | |
3614 (defun newsticker--parse-rss-1.0 (name time topnode) | |
3615 "Parse RSS 1.0 data. | |
3616 Return value as well as arguments NAME, TIME, and | |
3617 TOPNODE are the same as in `newsticker--parse-atom-1.0'. | |
3618 | |
3619 For the RSS 1.0 specification see http://web.resource.org/rss/1.0/spec." | |
3620 (newsticker--debug-msg "Parsing RSS 1.0 feed %s" name) | |
3621 (let* ((channelnode (car (xml-get-children topnode 'channel))) | |
3622 is-new-feed has-new-items) | |
3623 (setq is-new-feed (newsticker--parse-generic-feed | |
3624 name time | |
3625 ;; title | |
3626 (car (xml-node-children | |
3627 (car (xml-get-children channelnode 'title)))) | |
3628 ;; desc | |
3629 (car (xml-node-children | |
3630 (car (xml-get-children channelnode | |
3631 'description)))) | |
3632 ;; link | |
3633 (car (xml-node-children | |
3634 (car (xml-get-children channelnode 'link)))) | |
3635 ;; extra-elements | |
3636 (xml-node-children channelnode))) | |
3637 (setq has-new-items (newsticker--parse-generic-items | |
3638 name time (xml-get-children topnode 'item) | |
3639 ;; title-fn | |
3640 (lambda (node) | |
3641 (car (xml-node-children | |
3642 (car (xml-get-children node 'title))))) | |
3643 ;; desc-fn | |
3644 (lambda (node) | |
3645 (car (xml-node-children | |
3646 (car (xml-get-children node | |
3647 'description))))) | |
3648 ;; link-fn | |
3649 (lambda (node) | |
3650 (car (xml-node-children | |
3651 (car (xml-get-children node 'link))))) | |
3652 ;; time-fn | |
3653 (lambda (node) | |
3654 (newsticker--decode-iso8601-date | |
3655 (car (xml-node-children | |
3656 (car (xml-get-children node 'dc:date)))))) | |
3657 ;; guid-fn | |
3658 (lambda (node) | |
3659 nil) | |
3660 ;; extra-fn | |
3661 (lambda (node) | |
3662 (xml-node-children node)))) | |
3663 (or has-new-items is-new-feed))) | |
3664 | |
3665 (defun newsticker--parse-rss-2.0 (name time topnode) | |
3666 "Parse RSS 2.0 data. | |
3667 Return value as well as arguments NAME, TIME, and TOPNODE are the | |
3668 same as in `newsticker--parse-atom-1.0'. | |
3669 | |
3670 For the RSS 2.0 specification see http://blogs.law.harvard.edu/tech/rss." | |
3671 (newsticker--debug-msg "Parsing RSS 2.0 feed %s" name) | |
3672 (let* ((channelnode (car (xml-get-children topnode 'channel))) | |
3673 is-new-feed has-new-items) | |
3674 (setq is-new-feed (newsticker--parse-generic-feed | |
3675 name time | |
3676 ;; title | |
3677 (car (xml-node-children | |
3678 (car (xml-get-children channelnode 'title)))) | |
3679 ;; desc | |
3680 (car (xml-node-children | |
3681 (car (xml-get-children channelnode | |
3682 'description)))) | |
3683 ;; link | |
3684 (car (xml-node-children | |
3685 (car (xml-get-children channelnode 'link)))) | |
3686 ;; extra-elements | |
3687 (xml-node-children channelnode))) | |
3688 (setq has-new-items (newsticker--parse-generic-items | |
3689 name time (xml-get-children channelnode 'item) | |
3690 ;; title-fn | |
3691 (lambda (node) | |
3692 (car (xml-node-children | |
3693 (car (xml-get-children node 'title))))) | |
3694 ;; desc-fn | |
3695 (lambda (node) | |
3696 (or (car (xml-node-children | |
3697 (car (xml-get-children node | |
3698 'content:encoded)))) | |
3699 (car (xml-node-children | |
3700 (car (xml-get-children node | |
3701 'description)))))) | |
3702 ;; link-fn | |
3703 (lambda (node) | |
3704 (car (xml-node-children | |
3705 (car (xml-get-children node 'link))))) | |
3706 ;; time-fn | |
3707 (lambda (node) | |
3708 (newsticker--decode-rfc822-date | |
3709 (car (xml-node-children | |
3710 (car (xml-get-children node 'pubDate)))))) | |
3711 ;; guid-fn | |
3712 (lambda (node) | |
3713 (let* ((tguid (assoc 'guid | |
3714 (xml-node-children node)))) | |
3715 (if (stringp tguid) | |
3716 tguid | |
3717 (car (xml-node-children tguid))))) | |
3718 ;; extra-fn | |
3719 (lambda (node) | |
3720 (xml-node-children node)))) | |
3721 (or has-new-items is-new-feed))) | |
3722 | |
3723 (defun newsticker--parse-generic-feed (name time title desc link | |
3724 extra-elements) | |
3725 "Parse generic news feed data. | |
3726 Argument NAME gives the name of a news feed. TIME gives the | |
3727 system time at which the data have been retrieved. CHANNELNODE | |
3728 is the node in the feed data which contains the description, link | |
3729 etc. of the feed itself. | |
3730 | |
3731 The arguments TITLE, DESC, LINK, and EXTRA-ELEMENTS give the feed's title, | |
3732 description, link, and extra elements resp." | |
3733 (let ((title (or title "[untitled]")) | |
3734 (link (or link "")) | |
3735 (old-item nil) | |
3736 (position 0) | |
3737 (something-was-added nil)) | |
3738 ;; decode numeric entities | |
3739 (setq title (newsticker--decode-numeric-entities title)) | |
3740 (setq desc (newsticker--decode-numeric-entities desc)) | |
3741 (setq link (newsticker--decode-numeric-entities link)) | |
3742 ;; remove whitespace from title, desc, and link | |
3743 (setq title (newsticker--remove-whitespace title)) | |
3744 (setq desc (newsticker--remove-whitespace desc)) | |
3745 (setq link (newsticker--remove-whitespace link)) | |
3746 | |
3747 ;; handle the feed itself | |
3748 (unless (newsticker--cache-contains newsticker--cache | |
3749 (intern name) title | |
3750 desc link 'feed) | |
3751 (setq something-was-added t)) | |
3752 (setq newsticker--cache | |
3753 (newsticker--cache-add newsticker--cache (intern name) | |
3754 title desc link time 'feed position | |
3755 extra-elements 'feed time)) | |
3756 something-was-added)) | |
3757 | |
3758 (defun newsticker--parse-generic-items (name time itemlist | |
3759 title-fn desc-fn | |
3760 link-fn time-fn | |
3761 guid-fn extra-fn) | |
3762 "Parse generic news feed data. | |
3763 Argument NAME gives the name of a news feed. TIME gives the | |
3764 system time at which the data have been retrieved. ITEMLIST | |
3765 contains the news items returned by the xml parser. | |
3766 | |
3767 The arguments TITLE-FN, DESC-FN, LINK-FN, TIME-FN, GUID-FN, and | |
3768 EXTRA-FN give functions for extracting title, description, link, | |
3769 time, guid, and extra-elements resp. They are called with one | |
3770 argument, which is one of the items in ITEMLIST." | |
3771 (let (title desc link | |
3772 (old-item nil) | |
3773 (position 0) | |
3774 (something-was-added nil)) | |
3775 ;; gather all items for this feed | |
3776 (mapc (lambda (node) | |
3777 (setq position (1+ position)) | |
3778 (setq title (or (funcall title-fn node) "[untitled]")) | |
3779 (setq desc (funcall desc-fn node)) | |
3780 (setq link (or (funcall link-fn node) "")) | |
3781 (setq time (or (funcall time-fn node) time)) | |
3782 ;; It happened that the title or description | |
3783 ;; contained evil HTML code that confused the | |
3784 ;; xml parser. Therefore: | |
3785 (unless (stringp title) | |
3786 (setq title (prin1-to-string title))) | |
3787 (unless (or (stringp desc) (not desc)) | |
3788 (setq desc (prin1-to-string desc))) | |
3789 ;; ignore items with empty title AND empty desc | |
3790 (when (or (> (length title) 0) | |
3791 (> (length desc) 0)) | |
3792 ;; decode numeric entities | |
3793 (setq title (newsticker--decode-numeric-entities title)) | |
3794 (when desc | |
3795 (setq desc (newsticker--decode-numeric-entities desc))) | |
3796 (setq link (newsticker--decode-numeric-entities link)) | |
3797 ;; remove whitespace from title, desc, and link | |
3798 (setq title (newsticker--remove-whitespace title)) | |
3799 (setq desc (newsticker--remove-whitespace desc)) | |
3800 (setq link (newsticker--remove-whitespace link)) | |
3801 ;; add data to cache | |
3802 ;; do we have this item already? | |
3803 (let* ((guid (funcall guid-fn node))) | |
3804 ;;(message "guid=%s" guid) | |
3805 (setq old-item | |
3806 (newsticker--cache-contains newsticker--cache | |
3807 (intern name) title | |
3808 desc link nil guid))) | |
3809 ;; add this item, or mark it as old, or do nothing | |
3810 (let ((age1 'new) | |
3811 (age2 'old) | |
3812 (item-new-p nil)) | |
3813 (if old-item | |
3814 (let ((prev-age (newsticker--age old-item))) | |
3815 (unless | |
3816 newsticker-automatically-mark-items-as-old | |
3817 (if (eq prev-age 'obsolete-old) | |
3818 (setq age2 'old) | |
3819 (setq age2 'new))) | |
3820 (if (eq prev-age 'immortal) | |
3821 (setq age2 'immortal))) | |
3822 ;; item was not there | |
3823 (setq item-new-p t) | |
3824 (setq something-was-added t)) | |
3825 (setq newsticker--cache | |
3826 (newsticker--cache-add | |
3827 newsticker--cache (intern name) title desc link | |
3828 time age1 position (funcall extra-fn node) | |
3829 age2)) | |
3830 (when item-new-p | |
3831 (let ((item (newsticker--cache-contains | |
3832 newsticker--cache (intern name) title | |
3833 desc link nil))) | |
3834 (if newsticker-auto-mark-filter-list | |
3835 (newsticker--run-auto-mark-filter name item)) | |
3836 (run-hook-with-args | |
3837 'newsticker-new-item-functions name item)))))) | |
3838 itemlist) | |
3839 something-was-added)) | |
3390 | 3840 |
3391 (defun newsticker--display-tick () | 3841 (defun newsticker--display-tick () |
3392 "Called from the display timer. | 3842 "Called from the display timer. |
3393 This function calls a display function, according to the variable | 3843 This function calls a display function, according to the variable |
3394 `newsticker-scroll-smoothly'." | 3844 `newsticker-scroll-smoothly'." |
3458 (setq newsticker--item-position 0)))))) | 3908 (setq newsticker--item-position 0)))))) |
3459 | 3909 |
3460 ;; ====================================================================== | 3910 ;; ====================================================================== |
3461 ;;; misc | 3911 ;;; misc |
3462 ;; ====================================================================== | 3912 ;; ====================================================================== |
3463 (defun newsticker--decode-coding-string (string coding-system) | |
3464 "Wrapper around `decode-coding-string'. | |
3465 This functions passes the arguments STRING and CODING-SYSTEM to | |
3466 `decode-coding-string'. If the decoding is successful the | |
3467 decoded string is returned, otherwise the unmodified input string | |
3468 is returned." | |
3469 (condition-case nil | |
3470 (decode-coding-string string coding-system) | |
3471 (error | |
3472 (message "Cannot decode encoded string `%s'" string) | |
3473 string))) | |
3474 | |
3475 (defun newsticker--decode-numeric-entities (string) | 3913 (defun newsticker--decode-numeric-entities (string) |
3476 "Decode SGML numeric entities by their respective utf characters. | 3914 "Decode SGML numeric entities by their respective utf characters. |
3477 This function replaces numeric entities in the input STRING and | 3915 This function replaces numeric entities in the input STRING and |
3478 returns the modified string. For example \"*\" gets replaced | 3916 returns the modified string. For example \"*\" gets replaced |
3479 by \"*\"." | 3917 by \"*\"." |
3480 (let ((start 0)) | 3918 (if (and string (stringp string)) |
3481 (while (string-match "&#\\([0-9]+\\);" string start) | 3919 (let ((start 0)) |
3482 (condition-case nil | 3920 (while (string-match "&#\\([0-9]+\\);" string start) |
3483 (setq string (replace-match | 3921 (condition-case nil |
3484 (string (read (substring string (match-beginning 1) | 3922 (setq string (replace-match |
3485 (match-end 1)))) | 3923 (string (read (substring string |
3486 nil nil string)) | 3924 (match-beginning 1) |
3487 (error nil)) | 3925 (match-end 1)))) |
3488 (setq start (1+ (match-beginning 0)))) | 3926 nil nil string)) |
3489 string)) | 3927 (error nil)) |
3928 (setq start (1+ (match-beginning 0)))) | |
3929 string) | |
3930 nil)) | |
3490 | 3931 |
3491 (defun newsticker--remove-whitespace (string) | 3932 (defun newsticker--remove-whitespace (string) |
3492 "Remove leading and trailing whitespace from STRING." | 3933 "Remove leading and trailing whitespace from STRING." |
3493 ;; we must have ...+ but not ...* in the regexps otherwise xemacs loops | 3934 ;; we must have ...+ but not ...* in the regexps otherwise xemacs loops |
3494 ;; endlessly... | 3935 ;; endlessly... |
3495 (when string | 3936 (when (and string (stringp string)) |
3496 (replace-regexp-in-string | 3937 (replace-regexp-in-string |
3497 "[ \t\r\n]+$" "" | 3938 "[ \t\r\n]+$" "" |
3498 (replace-regexp-in-string "^[ \t\r\n]+" "" string)))) | 3939 (replace-regexp-in-string "^[ \t\r\n]+" "" string)))) |
3499 | 3940 |
3500 (defun newsticker--do-forget-preformatted (item) | 3941 (defun newsticker--do-forget-preformatted (item) |
3501 "Forget all cached pre-formatted data. | 3942 "Forget pre-formatted data for ITEM. |
3502 Remove the pre-formatted from `newsticker--cache'." | 3943 Remove the pre-formatted from `newsticker--cache'." |
3503 (if (nthcdr 7 item) | 3944 (if (nthcdr 7 item) |
3504 (setcar (nthcdr 7 item) nil)) | 3945 (setcar (nthcdr 7 item) nil)) |
3505 (if (nthcdr 6 item) | 3946 (if (nthcdr 6 item) |
3506 (setcar (nthcdr 6 item) nil))) | 3947 (setcar (nthcdr 6 item) nil))) |
3580 (defun newsticker--decode-rfc822-date (rfc822-string) | 4021 (defun newsticker--decode-rfc822-date (rfc822-string) |
3581 "Return RFC822-STRING in format like `decode-time'. | 4022 "Return RFC822-STRING in format like `decode-time'. |
3582 Converts from RFC822 to Emacs representation. | 4023 Converts from RFC822 to Emacs representation. |
3583 Examples: | 4024 Examples: |
3584 Sat, 07 Sep 2002 00:00:01 GMT | 4025 Sat, 07 Sep 2002 00:00:01 GMT |
3585 07 Sep 2002 00:00:01 GMT" | 4026 07 Sep 2002 00:00:01 GMT |
3586 (if rfc822-string | 4027 07 Sep 2002" |
4028 (if (and rfc822-string (stringp rfc822-string)) | |
3587 (when (string-match | 4029 (when (string-match |
3588 (concat | 4030 (concat |
3589 "\\s-*" | 4031 "\\s-*" |
3590 ;; week day | 4032 ;; week day |
3591 "\\(\\(Mon\\|Tue\\|Wed\\|Thu\\|Fri\\|Sat\\|Sun\\)\\s-*,?\\)\\s-+" | 4033 "\\(\\(Mon\\|Tue\\|Wed\\|Thu\\|Fri\\|Sat\\|Sun\\)\\s-*,?\\)?\\s-*" |
3592 ;; day | 4034 ;; day |
3593 "\\([0-9]\\{1,2\\}\\)\\s-+" | 4035 "\\([0-9]\\{1,2\\}\\)\\s-+" |
3594 ;; month | 4036 ;; month |
3595 "\\(Jan\\|Feb\\|Mar\\|Apr\\|May\\|Jun\\|Jul\\|Aug\\|" | 4037 "\\(Jan\\|Feb\\|Mar\\|Apr\\|May\\|Jun\\|Jul\\|Aug\\|" |
3596 "Sep\\|Oct\\|Nov\\|Dec\\)\\s-+" | 4038 "Sep\\|Oct\\|Nov\\|Dec\\)\\s-+" |
3597 ;; year | 4039 ;; year |
3598 "\\([0-9]\\{2,4\\}\\)\\s-+" | 4040 "\\([0-9]\\{2,4\\}\\)" |
4041 ;; time may be missing | |
4042 "\\(\\s-+" | |
3599 ;; hour | 4043 ;; hour |
3600 "\\([0-9]\\{2\\}\\)" | 4044 "\\([0-9]\\{2\\}\\)" |
3601 ;; minute | 4045 ;; minute |
3602 ":\\([0-9]\\{2\\}\\)" | 4046 ":\\([0-9]\\{2\\}\\)" |
3603 ;; second | 4047 ;; second |
3604 "\\(:\\([0-9]\\{2\\}\\)\\)?" | 4048 "\\(:\\([0-9]\\{2\\}\\)\\)?" |
3605 ;; zone -- fixme | 4049 ;; zone -- fixme |
3606 "\\(\\s-+.*\\)?") | 4050 "\\(\\s-+.*\\)?" |
4051 "\\)?") | |
3607 rfc822-string) | 4052 rfc822-string) |
3608 (let ((day (read (match-string 3 rfc822-string))) | 4053 (let ((day (read (match-string 3 rfc822-string))) |
3609 (month-name (match-string 4 rfc822-string)) | 4054 (month-name (match-string 4 rfc822-string)) |
3610 (month 0) | 4055 (month 0) |
3611 (year (read (match-string 5 rfc822-string))) | 4056 (year (read (match-string 5 rfc822-string))) |
3612 (hour (read (match-string 6 rfc822-string))) | 4057 (hour (read (or (match-string 7 rfc822-string) "0"))) |
3613 (minute (read (match-string 7 rfc822-string))) | 4058 (minute (read (or (match-string 8 rfc822-string) "0"))) |
3614 (second (read (or (match-string 9 rfc822-string) | 4059 (second (read (or (match-string 10 rfc822-string) "0"))) |
3615 "0"))) | 4060 ;;(zone (match-string 11 rfc822-string)) |
3616 ;;(zone (match-string 10 rfc822-string)) | |
3617 ) | 4061 ) |
3618 (condition-case error-data | 4062 (condition-case error-data |
3619 (let ((i 1)) | 4063 (let ((i 1)) |
3620 (mapc (lambda (m) | 4064 (mapc (lambda (m) |
3621 (if (string= month-name m) | 4065 (if (string= month-name m) |
3636 (mapc (lambda (elt) | 4080 (mapc (lambda (elt) |
3637 (if (memq elt list2) | 4081 (if (memq elt list2) |
3638 (setq result t))) | 4082 (setq result t))) |
3639 list1) | 4083 list1) |
3640 result)) | 4084 result)) |
4085 | |
4086 (defun newsticker--update-process-ids () | |
4087 "Update list of ids of active newsticker processes. | |
4088 Checks list of active processes against list of newsticker processes." | |
4089 (let ((active-procs (process-list)) | |
4090 (new-list nil)) | |
4091 (mapc (lambda (proc) | |
4092 (let ((id (process-id proc))) | |
4093 (if (memq id newsticker--process-ids) | |
4094 (setq new-list (cons id new-list))))) | |
4095 active-procs) | |
4096 (setq newsticker--process-ids new-list)) | |
4097 (force-mode-line-update)) | |
3641 | 4098 |
3642 ;; ====================================================================== | 4099 ;; ====================================================================== |
3643 ;;; images | 4100 ;;; images |
3644 ;; ====================================================================== | 4101 ;; ====================================================================== |
3645 (defun newsticker--image-get (feed-name url) | 4102 (defun newsticker--image-get (feed-name url) |
3683 (defun newsticker--image-sentinel (process event) | 4140 (defun newsticker--image-sentinel (process event) |
3684 "Sentinel for image-retrieving PROCESS caused by EVENT." | 4141 "Sentinel for image-retrieving PROCESS caused by EVENT." |
3685 (let* ((p-status (process-status process)) | 4142 (let* ((p-status (process-status process)) |
3686 (exit-status (process-exit-status process)) | 4143 (exit-status (process-exit-status process)) |
3687 (feed-name (process-name process))) | 4144 (feed-name (process-name process))) |
3688 ;; catch known errors (zombie processes, rubbish-xml etc. | 4145 ;; catch known errors (zombie processes, rubbish-xml, etc.) |
3689 ;; if an error occurs the news feed is not updated! | 4146 ;; if an error occurs the news feed is not updated! |
3690 (catch 'oops | 4147 (catch 'oops |
3691 (unless (and (eq p-status 'exit) | 4148 (unless (and (eq p-status 'exit) |
3692 (= exit-status 0)) | 4149 (= exit-status 0)) |
3693 (message "%s: Error while retrieving image from %s" | 4150 (message "%s: Error while retrieving image from %s" |
3728 'disabled) | 4185 'disabled) |
3729 :mask (and newsticker-enable-logo-manipulations | 4186 :mask (and newsticker-enable-logo-manipulations |
3730 'heuristic) | 4187 'heuristic) |
3731 :ascent 70)) | 4188 :ascent 70)) |
3732 (error | 4189 (error |
3733 (message "Error: cannot create image: %s" | 4190 (message "Error: cannot create image for %s: %s" |
3734 (cadr error-data))))) | 4191 feed-name-symbol error-data)))) |
3735 img)) | 4192 img)) |
3736 | 4193 |
3737 ;; ====================================================================== | 4194 ;; ====================================================================== |
3738 ;;; imenu stuff | 4195 ;;; imenu stuff |
3739 ;; ====================================================================== | 4196 ;; ====================================================================== |
3762 (nconc index-alist (list feed-list)) | 4219 (nconc index-alist (list feed-list)) |
3763 (setq index-alist (list feed-list))) | 4220 (setq index-alist (list feed-list))) |
3764 index-alist))) | 4221 index-alist))) |
3765 | 4222 |
3766 (defun newsticker--imenu-goto (name pos &rest args) | 4223 (defun newsticker--imenu-goto (name pos &rest args) |
3767 "Go item NAME at position POS and show item. | 4224 "Go to item NAME at position POS and show item. |
3768 ARGS are ignored." | 4225 ARGS are ignored." |
3769 (goto-char pos) | 4226 (goto-char pos) |
4227 ;; show headline | |
4228 (newsticker--buffer-goto '(desc extra feed item)) | |
4229 (let* ((inhibit-read-only t) | |
4230 (pos1 (max (point-min) (1- pos))) | |
4231 (pos2 (max pos1 (1- (point)))) | |
4232 (inv-prop (get-text-property pos 'invisible)) | |
4233 (org-inv-prop (get-text-property pos 'org-invisible))) | |
4234 (when (eq org-inv-prop nil) | |
4235 (add-text-properties pos1 pos2 (list 'invisible nil | |
4236 'org-invisible inv-prop)))) | |
4237 ;; show desc | |
3770 (newsticker-show-entry)) | 4238 (newsticker-show-entry)) |
3771 | 4239 |
3772 ;; ====================================================================== | 4240 ;; ====================================================================== |
3773 ;;; buffer stuff | 4241 ;;; buffer stuff |
3774 ;; ====================================================================== | 4242 ;; ====================================================================== |
3781 (save-excursion | 4249 (save-excursion |
3782 (set-buffer b) | 4250 (set-buffer b) |
3783 (if value | 4251 (if value |
3784 (setq mode-name "Newsticker -- up to date -- ") | 4252 (setq mode-name "Newsticker -- up to date -- ") |
3785 (setq mode-name "Newsticker -- NEED UPDATE -- "))) | 4253 (setq mode-name "Newsticker -- NEED UPDATE -- "))) |
3786 (sit-for 0)))) | 4254 (force-mode-line-update 0)))) |
3787 | 4255 |
3788 (defun newsticker--buffer-redraw () | 4256 (defun newsticker--buffer-redraw () |
3789 "Sometimes (CVS) Emacs forgets to update the window..." | 4257 "Sometimes (CVS) Emacs forgets to update the window..." |
3790 (if (fboundp 'force-window-update) | 4258 (if (fboundp 'force-window-update) |
3791 (force-window-update (current-buffer)) | 4259 (force-window-update (current-buffer)) |
3990 (list 'keymap w3-mode-map)))) | 4458 (list 'keymap w3-mode-map)))) |
3991 (setq is-rendered-HTML t))) | 4459 (setq is-rendered-HTML t))) |
3992 (error | 4460 (error |
3993 (message "Error: HTML rendering failed: %s, %s" | 4461 (message "Error: HTML rendering failed: %s, %s" |
3994 (car error-data) (cdr error-data))))) | 4462 (car error-data) (cdr error-data))))) |
4463 ;; After html rendering there might be chunks of blank | |
4464 ;; characters between rendered text and date, statistics or | |
4465 ;; whatever. Remove it | |
4466 (when (and (eq type 'item) is-rendered-HTML) | |
4467 (goto-char pos) | |
4468 (while (re-search-forward "[ \t]*\n[ \t]*" nil t) | |
4469 (replace-match " " nil nil)) | |
4470 (goto-char (point-max))) | |
3995 (when (and newsticker-justification | 4471 (when (and newsticker-justification |
3996 (eq type 'desc) | 4472 (eq type 'desc) |
3997 (not is-rendered-HTML)) | 4473 (not is-rendered-HTML)) |
3998 (condition-case nil | 4474 (condition-case nil |
3999 (let ((use-hard-newlines t)) | 4475 (let ((use-hard-newlines t)) |
4000 (fill-region pos (point-max) newsticker-justification)) | 4476 (fill-region pos (point-max) newsticker-justification)) |
4001 (error nil)))) | 4477 (error nil)))) |
4002 | 4478 |
4003 ;; remove leading and trailing newlines | 4479 ;; remove leading and trailing newlines |
4004 (goto-char pos) | 4480 (goto-char pos) |
4005 (unless (= 0 (skip-chars-forward " \t\r\n")) | 4481 (unless (= 0 (skip-chars-forward " \t\r\n")) |
4006 (delete-region pos (point))) | 4482 (delete-region pos (point))) |
4007 (goto-char (point-max)) | 4483 (goto-char (point-max)) |
4008 (let ((end (point))) | 4484 (let ((end (point))) |
4009 (unless (= 0 (skip-chars-backward " \t\r\n" (1+ pos))) | 4485 (unless (= 0 (skip-chars-backward " \t\r\n" (1+ pos))) |
4010 (delete-region (point) end))) | 4486 (delete-region (point) end))) |
4011 (goto-char (point-max)) | 4487 (goto-char (point-max)) |
4012 | |
4013 ;; closing newline | 4488 ;; closing newline |
4014 (unless nil ;;(eq pos (point)) | 4489 (unless nil ;;(eq pos (point)) |
4015 (insert "\n") | 4490 (insert "\n") |
4016 (put-text-property (1- (point)) (point) 'hard t)) | 4491 (put-text-property (1- (point)) (point) 'hard t)) |
4017 | 4492 |
4023 | 4498 |
4024 ;; show extra elements | 4499 ;; show extra elements |
4025 (when (eq type 'desc) | 4500 (when (eq type 'desc) |
4026 (goto-char (point-max)) | 4501 (goto-char (point-max)) |
4027 (setq pos-extra-start (point)) | 4502 (setq pos-extra-start (point)) |
4028 (mapc (lambda (extra-element) | 4503 (newsticker--buffer-print-extra-elements item) |
4029 (unless (memq (car extra-element) | |
4030 '(items link title description | |
4031 content:encoded | |
4032 dc:subject dc:date item guid | |
4033 pubDate | |
4034 enclosure)) | |
4035 (newsticker--buffer-print-extra-element | |
4036 extra-element))) | |
4037 (newsticker--extra item)) | |
4038 (setq pos-extra-end (point))) | 4504 (setq pos-extra-end (point))) |
4039 | 4505 |
4040 ;; text properties | 4506 ;; text properties |
4041 (when (memq type '(feed item)) | 4507 (when (memq type '(feed item)) |
4042 (add-text-properties pos (1- (point)) | 4508 (add-text-properties pos (1- (point)) |
4081 ((eq type 'item) | 4547 ((eq type 'item) |
4082 ;; preformatted title | 4548 ;; preformatted title |
4083 (newsticker--cache-set-preformatted-title | 4549 (newsticker--cache-set-preformatted-title |
4084 item (buffer-substring pos (point))))))))) | 4550 item (buffer-substring pos (point))))))))) |
4085 | 4551 |
4086 (defun newsticker--buffer-print-extra-element (extra-element) | 4552 (defun newsticker--buffer-print-extra-elements (item) |
4087 "Insert EXTRA-ELEMENT in a pretty form into the current buffer." | 4553 "Insert extra-elements of ITEM in a pretty form into the current buffer." |
4088 (insert (format "%s:\t" (car extra-element))) | 4554 (let ((ignored-elements '(items link title description |
4555 content:encoded | |
4556 dc:subject dc:date item guid | |
4557 pubDate enclosure)) | |
4558 (left-column-width 1)) | |
4559 (mapc (lambda (extra-element) | |
4560 (unless (memq (car extra-element) ignored-elements) | |
4561 (setq left-column-width (max left-column-width | |
4562 (length (symbol-name | |
4563 (car extra-element))))))) | |
4564 (newsticker--extra item)) | |
4565 (mapc (lambda (extra-element) | |
4566 (unless (memq (car extra-element) ignored-elements) | |
4567 (newsticker--buffer-do-print-extra-element extra-element | |
4568 left-column-width))) | |
4569 (newsticker--extra item)))) | |
4570 | |
4571 (defun newsticker--buffer-do-print-extra-element (extra-element width) | |
4572 "Actually print an EXTRA-ELEMENT using the given WIDTH." | |
4573 (let ((name (symbol-name (car extra-element)))) | |
4574 (insert (format "%s: " name)) | |
4575 (insert (make-string (- width (length name)) ? ))) | |
4089 (let (;;(attributes (cadr extra-element)) ;FIXME!!!! | 4576 (let (;;(attributes (cadr extra-element)) ;FIXME!!!! |
4090 (contents (cddr extra-element))) | 4577 (contents (cddr extra-element))) |
4091 (cond ((listp contents) | 4578 (cond ((listp contents) |
4092 (mapc (lambda (i) | 4579 (mapc (lambda (i) |
4093 (if (and (stringp i) | 4580 (if (and (stringp i) |
4107 (t | 4594 (t |
4108 (insert (format "%s" contents)))) | 4595 (insert (format "%s" contents)))) |
4109 (insert "\n"))) | 4596 (insert "\n"))) |
4110 | 4597 |
4111 (defun newsticker--buffer-insert-enclosure (item) | 4598 (defun newsticker--buffer-insert-enclosure (item) |
4112 "Insert enclosure element of an RSS ITEM into the current buffer." | 4599 "Insert enclosure element of a news ITEM into the current buffer." |
4113 (let ((enclosure (newsticker--enclosure item)) | 4600 (let ((enclosure (newsticker--enclosure item)) |
4114 (beg (point))) | 4601 (beg (point))) |
4115 (when enclosure | 4602 (when enclosure |
4116 (let ((url (cdr (assoc 'url enclosure))) | 4603 (let ((url (cdr (assoc 'url enclosure))) |
4117 (length (cdr (assoc 'length enclosure))) | 4604 (length (string-to-number (cdr (assoc 'length enclosure)))) |
4118 (type (cdr (assoc 'type enclosure)))) | 4605 (type (cdr (assoc 'type enclosure)))) |
4119 (insert (format "Enclosed file (%s, %1.2f kBytes)" type | 4606 (cond ((> length 1048576) |
4120 (/ (string-to-number length) 1024))) | 4607 (insert (format "Enclosed file (%s, %1.2f MBytes)" type |
4608 (/ length 1048576)))) | |
4609 ((> length 1024) | |
4610 (insert (format "Enclosed file (%s, %1.2f KBytes)" type | |
4611 (/ length 1024))))) | |
4121 (add-text-properties beg (point) | 4612 (add-text-properties beg (point) |
4122 (list 'mouse-face 'highlight | 4613 (list 'mouse-face 'highlight |
4123 'nt-link url | 4614 'nt-link url |
4124 'help-echo (format | 4615 'help-echo (format |
4125 "mouse-2: visit (%s)" url) | 4616 "mouse-2: visit (%s)" url) |
4825 ;; ====================================================================== | 5316 ;; ====================================================================== |
4826 ;;; Auto marking | 5317 ;;; Auto marking |
4827 ;; ====================================================================== | 5318 ;; ====================================================================== |
4828 (defun newsticker--run-auto-mark-filter (feed item) | 5319 (defun newsticker--run-auto-mark-filter (feed item) |
4829 "Automatically mark an item as old or immortal. | 5320 "Automatically mark an item as old or immortal. |
4830 This function checks the variable `newsticker-auto-mark-filter' | 5321 This function checks the variable `newsticker-auto-mark-filter-list' |
4831 for an entry that matches FEED and ITEM." | 5322 for an entry that matches FEED and ITEM." |
4832 (let ((case-fold-search t)) | 5323 (let ((case-fold-search t)) |
4833 (mapc (lambda (filter) | 5324 (mapc (lambda (filter) |
4834 (let ((filter-feed (car filter)) | 5325 (let ((filter-feed (car filter)) |
4835 (old-list (nth 1 filter)) | 5326 (pattern-list (cadr filter))) |
4836 (imm-list (nth 2 filter))) | |
4837 (when (string-match filter-feed feed) | 5327 (when (string-match filter-feed feed) |
4838 (newsticker--do-run-auto-mark-filter item 'old old-list) | 5328 (newsticker--do-run-auto-mark-filter item pattern-list)))) |
4839 (newsticker--do-run-auto-mark-filter item 'immortal imm-list)))) | 5329 newsticker-auto-mark-filter-list))) |
4840 newsticker-auto-mark-filter))) | 5330 |
4841 | 5331 (defun newsticker--do-run-auto-mark-filter (item list) |
4842 (defun newsticker--do-run-auto-mark-filter (item age list) | 5332 "Actually compare ITEM AGE LIST against `newsticker-auto-mark-filter-list'." |
4843 "Actually compare ITEM AGE LIST against `newsticker-auto-mark-filter'." | |
4844 (mapc (lambda (pattern) | 5333 (mapc (lambda (pattern) |
4845 (when (string-match pattern (newsticker--title item)) | 5334 (let ((age (nth 0 pattern)) |
4846 (setcar (nthcdr 4 item) age))) | 5335 (place (nth 1 pattern)) |
5336 (regexp (nth 2 pattern)) | |
5337 (title (newsticker--title item)) | |
5338 (desc (newsticker--desc item))) | |
5339 (when (or (eq place 'title) (eq place 'all)) | |
5340 (when (and title (string-match regexp title)) | |
5341 (newsticker--debug-msg "Auto-marking as %s: `%s'" | |
5342 age (newsticker--title item)) | |
5343 (setcar (nthcdr 4 item) age))) | |
5344 (when (or (eq place 'description) (eq place 'all)) | |
5345 (when (and desc (string-match regexp desc)) | |
5346 (newsticker--debug-msg "Auto-marking as %s: `%s'" | |
5347 age (newsticker--title item)) | |
5348 (setcar (nthcdr 4 item) age))))) | |
4847 list)) | 5349 list)) |
4848 | 5350 |
4849 | 5351 |
4850 ;; ====================================================================== | 5352 ;; ====================================================================== |
4851 ;;; hook samples | 5353 ;;; hook samples |