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 => \&notify);
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