2 # $Id: process.in,v 1.109 2006/02/09 22:02:04 don Exp $
7 use POSIX qw(strftime);
10 use Debbugs::MIME qw(decode_rfc1522 create_mime_message);
11 use Debbugs::Mail qw(send_mail_message encode_headers);
12 use Debbugs::Packages qw(getpkgsrc);
13 use Debbugs::User qw(read_usertags write_usertags);
15 # TODO DLA; needs config reworking and errorlib reworking
19 use Debbugs::Config qw(:globals);
20 my $lib_path = $gLibPath;
22 require "$lib_path/errorlib";
23 $ENV{'PATH'} = $lib_path.':'.$ENV{'PATH'};
25 chdir( "$gSpoolDir" ) || die "chdir spool: $!\n";
27 #open(DEBUG,"> /tmp/debbugs.debug");
29 open DEBUG, ">/dev/null";
31 my $intdate = time or quit("failed to get time: $!");
34 m/^([BMQFDUL])(\d*)\.\d+$/ or quit("bad argument: $_");
36 my $tryref= length($2) ? $2 : -1;
39 if (!rename("incoming/G$nn","incoming/P$nn"))
41 $_=$!.''; m/no such file or directory/i && exit 0;
42 &quit("renaming to lock: $!");
45 my $baddress= 'submit' if $codeletter eq 'B';
46 $baddress= 'maintonly' if $codeletter eq 'M';
47 $baddress= 'quiet' if $codeletter eq 'Q';
48 $baddress= 'forwarded' if $codeletter eq 'F';
49 $baddress= 'done' if $codeletter eq 'D';
50 $baddress= 'submitter' if $codeletter eq 'U';
51 bug_list_forward($nn) if $codeletter eq 'L';
52 $baddress || &quit("bad codeletter $codeletter");
53 my $baddressroot= $baddress;
54 $baddress= "$tryref-$baddress" if $tryref>=0;
56 open(M,"incoming/P$nn");
63 print DEBUG "###\n",join("##\n",@msg),"\n###\n";
65 my $tdate = strftime "%a, %d %h %Y %T +0000", gmtime;
67 Received: via spool by $baddress\@$gEmailDomain id=$nn
68 (code $codeletter ref $tryref); $tdate
71 # header and decoded body respectively
72 my (@headerlines, @bodylines);
74 my $parser = new MIME::Parser;
75 mkdir "$gSpoolDir/mime.tmp", 0777;
76 $parser->output_under("$gSpoolDir/mime.tmp");
77 my $entity = eval { $parser->parse_data(join('',@log)) };
80 if ($entity and $entity->head->tags) {
81 @headerlines = @{$entity->head->header};
84 my $entity_body = getmailbody($entity);
85 @bodylines = $entity_body ? $entity_body->as_lines() : ();
88 # set $i to beginning of encoded body data, so we can dump it out
91 ++$i while $msg[$i] =~ /./;
93 # Legacy pre-MIME code, kept around in case MIME::Parser fails.
94 for ($i = 0; $i <= $#msg; $i++) {
96 last unless length($_);
97 while ($msg[$i+1] =~ m/^\s/) {
101 push @headerlines, $_;
104 @bodylines = @msg[$i..$#msg];
109 for my $hdr (@headerlines) {
110 $hdr = decode_rfc1522($hdr);
113 &finish if m/^x-loop: (\S+)$/i && $1 eq "$gMaintainerEmail";
114 my $ins = !m/^subject:/i && !m/^reply-to:/i && !m/^return-path:/i
115 && !m/^From / && !m/^X-Debbugs-/i;
116 $fwd .= $hdr."\n" if $ins;
117 # print DEBUG ">$_<\n";
118 if (s/^(\S+):\s*//) {
120 print DEBUG ">$v=$_<\n";
123 print DEBUG "!>$_<\n";
128 shift @bodylines while @bodylines and $bodylines[0] !~ /\S/;
130 # Strip off RFC2440-style PGP clearsigning.
131 if (@bodylines and $bodylines[0] =~ /^-----BEGIN PGP SIGNED/) {
132 shift @bodylines while @bodylines and length $bodylines[0];
133 shift @bodylines while @bodylines and $bodylines[0] !~ /\S/;
134 for my $findsig (0 .. $#bodylines) {
135 if ($bodylines[$findsig] =~ /^-----BEGIN PGP SIGNATURE/) {
136 $#bodylines = $findsig - 1;
140 map { s/^- // } @bodylines;
143 # extract pseudo-headers
144 for my $phline (@bodylines)
146 last if $phline !~ m/^([\w-]+):\s*(\S.*)/;
147 my ($fn, $fv) = ($1, $2);
149 print DEBUG ">$fn|$fv|\n";
151 # Don't lc owner or forwarded
152 $fv = lc $fv unless $fh =~ /^(?:owner|forwarded|usertags)$/;
154 print DEBUG ">$fn~$fv<\n";
157 # Allow pseudo headers to set x-debbugs- stuff [#179340]
158 for my $key (grep /X-Debbugs-.*/i, keys %pheader) {
159 $header{$key} = $pheader{$key} if not exists $header{$key};
162 $fwd .= join("\n",@msg[$i..$#msg]);
164 print DEBUG "***\n$fwd\n***\n";
166 if (defined $header{'resent-from'} && !defined $header{'from'}) {
167 $header{'from'} = $header{'resent-from'};
169 defined($header{'from'}) || &quit("no From header");
171 my $replyto = $header{'reply-to'};
172 $replyto = '' unless defined $replyto;
175 unless (length $replyto) {
176 $replyto = $header{'from'};
179 my $subject = '(no subject)';
180 if (!defined($header{'subject'}))
184 Your message did not contain a Subject field. They are recommended and
185 useful because the title of a $gBug is determined using this field.
186 Please remember to include a Subject field in your messages in future.
190 $subject= $header{'subject'};
194 $subject =~ s/^Re:\s*//i; $_= $subject."\n";
195 if ($tryref < 0 && m/^Bug ?\#(\d+)\D/i) {
201 ($bfound, $data)= &lockreadbugmerge($tryref);
205 &htmllog("Reply","sent", $replyto,"Unknown problem report number <code>$tryref</code>.");
206 my $archivenote = '';
208 $archivenote = <<END;
209 This may be because that $gBug report has been resolved for more than $gRemoveAge
210 days, and the record of it has been archived and made read-only, or
211 because you mistyped the $gBug report number.
215 &sendmessage(<<END, '');
216 From: $gMaintainerEmail ($gProject $gBug Tracking System)
218 Subject: Unknown problem report $gBug#$tryref ($subject)
219 Message-ID: <handler.x.$nn.unknown\@$gEmailDomain>
220 In-Reply-To: $header{'message-id'}
221 References: $header{'message-id'} $data->{msgid}
223 X-$gProject-PR-Message: error
225 You sent a message to the $gBug tracking system which gave (in the
226 Subject line or encoded into the recipient at $gEmailDomain),
227 the number of a nonexistent $gBug report (#$tryref).
229 ${archivenote}Your message was dated $header{'date'} and was sent to
230 $baddress\@$gEmailDomain. It had
231 Message-ID $header{'message-id'}
232 and Subject $subject.
234 It has been filed (under junk) but otherwise ignored.
236 Please consult your records to find the correct $gBug report number, or
237 contact me, the system administrator, for assistance.
240 (administrator, $gProject $gBugs database)
242 (NB: If you are a system administrator and have no idea what I am
243 talking about this indicates a serious mail system misconfiguration
244 somewhere. Please contact me immediately.)
251 &filelock('lock/-1');
254 # Attempt to determine which source package this is
255 my $source_pr_header = '';
256 my $source_package = '';
257 if (defined $pheader{source}) {
258 $source_package = $pheader{source};
260 elsif (defined $data->{package} or defined $pheader{package}) {
261 my $pkg_src = getpkgsrc();
262 $source_package = $pkg_src->{defined $data->{package}?$data->{package}:$pheader{package}};
264 $source_pr_header = "X-$gProject-PR-Source: $source_package\n"
265 if defined $source_package and length $source_package;
267 # Done and Forwarded Bugs
268 if ($codeletter eq 'D' || $codeletter eq 'F')
270 if ($replyto =~ m/$gBounceFroms/o ||
271 $header{'from'} =~ m/$gBounceFroms/o)
273 &quit("bounce detected ! Mwaap! Mwaap!");
275 $markedby= $header{'from'} eq $replyto ? $replyto :
276 "$header{'from'} (reply to $replyto)";
278 if ($codeletter eq 'F') { # Forwarded
279 (&appendlog,&finish) if length($data->{forwarded});
280 $receivedat= "forwarded\@$gEmailDomain";
281 $markaswhat= 'forwarded';
282 $set_forwarded= $header{'to'};
283 # Dissallow forwarded being set to this bug tracking system
284 if (defined $set_forwarded and $set_forwarded =~ /\Q$gEmailDomain\E/) {
285 undef $set_forwarded;
287 if ( length( $gListDomain ) > 0 && length( $gForwardList ) > 0 ) {
288 push @generalcc, "$gForwardList\@$gListDomain";
289 $generalcc= "$gForwardList\@$gListDomain";
294 if (length($data->{done}) and
295 not defined $pheader{'source-version'} and
296 not defined $pheader{'version'}) {
300 $receivedat= "done\@$gEmailDomain";
302 $set_done= $header{'from'};
303 if ( length( $gListDomain ) > 0 && length( $gDoneList ) > 0 ) {
304 $generalcc= "$gDoneList\@$gListDomain";
305 push @generalcc, "$gDoneList\@$gListDomain";
310 if (defined $gStrongList and isstrongseverity($data->{severity})) {
311 $generalcc = join ', ', $generalcc, "$gStrongList\@$gListDomain";
312 push @generalcc,"$gStrongList\@$gListDomain";
315 &htmllog("Warning","sent",$replyto,"Message ignored.");
316 &sendmessage(<<END, '');
317 From: $gMaintainerEmail ($gProject $gBug Tracking System)
319 Subject: Message with no $gBug number ignored by $receivedat
321 Message-ID: <header.x.$nn.warnignore\@$gEmailDomain>
322 In-Reply-To: $header{'message-id'}
323 References: $header{'message-id'} $data->{msgid}
325 X-$gProject-PR-Message: error
327 You sent a message to the $gProject $gBug tracking system old-style
328 unified mark as $markaswhat address ($receivedat),
329 without a recognisable $gBug number in the Subject.
330 Your message has been filed under junk but otherwise ignored.
332 If you don't know what I'm talking about then probably either:
334 (a) you unwittingly sent a message to done\@$gEmailDomain
335 because you replied to all recipients of the message a developer used
336 to mark a $gBug as done and you modified the Subject. In this case,
337 please do not be alarmed. To avoid confusion do not do it again, but
338 there is no need to apologise or mail anyone asking for an explanation.
340 (b) you are a system administrator, reading this because the $gBug
341 tracking system is responding to a misdirected bounce message. In this
342 case there is a serious mail system misconfiguration somewhere - please
343 contact me immediately.
345 Your message was dated $header{'date'} and had
346 message-id $header{'message-id'}
347 and subject $subject.
349 If you need any assistance or explanation please contact me.
352 (administrator, $gProject $gBugs database)
361 my @noticecc = grep($_ ne $replyto,@maintaddrs);
362 $noticeccval.= join(', ', grep($_ ne $replyto,@maintaddrs));
363 $noticeccval =~ s/\s+\n\s+/ /g;
364 $noticeccval =~ s/^\s+/ /; $noticeccval =~ s/\s+$//;
366 @process= ($ref,split(/ /,$data->{mergedwith}));
369 for $ref (@process) {
370 if ($ref != $orgref) {
372 $data = &lockreadbug($ref)
373 || die "huh ? $ref from $orgref out of @process";
375 $data->{done}= $set_done if defined($set_done);
376 $data->{forwarded}= $set_forwarded if defined($set_forwarded);
377 if ($codeletter eq 'D') {
378 $data->{keywords} = join ' ', grep $_ ne 'pending',
379 split ' ', $data->{keywords};
380 if (defined $pheader{'source-version'}) {
381 addfixedversions($data, $pheader{source}, $pheader{'source-version'}, '');
382 } elsif (defined $pheader{version}) {
383 addfixedversions($data, $pheader{package}, $pheader{version}, 'binary');
387 # Add bug mailing list to $generalbcc as appropriate
388 # This array is used to specify bcc in the cases where we're using create_mime_message.
389 my @generalbcc = (@generalcc,@addsrcaddrs,"bugs=$ref\@$gListDomain");
390 my $generalbcc = join(', ', $generalcc, @addsrcaddrs,"bugs=$ref\@$gListDomain");
391 $generalbcc =~ s/\s+\n\s+/ /g;
392 $generalbcc =~ s/^\s+/ /; $generalbcc =~ s/\s+$//;
393 if (length $generalbcc) {$generalbcc = "Bcc: $generalbcc\n"};
395 writebug($ref, $data);
397 my $hash = get_hashname($ref);
398 open(O,"db-h/$hash/$ref.report") || &quit("read original report: $!");
399 $x= join('',<O>); close(O);
400 if ($codeletter eq 'F') {
401 &htmllog("Reply","sent",$replyto,"You have marked $gBug as forwarded.");
402 &sendmessage(create_mime_message(
403 ["X-Loop" => "$gMaintainerEmail",
404 From => "$gMaintainerEmail ($gProject $gBug Tracking System)",
406 Subject => "$gBug#$ref: marked as forwarded ($data->{subject})",
407 "Message-ID" => "<header.$ref.$nn.ackfwdd\@$gEmailDomain>",
408 "In-Reply-To" => $header{'message-id'},
409 References => "$header{'message-id'} $data->{msgid}",
410 Precedence => 'bulk',
411 "X-$gProject-PR-Message" => "forwarded $ref",
412 "X-$gProject-PR-Package" => $data->{package},
413 "X-$gProject-PR-Keywords" => $data->{keywords},
414 # Only have a X-$gProject-PR-Source when we know the source package
415 length($source_package)?("X-$gProject-PR-Source" => $source_package):(),
416 ],<<END ,[join("\n",@msg)]),'',[$replyto,@generalbcc,@noticecc],1);
417 Your message dated $header{'date'}
418 with message-id $header{'message-id'}
419 has caused the $gProject $gBug report #$ref,
420 regarding $data->{subject}
421 to be marked as having been forwarded to the upstream software
422 author(s) $data->{forwarded}.
424 (NB: If you are a system administrator and have no idea what I am
425 talking about this indicates a serious mail system misconfiguration
426 somewhere. Please contact me immediately.)
429 (administrator, $gProject $gBugs database)
434 &htmllog("Reply","sent",$replyto,"You have taken responsibility.");
435 &sendmessage(create_mime_message(
436 ["X-Loop" => "$gMaintainerEmail",
437 From => "$gMaintainerEmail ($gProject $gBug Tracking System)",
439 Subject => "$gBug#$ref: marked as done ($data->{subject})",
440 "Message-ID" => "<handler.$ref.$nn.ackdone\@$gEmailDomain>",
441 "In-Reply-To" => $header{'message-id'},
442 References => "$header{'message-id'} $data->{msgid}",
443 Precedence => 'bulk',
444 "X-$gProject-PR-Message" => "closed $ref",
445 "X-$gProject-PR-Package" => $data->{package},
446 "X-$gProject-PR-Keywords" => $data->{keywords},
447 # Only have a X-$gProject-PR-Source when we know the source package
448 length($source_package)?("X-$gProject-PR-Source" => $source_package):(),
449 ],<<END ,[$x,join("\n",@msg)]),'',[$replyto,@generalbcc,@noticecc],1);
450 Your message dated $header{'date'}
451 with message-id $header{'message-id'}
452 and subject line $subject
453 has caused the attached $gBug report to be marked as done.
455 This means that you claim that the problem has been dealt with.
456 If this is not the case it is now your responsibility to reopen the
457 $gBug report if necessary, and/or fix the problem forthwith.
459 (NB: If you are a system administrator and have no idea what I am
460 talking about this indicates a serious mail system misconfiguration
461 somewhere. Please contact me immediately.)
464 (administrator, $gProject $gBugs database)
467 &htmllog("Notification","sent",$data->{originator},
468 "$gBug acknowledged by developer.");
469 &sendmessage(create_mime_message(
470 ["X-Loop" => "$gMaintainerEmail",
471 From => "$gMaintainerEmail ($gProject $gBug Tracking System)",
472 To => "$data->{originator}",
473 Subject => "$gBug#$ref closed by $markedby ($header{'subject'})",
474 "Message-ID" => "<handler.$ref.$nn.notifdone\@$gEmailDomain>",
475 "In-Reply-To" => "$data->{msgid}",
476 References => "$header{'message-id'} $data->{msgid}",
477 "X-$gProject-PR-Message" => "they-closed $ref",
478 "X-$gProject-PR-Package" => "$data->{package}",
479 "X-$gProject-PR-Keywords" => "$data->{keywords}",
480 # Only have a X-$gProject-PR-Source when we know the source package
481 length($source_package)?("X-$gProject-PR-Source" => $source_package):(),
482 "Reply-To" => "$ref\@$gEmailDomain",
483 "Content-Type" => 'text/plain; charset="utf-8"',
484 ],<<END ,[join("\n",@msg)]),'',undef,1);
485 This is an automatic notification regarding your $gBug report
486 #$ref: $data->{subject},
487 which was filed against the $data->{package} package.
489 It has been closed by $markedby.
491 Their explanation is attached below. If this explanation is
492 unsatisfactory and you have not received a better one in a separate
493 message then please contact $markedby by replying
497 (administrator, $gProject $gBugs database)
507 if ($codeletter eq 'U') {
508 &htmllog("Warning","sent",$replyto,"Message not forwarded.");
509 &sendmessage(<<END, '');
510 From: $gMaintainerEmail ($gProject $gBug Tracking System)
512 Subject: Message with no $gBug number cannot be sent to submitter !
514 Message-ID: <handler.x.$nn.nonumnosub\@$gEmailDomain>
515 In-Reply-To: $header{'message-id'}
516 References: $header{'message-id'} $data->{msgid}
518 X-$gProject-PR-Message: error
520 You sent a message to the $gProject $gBug tracking system's $gBug
521 report submitter address $baddress\@$gEmailDomain, without a
522 recognisable $gBug number in the Subject. Your message has been filed
523 under junk but otherwise ignored.
525 If you don't know what I'm talking about then probably either:
527 (a) you unwittingly sent a message to $baddress\@$gEmailDomain
528 because you replied to all recipients of the message a developer sent
529 to a $gBug\'s submitter and you modified the Subject. In this case,
530 please do not be alarmed. To avoid confusion do not do it again, but
531 there is no need to apologise or mail anyone asking for an
534 (b) you are a system administrator, reading this because the $gBug
535 tracking system is responding to a misdirected bounce message. In this
536 case there is a serious mail system misconfiguration somewhere - please
537 contact me immediately.
539 Your message was dated $header{'date'} and had
540 message-id $header{'message-id'}
541 and subject $subject.
543 If you need any assistance or explanation please contact me.
546 (administrator, $gProject $gBugs database)
553 $data->{found_versions} = [];
554 $data->{fixed_versions} = [];
556 if (defined $pheader{source}) {
557 $data->{package} = $pheader{source};
558 } elsif (defined $pheader{package}) {
559 $data->{package} = $pheader{package};
561 &htmllog("Warning","sent",$replyto,"Message not forwarded.");
562 &sendmessage(create_mime_message(
563 ["X-Loop" => "$gMaintainerEmail",
564 From => "$gMaintainerEmail ($gProject $gBug Tracking System)",
566 Subject => "Message with no Package: tag cannot be processed! ($subject)",
567 "Message-ID" => "<handler.x.$nn.nonumnosub\@$gEmailDomain>",
568 "In-Reply-To" => $header{'message-id'},
569 References => "$header{'message-id'} $data->{msgid}",
570 Precedence => 'bulk',
571 "X-$gProject-PR-Message" => 'error'
572 ],<<END,[join("\n", @msg)]), '',undef,1);
574 Your message didn't have a Package: line at the start (in the
575 pseudo-header following the real mail header), or didn't have a
576 pseudo-header at all. Your message has been filed under junk but
579 This makes it much harder for us to categorise and deal with your
580 problem report. Please _resubmit_ your report to $baddress\@$gEmailDomain
581 and tell us which package the report is on. For help, check out
582 http://$gWebDomain/Reporting$gHTMLSuffix.
584 Your message was dated $header{'date'} and had
585 message-id $header{'message-id'}
586 and subject $subject.
587 The complete text of it is attached to this message.
589 If you need any assistance or explanation please contact me.
592 (administrator, $gProject $gBugs database)
599 $data->{keywords}= '';
600 if (defined($pheader{'keywords'})) {
601 $data->{keywords}= $pheader{'keywords'};
602 } elsif (defined($pheader{'tags'})) {
603 $data->{keywords}= $pheader{'tags'};
605 if (length($data->{keywords})) {
607 my %gkws = map { ($_, 1) } @gTags;
608 foreach my $kw (sort split(/[,\s]+/, lc($data->{keywords}))) {
609 push @kws, $kw if (defined $gkws{$kw});
611 $data->{keywords} = join(" ", @kws);
613 $data->{severity}= '';
614 if (defined($pheader{'severity'}) || defined($pheader{'priority'})) {
615 $data->{severity}= $pheader{'severity'};
616 $data->{severity}= $pheader{'priority'} unless ($data->{severity});
617 $data->{severity} =~ s/^\s*(.+)\s*$/$1/;
619 if (!grep($_ eq $data->{severity}, @severities, "$gDefaultSeverity")) {
622 Your message specified a Severity: in the pseudo-header, but
623 the severity value $data->{severity} was not recognised.
624 The default severity $gDefaultSeverity is being used instead.
625 The recognised values are: $gShowSeverities.
627 # if we use @gSeverityList array in the above line, perl -c gives:
628 # In string, @gSeverityList now must be written as \@gSeverityList at
629 # process line 452, near "$gDefaultSeverity is being used instead.
630 $data->{severity}= '';
633 if (defined($pheader{owner})) {
634 $data->{owner}= $pheader{owner};
636 if (defined($pheader{forwarded})) {
637 $data->{'forwarded-to'} = $pheader{forwarded};
639 &filelock("nextnumber.lock");
640 open(N,"nextnumber") || &quit("nextnumber: read: $!");
641 $v=<N>; $v =~ s/\n$// || &quit("nextnumber bad format");
642 $ref= $v+0; $v += 1; $newref=1;
643 &overwrite('nextnumber', "$v\n");
645 my $hash = get_hashname($ref);
646 &overwrite("db-h/$hash/$ref.log",'');
647 $data->{originator} = $replyto;
648 $data->{date} = $intdate;
649 $data->{subject} = $subject;
650 $data->{msgid} = $header{'message-id'};
651 writebug($ref, $data);
653 if (exists $pheader{usertags}) {
655 $user = $pheader{user} if exists $pheader{user};
657 $user =~ s/^.*<(.*)>.*$/$1/;
658 $user =~ s/[(].*[)]//;
659 $user =~ s/^\s*(\S+)\s+.*$/$1/;
660 if ($user ne '' and Debbugs::User::is_valid_user($user)) {
661 $pheader{usertags} =~ s/(?:^\s+|\s+$)//g;
663 read_usertags(\%user_tags,$user);
664 for my $tag (split /[,\s]+/, $pheader{usertags}) {
665 if ($tag =~ /^[a-zA-Z0-9.+\@-]+/) {
667 @bugs_with_tag{@{$user_tags{$tag}}} = (1) x @{$user_tags{$tag}};
668 $bugs_with_tag{$ref} = 1;
669 $user_tags{$tag} = [keys %bugs_with_tag];
672 write_usertags(\%usertags,$user);
676 Your message tried to set a usertag, but didn't have a valid
677 user set ('$user' isn't valid)
681 &overwrite("db-h/$hash/$ref.report",
682 join("\n",@msg)."\n");
687 print DEBUG "maintainers >@maintaddrs<\n";
689 $orgsender= defined($header{'sender'}) ? "Original-Sender: $header{'sender'}\n" : '';
690 $newsubject= $subject; $newsubject =~ s/^$gBug#$ref:*\s*//;
692 $xcchdr= $header{ 'x-debbugs-cc' };
693 if ($xcchdr =~ m/\S/) {
694 push(@resentccs,$xcchdr);
695 $resentccexplain.= <<END;
697 As you requested using X-Debbugs-CC, your message was also forwarded to
699 (after having been given a $gBug report number, if it did not have one).
703 if (@maintaddrs && ($codeletter eq 'B' || $codeletter eq 'M')) {
704 push(@resentccs,@maintaddrs);
705 $resentccexplain.= <<END." ".join("\n ",@maintaddrs)."\n";
707 Your message has been sent to the package maintainer(s):
711 @bccs = @addsrcaddrs;
712 if (defined $gStrongList and isstrongseverity($data->{severity})) {
713 push @bccs, "$gStrongList\@$gListDomain";
716 # Send mail to the per bug list subscription too
717 push @bccs, "bugs=$ref\@$gListDomain";
719 if (defined $pheader{source}) {
720 # Prefix source versions with the name of the source package. They
721 # appear that way in version trees so that we can deal with binary
722 # packages moving from one source package to another.
723 if (defined $pheader{'source-version'}) {
724 addfoundversions($data, $pheader{source}, $pheader{'source-version'}, '');
725 } elsif (defined $pheader{version}) {
726 addfoundversions($data, $pheader{source}, $pheader{version}, '');
728 writebug($ref, $data);
729 } elsif (defined $pheader{package}) {
730 # TODO: could handle Source-Version: by looking up the source package?
731 addfoundversions($data, $pheader{package}, $pheader{version}, 'binary');
732 writebug($ref, $data);
735 $veryquiet= $codeletter eq 'Q';
736 if ($codeletter eq 'M' && !@maintaddrs) {
740 You requested that the message be sent to the package maintainer(s)
741 but either the $gBug report is not associated with any package (probably
742 because of a missing Package pseudo-header field in the original $gBug
743 report), or the package(s) specified do not have any maintainer(s).
745 Your message has *not* been sent to any package maintainers; it has
746 merely been filed in the $gBug tracking system. If you require assistance
747 please contact $gMaintainerEmail quoting the $gBug number $ref.
751 $resentccval.= join(', ',@resentccs);
752 $resentccval =~ s/\s+\n\s+/ /g; $resentccval =~ s/^\s+/ /; $resentccval =~ s/\s+$//;
753 if (length($resentccval)) {
754 $resentcc= "Resent-CC: $resentccval\n";
757 if ($codeletter eq 'U') {
758 &htmllog("Message", "sent on", $data->{originator}, "$gBug#$ref.");
759 &sendmessage(<<END,[$data->{originator},@resentccs],[@bccs]);
760 Subject: $gBug#$ref: $newsubject
761 Reply-To: $replyto, $ref-quiet\@$gEmailDomain
762 ${orgsender}Resent-To: $data->{originator}
763 ${resentcc}Resent-Date: $tdate
764 Resent-Message-ID: <handler.$ref.$nn\@$gEmailDomain>
765 Resent-Sender: $gMaintainerEmail
766 X-$gProject-PR-Message: report $ref
767 X-$gProject-PR-Package: $data->{package}
768 X-$gProject-PR-Keywords: $data->{keywords}
769 ${source_pr_header}$fwd
771 } elsif ($codeletter eq 'B') { # Sent to submit
772 &htmllog($newref ? "Report" : "Information", "forwarded",
773 join(', ',"$gSubmitList\@$gListDomain",@resentccs),
774 "<code>$gBug#$ref</code>".
775 (length($data->{package})? "; Package <code>".&sani($data->{package})."</code>" : '').
777 &sendmessage(<<END,["$gSubmitList\@$gListDomain",@resentccs],[@bccs]);
778 Subject: $gBug#$ref: $newsubject
779 Reply-To: $replyto, $ref\@$gEmailDomain
780 Resent-From: $header{'from'}
781 ${orgsender}Resent-To: $gSubmitList\@$gListDomain
782 ${resentcc}Resent-Date: $tdate
783 Resent-Message-ID: <handler.$ref.$nn\@$gEmailDomain>
784 Resent-Sender: $gMaintainerEmail
785 X-$gProject-PR-Message: report $ref
786 X-$gProject-PR-Package: $data->{package}
787 X-$gProject-PR-Keywords: $data->{keywords}
788 ${source_pr_header}$fwd
790 } elsif (@resentccs or @bccs) { # Quiet or Maintainer
791 # D and F done far earlier; B just done - so this must be M or Q
792 # We preserve whichever it was in the Reply-To (possibly adding
795 &htmllog($newref ? "Report" : "Information", "forwarded",
797 "<code>$gBug#$ref</code>".
798 (length($data->{package}) ? "; Package <code>".&sani($data->{package})."</code>" : '').
801 &htmllog($newref ? "Report" : "Information", "stored",
803 "<code>$gBug#$ref</code>".
804 (length($data->{package}) ? "; Package <code>".&sani($data->{package})."</code>" : '').
807 &sendmessage(<<END,[@resentccs],[@bccs]);
808 Subject: $gBug#$ref: $newsubject
809 Reply-To: $replyto, $ref-$baddressroot\@$gEmailDomain
810 Resent-From: $header{'from'}
811 ${orgsender}Resent-To: $resentccval
813 Resent-Message-ID: <handler.$ref.$nn\@$gEmailDomain>
814 Resent-Sender: $gMaintainerEmail
815 X-$gProject-PR-Message: report $ref
816 X-$gProject-PR-Package: $data->{package}
817 X-$gProject-PR-Keywords: $data->{keywords}
818 ${source_pr_header}$fwd
822 $htmlbreak= length($brokenness) ? "<p>\n".&sani($brokenness)."\n<p>\n" : '';
823 $htmlbreak =~ s/\n\n/\n<P>\n\n/g;
824 if (length($resentccval)) {
825 $htmlbreak = " Copy sent to <code>".&sani($resentccval)."</code>.".
828 unless (exists $header{'x-debbugs-no-ack'}) {
830 &htmllog("Acknowledgement","sent",$replyto,
832 "New $gBug report received and filed, but not forwarded." :
833 "New $gBug report received and forwarded."). $htmlbreak);
835 &sendmessage(create_mime_message(
836 ["X-Loop" => "$gMaintainerEmail",
837 From => "$gMaintainerEmail ($gProject $gBug Tracking System)",
839 Subject => "$gBug#$ref: Acknowledgement of QUIET report ($subject)",
840 "Message-ID" => "<handler.$ref.$nn.ackquiet\@$gEmailDomain>",
841 "In-Reply-To" => $header{'message-id'},
842 References => $header{'message-id'},
843 Precedence => 'bulk',
844 "X-$gProject-PR-Message" => "ack-quiet $ref",
845 "X-$gProject-PR-Package" => $data->{package},
846 "X-$gProject-PR-Keywords" => $data->{keywords},
847 # Only have a X-$gProject-PR-Source when we know the source package
848 length($source_package)?("X-$gProject-PR-Source" => $source_package):(),
849 "Reply-To" => "$ref-quiet\@$gEmailDomain",
850 ],<<END,[join("\n", @msg)]), '',undef,1);
851 Thank you for the problem report you have sent regarding $gProject.
852 This is an automatically generated reply, to let you know your message
853 has been received. It has not been forwarded to the package maintainers
854 or other interested parties; you should ensure that the developers are
855 aware of the problem you have entered into the system - preferably
856 quoting the $gBug reference number, #$ref.
858 If you wish to submit further information on your problem, please send it
859 to $ref-$baddressroot\@$gEmailDomain (and *not*
860 to $baddress\@$gEmailDomain).
862 If you have filed this report in error and wish to close it, please
863 send mail to $ref-done\@$gEmailDomain with an explanation
864 why the bug report should be closed.
866 Please do not reply to the address at the top of this message,
867 unless you wish to report a problem with the $gBug-tracking system.
870 (administrator, $gProject $gBugs database)
873 elsif ($codeletter eq 'M') { # Maintonly
874 &sendmessage(create_mime_message(
875 ["X-Loop" => "$gMaintainerEmail",
876 From => "$gMaintainerEmail ($gProject $gBug Tracking System)",
878 Subject => "$gBug#$ref: Acknowledgement of maintainer-only report ($subject)",
879 "Message-ID" => "<handler.$ref.$nn.ackmaint\@$gEmailDomain>",
880 "In-Reply-To" => $header{'message-id'},
881 References => $header{'message-id'},
882 Precedence => 'bulk',
883 "X-$gProject-PR-Message" => "ack-maintonly $ref",
884 "X-$gProject-PR-Package" => $data->{package},
885 "X-$gProject-PR-Keywords" => $data->{keywords},
886 # Only have a X-$gProject-PR-Source when we know the source package
887 length($source_package)?("X-$gProject-PR-Source" => $source_package):(),
888 "Reply-To" => "$ref-maintonly\@$gEmailDomain",
889 ],<<END,[]), '',undef,1);
890 Thank you for the problem report you have sent regarding $gProject.
891 This is an automatically generated reply, to let you know your message has
892 been received. It is being forwarded to the package maintainers (but not
893 other interested parties, as you requested) for their attention; they will
896 If you wish to submit further information on your problem, please send
897 it to $ref-$baddressroot\@$gEmailDomain (and *not*
898 to $baddress\@$gEmailDomain).
900 If you have filed this report in error and wish to close it, please
901 send mail to $ref-done\@$gEmailDomain with an explanation
902 why the bug report should be closed.
904 Please do not reply to the address at the top of this message,
905 unless you wish to report a problem with the $gBug-tracking system.
908 (administrator, $gProject $gBugs database)
912 &sendmessage(create_mime_message(
913 ["X-Loop" => "$gMaintainerEmail",
914 From => "$gMaintainerEmail ($gProject $gBug Tracking System)",
916 Subject => "$gBug#$ref: Acknowledgement ($subject)",
917 "Message-ID" => "<handler.$ref.$nn.ack\@$gEmailDomain>",
918 "In-Reply-To" => $header{'message-id'},
919 References => $header{'message-id'},
920 Precedence => 'bulk',
921 "X-$gProject-PR-Message" => "ack $ref",
922 "X-$gProject-PR-Package" => $data->{package},
923 "X-$gProject-PR-Keywords" => $data->{keywords},
924 # Only have a X-$gProject-PR-Source when we know the source package
925 length($source_package)?("X-$gProject-PR-Source" => $source_package):(),
926 "Reply-To" => "$ref\@$gEmailDomain",
927 ],<<END,[]), '',undef,1);
928 Thank you for the problem report you have sent regarding $gProject.
929 This is an automatically generated reply, to let you know your message has
930 been received. It is being forwarded to the package maintainers and other
931 interested parties for their attention; they will reply in due course.
933 If you wish to submit further information on your problem, please send
934 it to $ref\@$gEmailDomain (and *not* to
935 $baddress\@$gEmailDomain).
937 If you have filed this report in error and wish to close it, please
938 send mail to $ref-done\@$gEmailDomain with an explanation
939 why the bug report should be closed.
941 Please do not reply to the address at the top of this message,
942 unless you wish to report a problem with the $gBug-tracking system.
945 (administrator, $gProject $gBugs database)
948 } elsif ($codeletter ne 'U' and
949 $header{'precedence'} !~ /\b(?:bulk|junk|list)\b/) {
950 &htmllog("Acknowledgement","sent",$replyto,
951 ($veryquiet ? "Extra info received and filed, but not forwarded." :
952 $codeletter eq 'M' ? "Extra info received and forwarded to maintainer." :
953 "Extra info received and forwarded to list."). $htmlbreak);
955 &sendmessage(create_mime_message(
956 ["X-Loop" => "$gMaintainerEmail",
957 From => "$gMaintainerEmail ($gProject $gBug Tracking System)",
959 Subject => "$gBug#$ref: Info received and FILED only (was $subject)",
960 "Message-ID" => "<handler.$ref.$nn.ackinfoquiet\@$gEmailDomain>",
961 "In-Reply-To" => $header{'message-id'},
962 References => $header{'message-id'},
963 Precedence => 'bulk',
964 "X-$gProject-PR-Message" => "ack-info-quiet $ref",
965 "X-$gProject-PR-Package" => $data->{package},
966 "X-$gProject-PR-Keywords" => $data->{keywords},
967 # Only have a X-$gProject-PR-Source when we know the source package
968 length($source_package)?("X-$gProject-PR-Source" => $source_package):(),
969 "Reply-To" => "$ref-maintonly\@$gEmailDomain",
970 ],<<END,[]), '',undef,1);
971 Thank you for the additional information you have supplied regarding
972 this problem report. It has NOT been forwarded to the package
973 maintainers, but will accompany the original report in the $gBug
974 tracking system. Please ensure that you yourself have sent a copy of
975 the additional information to any relevant developers or mailing lists.
977 If you wish to continue to submit further information on this problem,
978 please send it to $ref-$baddressroot\@$gEmailDomain, as before.
980 Please do not reply to the address at the top of this message,
981 unless you wish to report a problem with the $gBug-tracking system.
984 (administrator, $gProject $gBugs database)
987 elsif ($codeletter eq 'M') {
988 &sendmessage(create_mime_message(
989 ["X-Loop" => "$gMaintainerEmail",
990 From => "$gMaintainerEmail ($gProject $gBug Tracking System)",
992 Subject => "$gBug#$ref: Info received for maintainer only (was $subject)",
993 "Message-ID" => "<handler.$ref.$nn.ackinfomaint\@$gEmailDomain>",
994 "In-Reply-To" => $header{'message-id'},
995 References => "$header{'message-id'} $data->{msgid}",
996 Precedence => 'bulk',
997 "X-$gProject-PR-Message" => "ack-info-maintonly $ref",
998 "X-$gProject-PR-Package" => $data->{package},
999 "X-$gProject-PR-Keywords" => $data->{keywords},
1000 "Reply-To" => "$ref-maintonly\@$gEmailDomain",
1001 ],<<END,[]), '',undef,1);
1002 Thank you for the additional information you have supplied regarding
1003 this problem report. It has been forwarded to the package maintainer(s)
1004 (but not to other interested parties) to accompany the original report.
1006 If you wish to continue to submit further information on this problem,
1007 please send it to $ref-$baddressroot\@$gEmailDomain, as before.
1009 Please do not reply to the address at the top of this message,
1010 unless you wish to report a problem with the $gBug-tracking system.
1013 (administrator, $gProject $gBugs database)
1017 &sendmessage(create_mime_message(
1018 ["X-Loop" => "$gMaintainerEmail",
1019 From => "$gMaintainerEmail ($gProject $gBug Tracking System)",
1021 Subject => "$gBug#$ref: Info received ($subject)",
1022 "Message-ID" => "<handler.$ref.$nn.ackinfo\@$gEmailDomain>",
1023 "In-Reply-To" => $header{'message-id'},
1024 References => "$header{'message-id'} $data->{msgid}",
1025 Precedence => 'bulk',
1026 "X-$gProject-PR-Message" => "ack-info $ref",
1027 "X-$gProject-PR-Package" => $data->{package},
1028 "X-$gProject-PR-Keywords" => $data->{keywords},
1029 # Only have a X-$gProject-PR-Source when we know the source package
1030 length($source_package)?("X-$gProject-PR-Source" => $source_package):(),
1031 "Reply-To" => "$ref\@$gEmailDomain",
1032 ],<<END,[]), '',undef,1);
1033 Thank you for the additional information you have supplied regarding
1034 this problem report. It has been forwarded to the package maintainer(s)
1035 and to other interested parties to accompany the original report.
1037 If you wish to continue to submit further information on this problem,
1038 please send it to $ref\@$gEmailDomain, as before.
1040 Please do not reply to the address at the top of this message,
1041 unless you wish to report a problem with the $gBug-tracking system.
1044 (administrator, $gProject $gBugs database)
1056 open(NEW,">$f.new") || &quit("$f.new: create: $!");
1057 print(NEW "$v") || &quit("$f.new: write: $!");
1058 close(NEW) || &quit("$f.new: close: $!");
1059 rename("$f.new","$f") || &quit("rename $f.new to $f: $!");
1063 my $hash = get_hashname($ref);
1064 if (!open(AP,">>db-h/$hash/$ref.log")) {
1065 print DEBUG "failed open log<\n";
1066 print DEBUG "failed open log err $!<\n";
1067 &quit("opening db-h/$hash/$ref.log (li): $!");
1069 print(AP "\7\n",@{escapelog(@log)},"\n\3\n") || &quit("writing db-h/$hash/$ref.log (li): $!");
1070 close(AP) || &quit("closing db-h/$hash/$ref.log (li): $!");
1074 utime(time,time,"db");
1076 while ($u= $cleanups[$#cleanups]) { &$u; }
1077 unlink("incoming/P$nn") || &quit("unlinking incoming/P$nn: $!");
1081 &quit("wot no exit");
1084 local ($whatobj,$whatverb,$where,$desc) = @_;
1085 my $hash = get_hashname($ref);
1086 open(AP,">>db-h/$hash/$ref.log") || &quit("opening db-h/$hash/$ref.log (lh): $!");
1089 "<strong>$whatobj $whatverb</strong>".
1090 ($where eq '' ? "" : " to <code>".&sani($where)."</code>").
1092 "\n\3\n") || &quit("writing db-h/$hash/$ref.log (lh): $!");
1093 close(AP) || &quit("closing db-h/$hash/$ref.log (lh): $!");
1100 while ($msg =~ s/(.*\n)//) {
1107 # strip continuation lines too
1122 send_message($the_message,\@recipients,\@bcc,$do_not_encode)
1124 The first argument is the scalar message, the second argument is the
1125 arrayref of recipients, the third is the arrayref of Bcc:'ed
1128 The final argument turns off header encoding and the addition of the
1129 X-Loop header if true, defaults to false.
1135 my ($msg,$recips,$bcc,$no_encode) = @_;
1136 if (not defined $recips or (!ref($recips) && $recips eq '')
1140 # This is suboptimal. The right solution is to send headers
1141 # separately from the rest of the message and encode them rather
1143 $msg = "X-Loop: $gMaintainerEmail\n" . $msg unless $no_encode;
1144 # The original message received is written out in appendlog, so
1145 # before writing out the other messages we've sent out, we need to
1146 # RFC1522 encode the header.
1147 $msg = encode_headers($msg) unless $no_encode;
1149 my $hash = get_hashname($ref);
1150 #save email to the log
1151 open(AP,">>db-h/$hash/$ref.log") || &quit("opening db-h/$hash/$ref.log (lo): $!");
1152 print(AP "\2\n",join("\4",@$recips),"\n\5\n",
1153 @{escapelog(stripbccs($msg))},"\n\3\n") ||
1154 &quit("writing db-h/$hash/$ref.log (lo): $!");
1155 close(AP) || &quit("closing db-h/$hash/$ref.log (lo): $!");
1158 shift @$recips if $recips->[0] eq '-t';
1159 push @$recips, @$bcc;
1162 send_mail_message(message => $msg,
1163 # Because we encode the headers above, we do not want to encode them here
1164 encode_headers => 0,
1165 recipients => $recips);
1168 my $maintainerschecked = 0;
1169 sub checkmaintainers {
1170 return if $maintainerschecked++;
1171 return if !length($data->{package});
1172 open(MAINT,"$gMaintainerFile") || die &quit("maintainers open: $!");
1176 m/^(\S+)\s+(\S.*\S)\s*\n$/ || &quit("maintainers bogus \`$_'");
1177 $a= $1; $b= $2; $a =~ y/A-Z/a-z/;
1178 # use the package which is normalized to lower case; we do this because we lc the pseudo headers.
1179 $maintainerof{$a}= $2;
1182 open(MAINT,"$gMaintainerFileOverride") || die &quit("maintainers.override open: $!");
1186 m/^(\S+)\s+(\S.*\S)\s*\n$/ || &quit("maintainers.override bogus \`$_'");
1187 $a= $1; $b= $2; $a =~ y/A-Z/a-z/;
1188 # use the package which is normalized to lower case; we do this because we lc the pseudo headers.
1189 $maintainerof{$a}= $2;
1192 open(SOURCES,"$gPackageSource") || &quit("pkgsrc open: $!");
1194 next unless m/^(\S+)\s+\S+\s+(\S.*\S)\s*$/;
1200 $anymaintfound=0; $anymaintnotfound=0;
1201 for $p (split(m/[ \t?,():]+/,$data->{package})) {
1203 $p =~ /([a-z0-9.+-]+)/;
1205 next unless defined $p;
1206 if (defined $gSubscriptionDomain) {
1207 if (defined($pkgsrc{$p})) {
1208 push @addsrcaddrs, "$pkgsrc{$p}\@$gSubscriptionDomain";
1210 push @addsrcaddrs, "$p\@$gSubscriptionDomain";
1213 if (defined($maintainerof{$p})) {
1214 print DEBUG "maintainer add >$p|$maintainerof{$p}<\n";
1215 $addmaint= $maintainerof{$p};
1216 push(@maintaddrs,$addmaint) unless
1217 $addmaint eq $replyto || grep($_ eq $addmaint, @maintaddrs);
1220 print DEBUG "maintainer none >$p<\n";
1221 push(@maintaddrs,$gUnknownMaintainerEmail) unless $anymaintnotfound;
1222 $anymaintnotfound++;
1227 if (length $data->{owner}) {
1228 print DEBUG "owner add >$data->{package}|$data->{owner}<\n";
1229 $addmaint = $data->{owner};
1230 push(@maintaddrs, $addmaint) unless
1231 $addmaint eq $replyto or grep($_ eq $addmaint, @maintaddrs);
1235 =head2 bug_list_forward
1237 bug_list_forward($spool_filename) if $codeletter eq 'L';
1240 Given the spool file, will forward a bug to the per bug mailing list
1241 subscription system.
1245 sub bug_list_forward{
1247 # Read the bug information and package information for passing to
1249 my ($bug_number) = $bug_fn =~ /^L(\d+)\./;
1250 my ($bfound, $data)= lockreadbugmerge($bug_number);
1251 my $bug_fh = new IO::File "incoming/P$bug_fn" or die "Unable to open incoming/P$bug_fn $!";
1254 my $bug_message = <$bug_fh>;
1255 my ($bug_address) = $bug_message =~ /^Received: \(at ([^\)]+)\) by/;
1256 my ($envelope_from) = $bug_message =~ s/\nFrom\s+([^\s]+)[^\n]+\n/\n/;
1257 if (not defined $envelope_from) {
1258 # Try to use the From: header or something to set it
1259 ($envelope_from) = $bug_message =~ /\nFrom:\s+(.+?)\n/;
1260 # Kludgy, and should really be using a full scale header
1261 # parser to do this.
1262 $envelope_from =~ s/^.+?<([^>]+)>.+$/$1/;
1264 my ($header,$body) = split /\n\n/, $bug_message, 2;
1265 # Add X-$gProject-PR-Message: list bug_number, package name, and bug title headers
1266 $header .= qq(\nX-$gProject-PR-Message: list $bug_number\n).
1267 qq(X-$gProject-PR-Package: $data->{package}\n).
1268 qq(X-$gProject-PR-Title: $data->{subject})
1270 print STDERR "Tried to loop me with $envelope_from\n"
1271 and exit 1 if $envelope_from =~ /\Q$gListDomain\E|\Q$gEmailDomain\E/;
1272 print DEBUG $envelope_from,qq(\n);
1273 # If we don't have a bug address, something has gone horribly wrong.
1274 print STDERR "Doesn't match: $bug_address\n" and exit 1 unless defined $bug_address;
1275 $bug_address =~ s/\@.+//;
1276 print DEBUG "Sending message to bugs=$bug_address\@$gListDomain\n";
1277 print DEBUG $header.qq(\n\n).$body;
1278 send_mail_message(message => $header.qq(\n\n).$body,
1279 recipients => ["bugs=$bug_address\@$gListDomain"],
1280 envelope_from => $envelope_from,
1281 encode_headers => 0,
1283 unlink("incoming/P$bug_fn") || &quit("unlinking incoming/P$bug_fn: $!");