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