2 # Mail robot for processing of PCI ID submissions
3 # (c) 2001--2002 Martin Mares <mj@ucw.cz>
4 # (c) 2008 Michal Vaner <vorner@ucw.cz>
14 use PciIds::Notifications;
24 'emulate!' => \$emulate,
26 'orig=s' => \$original,
27 'author=s' => \$author
28 ) || die "Usage: mailbot [--patch] [--emulate] [--debug] [--orig <name>] [--author <mailaddr>]";
34 my $tables = PciIds::DBQ::new( connectDb() );
36 my $hasAuth = $tables->dbh()->prepare( 'SELECT id FROM users WHERE email = ?' );
37 my $hasItem = $tables->dbh()->prepare( "SELECT 1 FROM locations WHERE id = ?" );
38 my $addItem = $tables->dbh()->prepare( "INSERT INTO locations (id, parent) VALUES (?, ?)" );
39 my $addComment = $tables->dbh()->prepare( "INSERT INTO history (owner, location, discussion, nodename, nodenote) VALUES (?, ?, ?, ?, ?)" );
41 sub submitItem( $$$$$ ) {
42 my( $id, $name, $description, $text, $author ) = @_;
44 $id =~ s/(.{8})(.+)/$1\/$2/;
45 $id =~ s/(.{4})(.+)/$1\/$2/;
47 if( length $id > 12 ) {
48 my( $vendor ) = ( $id =~ /^PC\/....\/....\/(....)/ );
49 $vendor = "PC/$vendor";
50 $hasItem->execute( $vendor );
51 error( "Missing subsystem vendor" ) unless( $hasItem->fetchrow_array );
53 $hasItem->execute( $id );
54 unless( $hasItem->fetchrow_array ) {
55 tlog( "mailbot: Item created (empty) $id" );
57 $parent =~ s/\/[^\/]*$//;
58 $addItem->execute( $id, $parent );
61 $addComment->execute( $author, $id, $text, $name, $description );
62 my $hid = $tables->last();
63 tlog( "mailbot: History created $hid $id ".logEscape( $name )." ".logEscape( $description )." ".logEscape( $text ) );
64 notify( $tables, $id, $hid, $created ? 2 : 1, $created ? 0 : 1 );
65 if( !$tables->notifExists( $author, $id ) ) {
66 $tables->submitNotification( $author, $id, { 'recursive' => 0, 'notification' => 0, 'way' => 0 } );
71 $hdr = new Mail::Header;
73 $hdr->mail_from(COERCE);
74 $hdr->read(*STDIN{IO});
76 $mfrom = $hdr->get('Mail-From');
78 ($mfrom =~ /^MAILER-DAEMON@/i) && blackhole("From mailer daemon");
79 $mfrom =~ s/ .*// or blackhole("Malformed envelope sender");
80 ($reply = $hdr->get('Reply-To')) || ($reply = $hdr->get('From')) ||
81 blackhole("Don't know who should I reply to");
83 if ($reply =~ /<(\S*)>/) {
85 } elsif ($reply =~ /^\S+$/) {
86 $reply_plain = $reply;
88 $reply_plain = $mfrom;
90 $reply_plain =~ tr/\n'"\\//d;
91 $msgid = $hdr->get('Message-Id');
93 my $subj = $hdr->get('Subject');
95 if ($subj =~ /^IDS: (.*)/) {
98 $author = $reply_plain;
101 $home = "$ENV{HOME}/";
102 $tprefix = "${home}tmp/mbot-$$";
103 # Little hack to stop spam: ignore everything from people not already in database
104 $hasAuth->execute( $author );
105 my( $authorId ) = ( $hasAuth->fetchrow_array );
106 if( defined $authorId ) {
107 tlog( "mailbot: Active user ($author) id: $authorId" );
109 blackhole("Dropping email from $author, not in database.\n");
112 mkdir("${home}tmp", 0777);
113 mkdir($tprefix, 0777) || error("Cannot create tmpdir");
114 chdir($tprefix) || error("Cannot chdir to tmpdir");
116 open(TEMP, ">patch") || error("Cannot create tmpfile");
117 if ($debug || $reply eq "") {
118 open(LOG, ">&STDOUT") || error ("Cannot create outfile");
120 open(LOG, ">log") || error ("Cannot create outfile");
124 print LOG "Got mail from $reply, will reply to $reply_plain.\n";
125 print LOG "Scanning mail for patch.\n";
127 print LOG "Scanning STDIN for patch.\n";
139 if (/^\s*$/ || !/^[ +\@-]/) {
145 /^@@ -\d+,(\d+) \+\d+,(\d+) @@/ || error("Malformed patch");
148 while ($old || $new) {
151 if (/^ /) { $old--; $new--; }
152 elsif (/^-/) { $old--; }
153 elsif (/^\+/) { $new--; }
154 else { error("Malformed patch"); }
155 if ($old<0 || $new<0) { error("Malformed patch"); }
161 error("No patch found");
166 `rm -rf $tprefix` unless $debug;
172 my $reason = shift @_;
173 print STDERR "Blackholed: $reason\n";
179 my $reason = shift @_;
180 print LOG "$reason\n";
187 print LOG "Patch found.\n";
188 print LOG "Searching for original pci.ids version.\n";
189 foreach $orig (($original eq "") ? glob("$home/origs/*") : ("../../$original")) {
190 print LOG "Trying $orig\n";
193 print LOG `/usr/bin/patch <patch --no-backup -o pci.ids -r pci.rej $orig`;
195 print LOG "Failed.\n";
197 print LOG "Patch succeeded.\n";
198 print LOG "Parsing patched file.\n";
199 print LOG `$home/bin/ids_to_dbdump <$orig 2>&1 >orig.db.unsorted`;
200 $? && error("Error parsing original ID database");
201 print LOG `sort -k1 <orig.db.unsorted >orig.db`;
202 $? && error("Error sorting original ID database");
203 print LOG `$home/bin/ids_to_dbdump <pci.ids 2>&1 >new.db.unsorted`;
204 $? && error("Error parsing the patched pci.ids file");
205 print LOG `sort -k1 <new.db.unsorted >new.db`;
206 $? && error("Error sorting the patched pci.ids file");
207 print LOG "Finding ID differences.\n";
208 `diff -U0 new.db orig.db >diffs`;
209 if ($? > 256) { error("Diff failed. Why?"); }
210 elsif (!$?) { error("No ID changes encountered."); }
211 open(DIFF, "diffs") || error("Cannot open the diff");
212 $subject = undef if $subject eq '';
213 my $live = (!$emulate && !$debug);
216 /^(\+\+\+|---)/ && next;
218 ($tt,$id,$name,$stat,$cmt) = split /\t/;
219 if ($tt =~ /^\+(.*)/) {
220 defined $seen{$id} && next;
222 } elsif ($tt =~ /^-(.*)/) {
224 } else { error("Internal bug #23"); }
225 print LOG "$id\t$name\t$cmt\n";
226 submitItem( $id, $name, $cmt, $subject, $authorId ) if $live;
228 $tables->dbh->commit();
231 `echo >>$home/mailbot.log "## $time $reply"`;
232 `cat result >>$home/mailbot.log`;
238 error("Unable to find any version of pci.ids the patch applies to.");
243 my $reason = shift @_;
244 my $sendmail_opts = "-fvorner+iderr\@ucw.cz '$reply_plain' vorner+idecho\@ucw.cz";
245 if ($debug || $reply eq "") {
249 open(MAIL, ">&STDOUT") || die;
250 print MAIL "SENDMAIL $sendmail_opts\n";
251 } elsif (!open MAIL, "|/usr/sbin/sendmail $sendmail_opts") {
252 print STDERR "Unable to ask mailer for replying!!!\n";
253 print LOG "Unable to ask mailer for replying!!!\n";
256 print MAIL "From: The PCI ID Robot <vorner+iderr\@ucw.cz>\n";
257 print MAIL "To: $reply\n";
258 print MAIL "Subject: IDbot: $reason\n";
259 print MAIL "In-Reply-To: $msgid\n" if $msgid ne "";
262 This is an automatic reply from the PCI ID Mail Robot. If you want to contact
263 the administrator of the robot, please write to pciids-devel\@lists.sourceforge.net.
267 if ($reason eq "OK") {
268 print MAIL "Your submission has been accepted.\n\n";
271 Your submission has been rejected. Please make sure that the mail you've sent
272 is a unified diff (output of diff -u) against the latest pci.ids file, that
273 the diff is not reversed and that your mailer doesn't damage long lines
274 and doesn't change tabs to spaces or vice versa. Also, we don't accept MIME
275 attachments in base64 encoding yet. If you are unable to fix your problems,
276 just use the Web interface at http://pciids.sf.net/ or submit the patch
277 to pciids-devel\@lists.sourceforge.net where it will be processed manually.
278 See the log below for additional information.
283 print MAIL "--- Processing Log ---\n\n";
284 if (open L, "<log") {
285 while (<L>) { print MAIL "$_"; }
288 print MAIL "\n--- End ---\n";
295 s/([^a-zA-Z0-9.!*,_-])/'%'.unpack('H2',$1)/ge;