aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Jasper2014-10-19 18:50:15 +0200
committerUlf Jasper2014-10-19 18:50:15 +0200
commit8259e90ecdd4fd4d85d81fa410f676e8c245f3f4 (patch)
tree19ea666d2bfb02720be899b502376339de5093ff
parent58af643d69eeb911ac8842c6dc4ddd06f6ea0b00 (diff)
downloademacs-8259e90ecdd4fd4d85d81fa410f676e8c245f3f4.tar.gz
emacs-8259e90ecdd4fd4d85d81fa410f676e8c245f3f4.zip
Newsticker: Show feedicons in treeview. Small fix in opml export.
* etc/images/newsticker/README: Add rss-feed.png, rss-feed.svg. * etc/images/newsticker/rss-feed.png: New. * etc/images/newsticker/rss-feed.svg: New. * lisp/net/newst-backend.el: Require url-parse. (newsticker--get-news-by-wget): Store feed name as process property. (newsticker--sentinel): Read feed name from process property. (newsticker--sentinel-work): Rename argument name to feed-name. Rename variable imageurl to image-url. Pick icon url from Atom 1.0 data. Launch download of feed icon. (newsticker--get-icon-url-atom-1.0): New. (newsticker--unxml) (newsticker--unxml-node) (newsticker--unxml-attribute): Documentation. (newsticker--icons-dir): New. (newsticker--image-get): New arguments FILENAME and DIRECTORY. Use `url-retrieve' if `newsticker-retrieval-method' is 'intern. (newsticker--image-download-by-wget): New. Use process properties for storing informations. (newsticker--image-sentinel): Read informations from process properties. (newsticker--image-save) (newsticker--image-remove) (newsticker--image-download-by-url) (newsticker--image-download-by-url-callback): New. (newsticker-opml-export): Handle url list entries containing a function instead of an url string. * lisp/net/newst-reader.el (newsticker-html-renderer): Whitespace. (newsticker--print-extra-elements) (newsticker--do-print-extra-element): Documentation (newsticker--image-read): Optionally limit image height. Use imagemagick if possible. (newsticker--icon-read): New. * lisp/net/newst-treeview.el (newsticker--treeview-item-show): Limit height of feed logo. (newsticker--treeview-tree-expand): Use feed icons in treeview. (newsticker--tree-widget-icon-create): New. Set the tree widget icon. (newsticker--tree-widget-leaf-icon): Use feed icon.
-rw-r--r--etc/ChangeLog8
-rw-r--r--etc/images/newsticker/README2
-rw-r--r--etc/images/newsticker/rss-feed.pngbin0 -> 639 bytes
-rw-r--r--etc/images/newsticker/rss-feed.svg121
-rw-r--r--lisp/ChangeLog37
-rw-r--r--lisp/net/newst-backend.el212
-rw-r--r--lisp/net/newst-reader.el44
-rw-r--r--lisp/net/newst-treeview.el21
8 files changed, 378 insertions, 67 deletions
diff --git a/etc/ChangeLog b/etc/ChangeLog
index 5b70ee83c8a..4968084b7ec 100644
--- a/etc/ChangeLog
+++ b/etc/ChangeLog
@@ -1,3 +1,11 @@
12014-10-19 Ulf Jasper <ulf.jasper@web.de>
2
3 * images/newsticker/rss-feed.png: New.
4
5 * images/newsticker/rss-feed.svg: New.
6
7 * images/newsticker/README: Add rss-feed.png, rss-feed.svg.
8
12014-10-18 Michal Nazarewicz <mina86@mina86.com> 92014-10-18 Michal Nazarewicz <mina86@mina86.com>
2 10
3 * NEWS: Mention new whitespace-mode option: big-indent. 11 * NEWS: Mention new whitespace-mode option: big-indent.
diff --git a/etc/images/newsticker/README b/etc/images/newsticker/README
index 237b7f08e66..31ca46c8aff 100644
--- a/etc/images/newsticker/README
+++ b/etc/images/newsticker/README
@@ -2,7 +2,7 @@ COPYRIGHT AND LICENSE INFORMATION FOR IMAGE FILES
2 2
3Files: browse-url.xpm get-all.xpm mark-immortal.xpm mark-read.xpm 3Files: browse-url.xpm get-all.xpm mark-immortal.xpm mark-read.xpm
4 narrow.xpm next-feed.xpm next-item.xpm prev-feed.xpm 4 narrow.xpm next-feed.xpm next-item.xpm prev-feed.xpm
5 prev-item.xpm update.xpm 5 prev-item.xpm rss-feed.png rss-feed.svg update.xpm
6Author: Ulf Jasper 6Author: Ulf Jasper
7Copyright (C) 2011-2014 Free Software Foundation, Inc. 7Copyright (C) 2011-2014 Free Software Foundation, Inc.
8License: GNU General Public License version 3 or later (see COPYING) 8License: GNU General Public License version 3 or later (see COPYING)
diff --git a/etc/images/newsticker/rss-feed.png b/etc/images/newsticker/rss-feed.png
new file mode 100644
index 00000000000..41a3263390a
--- /dev/null
+++ b/etc/images/newsticker/rss-feed.png
Binary files differ
diff --git a/etc/images/newsticker/rss-feed.svg b/etc/images/newsticker/rss-feed.svg
new file mode 100644
index 00000000000..a4abd6cc19f
--- /dev/null
+++ b/etc/images/newsticker/rss-feed.svg
@@ -0,0 +1,121 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!-- Created with Inkscape (http://www.inkscape.org/) -->
3
4<svg
5 xmlns:dc="http://purl.org/dc/elements/1.1/"
6 xmlns:cc="http://creativecommons.org/ns#"
7 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8 xmlns:svg="http://www.w3.org/2000/svg"
9 xmlns="http://www.w3.org/2000/svg"
10 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12 width="16px"
13 height="16px"
14 id="svg3028"
15 version="1.1"
16 inkscape:version="0.48.5 r10040"
17 sodipodi:docname="newst-rss.svg">
18 <defs
19 id="defs3030" />
20 <sodipodi:namedview
21 id="base"
22 pagecolor="#ffffff"
23 bordercolor="#666666"
24 borderopacity="1.0"
25 inkscape:pageopacity="0.0"
26 inkscape:pageshadow="2"
27 inkscape:zoom="22.197802"
28 inkscape:cx="-0.87475255"
29 inkscape:cy="-1.0099011"
30 inkscape:current-layer="layer1"
31 showgrid="true"
32 inkscape:grid-bbox="true"
33 inkscape:document-units="px"
34 inkscape:snap-global="true"
35 inkscape:snap-object-midpoints="false"
36 inkscape:window-width="1680"
37 inkscape:window-height="1026"
38 inkscape:window-x="0"
39 inkscape:window-y="24"
40 inkscape:window-maximized="0">
41 <inkscape:grid
42 type="xygrid"
43 id="grid3036" />
44 </sodipodi:namedview>
45 <metadata
46 id="metadata3033">
47 <rdf:RDF>
48 <cc:Work
49 rdf:about="">
50 <dc:format>image/svg+xml</dc:format>
51 <dc:type
52 rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
53 </cc:Work>
54 </rdf:RDF>
55 </metadata>
56 <g
57 id="layer1"
58 inkscape:label="Layer 1"
59 inkscape:groupmode="layer">
60 <rect
61 style="fill:#ff8000;fill-opacity:1;stroke:#0000ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
62 id="rect3038"
63 width="16"
64 height="16"
65 x="0"
66 y="0"
67 ry="2"
68 rx="2" />
69 <path
70 sodipodi:type="arc"
71 style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
72 id="path3814"
73 sodipodi:cx="-4.5"
74 sodipodi:cy="7.5"
75 sodipodi:rx="2"
76 sodipodi:ry="2"
77 d="m -2.5,7.5 a 2,2 0 1 1 -4,0 2,2 0 1 1 4,0 z"
78 transform="matrix(0,1,-1,0,11.5,16.5)" />
79 <path
80 sodipodi:type="arc"
81 style="fill:none;stroke:#ffffff;stroke-width:1.89999996;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
82 id="path3847"
83 sodipodi:cx="8.5"
84 sodipodi:cy="7.5"
85 sodipodi:rx="9.5"
86 sodipodi:ry="9.5"
87 d="m 18,7.5 a 9.5,9.5 0 1 1 -19,0 9.5,9.5 0 1 1 19,0 z"
88 transform="matrix(1.0526316,0,0,1.0526316,-8.9473684,8.1052632)" />
89 <path
90 sodipodi:type="arc"
91 style="fill:none;stroke:#ffffff;stroke-width:0.96362412;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
92 id="path3849"
93 sodipodi:cx="2"
94 sodipodi:cy="14.5"
95 sodipodi:rx="7"
96 sodipodi:ry="6.5"
97 d="m 9,14.5 a 7,6.5 0 1 1 -14,0 7,6.5 0 1 1 14,0 z"
98 transform="matrix(2,0,0,2.1538461,-3.9999999,-15.230768)" />
99 <rect
100 style="fill:none;fill-opacity:1;stroke:#ff8000;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
101 id="rect3869"
102 width="15"
103 height="15"
104 x="2"
105 y="-1"
106 rx="0"
107 ry="0" />
108 <path
109 style="fill:#ff8000;fill-opacity:1;stroke:none"
110 d="M 2 0 C 0.892 0 0 0.892 0 2 L 0 14 C 0 15.108 0.892 16 2 16 L 2 0 z "
111 id="rect3891" />
112 <path
113 style="fill:#ff8000;fill-opacity:1;stroke:none"
114 d="M 0 14 C 0 15.108 0.892 16 2 16 L 14 16 C 15.108 16 16 15.108 16 14 L 0 14 z "
115 id="rect3913" />
116 </g>
117 <g
118 inkscape:groupmode="layer"
119 id="layer2"
120 inkscape:label="Ebene" />
121</svg>
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index af4d5e0e055..3f75bbdc355 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,40 @@
12014-10-19 Ulf Jasper <ulf.jasper@web.de>
2
3 * net/newst-backend.el: Require url-parse.
4 (newsticker--get-news-by-wget): Store feed name as process property.
5 (newsticker--sentinel): Read feed name from process property.
6 (newsticker--sentinel-work): Rename argument name to feed-name.
7 Rename variable imageurl to image-url. Pick icon url from Atom
8 1.0 data. Launch download of feed icon.
9 (newsticker--get-icon-url-atom-1.0): New.
10 (newsticker--unxml)
11 (newsticker--unxml-node)
12 (newsticker--unxml-attribute): Documentation.
13 (newsticker--icons-dir): New.
14 (newsticker--image-get): New arguments FILENAME and DIRECTORY.
15 Use `url-retrieve' if `newsticker-retrieval-method' is 'intern.
16 (newsticker--image-download-by-wget): New. Use process properties
17 for storing informations.
18 (newsticker--image-sentinel): Read informations from process properties.
19 (newsticker--image-save)
20 (newsticker--image-remove)
21 (newsticker--image-download-by-url)
22 (newsticker--image-download-by-url-callback): New.
23 (newsticker-opml-export): Handle url list entries containing a
24 function instead of an url string.
25
26 * net/newst-reader.el (newsticker-html-renderer): Whitespace.
27 (newsticker--print-extra-elements)
28 (newsticker--do-print-extra-element): Documentation
29 (newsticker--image-read): Optionally limit image height. Use
30 imagemagick if possible.
31 (newsticker--icon-read): New.
32
33 * net/newst-treeview.el (newsticker--treeview-item-show): Limit height of feed logo.
34 (newsticker--treeview-tree-expand): Use feed icons in treeview.
35 (newsticker--tree-widget-icon-create): New. Set the tree widget icon.
36 (newsticker--tree-widget-leaf-icon): Use feed icon.
37
12014-10-19 Stefan Monnier <monnier@iro.umontreal.ca> 382014-10-19 Stefan Monnier <monnier@iro.umontreal.ca>
2 39
3 * emacs-lisp/eieio-opt.el (eieio-lambda-arglist): Remove. 40 * emacs-lisp/eieio-opt.el (eieio-lambda-arglist): Remove.
diff --git a/lisp/net/newst-backend.el b/lisp/net/newst-backend.el
index b7bd3d0933e..4052116074d 100644
--- a/lisp/net/newst-backend.el
+++ b/lisp/net/newst-backend.el
@@ -36,6 +36,7 @@
36 36
37(require 'derived) 37(require 'derived)
38(require 'xml) 38(require 'xml)
39(require 'url-parse)
39 40
40;; Silence warnings 41;; Silence warnings
41(defvar w3-mode-map) 42(defvar w3-mode-map)
@@ -776,6 +777,7 @@ See `newsticker-get-news'."
776 newsticker-wget-name args))) 777 newsticker-wget-name args)))
777 (set-process-coding-system proc 'no-conversion 'no-conversion) 778 (set-process-coding-system proc 'no-conversion 'no-conversion)
778 (set-process-sentinel proc 'newsticker--sentinel) 779 (set-process-sentinel proc 'newsticker--sentinel)
780 (process-put proc 'nt-feed-name feed-name)
779 (setq newsticker--process-ids (cons (process-id proc) 781 (setq newsticker--process-ids (cons (process-id proc)
780 newsticker--process-ids)) 782 newsticker--process-ids))
781 (force-mode-line-update))))) 783 (force-mode-line-update)))))
@@ -811,24 +813,24 @@ Argument PROCESS is the process which has just changed its state.
811Argument EVENT tells what has happened to the process." 813Argument EVENT tells what has happened to the process."
812 (let ((p-status (process-status process)) 814 (let ((p-status (process-status process))
813 (exit-status (process-exit-status process)) 815 (exit-status (process-exit-status process))
814 (name (process-name process)) 816 (feed-name (process-get process 'nt-feed-name))
815 (command (process-command process)) 817 (command (process-command process))
816 (buffer (process-buffer process))) 818 (buffer (process-buffer process)))
817 (newsticker--sentinel-work event 819 (newsticker--sentinel-work event
818 (and (eq p-status 'exit) 820 (and (eq p-status 'exit)
819 (= exit-status 0)) 821 (= exit-status 0))
820 name command buffer))) 822 feed-name command buffer)))
821 823
822(defun newsticker--sentinel-work (event status-ok name command buffer) 824(defun newsticker--sentinel-work (event status-ok feed-name command buffer)
823 "Actually do the sentinel work. 825 "Actually do the sentinel work.
824Argument EVENT tells what has happened to the retrieval process. 826Argument EVENT tells what has happened to the retrieval process.
825Argument STATUS-OK is the final status of the retrieval process, 827Argument STATUS-OK is the final status of the retrieval process,
826non-nil meaning retrieval was successful. 828non-nil meaning retrieval was successful.
827Argument NAME is the name of the retrieval process. 829Argument FEED-NAME is the name of the retrieved feed.
828Argument COMMAND is the command of the retrieval process. 830Argument COMMAND is the command of the retrieval process.
829Argument BUFFER is the buffer of the retrieval process." 831Argument BUFFER is the buffer of the retrieval process."
830 (let ((time (current-time)) 832 (let ((time (current-time))
831 (name-symbol (intern name)) 833 (name-symbol (intern feed-name))
832 (something-was-added nil)) 834 (something-was-added nil))
833 ;; catch known errors (zombie processes, rubbish-xml etc. 835 ;; catch known errors (zombie processes, rubbish-xml etc.
834 ;; if an error occurs the news feed is not updated! 836 ;; if an error occurs the news feed is not updated!
@@ -844,14 +846,14 @@ Argument BUFFER is the buffer of the retrieval process."
844 "Return status: `%s'\n" 846 "Return status: `%s'\n"
845 "Command was `%s'") 847 "Command was `%s'")
846 (format-time-string "%A, %H:%M" (current-time)) 848 (format-time-string "%A, %H:%M" (current-time))
847 name event command) 849 feed-name event command)
848 "" 850 ""
849 (current-time) 851 (current-time)
850 'new 852 'new
851 0 nil)) 853 0 nil))
852 (message "%s: Error while retrieving news from %s" 854 (message "%s: Error while retrieving news from %s"
853 (format-time-string "%A, %H:%M" (current-time)) 855 (format-time-string "%A, %H:%M" (current-time))
854 name) 856 feed-name)
855 (throw 'oops nil)) 857 (throw 'oops nil))
856 (let* ((coding-system 'utf-8) 858 (let* ((coding-system 'utf-8)
857 (node-list 859 (node-list
@@ -870,7 +872,7 @@ Argument BUFFER is the buffer of the retrieval process."
870 (coding-system-error 872 (coding-system-error
871 (message 873 (message
872 "newsticker.el: ignoring coding system %s for %s" 874 "newsticker.el: ignoring coding system %s for %s"
873 coding-system name) 875 coding-system feed-name)
874 nil)))) 876 nil))))
875 ;; Decode if possible 877 ;; Decode if possible
876 (when coding-system 878 (when coding-system
@@ -886,7 +888,8 @@ Argument BUFFER is the buffer of the retrieval process."
886 (buffer-name) (cadr errordata)) 888 (buffer-name) (cadr errordata))
887 (throw 'oops nil))))) 889 (throw 'oops nil)))))
888 (topnode (car node-list)) 890 (topnode (car node-list))
889 (imageurl nil)) 891 (image-url nil)
892 (icon-url nil))
890 ;; mark all items as obsolete 893 ;; mark all items as obsolete
891 (newsticker--cache-replace-age newsticker--cache 894 (newsticker--cache-replace-age newsticker--cache
892 name-symbol 895 name-symbol
@@ -904,29 +907,29 @@ Argument BUFFER is the buffer of the retrieval process."
904 ;; RSS 0.91 907 ;; RSS 0.91
905 ((and (eq 'rss (xml-node-name topnode)) 908 ((and (eq 'rss (xml-node-name topnode))
906 (string= "0.91" (xml-get-attribute topnode 'version))) 909 (string= "0.91" (xml-get-attribute topnode 'version)))
907 (setq imageurl (newsticker--get-logo-url-rss-0.91 topnode)) 910 (setq image-url (newsticker--get-logo-url-rss-0.91 topnode))
908 (newsticker--parse-rss-0.91 name time topnode)) 911 (newsticker--parse-rss-0.91 feed-name time topnode))
909 ;; RSS 0.92 912 ;; RSS 0.92
910 ((and (eq 'rss (xml-node-name topnode)) 913 ((and (eq 'rss (xml-node-name topnode))
911 (string= "0.92" (xml-get-attribute topnode 'version))) 914 (string= "0.92" (xml-get-attribute topnode 'version)))
912 (setq imageurl (newsticker--get-logo-url-rss-0.92 topnode)) 915 (setq image-url (newsticker--get-logo-url-rss-0.92 topnode))
913 (newsticker--parse-rss-0.92 name time topnode)) 916 (newsticker--parse-rss-0.92 feed-name time topnode))
914 ;; RSS 1.0 917 ;; RSS 1.0
915 ((or (eq 'RDF (xml-node-name topnode)) 918 ((or (eq 'RDF (xml-node-name topnode))
916 (eq 'rdf:RDF (xml-node-name topnode))) 919 (eq 'rdf:RDF (xml-node-name topnode)))
917 (setq imageurl (newsticker--get-logo-url-rss-1.0 topnode)) 920 (setq image-url (newsticker--get-logo-url-rss-1.0 topnode))
918 (newsticker--parse-rss-1.0 name time topnode)) 921 (newsticker--parse-rss-1.0 feed-name time topnode))
919 ;; RSS 2.0 922 ;; RSS 2.0
920 ((and (eq 'rss (xml-node-name topnode)) 923 ((and (eq 'rss (xml-node-name topnode))
921 (string= "2.0" (xml-get-attribute topnode 'version))) 924 (string= "2.0" (xml-get-attribute topnode 'version)))
922 (setq imageurl (newsticker--get-logo-url-rss-2.0 topnode)) 925 (setq image-url (newsticker--get-logo-url-rss-2.0 topnode))
923 (newsticker--parse-rss-2.0 name time topnode)) 926 (newsticker--parse-rss-2.0 feed-name time topnode))
924 ;; Atom 0.3 927 ;; Atom 0.3
925 ((and (eq 'feed (xml-node-name topnode)) 928 ((and (eq 'feed (xml-node-name topnode))
926 (string= "http://purl.org/atom/ns#" 929 (string= "http://purl.org/atom/ns#"
927 (xml-get-attribute topnode 'xmlns))) 930 (xml-get-attribute topnode 'xmlns)))
928 (setq imageurl (newsticker--get-logo-url-atom-0.3 topnode)) 931 (setq image-url (newsticker--get-logo-url-atom-0.3 topnode))
929 (newsticker--parse-atom-0.3 name time topnode)) 932 (newsticker--parse-atom-0.3 feed-name time topnode))
930 ;; Atom 1.0 933 ;; Atom 1.0
931 (t 934 (t
932 ;; The test for Atom 1.0 does not work when using 935 ;; The test for Atom 1.0 does not work when using
@@ -938,16 +941,17 @@ Argument BUFFER is the buffer of the retrieval process."
938 ;; (and (eq 'feed (xml-node-name topnode)) 941 ;; (and (eq 'feed (xml-node-name topnode))
939 ;; (string= "http://www.w3.org/2005/Atom" 942 ;; (string= "http://www.w3.org/2005/Atom"
940 ;; (xml-get-attribute topnode 'xmlns))) 943 ;; (xml-get-attribute topnode 'xmlns)))
941 (setq imageurl (newsticker--get-logo-url-atom-1.0 topnode)) 944 (setq image-url (newsticker--get-logo-url-atom-1.0 topnode))
942 (newsticker--parse-atom-1.0 name time topnode)) 945 (setq icon-url (newsticker--get-icon-url-atom-1.0 topnode))
946 (newsticker--parse-atom-1.0 feed-name time topnode))
943 ;; unknown feed type 947 ;; unknown feed type
944 ;; (t 948 ;; (t
945 ;; (newsticker--debug-msg "Feed type unknown: %s: %s" 949 ;; (newsticker--debug-msg "Feed type unknown: %s: %s"
946 ;; (xml-node-name topnode) name) 950 ;; (xml-node-name topnode) feed-name)
947 ;; nil) 951 ;; nil)
948 ) 952 )
949 (setq something-was-added t)) 953 (setq something-was-added t))
950 (error (message "sentinelerror in %s: %s" name error-data))) 954 (error (message "sentinelerror in %s: %s" feed-name error-data)))
951 955
952 ;; Remove those old items from cache which have been removed from 956 ;; Remove those old items from cache which have been removed from
953 ;; the feed 957 ;; the feed
@@ -988,10 +992,29 @@ Argument BUFFER is the buffer of the retrieval process."
988 ;; kill the process buffer if wanted 992 ;; kill the process buffer if wanted
989 (unless newsticker-debug 993 (unless newsticker-debug
990 (kill-buffer buffer)) 994 (kill-buffer buffer))
991 ;; launch retrieval of image 995 ;; launch retrieval of images
992 (when (and imageurl (boundp 'newsticker-download-logos) 996 (when (and (boundp 'newsticker-download-logos)
993 newsticker-download-logos) 997 newsticker-download-logos)
994 (newsticker--image-get name imageurl))))) 998 ;; feed logo
999 (when image-url
1000 (newsticker--image-get feed-name feed-name (newsticker--images-dir)
1001 image-url))
1002 ;; icon / favicon
1003 (setq icon-url
1004 (or icon-url
1005 (let* ((feed-url (newsticker--link (cadr (newsticker--cache-get-feed
1006 (intern feed-name)))))
1007 (uri (url-generic-parse-url feed-url)))
1008 (when (and feed-url uri)
1009 (setf (url-filename uri) nil)
1010 (setf (url-target uri) nil)
1011 (concat (url-recreate-url uri) "favicon.ico")))))
1012 (when icon-url
1013 (newsticker--image-get feed-name
1014 (concat feed-name "."
1015 (file-name-extension icon-url))
1016 (newsticker--icons-dir)
1017 icon-url))))))
995 (when newsticker--sentinel-callback 1018 (when newsticker--sentinel-callback
996 (funcall newsticker--sentinel-callback))) 1019 (funcall newsticker--sentinel-callback)))
997 1020
@@ -1055,6 +1078,11 @@ Argument BUFFER is the buffer of the retrieval process."
1055 (car (xml-node-children 1078 (car (xml-node-children
1056 (car (xml-get-children node 'logo))))) 1079 (car (xml-get-children node 'logo)))))
1057 1080
1081(defun newsticker--get-icon-url-atom-1.0 (node)
1082 "Return icon URL from atom 1.0 data in NODE."
1083 (car (xml-node-children
1084 (car (xml-get-children node 'icon)))))
1085
1058(defun newsticker--get-logo-url-atom-0.3 (node) 1086(defun newsticker--get-logo-url-atom-0.3 (node)
1059 "Return logo URL from atom 0.3 data in NODE." 1087 "Return logo URL from atom 0.3 data in NODE."
1060 (car (xml-node-children 1088 (car (xml-node-children
@@ -1133,13 +1161,13 @@ same as in `newsticker--parse-atom-1.0'."
1133 1161
1134(defun newsticker--unxml (node) 1162(defun newsticker--unxml (node)
1135 "Reverse parsing of an xml string. 1163 "Reverse parsing of an xml string.
1136Restore an xml-string from a an xml-node that was returned by xml-parse..." 1164Restore an xml-string from a an xml NODE that was returned by xml-parse..."
1137 (if (or (not node) (stringp node)) 1165 (if (or (not node) (stringp node))
1138 node 1166 node
1139 (newsticker--unxml-node node))) 1167 (newsticker--unxml-node node)))
1140 1168
1141(defun newsticker--unxml-node (node) 1169(defun newsticker--unxml-node (node)
1142 "Actually restore xml-string of an xml node." 1170 "Actually restore xml-string of an xml NODE."
1143 (let ((qname (symbol-name (car node))) 1171 (let ((qname (symbol-name (car node)))
1144 (att-list (cadr node)) 1172 (att-list (cadr node))
1145 (children (cddr node))) 1173 (children (cddr node)))
@@ -1149,10 +1177,10 @@ Restore an xml-string from a an xml-node that was returned by xml-parse..."
1149 ">" 1177 ">"
1150 (mapconcat 'newsticker--unxml children "") "</" qname ">"))) 1178 (mapconcat 'newsticker--unxml children "") "</" qname ">")))
1151 1179
1152(defun newsticker--unxml-attribute (att) 1180(defun newsticker--unxml-attribute (attribute)
1153 "Actually restore xml-string of an attribute of an xml node." 1181 "Actually restore xml-string of an ATTRIBUTE of an xml node."
1154 (let ((name (symbol-name (car att))) 1182 (let ((name (symbol-name (car attribute)))
1155 (value (cdr att))) 1183 (value (cdr attribute)))
1156 (concat name "=\"" value "\""))) 1184 (concat name "=\"" value "\"")))
1157 1185
1158(defun newsticker--parse-atom-1.0 (name time topnode) 1186(defun newsticker--parse-atom-1.0 (name time topnode)
@@ -1766,14 +1794,19 @@ Checks list of active processes against list of newsticker processes."
1766 "Return directory where feed images are saved." 1794 "Return directory where feed images are saved."
1767 (concat newsticker-dir "/images/")) 1795 (concat newsticker-dir "/images/"))
1768 1796
1769(defun newsticker--image-get (feed-name url) 1797(defun newsticker--icons-dir ()
1770 "Get image of the news site FEED-NAME from URL. 1798 "Return directory where feed icons are saved."
1771If the image has been downloaded in the last 24h do nothing." 1799 (concat newsticker-dir "/icons/"))
1772 (let ((image-name (concat (newsticker--images-dir) feed-name))) 1800
1801(defun newsticker--image-get (feed-name filename directory url)
1802 "Get image for FEED-NAME by returning FILENAME from DIRECTORY.
1803If the file does no exist or if it is older than 24 hours
1804download it from URL first."
1805 (let ((image-name (concat directory feed-name)))
1773 (if (and (file-exists-p image-name) 1806 (if (and (file-exists-p image-name)
1774 (time-less-p (current-time) 1807 (time-less-p (current-time)
1775 (time-add (nth 5 (file-attributes image-name)) 1808 (time-add (nth 5 (file-attributes image-name))
1776 (seconds-to-time 86400)))) 1809 (seconds-to-time 86400))))
1777 (newsticker--debug-msg "%s: Getting image for %s skipped" 1810 (newsticker--debug-msg "%s: Getting image for %s skipped"
1778 (format-time-string "%A, %H:%M" (current-time)) 1811 (format-time-string "%A, %H:%M" (current-time))
1779 feed-name) 1812 feed-name)
@@ -1781,14 +1814,22 @@ If the image has been downloaded in the last 24h do nothing."
1781 (newsticker--debug-msg "%s: Getting image for %s" 1814 (newsticker--debug-msg "%s: Getting image for %s"
1782 (format-time-string "%A, %H:%M" (current-time)) 1815 (format-time-string "%A, %H:%M" (current-time))
1783 feed-name) 1816 feed-name)
1784 (let* ((buffername (concat " *newsticker-wget-image-" feed-name "*")) 1817 (if (eq newsticker-retrieval-method 'intern)
1785 (item (or (assoc feed-name newsticker-url-list) 1818 (newsticker--image-download-by-url feed-name filename directory url)
1819 (newsticker--image-download-by-wget feed-name filename directory url)))))
1820
1821(defun newsticker--image-download-by-wget (feed-name filename directory url)
1822 "Download image for FEED-NAME using external program.
1823Save image as FILENAME in DIRECTORY, download it from URL."
1824 (let* ((proc-name (concat feed-name "-" filename))
1825 (buffername (concat " *newsticker-wget-image-" proc-name "*"))
1826 (item (or (assoc feed-name newsticker-url-list)
1786 (assoc feed-name newsticker-url-list-defaults) 1827 (assoc feed-name newsticker-url-list-defaults)
1787 (error 1828 (error
1788 "Cannot get image for %s: Check newsticker-url-list" 1829 "Cannot get image for %s: Check newsticker-url-list"
1789 feed-name))) 1830 feed-name)))
1790 (wget-arguments (or (car (cdr (cdr (cdr (cdr item))))) 1831 (wget-arguments (or (car (cdr (cdr (cdr (cdr item)))))
1791 newsticker-wget-arguments))) 1832 newsticker-wget-arguments)))
1792 (with-current-buffer (get-buffer-create buffername) 1833 (with-current-buffer (get-buffer-create buffername)
1793 (erase-buffer) 1834 (erase-buffer)
1794 ;; throw an error if there is an old wget-process around 1835 ;; throw an error if there is an old wget-process around
@@ -1797,16 +1838,21 @@ If the image has been downloaded in the last 24h do nothing."
1797 feed-name)) 1838 feed-name))
1798 ;; start wget 1839 ;; start wget
1799 (let* ((args (append wget-arguments (list url))) 1840 (let* ((args (append wget-arguments (list url)))
1800 (proc (apply 'start-process feed-name buffername 1841 (proc (apply 'start-process proc-name buffername
1801 newsticker-wget-name args))) 1842 newsticker-wget-name args)))
1802 (set-process-coding-system proc 'no-conversion 'no-conversion) 1843 (set-process-coding-system proc 'no-conversion 'no-conversion)
1803 (set-process-sentinel proc 'newsticker--image-sentinel))))))) 1844 (set-process-sentinel proc 'newsticker--image-sentinel)
1845 (process-put proc 'nt-directory directory)
1846 (process-put proc 'nt-feed-name feed-name)
1847 (process-put proc 'nt-filename filename)))))
1804 1848
1805(defun newsticker--image-sentinel (process event) 1849(defun newsticker--image-sentinel (process event)
1806 "Sentinel for image-retrieving PROCESS caused by EVENT." 1850 "Sentinel for image-retrieving PROCESS caused by EVENT."
1807 (let* ((p-status (process-status process)) 1851 (let* ((p-status (process-status process))
1808 (exit-status (process-exit-status process)) 1852 (exit-status (process-exit-status process))
1809 (feed-name (process-name process))) 1853 (feed-name (process-get process 'nt-feed-name))
1854 (directory (process-get process 'nt-directory))
1855 (filename (process-get process 'nt-filename)))
1810 ;; catch known errors (zombie processes, rubbish-xml, etc.) 1856 ;; catch known errors (zombie processes, rubbish-xml, etc.)
1811 ;; if an error occurs the news feed is not updated! 1857 ;; if an error occurs the news feed is not updated!
1812 (catch 'oops 1858 (catch 'oops
@@ -1815,21 +1861,67 @@ If the image has been downloaded in the last 24h do nothing."
1815 (message "%s: Error while retrieving image from %s" 1861 (message "%s: Error while retrieving image from %s"
1816 (format-time-string "%A, %H:%M" (current-time)) 1862 (format-time-string "%A, %H:%M" (current-time))
1817 feed-name) 1863 feed-name)
1864 (newsticker--image-remove directory feed-name)
1818 (throw 'oops nil)) 1865 (throw 'oops nil))
1819 (let (image-name) 1866 (newsticker--image-save (process-buffer process) directory filename))))
1820 (with-current-buffer (process-buffer process) 1867
1821 (setq image-name (concat (newsticker--images-dir) feed-name)) 1868(defun newsticker--image-save (buffer directory file-name)
1822 (set-buffer-file-coding-system 'no-conversion) 1869 "Save contents of BUFFER in DIRECTORY as FILE-NAME.
1823 ;; make sure the cache dir exists 1870Finally kill buffer."
1824 (unless (file-directory-p (newsticker--images-dir)) 1871 (with-current-buffer buffer
1825 (make-directory (newsticker--images-dir))) 1872 (let ((image-name (concat directory file-name)))
1826 ;; write and close buffer 1873 (set-buffer-file-coding-system 'no-conversion)
1827 (let ((require-final-newline nil) 1874 ;; make sure the cache dir exists
1828 (backup-inhibited t) 1875 (unless (file-directory-p directory)
1829 (coding-system-for-write 'no-conversion)) 1876 (make-directory directory))
1830 (write-region nil nil image-name nil 'quiet)) 1877 ;; write and close buffer
1831 (set-buffer-modified-p nil) 1878 (let ((require-final-newline nil)
1832 (kill-buffer (current-buffer))))))) 1879 (backup-inhibited t)
1880 (coding-system-for-write 'no-conversion))
1881 (write-region nil nil image-name nil 'quiet))
1882 (set-buffer-modified-p nil)
1883 (kill-buffer buffer))))
1884
1885(defun newsticker--image-remove (directory file-name)
1886 "In DIRECTORY remove FILE-NAME."
1887 (let ((image-name (concat directory file-name)))
1888 (when (file-exists-p file-name)
1889 (delete-file image-name))))
1890
1891(defun newsticker--image-download-by-url (feed-name filename directory url)
1892 "Download image for FEED-NAME using `url-retrieve'.
1893Save image as FILENAME in DIRECTORY, download it from URL."
1894 (let ((coding-system-for-read 'no-conversion))
1895 (condition-case error-data
1896 (url-retrieve url 'newsticker--image-download-by-url-callback
1897 (list feed-name directory filename))
1898 (error (message "Error retrieving image from %s: %s" feed-name
1899 error-data))))
1900 (force-mode-line-update))
1901
1902(defun newsticker--image-download-by-url-callback (status feed-name directory filename)
1903 "Callback function for `newsticker--image-download-by-url'.
1904STATUS is the return status as delivered by `url-retrieve'.
1905FEED-NAME is the name of the feed that the news were retrieved
1906from.
1907The image is saved in DIRECTORY as FILENAME."
1908 (when status
1909 (let ((status-type (car status))
1910 (status-details (cdr status)))
1911 (cond ((eq status-type :error)
1912 (newsticker--image-remove directory feed-name))
1913 (t
1914 (let ((buf (get-buffer-create (concat " *newsticker-url-image-" feed-name "-" directory "*")))
1915 (result (string-to-multibyte (buffer-string))))
1916 (set-buffer buf)
1917 (erase-buffer)
1918 (insert result)
1919 ;; remove MIME header
1920 (goto-char (point-min))
1921 (search-forward "\n\n")
1922 (delete-region (point-min) (point))
1923 ;; save
1924 (newsticker--image-save buf directory filename)))))))
1833 1925
1834(defun newsticker--insert-image (img string) 1926(defun newsticker--insert-image (img string)
1835 "Insert IMG with STRING at point." 1927 "Insert IMG with STRING at point."
@@ -2244,6 +2336,7 @@ If AGE is nil, the total number of items is returned."
2244(defun newsticker-opml-export () 2336(defun newsticker-opml-export ()
2245 "OPML subscription export. 2337 "OPML subscription export.
2246Export subscriptions to a buffer in OPML Format." 2338Export subscriptions to a buffer in OPML Format."
2339 ;; FIXME: use newsticker-groups
2247 (interactive) 2340 (interactive)
2248 (with-current-buffer (get-buffer-create "*OPML Export*") 2341 (with-current-buffer (get-buffer-create "*OPML Export*")
2249 (set-buffer-file-coding-system 'utf-8) 2342 (set-buffer-file-coding-system 'utf-8)
@@ -2263,7 +2356,8 @@ Export subscriptions to a buffer in OPML Format."
2263 (insert " <outline text=\"") 2356 (insert " <outline text=\"")
2264 (insert (newsticker--title sub)) 2357 (insert (newsticker--title sub))
2265 (insert "\" xmlUrl=\"") 2358 (insert "\" xmlUrl=\"")
2266 (insert (cadr sub)) 2359 (insert (xml-escape-string (let ((url (cadr sub)))
2360 (if (stringp url) url (prin1-to-string url)))))
2267 (insert "\"/>\n")) 2361 (insert "\"/>\n"))
2268 (append newsticker-url-list newsticker-url-list-defaults)) 2362 (append newsticker-url-list newsticker-url-list-defaults))
2269 (insert " </body>\n</opml>\n")) 2363 (insert " </body>\n</opml>\n"))
diff --git a/lisp/net/newst-reader.el b/lisp/net/newst-reader.el
index 8232e4bd9bd..fcf4d19503e 100644
--- a/lisp/net/newst-reader.el
+++ b/lisp/net/newst-reader.el
@@ -110,7 +110,7 @@ window is used when filling. See also `newsticker-justification'."
110 #'shr-render-region) 110 #'shr-render-region)
111 "Function for rendering HTML contents. 111 "Function for rendering HTML contents.
112If non-nil, newsticker.el will call this function whenever it 112If non-nil, newsticker.el will call this function whenever it
113finds HTML-like tags in item descriptions. 113finds HTML-like tags in item descriptions.
114Possible functions include `shr-render-region', `w3m-region', `w3-region', and 114Possible functions include `shr-render-region', `w3m-region', `w3-region', and
115`newsticker-htmlr-render'. 115`newsticker-htmlr-render'.
116Newsticker automatically loads the respective package w3m, w3, or 116Newsticker automatically loads the respective package w3m, w3, or
@@ -193,7 +193,8 @@ KEYMAP will be applied."
193 193
194(defun newsticker--print-extra-elements (item keymap &optional htmlish) 194(defun newsticker--print-extra-elements (item keymap &optional htmlish)
195 "Insert extra-elements of ITEM in a pretty form into the current buffer. 195 "Insert extra-elements of ITEM in a pretty form into the current buffer.
196KEYMAP is applied." 196KEYMAP is applied. If HTMLISH is non-nil then HTML-markup is used
197for formatting."
197 (let ((ignored-elements '(items link title description content 198 (let ((ignored-elements '(items link title description content
198 content:encoded encoded 199 content:encoded encoded
199 dc:subject subject 200 dc:subject subject
@@ -223,7 +224,8 @@ KEYMAP is applied."
223 224
224(defun newsticker--do-print-extra-element (extra-element width keymap htmlish) 225(defun newsticker--do-print-extra-element (extra-element width keymap htmlish)
225 "Actually print an EXTRA-ELEMENT using the given WIDTH. 226 "Actually print an EXTRA-ELEMENT using the given WIDTH.
226KEYMAP is applied." 227KEYMAP is applied. If HTMLISH is non-nil then HTML-markup is used
228for formatting."
227 (let ((name (symbol-name (car extra-element)))) 229 (let ((name (symbol-name (car extra-element))))
228 (if htmlish 230 (if htmlish
229 (insert (format "<li>%s: " name)) 231 (insert (format "<li>%s: " name))
@@ -253,10 +255,11 @@ KEYMAP is applied."
253 (insert "</li>") 255 (insert "</li>")
254 (insert "\n")))) 256 (insert "\n"))))
255 257
256(defun newsticker--image-read (feed-name-symbol disabled) 258(defun newsticker--image-read (feed-name-symbol disabled &optional max-height)
257 "Read the cached image for FEED-NAME-SYMBOL from disk. 259 "Read the cached image for FEED-NAME-SYMBOL from disk.
258If DISABLED is non-nil the image will be converted to a disabled look 260If DISABLED is non-nil the image will be converted to a disabled look
259\(unless `newsticker-enable-logo-manipulations' is not t\). 261\(unless `newsticker-enable-logo-manipulations' is not t\).
262Optional argument MAX-HEIGHT specifies the maximal image height.
260Return the image." 263Return the image."
261 (let ((image-name (concat (newsticker--images-dir) 264 (let ((image-name (concat (newsticker--images-dir)
262 (symbol-name feed-name-symbol))) 265 (symbol-name feed-name-symbol)))
@@ -264,18 +267,47 @@ Return the image."
264 (when (file-exists-p image-name) 267 (when (file-exists-p image-name)
265 (condition-case error-data 268 (condition-case error-data
266 (setq img (create-image 269 (setq img (create-image
267 image-name nil nil 270 image-name
271 (and (fboundp 'imagemagick-types)
272 (imagemagick-types)
273 'imagemagick)
274 nil
268 :conversion (and newsticker-enable-logo-manipulations 275 :conversion (and newsticker-enable-logo-manipulations
269 disabled 276 disabled
270 'disabled) 277 'disabled)
271 :mask (and newsticker-enable-logo-manipulations 278 :mask (and newsticker-enable-logo-manipulations
272 'heuristic) 279 'heuristic)
273 :ascent 70)) 280 :ascent 100
281 :max-height max-height))
274 (error 282 (error
275 (message "Error: cannot create image for %s: %s" 283 (message "Error: cannot create image for %s: %s"
276 feed-name-symbol error-data)))) 284 feed-name-symbol error-data))))
277 img)) 285 img))
278 286
287(defun newsticker--icon-read (feed-name-symbol)
288 "Read the cached icon for FEED-NAME-SYMBOL from disk.
289Return the image."
290 (catch 'icon
291 (when (file-exists-p (newsticker--icons-dir))
292 (mapc (lambda (file)
293 (condition-case error-data
294 (progn (setq img (create-image
295 file (and (fboundp 'imagemagick-types)
296 (imagemagick-types)
297 'imagemagick)
298 nil
299 :ascent 'center
300 :max-width 16
301 :max-height 16))
302 (throw 'icon img))
303 (error
304 (message "Error: cannot create icon for %s: %s"
305 feed-name-symbol error-data))))
306 (directory-files (newsticker--icons-dir) t
307 (concat (symbol-name feed-name-symbol) "\\..*"))))
308 ;; fallback: default icon
309 (find-image '((:type png :file "newsticker/rss-feed.png" :ascent center)))))
310
279;; the functions we need for retrieval and display 311;; the functions we need for retrieval and display
280;;;###autoload 312;;;###autoload
281(defun newsticker-show-news () 313(defun newsticker-show-news ()
diff --git a/lisp/net/newst-treeview.el b/lisp/net/newst-treeview.el
index 097a2a58805..6d0720d074e 100644
--- a/lisp/net/newst-treeview.el
+++ b/lisp/net/newst-treeview.el
@@ -735,7 +735,7 @@ for the button."
735 (goto-char (point-min)) 735 (goto-char (point-min))
736 ;; insert logo at top 736 ;; insert logo at top
737 (let* ((newsticker-enable-logo-manipulations nil) 737 (let* ((newsticker-enable-logo-manipulations nil)
738 (img (newsticker--image-read feed-name-symbol nil))) 738 (img (newsticker--image-read feed-name-symbol nil 40)))
739 (if (and (display-images-p) img) 739 (if (and (display-images-p) img)
740 (newsticker--insert-image img (car item)) 740 (newsticker--insert-image img (car item))
741 (insert (newsticker--real-feed-name feed-name-symbol)))) 741 (insert (newsticker--real-feed-name feed-name-symbol))))
@@ -829,6 +829,7 @@ Callback function for tree widget that adds nodes for feeds and subgroups."
829 :nt-group ,(cdr g) 829 :nt-group ,(cdr g)
830 :nt-feed ,g-name 830 :nt-feed ,g-name
831 :nt-id ,nt-id 831 :nt-id ,nt-id
832 :leaf-icon newsticker--tree-widget-leaf-icon
832 :keep (:nt-feed :num-new :nt-id :open);; :nt-group 833 :keep (:nt-feed :num-new :nt-id :open);; :nt-group
833 :open nil)) 834 :open nil))
834 (let ((tag (newsticker--treeview-tree-get-tag g nil nt-id))) 835 (let ((tag (newsticker--treeview-tree-get-tag g nil nt-id)))
@@ -841,6 +842,23 @@ Callback function for tree widget that adds nodes for feeds and subgroups."
841 :open t)))) 842 :open t))))
842 group))) 843 group)))
843 844
845(defun newsticker--tree-widget-icon-create (icon)
846 "Create the ICON widget."
847 (let* ((g (widget-get (widget-get icon :node) :nt-feed))
848 (ico (and g (newsticker--icon-read (intern g)))))
849 (if ico
850 (progn
851 (widget-put icon :tag-glyph ico)
852 (widget-default-create icon)
853 ;; Insert space between the icon and the node widget.
854 (insert-char ? 1)
855 (put-text-property
856 (1- (point)) (point)
857 'display (list 'space :width tree-widget-space-width)))
858 ;; fallback: default icon
859 (widget-put icon :leaf-icon 'tree-widget-leaf-icon)
860 (tree-widget-icon-create icon))))
861
844(defun newsticker--treeview-tree-expand-status (tree &optional changed-widget 862(defun newsticker--treeview-tree-expand-status (tree &optional changed-widget
845 event) 863 event)
846 "Expand the vfeed TREE. 864 "Expand the vfeed TREE.
@@ -875,6 +893,7 @@ Optional arguments CHANGED-WIDGET and EVENT are ignored."
875 "Icon for a tree-widget leaf node." 893 "Icon for a tree-widget leaf node."
876 :tag "O" 894 :tag "O"
877 :glyph-name "leaf" 895 :glyph-name "leaf"
896 :create 'newsticker--tree-widget-icon-create
878 :button-face 'default) 897 :button-face 'default)
879 898
880(defun newsticker--treeview-tree-update () 899(defun newsticker--treeview-tree-update ()