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