]> git.donarmstrong.com Git - debbugs.git/blob - scripts/process.in
[project @ 2003-05-27 02:39:17 by cjwatson]
[debbugs.git] / scripts / process.in
1 #!/usr/bin/perl
2 # $Id: process.in,v 1.71 2003/05/27 02:39:17 cjwatson Exp $
3 #
4 # Usage: process nn
5 # Temps:  incoming/Pnn
6
7 use POSIX qw(strftime tzset);
8 $ENV{"TZ"} = 'UTC';
9 tzset();
10
11 use Mail::Address;
12 use MIME::Parser;
13
14 $config_path = '/etc/debbugs';
15 $lib_path = '/usr/lib/debbugs';
16
17 require "$config_path/config";
18 require "$lib_path/errorlib";
19 $ENV{'PATH'} = $lib_path.':'.$ENV{'PATH'};
20
21 chdir( "$gSpoolDir" ) || die "chdir spool: $!\n";
22
23 #open(DEBUG,"> /tmp/debbugs.debug");
24 umask(002);
25 open DEBUG, ">/dev/null";
26
27 defined( $intdate= time ) || &quit( "failed to get time: $!" );
28
29 $_=shift;
30 m/^([BMQFDU])(\d*)\.\d+$/ || &quit("bad argument");
31 $codeletter= $1;
32 $tryref= length($2) ? $2+0 : -1;
33 $nn= $_;
34
35 if (!rename("incoming/G$nn","incoming/P$nn")) 
36 {
37     $_=$!.'';  m/no such file or directory/i && exit 0;
38     &quit("renaming to lock: $!");
39 }
40
41 $baddress= 'submit' if $codeletter eq 'B';
42 $baddress= 'maintonly' if $codeletter eq 'M';
43 $baddress= 'quiet' if $codeletter eq 'Q';
44 $baddress= 'forwarded' if $codeletter eq 'F';
45 $baddress= 'done' if $codeletter eq 'D';
46 $baddress= 'submitter' if $codeletter eq 'U';
47 $baddress || &quit("bad codeletter $codeletter");
48 $baddressroot= $baddress;
49 $baddress= "$tryref-$baddress" if $tryref>=0;
50
51 open(M,"incoming/P$nn");
52 @log=<M>;
53 close(M);
54
55 @msg=@log;
56 chomp @msg;
57
58 print DEBUG "###\n",join("##\n",@msg),"\n###\n";
59
60 $tdate = strftime "%a, %d %h %Y %T UTC", localtime;
61 $fwd= <<END;
62 Received: via spool by $baddress\@$gEmailDomain id=$nn
63           (code $codeletter ref $tryref); $tdate
64 END
65
66 # header and decoded body respectively
67 my (@headerlines, @bodylines);
68
69 my $parser = new MIME::Parser;
70 mkdir "$gSpoolDir/mime.tmp", 0777;
71 $parser->output_under("$gSpoolDir/mime.tmp");
72 my $entity = eval { $parser->parse_data(join('',@log)) };
73
74 if ($entity and $entity->head->tags) {
75     @headerlines = @{$entity->head->header};
76     chomp @headerlines;
77
78     my $entity_body = getmailbody($entity);
79     @bodylines = $entity_body ? $entity_body->as_lines() : ();
80     chomp @bodylines;
81
82     # set $i to beginning of encoded body data, so we can dump it out
83     # verbatim later
84     $i = 0;
85     ++$i while $msg[$i] =~ /./;
86 } else {
87     # Legacy pre-MIME code, kept around in case MIME::Parser fails.
88     for ($i = 0; $i <= $#msg; $i++) {
89         $_ = $msg[$i];
90         last unless length($_);
91         while ($msg[$i+1] =~ m/^\s/) {
92             $i++;
93             $_ .= "\n".$msg[$i];
94         }
95         push @headerlines, $_;
96     }
97
98     @bodylines = @msg[$i..$#msg];
99 }
100
101 for my $hdr (@headerlines) {
102     $_ = $hdr;
103     s/\n\s/ /g;
104     &finish if m/^x-loop: (\S+)$/i && $1 eq "$gMaintainerEmail";
105     my $ins = !m/^subject:/i && !m/^reply-to:/i && !m/^return-path:/i
106            && !m/^From / && !m/^X-Debbugs-CC:/i;
107     $fwd .= $hdr."\n" if $ins;
108     # print DEBUG ">$_<\n";
109     if (s/^(\S+):\s*//) {
110         my $v = lc $1;
111         print DEBUG ">$v=$_<\n";
112         $header{$v} = $_;
113     } else {
114         print DEBUG "!>$_<\n";
115     }
116 }
117
118 # remove blank lines
119 shift @bodylines while @bodylines and $bodylines[0] !~ /\S/;
120
121 # Strip off RFC2440-style PGP clearsigning.
122 if (@bodylines and $bodylines[0] =~ /^-----BEGIN PGP SIGNED/) {
123     shift @bodylines while @bodylines and length $bodylines[0];
124     shift @bodylines while @bodylines and $bodylines[0] !~ /\S/;
125     for my $findsig (0 .. $#bodylines) {
126         if ($bodylines[$findsig] =~ /^-----BEGIN PGP SIGNATURE/) {
127             $#bodylines = $findsig - 1;
128             last;
129         }
130     }
131     map { s/^- // } @bodylines;
132 }
133
134 # extract pseudo-headers
135 for my $phline (@bodylines)
136 {
137     last if $phline !~ m/^([\w]+):\s*(\S.*)/;
138     my ($fn, $fv) = ($1, $2);
139     $fv =~ s/\s*$//;
140     print DEBUG ">$fn|$fv|\n";
141     $fn = lc $fn;
142     $fv = lc $fv;
143     $pheader{$fn} = $fv;
144     print DEBUG ">$fn~$fv<\n";
145 }
146
147
148 $fwd .= join("\n",@msg[$i..$#msg]);
149
150 print DEBUG "***\n$fwd\n***\n";
151
152 if (defined $header{'resent-from'} && !defined $header{'from'}) {
153     $header{'from'} = $header{'resent-from'};
154 }
155 defined($header{'from'}) || &quit("no From header");
156 $replyto= defined($header{'reply-to'}) ? $header{'reply-to'} : $header{'from'};
157
158 $_= $replyto;
159 $_= "$2 <$1>" if m/^([^\<\> \t\n\(\)]+) \(([^\(\)\<\>]+)\)$/;
160 $replytocompare= $_;
161 print DEBUG "replytocompare >$replytocompare<\n";
162     
163 if (!defined($header{'subject'})) 
164 {
165         $brokenness.= <<END;
166
167 Your message did not contain a Subject field. They are recommended and
168 useful because the title of a $gBug is determined using this field.
169 Please remember to include a Subject field in your messages in future.
170 END
171
172 # RFC822 actually lists it as an `optional-field'.
173
174     $subject= '(no subject)';
175 } else { 
176     $subject= $header{'subject'}; 
177 }
178
179 $ref=-1;
180 $subject =~ s/^Re:\s*//i; $_= $subject."\n";
181 if ($tryref < 0 && m/^Bug ?\#(\d+)\D/i) {
182     $tryref= $1+0; 
183 }
184
185 if ($tryref >= 0) 
186 {
187     ($bfound, $data)= &lockreadbugmerge($tryref);
188     if ($bfound) { 
189         $ref= $tryref; 
190     } else {
191         &htmllog("Reply","sent", $replyto,"Unknown problem report number <code>$tryref</code>.");
192         &sendmessage(<<END, '');
193 From: $gMaintainerEmail ($gProject $gBug Tracking System)
194 To: $replyto
195 Subject: Unknown problem report $gBug#$tryref ($subject)
196 Message-ID: <handler.x.$nn.unknown\@$gEmailDomain>
197 In-Reply-To: $header{'message-id'}
198 References: $header{'message-id'} $data->{msgid}
199 Precedence: bulk
200 X-$gProject-PR-Message: error
201
202 You sent a message to the $gBug tracking system which gave (in the
203 Subject line or encoded into the recipient at $gEmailDomain),
204 the number of a nonexistent $gBug report (#$tryref).
205
206 This may be because that $gBug report has been resolved for more than $gRemoveAge
207 days, and the record of it has been expunged, or because you mistyped
208 the $gBug report number.
209
210 Your message was dated $header{'date'} and was sent to
211 $baddress\@$gEmailDomain.  It had
212 Message-ID $header{'message-id'}
213 and Subject $subject.
214
215 It has been filed (under junk) but otherwise ignored.
216
217 Please consult your records to find the correct $gBug report number, or
218 contact me, the system administrator, for assistance.
219
220 $gMaintainer
221 (administrator, $gProject $gBugs database)
222
223 (NB: If you are a system administrator and have no idea what I am
224 talking about this indicates a serious mail system misconfiguration
225 somewhere.  Please contact me immediately.)
226
227 END
228         &appendlog;
229         &finish;
230     }
231 } else { 
232     &filelock('lock/-1'); 
233 }
234
235 if ($codeletter eq 'D' || $codeletter eq 'F') 
236 {
237     if ($replyto =~ m/$gBounceFroms/o ||
238         $header{'from'} =~ m/$gBounceFroms/o)
239     { 
240         &quit("bounce detected !  Mwaap! Mwaap!"); 
241     }
242     $markedby= $header{'from'} eq $replyto ? $replyto :
243                "$header{'from'} (reply to $replyto)";
244     if ($codeletter eq 'F') {
245         (&appendlog,&finish) if length($data->{forwarded});
246         $receivedat= "forwarded\@$gEmailDomain";
247         $markaswhat= 'forwarded';
248         $set_forwarded= $header{'to'};
249         if ( length( $gListDomain ) > 0 && length( $gFowardList ) > 0 ) {
250             $generalcc= "$gFowardList\@$gListDomain";
251         } else { 
252             $generalcc=''; 
253         }
254     } else {
255         (&appendlog,&finish) if length($data->{done});
256         $receivedat= "done\@$gEmailDomain";
257         $markaswhat= 'done';
258         $set_done= $header{'from'};
259         if ( length( $gListDomain ) > 0 && length( $gDoneList ) > 0 ) {
260             $generalcc= "$gDoneList\@$gListDomain";
261         } else { 
262             $generalcc=''; 
263         }
264     }
265     if ($ref<0) {
266         &htmllog("Warning","sent",$replyto,"Message ignored.");
267         &sendmessage(<<END, '');
268 From: $gMaintainerEmail ($gProject $gBug Tracking System)
269 To: $replyto
270 Subject: Message with no $gBug number ignored by $receivedat
271          ($subject)
272 Message-ID: <header.x.$nn.warnignore\@$gEmailDomain>
273 In-Reply-To: $header{'message-id'}
274 References: $header{'message-id'} $data->{msgid}
275 Precedence: bulk
276 X-$gProject-PR-Message: error
277
278 You sent a message to the $gProject $gBug tracking system old-style
279 unified mark as $markaswhat address ($receivedat),
280 without a recognisable $gBug number in the Subject.
281 Your message has been filed under junk but otherwise ignored.
282
283 If you don't know what I'm talking about then probably either:
284
285 (a) you unwittingly sent a message to done\@$gEmailDomain
286 because you replied to all recipients of the message a developer used
287 to mark a $gBug as done and you modified the Subject.  In this case,
288 please do not be alarmed.  To avoid confusion do not do it again, but
289 there is no need to apologise or mail anyone asking for an explanation.
290
291 (b) you are a system administrator, reading this because the $gBug 
292 tracking system is responding to a misdirected bounce message.  In this
293 case there is a serious mail system misconfiguration somewhere - please
294 contact me immediately.
295
296 Your message was dated $header{'date'} and had
297 message-id $header{'message-id'}
298 and subject $subject.
299
300 If you need any assistance or explanation please contact me.
301
302 $gMaintainer
303 (administrator, $gProject $gBugs database)
304
305 END
306         &appendlog;
307         &finish;
308     }
309
310     &checkmaintainers;
311
312     $noticeccval.= join(', ', grep($_ ne $replyto,@maintaddrs));
313     $noticeccval =~ s/\s+\n\s+/ /g; 
314     $noticeccval =~ s/^\s+/ /; $noticeccval =~ s/\s+$//;
315
316     $generalcc = join(', ', $generalcc, @addsrcaddrs);
317     $generalcc =~ s/\s+\n\s+/ /g; 
318     $generalcc =~ s/^\s+/ /; $generalcc =~ s/\s+$//;
319
320     if (length($noticeccval)) { $noticecc= "Cc: $noticeccval\n"; }
321     if (length($generalcc)) { $noticecc.= "Bcc: $generalcc\n"; }
322
323     @process= ($ref,split(/ /,$data->{mergedwith}));
324     $orgref= $ref;
325
326     for $ref (@process) {
327         if ($ref != $orgref) {
328             &unfilelock;
329             $data = &lockreadbug($ref)
330                 || die "huh ? $ref from $orgref out of @process";
331         }
332         $data->{done}= $set_done if defined($set_done);
333         $data->{forwarded}= $set_forwarded if defined($set_forwarded);
334         writebug($ref, $data);
335
336         my $hash = get_hashname($ref);
337         open(O,"db-h/$hash/$ref.report") || &quit("read original report: $!");
338         $x= join('',<O>); close(O);
339         if ($codeletter eq 'F') {
340             &htmllog("Reply","sent",$replyto,"You have marked $gBug as forwarded.");
341             &sendmessage(<<END."---------------------------------------\n".join( "\n", @msg ), '');
342 From: $gMaintainerEmail ($gProject $gBug Tracking System)
343 To: $replyto
344 ${noticecc}Subject: $gBug#$ref: marked as forwarded ($data->{subject})
345 Message-ID: <header.$ref.$nn.ackfwdd\@$gEmailDomain>
346 In-Reply-To: $header{'message-id'}
347 References: $header{'message-id'} $data->{msgid}
348 Precedence: bulk
349 X-$gProject-PR-Message: forwarded $ref
350 X-$gProject-PR-Package: $data->{package}
351 X-$gProject-PR-Keywords: $data->{keywords}
352
353 Your message dated $header{'date'}
354 with message-id $header{'message-id'}
355 has caused the $gProject $gBug report #$ref,
356 regarding $data->{subject}
357 to be marked as having been forwarded to the upstream software
358 author(s) $data->{forwarded}.
359
360 (NB: If you are a system administrator and have no idea what I am
361 talking about this indicates a serious mail system misconfiguration
362 somewhere.  Please contact me immediately.)
363
364 $gMaintainer
365 (administrator, $gProject $gBugs database)
366
367 END
368
369         } else {
370             &htmllog("Reply","sent",$replyto,"You have taken responsibility.");
371             &sendmessage(<<END."--------------------------------------\n".$x."---------------------------------------\n".join( "\n", @msg ), '');
372 From: $gMaintainerEmail ($gProject $gBug Tracking System)
373 To: $replyto
374 ${noticecc}Subject: $gBug#$ref: marked as done ($data->{subject})
375 Message-ID: <handler.$ref.$nn.ackdone\@$gEmailDomain>
376 In-Reply-To: $header{'message-id'}
377 References: $header{'message-id'} $data->{msgid}
378 Precedence: bulk
379 X-$gProject-PR-Message: closed $ref
380 X-$gProject-PR-Package: $data->{package}
381 X-$gProject-PR-Keywords: $data->{keywords}
382
383 Your message dated $header{'date'}
384 with message-id $header{'message-id'}
385 and subject line $subject
386 has caused the attached $gBug report to be marked as done.
387
388 This means that you claim that the problem has been dealt with.
389 If this is not the case it is now your responsibility to reopen the
390 $gBug report if necessary, and/or fix the problem forthwith.
391
392 (NB: If you are a system administrator and have no idea what I am
393 talking about this indicates a serious mail system misconfiguration
394 somewhere.  Please contact me immediately.)
395
396 $gMaintainer
397 (administrator, $gProject $gBugs database)
398
399 END
400             &htmllog("Notification","sent",$data->{originator}, 
401                 "$gBug acknowledged by developer.");
402             &sendmessage(<<END.join("\n",@msg),'');
403 From: $gMaintainerEmail ($gProject $gBug Tracking System)
404 To: $data->{originator}
405 Subject: $gBug#$ref acknowledged by developer
406          ($header{'subject'})
407 Message-ID: <handler.$ref.$nn.notifdone\@$gEmailDomain>
408 In-Reply-To: $data->{msgid}
409 References: $header{'message-id'} $data->{msgid}
410 X-$gProject-PR-Message: they-closed $ref
411 X-$gProject-PR-Package: $data->{package}
412 X-$gProject-PR-Keywords: $data->{keywords}
413 Reply-To: $ref\@$gEmailDomain
414
415 This is an automatic notification regarding your $gBug report
416 #$ref: $data->{subject},
417 which was filed against the $data->{package} package.
418
419 It has been closed by one of the developers, namely
420 $markedby.
421
422 Their explanation is attached below.  If this explanation is
423 unsatisfactory and you have not received a better one in a separate
424 message then please contact the developer, by replying to this email.
425
426 $gMaintainer
427 (administrator, $gProject $gBugs database)
428
429 END
430         }
431         &appendlog;
432     }
433     &finish;
434 }
435
436 if ($ref<0) {
437     if ($codeletter eq 'U') {
438         &htmllog("Warning","sent",$replyto,"Message not forwarded.");
439         &sendmessage(<<END, '');
440 From: $gMaintainerEmail ($gProject $gBug Tracking System)
441 To: $replyto
442 Subject: Message with no $gBug number cannot be sent to submitter !
443          ($subject)
444 Message-ID: <handler.x.$nn.nonumnosub\@$gEmailDomain>
445 In-Reply-To: $header{'message-id'}
446 References: $header{'message-id'} $data->{msgid}
447 Precedence: bulk
448 X-$gProject-PR-Message: error
449
450 You sent a message to the $gProject $gBug tracking system send to $gBug 
451 report submitter address $baddress\@$gEmailDomain, without a
452 recognisable $gBug number in the Subject.  Your message has been filed
453 under junk but otherwise ignored.
454
455 If you don't know what I'm talking about then probably either:
456
457 (a) you unwittingly sent a message to $baddress\@$gEmailDomain
458 because you replied to all recipients of the message a developer sent
459 to a $gBug's submitter and you modified the Subject.  In this case,
460 please do not be alarmed.  To avoid confusion do not do it again, but
461 there is no need to apologise or mail anyone asking for an
462 explanation.
463
464 (b) you are a system administrator, reading this because the $gBug 
465 tracking system is responding to a misdirected bounce message.  In this
466 case there is a serious mail system misconfiguration somewhere - please
467 contact me immediately.
468
469 Your message was dated $header{'date'} and had
470 message-id $header{'message-id'}
471 and subject $subject.
472
473 If you need any assistance or explanation please contact me.
474
475 $gMaintainer
476 (administrator, $gProject $gBugs database)
477
478 END
479         &appendlog;
480         &finish;
481     }
482     if (!defined($pheader{'package'})) {
483         &htmllog("Warning","sent",$replyto,"Message not forwarded.");
484         &sendmessage(<<END."---------------------------------------------------------------------------\n".join("\n", @msg), '');
485 From: $gMaintainerEmail ($gProject $gBug Tracking System)
486 To: $replyto
487 Subject: Message with no Package: tag cannot be processed!
488          ($subject)
489 Message-ID: <handler.x.$nn.nonumnosub\@$gEmailDomain>
490 In-Reply-To: $header{'message-id'}
491 References: $header{'message-id'} $data->{msgid}
492 Precedence: bulk
493 X-$gProject-PR-Message: error
494
495 Your message didn't have a Package: line at the start (in the
496 pseudo-header following the real mail header), or didn't have a
497 pseudo-header at all.
498
499 This makes it much harder for us to categorise and deal with your
500 problem report. Please _resubmit_ your report to $baddress\@$gEmailDomain
501 and tell us which package the report is on. For help, check out
502 http://$gWebDomain/Reporting$gHTMLSuffix.
503
504 Your message was dated $header{'date'} and had
505 message-id $header{'message-id'}
506 and subject $subject.
507 The complete text of it is attached to this message.
508
509 If you need any assistance or explanation please contact me.
510
511 $gMaintainer
512 (administrator, $gProject $gBugs database)
513
514 END
515         &appendlog;
516         &finish;
517     } else {
518         $data->{package}= $pheader{'package'}; 
519     }
520
521     $data->{versions}= '';
522     if (defined($pheader{'version'})) {
523         $data->{versions} = $pheader{'version'};
524         $data->{versions} =~ s/\s+/ /;
525         # BUG: need to bounce unknown versions back to submitter here
526     }
527
528     $data->{fixed_versions}= '';
529     if (defined($pheader{'fixed-in-version'})) {
530         $data->{fixed_versions} = $pheader{'fixed-in-version'};
531         $data->{fixed_versions} =~ s/\s+/ /;
532     }
533
534     $data->{keywords}= '';
535     if (defined($pheader{'keywords'})) {
536         $data->{keywords}= $pheader{'keywords'};
537     } elsif (defined($pheader{'tags'})) {
538         $data->{keywords}= $pheader{'tags'};
539     }
540     if (length($data->{keywords})) {
541         my @kws;
542         my %gkws = map { ($_, 1) } @gTags;
543         foreach my $kw (sort split(/[,\s]+/, lc($data->{keywords}))) {
544             push @kws, $kw if (defined $gkws{$kw});
545         }
546         $data->{keywords} = join(" ", @kws);
547     }
548     $data->{severity}= '';
549     if (defined($pheader{'severity'}) || defined($pheader{'priority'})) {
550         $data->{severity}= $pheader{'severity'};
551         $data->{severity}= $pheader{'priority'} unless ($data->{severity});
552         $data->{severity} =~ s/^\s*(.+)\s*$/$1/;
553
554         if (!grep($_ eq $data->{severity}, @severities, "$gDefaultSeverity")) {
555             $brokenness.= <<END;
556
557 Your message specified a Severity: in the pseudo-header, but
558 the severity value $data->{severity} was not recognised.
559 The default severity $gDefaultSeverity is being used instead.
560 The recognised values are: $gShowSeverities.
561 END
562 # if we use @gSeverityList array in the above line, perl -c gives:
563 # In string, @gSeverityList now must be written as \@gSeverityList at
564 #          process line 452, near "$gDefaultSeverity is being used instead.
565             $data->{severity}= '';
566         }
567     }
568     &filelock("nextnumber.lock");
569     open(N,"nextnumber") || &quit("nextnumber: read: $!");
570     $v=<N>; $v =~ s/\n$// || &quit("nextnumber bad format");
571     $ref= $v+0;  $v += 1;  $newref=1;
572     &overwrite('nextnumber', "$v\n");
573     &unfilelock;
574     my $hash = get_hashname($ref);
575     &overwrite("db-h/$hash/$ref.log",'');
576     $data->{originator} = $replyto;
577     $data->{date} = $intdate;
578     $data->{subject} = $subject;
579     $data->{msgid} = $header{'message-id'};
580     writebug($ref, $data);
581     &overwrite("db-h/$hash/$ref.report",
582                join("\n",@msg)."\n");
583 }
584
585 &checkmaintainers;
586
587 print DEBUG "maintainers >@maintaddrs<\n";
588
589 $orgsender= defined($header{'sender'}) ? "Original-Sender: $header{'sender'}\n" : '';
590 $newsubject= $subject;  $newsubject =~ s/^$gBug#$ref:*\s*//;
591
592 $xcchdr= $header{ 'x-debbugs-cc' };
593 if ($xcchdr =~ m/\S/) {
594     push(@resentccs,$xcchdr);
595     $resentccexplain.= <<END;
596
597 As you requested using X-Debbugs-CC, your message was also forwarded to
598    $xcchdr
599 (after having been given a $gBug report number, if it did not have one).
600 END
601 }
602
603 if (@maintaddrs && ($codeletter eq 'B' || $codeletter eq 'M')) {
604     push(@resentccs,@maintaddrs);
605     $resentccexplain.= <<END." ".join("\n ",@maintaddrs)."\n";
606
607 Your message has been sent to the package maintainer(s):
608 END
609 }
610
611 @bccs = @addsrcaddrs;
612
613 $veryquiet= $codeletter eq 'Q';
614 if ($codeletter eq 'M' && !@maintaddrs) {
615     $veryquiet= 1;
616     $brokenness.= <<END;
617
618 You requested that the message be sent to the package maintainer(s)
619 but either the $gBug report is not associated with any package (probably
620 because of a missing Package pseudo-header field in the original $gBug
621 report), or the package(s) specified do not have any maintainer(s).
622
623 Your message has *not* been sent to any package maintainers; it has
624 merely been filed in the $gBug tracking system.  If you require assistance
625 please contact $gMaintainerEmail quoting the $gBug number $ref.
626 END
627 }
628
629 $resentccval.= join(', ',@resentccs);
630 $resentccval =~ s/\s+\n\s+/ /g; $resentccval =~ s/^\s+/ /; $resentccval =~ s/\s+$//;
631 if (length($resentccval)) { 
632     $resentcc= "Resent-CC: $resentccval\n"; 
633 }
634
635 if ($codeletter eq 'U') {
636     &htmllog("Message", "sent on", $data->{originator}, "$gBug#$ref.");
637     &sendmessage(<<END,[$data->{originator},@resentccs],[@bccs]);
638 Subject: $gBug#$ref: $newsubject
639 Reply-To: $replyto, $ref-quiet\@$gEmailDomain
640 ${orgsender}Resent-To: $data->{originator}
641 ${resentcc}Resent-Date: $tdate
642 Resent-Message-ID: <handler.$ref.$nn\@$gEmailDomain>
643 Resent-Sender: $gMaintainerEmail
644 X-$gProject-PR-Message: report $ref
645 X-$gProject-PR-Package: $data->{package}
646 X-$gProject-PR-Keywords: $data->{keywords}
647 $fwd
648 END
649 } elsif ($codeletter eq 'B') {
650     &htmllog($newref ? "Report" : "Information", "forwarded",
651              join(', ',"$gSubmitList\@$gListDomain",@resentccs),
652              "<code>$gBug#$ref</code>".
653              (length($data->{package})? "; Package <code>".&sani($data->{package})."</code>" : '').
654              ".");
655     &sendmessage(<<END,["$gSubmitList\@$gListDomain",@resentccs],[@bccs]);
656 Subject: $gBug#$ref: $newsubject
657 Reply-To: $replyto, $ref\@$gEmailDomain
658 Resent-From: $header{'from'}
659 ${orgsender}Resent-To: $gSubmitList\@$gListDomain
660 ${resentcc}Resent-Date: $tdate
661 Resent-Message-ID: <handler.$ref.$nn\@$gEmailDomain>
662 Resent-Sender: $gMaintainerEmail
663 X-$gProject-PR-Message: report $ref
664 X-$gProject-PR-Package: $data->{package}
665 X-$gProject-PR-Keywords: $data->{keywords}
666 $fwd
667 END
668 } elsif (@resentccs or @bccs) {
669     # D and F done far earlier; B just done - so this must be M or Q
670     # We preserve whichever it was in the Reply-To (possibly adding
671     # the $gBug#).
672     if (@resentccs) {
673         &htmllog($newref ? "Report" : "Information", "forwarded",
674                  $resentccval,
675                  "<code>$gBug#$ref</code>".
676                  (length($data->{package}) ? "; Package <code>".&sani($data->{package})."</code>" : '').
677                  ".");
678     } else {
679         &htmllog($newref ? "Report" : "Information", "stored",
680                  "",
681                  "<code>$gBug#$ref</code>".
682                  (length($data->{package}) ? "; Package <code>".&sani($data->{package})."</code>" : '').
683                  ".");
684     }
685     &sendmessage(<<END,[@resentccs],[@bccs]);
686 Subject: $gBug#$ref: $newsubject
687 Reply-To: $replyto, $ref-$baddressroot\@$gEmailDomain
688 Resent-From: $header{'from'}
689 ${orgsender}Resent-To: $resentccval
690 Resent-Date: $tdate
691 Resent-Message-ID: <handler.$ref.$nn\@$gEmailDomain>
692 Resent-Sender: $gMaintainerEmail
693 X-$gProject-PR-Message: report $ref
694 X-$gProject-PR-Package: $data->{package}
695 X-$gProject-PR-Keywords: $data->{keywords}
696 $fwd
697 END
698 }
699
700 $htmlbreak= length($brokenness) ? "<p>\n".&sani($brokenness)."\n<p>\n" : '';
701 $htmlbreak =~ s/\n\n/\n<P>\n\n/g;
702 if (length($resentccval)) {
703     $htmlbreak = "  Copy sent to <code>".&sani($resentccval)."</code>.".
704         $htmlbreak;
705 }
706 if ($newref) {
707     &htmllog("Acknowledgement","sent",$replyto,
708              ($veryquiet ?
709               "New $gBug report received and filed, but not forwarded." :
710               "New $gBug report received and forwarded."). $htmlbreak);
711     &sendmessage($veryquiet ? <<END : $codeletter eq 'M' ? <<END : <<END,'');
712 From: $gMaintainerEmail ($gProject $gBug Tracking System)
713 To: $replyto
714 Subject: $gBug#$ref: Acknowledgement of QUIET report
715          ($subject)
716 Message-ID: <handler.$ref.$nn.ackquiet\@$gEmailDomain>
717 In-Reply-To: $header{'message-id'}
718 References: $header{'message-id'}
719 Precedence: bulk
720 X-$gProject-PR-Message: ack-quiet $ref
721 X-$gProject-PR-Package: $data->{package}
722 X-$gProject-PR-Keywords: $data->{keywords}
723 Reply-To: $ref-quiet\@$gEmailDomain
724
725 Thank you for the problem report you have sent regarding $gProject.
726 This is an automatically generated reply, to let you know your message
727 has been received.  It has not been forwarded to the developers or
728 their mailing list; you should ensure that the developers are aware of
729 the problem you have entered into the system - preferably quoting the
730 $gBug reference number, #$ref.
731 $resentccexplain
732 If you wish to submit further information on your problem, please send it
733 to $ref-$baddressroot\@$gEmailDomain (and *not*
734 to $baddress\@$gEmailDomain).
735
736 Please do not reply to the address at the top of this message,
737 unless you wish to report a problem with the $gBug-tracking system.
738 $brokenness
739 $gMaintainer
740 (administrator, $gProject $gBugs database)
741 END
742 From: $gMaintainerEmail ($gProject $gBug Tracking System)
743 To: $replyto
744 Subject: $gBug#$ref: Acknowledgement of maintainer-only report
745          ($subject)
746 Message-ID: <handler.$ref.$nn.ackmaint\@$gEmailDomain>
747 In-Reply-To: $header{'message-id'}
748 References: $header{'message-id'}
749 Precedence: bulk
750 X-$gProject-PR-Message: ack-maintonly $ref
751 X-$gProject-PR-Package: $data->{package}
752 X-$gProject-PR-Keywords: $data->{keywords}
753 Reply-To: $ref-maintonly\@$gEmailDomain
754
755 Thank you for the problem report you have sent regarding $gProject.
756 This is an automatically generated reply, to let you know your message has
757 been received.  It is being forwarded to the developers (but not the mailing
758 list, as you requested) for their attention; they will reply in due course.
759 $resentccexplain
760 If you wish to submit further information on your problem, please send
761 it to $ref-$baddressroot\@$gEmailDomain (and *not*
762 to $baddress\@$gEmailDomain).
763
764 Please do not reply to the address at the top of this message,
765 unless you wish to report a problem with the $gBug-tracking system.
766 $brokenness
767 $gMaintainer
768 (administrator, $gProject $gBugs database)
769 END
770 From: $gMaintainerEmail ($gProject $gBug Tracking System)
771 To: $replyto
772 Subject: $gBug#$ref: Acknowledgement ($subject)
773 Message-ID: <handler.$ref.$nn.ack\@$gEmailDomain>
774 In-Reply-To: $header{'message-id'}
775 References: $header{'message-id'}
776 Precedence: bulk
777 X-$gProject-PR-Message: ack $ref
778 X-$gProject-PR-Package: $data->{package}
779 X-$gProject-PR-Keywords: $data->{keywords}
780 Reply-To: $ref\@$gEmailDomain
781
782 Thank you for the problem report you have sent regarding $gProject.
783 This is an automatically generated reply, to let you know your message has
784 been received.  It is being forwarded to the developers mailing list for
785 their attention; they will reply in due course.
786 $resentccexplain
787 If you wish to submit further information on your problem, please send
788 it to $ref\@$gEmailDomain (and *not* to
789 $baddress\@$gEmailDomain).
790
791 Please do not reply to the address at the top of this message,
792 unless you wish to report a problem with the $gBug-tracking system.
793 $brokenness
794 $gMaintainer
795 (administrator, $gProject $gBugs database)
796 END
797 } elsif ($codeletter ne 'U' and
798          $header{'precedence'} !~ /\b(?:bulk|junk|list)\b/) {
799     &htmllog("Acknowledgement","sent",$replyto,
800              ($veryquiet ? "Extra info received and filed, but not forwarded." :
801               $codeletter eq 'M' ? "Extra info received and forwarded to maintainer." :
802               "Extra info received and forwarded to list."). $htmlbreak);
803     &sendmessage($veryquiet ? <<END : $codeletter eq 'M' ? <<END : <<END,'');
804 From: $gMaintainerEmail ($gProject $gBug Tracking System)
805 To: $replyto
806 Subject: $gBug#$ref: Info received and FILED only
807          (was $subject)
808 Message-ID: <handler.$ref.$nn.ackinfoquiet\@$gEmailDomain>
809 In-Reply-To: $header{'message-id'}
810 References: $header{'message-id'}
811 Precedence: bulk
812 X-$gProject-PR-Message: ack-info-quiet $ref
813 X-$gProject-PR-Package: $data->{package}
814 X-$gProject-PR-Keywords: $data->{keywords}
815 Reply-To: $ref-quiet\@$gEmailDomain
816
817 Thank you for the additional information you have supplied regarding
818 this problem report.  It has NOT been forwarded to the developers, but
819 will accompany the original report in the $gBug tracking system.  Please
820 ensure that you yourself have sent a copy of the additional
821 information to any relevant developers or mailing lists.
822 $resentccexplain
823 If you wish to continue to submit further information on your problem,
824 please send it to $ref-$baddressroot\@$gEmailDomain, as before.
825
826 Please do not reply to the address at the top of this message,
827 unless you wish to report a problem with the $gBug-tracking system.
828 $brokenness
829 $gMaintainer
830 (administrator, $gProject $gBugs database)
831 END
832 From: $gMaintainerEmail ($gProject $gBug Tracking System)
833 To: $replyto
834 Subject: $gBug#$ref: Info received for maintainer only
835          (was $subject)
836 Message-ID: <handler.$ref.$nn.ackinfomaint\@$gEmailDomain>
837 In-Reply-To: $header{'message-id'}
838 References: $header{'message-id'}
839 Precedence: bulk
840 X-$gProject-PR-Message: ack-info-maintonly $ref
841 X-$gProject-PR-Package: $data->{package}
842 X-$gProject-PR-Keywords: $data->{keywords}
843 Reply-To: $ref-maintonly\@$gEmailDomain
844
845 Thank you for the additional information you have supplied regarding
846 this problem report.  It has been forwarded to the developer(s) (but
847 not to the mailing list) to accompany the original report.
848 $resentccexplain
849 If you wish to continue to submit further information on your problem,
850 please send it to $ref-$baddressroot\@$gEmailDomain, as before.
851
852 Please do not reply to the address at the top of this message,
853 unless you wish to report a problem with the $gBug-tracking system.
854 $brokenness
855 $gMaintainer
856 (administrator, $gProject $gBugs database)
857 END
858 From: $gMaintainerEmail ($gProject $gBug Tracking System)
859 To: $replyto
860 Subject: $gBug#$ref: Info received (was $subject)
861 Message-ID: <handler.$ref.$nn.ackinfo\@$gEmailDomain>
862 In-Reply-To: $header{'message-id'}
863 References: $header{'message-id'}
864 Precedence: bulk
865 X-$gProject-PR-Message: ack-info $ref
866 X-$gProject-PR-Package: $data->{package}
867 X-$gProject-PR-Keywords: $data->{keywords}
868 Disabled-Doogie-Reply-To: $ref\@$gEmailDomain
869
870 Thank you for the additional information you have supplied regarding
871 this problem report.  It has been forwarded to the developer(s) and
872 to the developers mailing list to accompany the original report.
873 $resentccexplain
874 If you wish to continue to submit further information on your problem,
875 please send it to $ref\@$gEmailDomain, as before.
876
877 Please do not reply to the address at the top of this message,
878 unless you wish to report a problem with the $gBug-tracking system.
879 $brokenness
880 $gMaintainer
881 (administrator, $gProject $gBugs database)
882 END
883 }
884
885 &appendlog;
886 &finish;
887
888 sub overwrite {
889     local ($f,$v) = @_;
890     open(NEW,">$f.new") || &quit("$f.new: create: $!");
891     print(NEW "$v") || &quit("$f.new: write: $!");
892     close(NEW) || &quit("$f.new: close: $!");
893     rename("$f.new","$f") || &quit("rename $f.new to $f: $!");
894 }
895
896 sub appendlog {
897     my $hash = get_hashname($ref);
898     if (!open(AP,">>db-h/$hash/$ref.log")) {
899         print DEBUG "failed open log<\n";
900         print DEBUG "failed open log err $!<\n";
901         &quit("opening db-h/$hash/$ref.log (li): $!");
902     }
903     print(AP "\7\n",@{escapelog(@log)},"\n\3\n") || &quit("writing db-h/$hash/$ref.log (li): $!");
904     close(AP) || &quit("closing db-h/$hash/$ref.log (li): $!");
905 }
906
907 sub finish {
908     utime(time,time,"db");
909     local ($u);
910     while ($u= $cleanups[$#cleanups]) { &$u; }
911     unlink("incoming/P$nn") || &quit("unlinking incoming/P$nn: $!");
912     exit $_[0];
913 }
914
915 &quit("wot no exit");
916
917 sub chldhandle { $chldexit = 'yes'; }
918
919 sub htmllog {
920     local ($whatobj,$whatverb,$where,$desc) = @_;
921     my $hash = get_hashname($ref);
922     open(AP,">>db-h/$hash/$ref.log") || &quit("opening db-h/$hash/$ref.log (lh): $!");
923     print(AP
924           "\6\n".
925           "<strong>$whatobj $whatverb</strong>".
926           ($where eq '' ? "" : " to <code>".&sani($where)."</code>").
927           ":<br>\n". $desc.
928           "\n\3\n") || &quit("writing db-h/$hash/$ref.log (lh): $!");
929     close(AP) || &quit("closing db-h/$hash/$ref.log (lh): $!");
930 }    
931
932 sub get_addresses {
933         return
934                 map { $_->address() }
935                 map { Mail::Address->parse($_) } @_;
936 }
937
938 sub stripbccs {
939     my $msg = shift;
940     my $ret = '';
941     my $bcc = 0;
942     while ($msg =~ s/(.*\n)//) {
943         local $_ = $1;
944         if (/^$/) {
945             $ret .= $_;
946             last;
947         }
948         if ($bcc) {
949             # strip continuation lines too
950             next if /^\s/;
951             $bcc = 0;
952         }
953         if (/^Bcc:/i) {
954             $bcc = 1;
955         } else {
956             $ret .= $_;
957         }
958     }
959     return $ret . $msg;
960 }
961
962 sub sendmessage {
963     local ($msg,$recips,$bcc) = @_;
964     if ((!ref($recips) && $recips eq '') || @$recips == 0) {
965         $recips = ['-t'];
966     }
967     $msg = "X-Loop: $gMaintainerEmail\n" . $msg;
968
969     my $hash = get_hashname($ref);
970     #save email to the log
971     open(AP,">>db-h/$hash/$ref.log") || &quit("opening db-h/$hash/$ref.log (lo): $!");
972     print(AP "\2\n",join("\4",@$recips),"\n\5\n",
973           @{escapelog(stripbccs($msg))},"\n\3\n") ||
974         &quit("writing db-h/$hash/$ref.log (lo): $!");
975     close(AP) || &quit("closing db-h/$hash/$ref.log (lo): $!");
976
977     if (ref($bcc)) {
978         shift @$recips if $recips->[0] eq '-t';
979         push @$recips, @$bcc;
980     }
981
982 #if debugging.. save email to a log
983 #    open AP, ">>debug";
984 #    print AP join( '|', @$recips )."\n>>";
985 #    print AP get_addresses( @$recips );
986 #    print AP "<<\n".$msg;
987 #    print AP "\n--------------------------------------------------------\n";
988 #    close AP;
989
990     #start mailing
991     $_ = '';
992     $SIG{'CHLD'}='chldhandle';
993     #print DEBUG "mailing sigchild set up<\n";
994     $chldexit = 'no';
995     $c= open(U,"-|");
996     #print DEBUG "mailing opened pipe fork<\n";
997     defined($c) || die $!;
998     #print DEBUG "mailing opened pipe fork ok $c<\n";
999     if (!$c) { # ie, we are in the child process
1000         #print DEBUG "mailing child<\n";
1001         unless (open(STDERR,">&STDOUT")) {
1002             #print DEBUG "mailing child opened stderr<\n";
1003             print STDOUT "redirect stderr: $!\n";
1004             #print DEBUG "mailing child opened stderr fail<\n";
1005             exit 1;
1006             #print DEBUG "mailing child opened stderr fail exit !?<\n";
1007         }
1008         #print DEBUG "mailing child opened stderr ok<\n";
1009         $c= open(D,"|-");
1010         #print DEBUG "mailing child forked again<\n";
1011         defined($c) || die $!;
1012         #print DEBUG "mailing child forked again ok $c<\n";
1013         if (!$c) { # ie, we are the child process
1014             #print DEBUG "mailing grandchild<\n";
1015             exec '/usr/lib/sendmail','-f'."$gMaintainerEmail",'-odq','-oem','-oi',get_addresses(@$recips);
1016             #print DEBUG "mailing grandchild exec failed<\n";
1017             die $!;
1018             #print DEBUG "mailing grandchild died !?<\n";
1019         }
1020         #print DEBUG "mailing child not grandchild<\n";
1021         print(D $msg) || die $!;
1022         #print DEBUG "mailing child printed msg<\n";
1023         close(D);
1024         #print DEBUG "mailing child closed pipe<\n";
1025         die "\n*** command returned exit status $?\n" if $?;
1026         #print DEBUG "mailing child exit status ok<\n";
1027         exit 0;
1028         #print DEBUG "mailing child exited ?!<\n";
1029     }
1030     #print DEBUG "mailing parent<\n";
1031     $results='';
1032     #print DEBUG "mailing parent results emptied<\n";
1033     while( $chldexit eq 'no' ) { $results.= $_; }
1034     #print DEBUG "mailing parent results read >$results<\n";
1035     close(U);
1036     #print DEBUG "mailing parent results closed<\n";
1037     $results.= "\n*** child returned exit status $?\n" if $?;
1038     #print DEBUG "mailing parent exit status ok<\n";
1039     $SIG{'CHLD'}='DEFAULT';
1040     #print DEBUG "mailing parent sigchild default<\n";
1041     if (length($results)) { &quit("running sendmail: $results"); }
1042     #print DEBUG "mailing parent results ok<\n";
1043 }
1044
1045 sub checkmaintainers {
1046     return if $maintainerschecked++;
1047     return if !length($data->{package});
1048     open(MAINT,"$gMaintainerFile") || die &quit("maintainers open: $!");
1049     while (<MAINT>) {
1050         m/^\n$/ && next;
1051         m/^\s*$/ && next;
1052         m/^(\S+)\s+(\S.*\S)\s*\n$/ || &quit("maintainers bogus \`$_'");
1053         $a= $1; $b= $2; $a =~ y/A-Z/a-z/;
1054         $maintainerof{$1}= $2;
1055     }
1056     close(MAINT);
1057     open(MAINT,"$gMaintainerFileOverride") || die &quit("maintainers.override open: $!");
1058     while (<MAINT>) {
1059         m/^\n$/ && next;
1060         m/^\s*$/ && next;
1061         m/^(\S+)\s+(\S.*\S)\s*\n$/ || &quit("maintainers.override bogus \`$_'");
1062         $a= $1; $b= $2; $a =~ y/A-Z/a-z/;
1063         $maintainerof{$1}= $2;
1064     }
1065     close(MAINT);
1066     open(SOURCES,"$gPackageSource") || &quit("pkgsrc open: $!");
1067     while (<SOURCES>) {
1068         next unless m/^(\S+)\s+\S+\s+(\S.*\S)\s*$/;
1069         ($a,$b)=($1,$2);
1070         $a =~ y/A-Z/a-z/;
1071         $pkgsrc{$a} = $b;
1072     }
1073     close(SOURCES);
1074     $anymaintfound=0; $anymaintnotfound=0;
1075     for $p (split(m/[ \t?,()]+/,$data->{package})) {
1076         $p =~ y/A-Z/a-z/;
1077         if (defined $gSubscriptionDomain) {
1078             if (defined($pkgsrc{$p})) {
1079                 push @addsrcaddrs, "$pkgsrc{$p}\@$gSubscriptionDomain";
1080             } else {
1081                 push @addsrcaddrs, "$p\@$gSubscriptionDomain";
1082             }
1083         }
1084         if (defined($maintainerof{$p})) {
1085             print DEBUG "maintainer add >$p|$maintainerof{$p}<\n";
1086             $addmaint= $maintainerof{$p};
1087             push(@maintaddrs,$addmaint) unless
1088                 $addmaint eq $replyto || grep($_ eq $addmaint, @maintaddrs);
1089             $anymaintfound++;
1090         } else {
1091             print DEBUG "maintainer none >$p<\n";
1092             push(@maintaddrs,$gUnknownMaintainerEmail) unless $anymaintnotfound;
1093             $anymaintnotfound++;
1094             last;
1095         }
1096     }
1097 }