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 \"&#42;\" gets replaced 3916 returns the modified string. For example \"&#42;\" 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