aboutsummaryrefslogtreecommitdiff
path: root/IkiWiki/Plugin/changemail.pm
blob: c112502a4f3c632adac01576ed7ce44b810e7ed9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#!/usr/bin/perl
package IkiWiki::Plugin::changemail;

use warnings;
use strict;
use IkiWiki 3.00;

sub import {
	hook(type => "formbuilder_setup", id => "changemail", call => \&formbuilder_setup);
	hook(type => "formbuilder", id => "changemail", call => \&formbuilder);
	hook(type => "getsetup", id => "changemail",  call => \&getsetup);
	hook(type => "change", id => "changemail", call => \&notify);
}

sub getsetup () {
	return
		plugin => {
			safe => 1,
			rebuild => 0,
			section => "misc",
		},
}

sub formbuilder_setup (@) {
	my %params=@_;

	my $form=$params{form};
	return unless $form->title eq "preferences";
	my $session=$params{session};
	my $user_name=$session->param("name");
	eval q{use IkiWiki::UserInfo};
	error $@ if $@;
	$form->field(name => "subscriptions", force => 1, size => 50,
		fieldset => "preferences",
		comment => "(".htmllink("", "", "ikiwiki/PageSpec", noimageinline => 1).")",
		value => IkiWiki::userinfo_get($user_name, "subscriptions"));
}

sub formbuilder (@) {
	my %params=@_;
	my $form=$params{form};
	return unless $form->title eq "preferences" &&
		$form->submitted eq "Save Preferences" && $form->validate &&
		defined $form->field("subscriptions");
	setsubscriptions($form->field('name'), $form->field('subscriptions'));
}

sub setsubscriptions ($$) {
	my $user=shift;
	my $subscriptions=shift;
	eval q{use IkiWiki::UserInfo};
	error $@ if $@;
	IkiWiki::userinfo_set($user, "subscriptions", $subscriptions);
}

sub notify (@) {
	my @files=@_;
	return unless @files;

	eval q{use Mail::Sendmail};
	error $@ if $@;
	eval q{use IkiWiki::UserInfo};
	error $@ if $@;

	# Daemonize, in case the mail sending takes a while.
	defined(my $pid = fork) or error("Can't fork: $!");
	return if $pid; # parent
	chdir '/';
	open STDIN, '/dev/null';
	open STDOUT, '>/dev/null';
	POSIX::setsid() or error("Can't start a new session: $!");
	open STDERR, '>&STDOUT' or error("Can't dup stdout: $!");

	# Don't need to keep a lock on the wiki as a daemon.
	IkiWiki::unlockwiki();

	my $userinfo=IkiWiki::userinfo_retrieve();
	exit 0 unless defined $userinfo;

	foreach my $user (keys %$userinfo) {
		my $pagespec=$userinfo->{$user}->{"subscriptions"};
		next unless defined $pagespec && length $pagespec;
		my $email=$userinfo->{$user}->{email};
		next unless defined $email && length $email;

		foreach my $file (@files) {
			my $page=pagename($file);
			next unless pagespec_match($page, $pagespec);
			my $ispage=defined pagetype($file);
			my $url;
			if (! IkiWiki::isinternal($page)) {
				$url=urlto($page, undef, 1);
			}
			elsif (defined $pagestate{$page}{meta}{permalink}) {
				# need to use permalink for an internal page
				$url=$pagestate{$page}{meta}{permalink};
			}
			else {
				$url=$config{wikiurl}; # crummy fallback url
			}
			my $template=template("changemail.tmpl");
			$template->param(
				wikiname => $config{wikiname},
				url => $url,
				prefsurl => IkiWiki::cgiurl(do => "prefs"),
				ispage => $ispage,
				content => $ispage ? readfile(srcfile($file)) : "",
			);
			#translators: The two variables are the name of the wiki,
			#translators: and a page that was changed.
			#translators: This is used as the subject of a commit email.
			my $subject=sprintf(gettext("%s: change notification for %s"),
				$config{wikiname}, $page);
			sendmail(
				To => $email,
				From => "$config{wikiname} <$config{adminemail}>",
				Subject => $subject,
				Message => $template->output,
			);
		}
	}

	exit 0; # daemon child
}

1