fix adding first subscription to pagespec
[ikiwiki.git] / IkiWiki / Plugin / notifyemail.pm
1 #!/usr/bin/perl
2 package IkiWiki::Plugin::notifyemail;
3
4 use warnings;
5 use strict;
6 use IkiWiki 3.00;
7
8 sub import {
9         hook(type => "formbuilder_setup", id => "notifyemail", call => \&formbuilder_setup);
10         hook(type => "formbuilder", id => "notifyemail", call => \&formbuilder);
11         hook(type => "getsetup", id => "notifyemail",  call => \&getsetup);
12         hook(type => "changes", id => "notifyemail", call => \&notify);
13 }
14
15 sub getsetup () {
16         return
17                 plugin => {
18                         safe => 1,
19                         rebuild => 0,
20                 },
21 }
22
23 sub formbuilder_setup (@) {
24         my %params=@_;
25
26         my $form=$params{form};
27         return unless $form->title eq "preferences";
28         my $session=$params{session};
29         $form->field(name => "subscriptions", size => 50,
30                 fieldset => "preferences",
31                 comment => "(".htmllink("", "", "ikiwiki/PageSpec", noimageinline => 1).")",
32                 value => getsubscriptions($session->param("name")));
33 }
34
35 sub formbuilder (@) {
36         my %params=@_;
37         my $form=$params{form};
38         return unless $form->title eq "preferences" &&
39                 $form->submitted eq "Save Preferences" && $form->validate &&
40                 defined $form->field("subscriptions");
41         setsubscriptions($form->field('name'), $form->field('subscriptions'));
42 }
43
44 sub getsubscriptions ($) {
45         my $user=shift;
46         eval q{use IkiWiki::UserInfo};
47         error $@ if $@;
48         IkiWiki::userinfo_get($user, "subscriptions");
49 }
50
51 sub setsubscriptions ($$) {
52         my $user=shift;
53         my $subscriptions=shift;
54         eval q{use IkiWiki::UserInfo};
55         error $@ if $@;
56         IkiWiki::userinfo_set($user, "subscriptions", $subscriptions);
57 }
58
59 # Called by other plugins to subscribe the user to a pagespec.
60 sub subscribe ($$) {
61         my $user=shift;
62         my $addpagespec=shift;
63         my $pagespec=getsubscriptions($user);
64         setsubscriptions($user,
65                 length $pagespec ? $pagespec." or ".$addpagespec : $addpagespec);
66 }
67
68 sub notify (@) {
69         my @files=@_;
70         return unless @files;
71
72         eval q{use Mail::Sendmail};
73         error $@ if $@;
74         eval q{use IkiWiki::UserInfo};
75         error $@ if $@;
76         eval q{use URI};
77         error($@) if $@;
78
79         # Daemonize, in case the mail sending takes a while.
80         defined(my $pid = fork) or error("Can't fork: $!");
81         return if $pid; # parent
82         chdir '/';
83         open STDIN, '/dev/null';
84         open STDOUT, '>/dev/null';
85         POSIX::setsid() or error("Can't start a new session: $!");
86         open STDERR, '>&STDOUT' or error("Can't dup stdout: $!");
87
88         # Don't need to keep a lock on the wiki as a daemon.
89         IkiWiki::unlockwiki();
90
91         my $userinfo=IkiWiki::userinfo_retrieve();
92         exit 0 unless defined $userinfo;
93
94         foreach my $user (keys %$userinfo) {
95                 my $pagespec=$userinfo->{$user}->{"subscriptions"};
96                 next unless defined $pagespec && length $pagespec;
97                 my $email=$userinfo->{$user}->{email};
98                 next unless defined $email && length $email;
99
100                 foreach my $file (@files) {
101                         my $page=pagename($file);
102                         next unless pagespec_match($page, $pagespec);
103                         my $content="";
104                         my $showcontent=defined pagetype($file);
105                         if ($showcontent) {
106                                 $content=eval { readfile(srcfile($file)) };
107                                 $showcontent=0 if $@;
108                         }
109                         my $url;
110                         if (! IkiWiki::isinternal($page)) {
111                                 $url=urlto($page, undef, 1);
112                         }
113                         elsif (defined $pagestate{$page}{meta}{permalink}) {
114                                 # need to use permalink for an internal page
115                                 $url=URI->new_abs($pagestate{$page}{meta}{permalink}, $config{url});
116                         }
117                         else {
118                                 $url=$config{url}; # crummy fallback url
119                         }
120                         my $pagedesc=$page;
121                         if (defined $pagestate{$page}{meta}{title} &&
122                             length $pagestate{$page}{meta}{title}) {
123                                 $pagedesc=qq{"$pagestate{$page}{meta}{title}"};
124                         }
125                         my $subject=gettext("change notification:")." ".$pagedesc;
126                         if (pagetype($file) eq '_comment') {
127                                 $subject=gettext("comment notification:")." ".$pagedesc;
128                         }
129                         my $template=template("notifyemail.tmpl");
130                         $template->param(
131                                 wikiname => $config{wikiname},
132                                 url => $url,
133                                 prefsurl => $config{cgiurl}."?do=prefs",
134                                 showcontent => $showcontent,
135                                 content => $content,
136                         );
137                         sendmail(
138                                 To => $email,
139                                 From => "$config{wikiname} <$config{adminemail}>",
140                                 Subject => $subject,
141                                 Message => $template->output,
142                         );
143                 }
144         }
145
146         exit 0; # daemon child
147 }
148
149 1