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