e5c0d046c188e1eeb8dcb2a592dcd9ac1f3ba975
[onak.git] / onak-mail.pl
1 #!/usr/bin/perl -w
2 #
3 # onak-mail.pl - Mail processing interface for onak, an OpenPGP Keyserver.
4 #
5 # Written by Jonathan McDowell <noodles@earth.li>
6 # Copyright 2002 Project Purple
7 # Released under the GPL.
8 #
9 # $Id: onak-mail.pl,v 1.9 2004/01/04 18:48:37 noodles Exp $
10 #
11
12 use strict;
13 use Fcntl ':flock';
14 use IPC::Open3;
15
16 my %config;
17
18 #
19 # readconfig
20 #
21 # Reads in our config file. Ignores any command it doesn't understand rather
22 # than having to list all the ones that are of no interest to us.
23 #
24 sub readconfig {
25
26         open(CONFIG, "/home/noodles/projects/onak/onak.conf") or
27                 die "Can't read config file: $!";
28         
29         while (<CONFIG>) {
30                 if (/^#/ or /^$/) {
31                         # Ignore; comment line.
32                 } elsif (/^this_site (.*)/) {
33                         $config{'thissite'} = $1;
34                 } elsif (/^logfile (.*)/) {
35                         $config{'logfile'} = $1;
36                 } elsif (/^maintainer_email (.*)/) {
37                         $config{'adminemail'} = $1;
38                 } elsif (/^mail_delivery_client (.*)/) {
39                         $config{'mta'} = $1;
40                 } elsif (/^pks_bin_dir (.*)/) {
41                         $config{'pks_bin_dir'} = $1;
42                 } elsif (/^db_dir (.*)/) {
43                         $config{'db_dir'} = $1;
44                 } elsif (/^syncsite (.*)/) {
45                         push @{$config{'syncsites'}}, $1;
46                 }
47         }
48
49         close(CONFIG);
50
51         return;
52 }
53
54 #
55 # submitupdate
56 #
57 # Takes an armored OpenPGP stream and submits it to the keyserver. Returns the
58 # difference between what we just added and what we had before (ie the least
59 # data need to get from what we had to what we have).
60 #
61 sub submitupdate {
62         my @data = @_;
63         my (@errors, @mergedata);
64
65         open(LOCKFILE, '>'.$config{'db_dir'}.'/onak-mail.lck');
66         flock(LOCKFILE, LOCK_EX);
67         print LOCKFILE "$$";
68
69         open3(\*MERGEIN, \*MERGEOUT, \*MERGEERR,
70                 $config{'pks_bin_dir'}."/onak", "-u", "add");
71
72         print MERGEIN @data;
73         close MERGEIN;
74         @mergedata = <MERGEOUT>;
75         close MERGEOUT;
76         @errors = <MERGEERR>;
77         close MERGEERR;
78
79         flock(LOCKFILE, LOCK_UN);
80         close(LOCKFILE);
81
82         return @mergedata;
83 }
84
85 my ($inheader, %seenby, $subject, $from, $replyto, @body, @syncmail);
86
87 $inheader = 1;
88 $subject = "";
89 &readconfig;
90
91 while (<>) {
92         if ($inheader) {
93                 if (/^Subject:\s*(.*)\s*$/i) {
94                         $subject = $1;
95                 } elsif (/^X-KeyServer-Sent:\s*(.*)\s*$/i) {
96                         $seenby{$1} = 1;
97                 } elsif (/^From:\s*(.*)\s*$/i) {
98                         $from = $1;
99                 } elsif (/^Reply-To:\s*(.*)\s*$/i) {
100                         $replyto = $1;
101                 } elsif (/^$/) {
102                         $inheader = 0;
103                 }
104         }
105         if (!$inheader) {
106                 push @body, $_;
107         }
108 }
109 if (! defined($replyto)) {
110         $replyto = $from;
111 }
112
113 # HELP, ADD, INCREMENTAL, VERBOSE INDEX <keyid>, INDEX <keyid>, GET <keyid>,
114 # LAST <days>
115
116 if ($subject =~ /^INCREMENTAL$/i) {
117         my $site;
118         my $count;
119         my $i;
120         my @newupdate = submitupdate(@body);
121         my @time;
122
123         $count = 0;
124         foreach $i (@{$config{'syncsites'}}) {
125                 if (! defined($seenby{$i})) {
126                         $count++;
127                 }
128         }
129
130         open (LOG, ">>$config{'logfile'}");
131         @time = localtime(time);
132         print LOG "[";
133         print LOG sprintf "%02d/%02d/%04d %02d:%02d:%02d",
134                 $time[3], $time[4] + 1, $time[5] + 1900,
135                 $time[2], $time[1], $time[0];
136         print LOG "] onak-mail[$$]: Syncing with $count sites.\n";
137         close LOG;
138
139         if ((! defined($newupdate[0])) || $newupdate[0] eq '') {
140                 open (LOG, ">>$config{'logfile'}");
141                 print LOG "[";
142                 print LOG sprintf "%02d/%02d/%04d %02d:%02d:%02d",
143                         $time[3], $time[4] + 1, $time[5] + 1900,
144                         $time[2], $time[1], $time[0];
145                 print LOG "] onak-mail[$$]: Nothing to sync.\n";
146                 close LOG;
147                 $count = 0;
148         }
149
150         if ($count > 0) {
151                 open(MAIL, "|$config{mta}");
152                 print MAIL "From: $config{adminemail}\n";
153                 print MAIL "To: ";
154                 foreach $i (@{$config{'syncsites'}}) {
155                         if (! defined($seenby{$i})) {
156                                 print MAIL "$i";
157                                 $count--;
158                                 if ($count > 0) {
159                                         print MAIL ", ";
160                                 }
161                         }
162                 }
163                 print MAIL "\n";
164                 print MAIL "Subject: incremental\n";
165                 foreach $site (keys %seenby) {
166                         print MAIL "X-KeyServer-Sent: $site\n";
167                 }
168                 print MAIL "X-KeyServer-Sent: $config{thissite}\n";
169                 print MAIL "Precedence: list\n";
170                 print MAIL "MIME-Version: 1.0\n";
171                 print MAIL "Content-Type: application/pgp-keys\n";
172                 print MAIL "\n";
173                 print MAIL @newupdate;
174                 close MAIL;
175         }
176 } elsif ($subject =~ /^(VERBOSE )?INDEX (.*)$/i) {
177         my (@indexdata, $command);
178
179         $command = "index";
180         if (defined($1)) {
181                 $command = "vindex";
182         }
183
184         open3(\*INDEXIN, \*INDEXOUT, \*INDEXERR,
185                 $config{'pks_bin_dir'}."/onak", $command, "$2");
186         close INDEXIN;
187         @indexdata = <INDEXOUT>;
188         close INDEXOUT;
189         close INDEXERR;
190
191         open(MAIL, "|$config{mta}");
192         print MAIL "From: $config{adminemail}\n";
193         print MAIL "To: $replyto\n";
194         print MAIL "Subject: Reply to INDEX $2\n";
195         print MAIL "Precedence: list\n";
196         print MAIL "MIME-Version: 1.0\n";
197         print MAIL "Content-Type: text/plain\n";
198         print MAIL "\n";
199         print MAIL "Below follows the reply to your recent keyserver query:\n";
200         print MAIL "\n";
201         print MAIL @indexdata;
202         close MAIL;
203 }