Fix overgeneralised story hook in rss20.
[matthijs/upstream/blosxom-plugins.git] / gavinc / rss20
1 # Blosxom Plugin: rss20
2 # Author(s): Gavin Carr <gavin@openfusion.com.au>
3 # Version: 0.001002
4 # Requires: storydate, lastmodified2
5 # Suggests: absolute
6 # Follows:  storydate, lastmodified2
7
8 package rss20;
9
10 use strict;
11 use vars qw(
12   $flavour
13   $author_email 
14   $error_email 
15   $permalink
16   $trackback_link
17   $copyright
18   $generator_url
19 );
20
21 # --- Configuration variables -----
22
23 # What flavour string to you want to use for your feed?
24 $flavour = 'rss';
25 #$flavour = 'rss20';
26
27 # What email address should be used as the default author email?
28 $author_email = 'author@example.com';
29
30 # What email address should feed errors be reported to?
31 $error_email = '';
32
33 # What do your story permalinks look like?
34 # This must be single-quoted, to defer evaluation; blosxom namespace applies
35 $permalink = '$url$path/$fn.$default_flavour';
36
37 # What link should be used for trackbacks on a story?
38 # This must be single-quoted, to defer evaluation; blosxom namespace applies
39 $trackback_link = '';
40 # $trackback_link = '$url$path/$fn.writeback';
41 # $trackback_link = '$url$path/$fn.$feedback::trackback_flavour';
42
43 # Copyright statement; leave blank to omit.
44 $copyright = '';
45
46 # Generator that produced this feed
47 $generator_url = "http://blosxom.sourceforge.net/?v=$blosxom::version";
48
49 # --------------------------------
50
51 $error_email ||= $author_email;
52
53 # Escape <, >, and & to hex-encoded entities for max compatibility in text elements
54 # See http://www.rssboard.org/rss-profile#data-types-characterdata
55 my %escape_text = (
56   '<' => '&#x3C;',
57   '>' => '&#x3E;',
58   '&' => '&#x26;',
59 );
60 my $escape_text_re = join '|' => keys %escape_text;
61
62 # Escape <, >, and & to standard html-encoded entities for in html elements
63 my %escape_html = (
64   '<' => '&lt;',
65   '>' => '&gt;',
66   '&' => '&amp;',
67 );
68 my $escape_html_re = join '|' => keys %escape_html;
69
70 sub start { 
71   _load_templates();
72 }
73
74 sub story {
75   my ($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
76
77   # Ignore flavours other than ours
78   return unless $blosxom::flavour eq $flavour;
79
80   # Don't double-encode if someone else has already done it
81   return unless $blosxom::encode_xml_entities;
82
83   # Encode and reset encode_xml_entities flag
84   $$title_ref = _escape_text( $$title_ref );
85   $$body_ref  = _escape_html( $$body_ref );
86   $blosxom::encode_xml_entities = 0;
87 }
88
89 # --- Private subroutines
90
91 sub _escape_text {
92   my ($text) = @_;
93   $text =~ s/($escape_text_re)/$escape_text{$1}/g;
94   return $text;
95 }
96
97 sub _escape_html {
98   my ($html) = @_;
99   $html =~ s/($escape_html_re)/$escape_html{$1}/g;
100   return $html;
101 }
102
103 sub _load_templates {
104   $blosxom::template{$flavour}{'content_type'} = 'text/xml; charset=$blog_encoding';
105
106   $blosxom::template{$flavour}{'date'} = "\n";
107
108   $blosxom::template{$flavour}{'head'} = <<HEAD;
109 <?xml version="1.0" encoding="$blosxom::blog_encoding"?>
110 <rss version="2.0"
111     xmlns:dc="http://purl.org/dc/elements/1.1/"
112     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
113     xmlns:admin="http://webns.net/mvcb/"
114     xmlns:atom="http://www.w3.org/2005/Atom"
115     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
116     xmlns:content="http://purl.org/rss/1.0/modules/content/">
117
118     <channel>
119         <title>$blosxom::blog_title</title>
120         <link>$blosxom::url</link>
121         <description>$blosxom::blog_description</description>
122         <dc:date>\$lastmodified2::latest_iso8601</dc:date>
123         <dc:language>$blosxom::blog_language</dc:language>
124         <dc:creator>mailto:$rss20::author_email</dc:creator>
125         <dc:rights>$rss20::copyright</dc:rights>
126         <admin:generatorAgent rdf:resource="$rss20::generator_url" />
127         <admin:errorReportsTo rdf:resource="mailto:$rss20::error_email" />
128         <atom:link href="$blosxom::url$ENV{PATH_INFO}" rel="self" type="application/rss+xml" />
129         <sy:updatePeriod>hourly</sy:updatePeriod>
130         <sy:updateFrequency>1</sy:updateFrequency>
131         <sy:updateBase>2000-01-01T12:00+00:00</sy:updateBase>
132
133 HEAD
134
135   $blosxom::template{$flavour}{'story'} = <<STORY;
136         <item>
137             <title>\$title</title>
138             <link>$rss20::permalink</link>                                                                             
139             <description>\$body</description>                                                   
140             <comments>$rss20::trackback_link</comments>                                                            
141             <guid isPermaLink="true">$rss20::permalink</guid>                                                          
142             <dc:date>\$storydate::story_iso8601</dc:date>
143         </item>
144 STORY
145
146   $blosxom::template{$flavour}{'foot'} = <<'FOOT';
147     </channel>                                    
148 </rss>  
149 FOOT
150
151   1;
152 }
153
154
155 1;
156
157 __END__
158
159 =head1 NAME
160
161 rss20 - blosxom plugin to generate an RSS 2.0 feed of your blog
162
163 =head1 DESCRIPTION
164
165 rss20 is a blosxom plugin to generate an RSS 2.0 feed of your blog. It
166 is self-contained, including the required flavours, and has a bunch of
167 configuration variables to allow for configuration.
168
169 =head2 CONFIGURATION
170
171 The following package variables can be configured:
172
173 =over 4
174
175 =item $flavour
176
177 Flavour string to use for your feed (typically 'rss' or 'rss20').
178
179 =item $author_email
180
181 Default author email address for posts.
182
183 =item $error_email
184
185 Email address to use to report errors with the feed (defaults to 
186 $author_email).
187
188 =item $permalink
189
190 Story permalink. Default is '$url$path/$fn.$default_flavour'.
191 Note that this value should probably be single quoted to defer
192 variable evaluation until rendering time.
193
194 =item $trackback_link
195
196 Story trackback or comment link. Default is ''. Useful if you
197 are using a comments plugin like C<writeback> or C<feedback>,
198 and the format you want will be plugin-dependant.
199
200 Like $permalink, this value should be single quoted to defer
201 variable evaluation till rendering time.
202
203 =item $copyright
204
205 Default copyright clause for posts, if any.
206
207 =back
208
209 =head1 USAGE
210
211 rss20 should be loaded relatively late, since you'll typically want
212 plugins that manipulate your story content to have run already. It 
213 also should be run after the 'story' or 'prefs' plugins if you want
214 to use those to customise your configuration variables.
215
216
217 =head1 SEE ALSO
218
219 Blosxom: http://blosxom.sourceforge.net/
220
221 rss20 is based on the 'atomfeed' and 'rss10' plugins, by Rael
222 Dornfest and contributors.
223
224
225 =head1 BUGS
226
227 Please report bugs either directly to the author or to the blosxom 
228 development mailing list: <blosxom-devel@lists.sourceforge.net>.
229
230
231 =head1 AUTHOR
232
233 Gavin Carr <gavin@openfusion.com.au>, http://www.openfusion.net/
234
235
236 =head1 LICENSE
237
238 Copyright 2007 Gavin Carr.
239
240 This plugin is licensed under the same terms as blosxom itself i.e.
241
242 Permission is hereby granted, free of charge, to any person obtaining a
243 copy of this software and associated documentation files (the "Software"),
244 to deal in the Software without restriction, including without limitation
245 the rights to use, copy, modify, merge, publish, distribute, sublicense,
246 and/or sell copies of the Software, and to permit persons to whom the
247 Software is furnished to do so, subject to the following conditions:
248
249 The above copyright notice and this permission notice shall be included
250 in all copies or substantial portions of the Software.
251
252 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
253 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
254 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
255 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
256 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
257 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
258 OTHER DEALINGS IN THE SOFTWARE.
259
260 =cut
261
262 # vim:ft=perl