]> sipb.mit.edu Git - ikiwiki.git/blob - IkiWiki/Plugin/inline.pm
* Support pinging services such as Technorati using XML-RPC to notify them
[ikiwiki.git] / IkiWiki / Plugin / inline.pm
1 #!/usr/bin/perl
2 # Page inlining and blogging.
3 package IkiWiki::Plugin::inline;
4
5 use warnings;
6 use strict;
7 use IkiWiki;
8
9 sub import { #{{{
10         IkiWiki::hook(type => "preprocess", id => "inline", 
11                 call => \&IkiWiki::preprocess_inline);
12         # Hook to change to do pinging since it's called late.
13         # This ensures each page only pings once and prevents slow
14         # pings interrupting page builds.
15         IkiWiki::hook(type => "change", id => "inline", 
16                 call => \&IkiWiki::pingurl);
17 } # }}}
18
19 # Back to ikiwiki namespace for the rest, this code is very much
20 # internal to ikiwiki even though it's separated into a plugin.
21 package IkiWiki;
22
23 my %toping;
24
25 sub preprocess_inline (@) { #{{{
26         my %params=@_;
27
28         if (! exists $params{pages}) {
29                 return "";
30         }
31         if (! exists $params{archive}) {
32                 $params{archive}="no";
33         }
34         if (! exists $params{show} && $params{archive} eq "no") {
35                 $params{show}=10;
36         }
37         add_depends($params{page}, $params{pages});
38
39         my $ret="";
40         
41         if (exists $params{rootpage}) {
42                 # Add a blog post form, with a rss link button.
43                 my $formtemplate=HTML::Template->new(blind_cache => 1,
44                         filename => "$config{templatedir}/blogpost.tmpl");
45                 $formtemplate->param(cgiurl => $config{cgiurl});
46                 $formtemplate->param(rootpage => $params{rootpage});
47                 if ($config{rss}) {
48                         $formtemplate->param(rssurl => rsspage(basename($params{page})));
49                 }
50                 $ret.=$formtemplate->output;
51         }
52         elsif ($config{rss}) {
53                 # Add a rss link button.
54                 my $linktemplate=HTML::Template->new(blind_cache => 1,
55                         filename => "$config{templatedir}/rsslink.tmpl");
56                 $linktemplate->param(rssurl => rsspage(basename($params{page})));
57                 $ret.=$linktemplate->output;
58         }
59         
60         my $template=HTML::Template->new(blind_cache => 1,
61                 filename => (($params{archive} eq "no") 
62                                 ? "$config{templatedir}/inlinepage.tmpl"
63                                 : "$config{templatedir}/inlinepagetitle.tmpl"));
64         
65         my @pages;
66         foreach my $page (blog_list($params{pages}, $params{show})) {
67                 next if $page eq $params{page};
68                 push @pages, $page;
69                 $template->param(pagelink => htmllink($params{page}, $params{page}, $page));
70                 $template->param(content => get_inline_content($params{page}, $page))
71                         if $params{archive} eq "no";
72                 $template->param(ctime => displaytime($pagectime{$page}));
73                 $ret.=$template->output;
74         }
75         
76         # TODO: should really add this to renderedfiles and call
77         # check_overwrite, but currently renderedfiles
78         # only supports listing one file per page.
79         if ($config{rss}) {
80                 writefile(rsspage($params{page}), $config{destdir},
81                         genrss($params{page}, @pages));
82                 $toping{$params{page}}=1;
83         }
84         
85         return $ret;
86 } #}}}
87
88 sub blog_list ($$) { #{{{
89         my $globlist=shift;
90         my $maxitems=shift;
91
92         my @list;
93         foreach my $page (keys %pagesources) {
94                 if (globlist_match($page, $globlist)) {
95                         push @list, $page;
96                 }
97         }
98
99         @list=sort { $pagectime{$b} <=> $pagectime{$a} } @list;
100         return @list if ! $maxitems || @list <= $maxitems;
101         return @list[0..$maxitems - 1];
102 } #}}}
103
104 sub get_inline_content ($$) { #{{{
105         my $parentpage=shift;
106         my $page=shift;
107         
108         my $file=$pagesources{$page};
109         my $type=pagetype($file);
110         if ($type ne 'unknown') {
111                 return htmlize($type, preprocess($page, linkify($page, $parentpage, readfile(srcfile($file))), 1));
112         }
113         else {
114                 return "";
115         }
116 } #}}}
117
118 sub date_822 ($) { #{{{
119         my $time=shift;
120
121         eval q{use POSIX};
122         return POSIX::strftime("%a, %d %b %Y %H:%M:%S %z", localtime($time));
123 } #}}}
124
125 sub absolute_urls ($$) { #{{{
126         # sucky sub because rss sucks
127         my $content=shift;
128         my $url=shift;
129
130         $url=~s/[^\/]+$//;
131         
132         $content=~s/<a\s+href="(?![^:]+:\/\/)([^"]+)"/<a href="$url$1"/ig;
133         $content=~s/<img\s+src="(?![^:]+:\/\/)([^"]+)"/<img src="$url$1"/ig;
134         return $content;
135 } #}}}
136
137 sub rsspage ($) { #{{{
138         my $page=shift;
139
140         return $page.".rss";
141 } #}}}
142
143 sub genrss ($@) { #{{{
144         my $page=shift;
145         my @pages=@_;
146         
147         my $url="$config{url}/".htmlpage($page);
148         
149         my $template=HTML::Template->new(blind_cache => 1,
150                 filename => "$config{templatedir}/rsspage.tmpl");
151         
152         my @items;
153         foreach my $p (@pages) {
154                 push @items, {
155                         itemtitle => pagetitle(basename($p)),
156                         itemurl => "$config{url}/$renderedfiles{$p}",
157                         itempubdate => date_822($pagectime{$p}),
158                         itemcontent => absolute_urls(get_inline_content($page, $p), $url),
159                 } if exists $renderedfiles{$p};
160         }
161
162         $template->param(
163                 title => $config{wikiname},
164                 pageurl => $url,
165                 items => \@items,
166         );
167         
168         return $template->output;
169 } #}}}
170
171 sub pingurl (@) { #{{{
172         return unless $config{pingurl} && %toping;
173
174         eval q{require RPC::XML::Client};
175         if ($@) {
176                 debug("RPC::XML::Client not found, not pinging");
177         }
178
179         foreach my $page (keys %toping) {
180                 my $title=pagetitle(basename($page));
181                 my $url="$config{url}/".htmlpage($page);
182                 foreach my $pingurl (@{$config{pingurl}}) {
183                         my $client = RPC::XML::Client->new($pingurl);
184                         my $req = RPC::XML::request->new('weblogUpdates.ping',
185                                 $title, $url);
186                         debug("Pinging $pingurl for $page");
187                         my $res = $client->send_request($req);
188                         if (! ref $res) {
189                                 debug("Did not receive response to ping");
190                         }
191                         my $r=$res->value;
192                         if (! exists $r->{flerror} || $r->{flerror}) {
193                                 debug("Ping rejected: ".$r->{message});
194                         }
195                 }
196         }
197 } #}}}
198
199 1