]> git.donarmstrong.com Git - debbugs.git/blobdiff - scripts/process.in
merge changes from dla source tree
[debbugs.git] / scripts / process.in
index b857d1b18bb4eb3f3644e930e23e38be25d5c985..86efc053355414060c1e72c8d0c47940ef8797e1 100755 (executable)
@@ -4,18 +4,24 @@
 # Usage: process nn
 # Temps:  incoming/Pnn
 
-use POSIX qw(strftime tzset);
-$ENV{"TZ"} = 'UTC';
-tzset();
+use POSIX qw(strftime);
 
 use MIME::Parser;
 use Debbugs::MIME qw(decode_rfc1522 create_mime_message);
 use Debbugs::Mail qw(send_mail_message encode_headers);
+use Debbugs::Packages qw(getpkgsrc);
+use Debbugs::User qw(read_usertags write_usertags);
 
-$config_path = '/etc/debbugs';
-$lib_path = '/usr/lib/debbugs';
+use Debbugs::CGI qw(html_escape);
+
+# TODO DLA; needs config reworking and errorlib reworking
+# use warnings;
+# use strict;
+
+use Debbugs::Status qw(:versions);
+use Debbugs::Config qw(:globals);
+my $lib_path = $gLibPath;
 
-require "$config_path/config";
 require "$lib_path/errorlib";
 $ENV{'PATH'} = $lib_path.':'.$ENV{'PATH'};
 
@@ -25,13 +31,13 @@ chdir( "$gSpoolDir" ) || die "chdir spool: $!\n";
 umask(002);
 open DEBUG, ">/dev/null";
 
-defined( $intdate= time ) || &quit( "failed to get time: $!" );
+my $intdate = time or quit("failed to get time: $!");
 
 $_=shift;
-m/^([BMQFDUL])(\d*)\.\d+$/ || &quit("bad argument");
-$codeletter= $1;
-$tryref= length($2) ? $2+0 : -1;
-$nn= $_;
+m/^([BMQFDUL])(\d*)\.\d+$/ or quit("bad argument: $_");
+my $codeletter= $1;
+my $tryref= length($2) ? $2 : -1;
+my $nn= $_;
 
 if (!rename("incoming/G$nn","incoming/P$nn")) 
 {
@@ -39,7 +45,7 @@ if (!rename("incoming/G$nn","incoming/P$nn"))
     &quit("renaming to lock: $!");
 }
 
-$baddress= 'submit' if $codeletter eq 'B';
+my $baddress= 'submit' if $codeletter eq 'B';
 $baddress= 'maintonly' if $codeletter eq 'M';
 $baddress= 'quiet' if $codeletter eq 'Q';
 $baddress= 'forwarded' if $codeletter eq 'F';
@@ -47,20 +53,20 @@ $baddress= 'done' if $codeletter eq 'D';
 $baddress= 'submitter' if $codeletter eq 'U';
 bug_list_forward($nn) if $codeletter eq 'L';
 $baddress || &quit("bad codeletter $codeletter");
-$baddressroot= $baddress;
+my $baddressroot= $baddress;
 $baddress= "$tryref-$baddress" if $tryref>=0;
 
 open(M,"incoming/P$nn");
-@log=<M>;
+my @log=<M>;
 close(M);
 
-@msg=@log;
+my @msg = @log;
 chomp @msg;
 
 print DEBUG "###\n",join("##\n",@msg),"\n###\n";
 
-$tdate = strftime "%a, %d %h %Y %T UTC", localtime;
-$fwd= <<END;
+my $tdate = strftime "%a, %d %h %Y %T +0000", gmtime;
+my $fwd= <<END;
 Received: via spool by $baddress\@$gEmailDomain id=$nn
           (code $codeletter ref $tryref); $tdate
 END
@@ -73,6 +79,7 @@ mkdir "$gSpoolDir/mime.tmp", 0777;
 $parser->output_under("$gSpoolDir/mime.tmp");
 my $entity = eval { $parser->parse_data(join('',@log)) };
 
+my $i;
 if ($entity and $entity->head->tags) {
     @headerlines = @{$entity->head->header};
     chomp @headerlines;
@@ -144,7 +151,8 @@ for my $phline (@bodylines)
     $fv =~ s/\s*$//;
     print DEBUG ">$fn|$fv|\n";
     $fn = lc $fn;
-    $fv = lc $fv;
+    # Don't lc owner or forwarded
+    $fv = lc $fv unless $fh =~ /^(?:owner|forwarded|usertags|version|source-version)$/;
     $pheader{$fn} = $fv;
     print DEBUG ">$fn~$fv<\n";
 }
@@ -163,7 +171,7 @@ if (defined $header{'resent-from'} && !defined $header{'from'}) {
 }
 defined($header{'from'}) || &quit("no From header");
 
-$replyto = $header{'reply-to'};
+my $replyto = $header{'reply-to'};
 $replyto = '' unless defined $replyto;
 $replyto =~ s/^ +//;
 $replyto =~ s/ +$//;
@@ -171,11 +179,7 @@ unless (length $replyto) {
     $replyto = $header{'from'};
 }
 
-$_= $replyto;
-$_= "$2 <$1>" if m/^([^\<\> \t\n\(\)]+) \(([^\(\)\<\>]+)\)$/;
-$replytocompare= $_;
-print DEBUG "replytocompare >$replytocompare<\n";
-    
+my $subject = '(no subject)';
 if (!defined($header{'subject'})) 
 {
        $brokenness.= <<END;
@@ -185,14 +189,11 @@ useful because the title of a $gBug is determined using this field.
 Please remember to include a Subject field in your messages in future.
 END
 
-# RFC822 actually lists it as an `optional-field'.
-
-    $subject= '(no subject)';
 } else { 
     $subject= $header{'subject'}; 
 }
 
-$ref=-1;
+my $ref=-1;
 $subject =~ s/^Re:\s*//i; $_= $subject."\n";
 if ($tryref < 0 && m/^Bug ?\#(\d+)\D/i) {
     $tryref= $1+0; 
@@ -253,6 +254,20 @@ END
     &filelock('lock/-1'); 
 }
 
+# Attempt to determine which source package this is
+my $source_pr_header = '';
+my $source_package = '';
+if (defined $pheader{source}) {
+     $source_package = $pheader{source};
+}
+elsif (defined $data->{package} or defined $pheader{package}) {
+     my $pkg_src = getpkgsrc();
+     $source_package = $pkg_src->{defined $data->{package}?$data->{package}:$pheader{package}};
+}
+$source_pr_header = "X-$gProject-PR-Source: $source_package\n"
+     if defined $source_package and length $source_package;
+
+# Done and Forwarded Bugs
 if ($codeletter eq 'D' || $codeletter eq 'F') 
 {
     if ($replyto =~ m/$gBounceFroms/o ||
@@ -263,18 +278,22 @@ if ($codeletter eq 'D' || $codeletter eq 'F')
     $markedby= $header{'from'} eq $replyto ? $replyto :
                "$header{'from'} (reply to $replyto)";
     my @generalcc;
-    if ($codeletter eq 'F') {
+    if ($codeletter eq 'F') { # Forwarded
         (&appendlog,&finish) if length($data->{forwarded});
         $receivedat= "forwarded\@$gEmailDomain";
         $markaswhat= 'forwarded';
         $set_forwarded= $header{'to'};
+       # Dissallow forwarded being set to this bug tracking system
+       if (defined $set_forwarded and $set_forwarded =~ /\Q$gEmailDomain\E/) {
+            undef $set_forwarded;
+       }
        if ( length( $gListDomain ) > 0 && length( $gForwardList ) > 0 ) {
            push @generalcc, "$gForwardList\@$gListDomain";
            $generalcc= "$gForwardList\@$gListDomain";
        } else { 
            $generalcc=''; 
         }
-    } else {
+    } else { # Done
         if (length($data->{done}) and
                 not defined $pheader{'source-version'} and
                 not defined $pheader{'version'}) {
@@ -346,7 +365,6 @@ END
     $noticeccval.= join(', ', grep($_ ne $replyto,@maintaddrs));
     $noticeccval =~ s/\s+\n\s+/ /g; 
     $noticeccval =~ s/^\s+/ /; $noticeccval =~ s/\s+$//;
-    if (length($noticeccval)) { $noticecc= "Cc: $noticeccval\n"; }
 
     @process= ($ref,split(/ /,$data->{mergedwith}));
     $orgref= $ref;
@@ -395,7 +413,9 @@ END
               Precedence    => 'bulk',
               "X-$gProject-PR-Message"  => "forwarded $ref",
               "X-$gProject-PR-Package"  => $data->{package},
-              "X-$gProject-PR-Keywords" => $data->{keywords}
+              "X-$gProject-PR-Keywords" => $data->{keywords},
+             # Only have a X-$gProject-PR-Source when we know the source package
+             length($source_package)?("X-$gProject-PR-Source" => $source_package):(),
              ],<<END ,[join("\n",@msg)]),'',[$replyto,@generalbcc,@noticecc],1);
 Your message dated $header{'date'}
 with message-id $header{'message-id'}
@@ -426,7 +446,9 @@ END
               Precedence    => 'bulk',
               "X-$gProject-PR-Message"  => "closed $ref",
               "X-$gProject-PR-Package"  => $data->{package},
-              "X-$gProject-PR-Keywords" => $data->{keywords}
+              "X-$gProject-PR-Keywords" => $data->{keywords},
+             # Only have a X-$gProject-PR-Source when we know the source package
+             length($source_package)?("X-$gProject-PR-Source" => $source_package):(),
              ],<<END ,[$x,join("\n",@msg)]),'',[$replyto,@generalbcc,@noticecc],1);
 Your message dated $header{'date'}
 with message-id $header{'message-id'}
@@ -458,6 +480,8 @@ END
               "X-$gProject-PR-Message"  => "they-closed $ref",
               "X-$gProject-PR-Package"  => "$data->{package}",
               "X-$gProject-PR-Keywords" => "$data->{keywords}",
+             # Only have a X-$gProject-PR-Source when we know the source package
+             length($source_package)?("X-$gProject-PR-Source" => $source_package):(),
               "Reply-To"                => "$ref\@$gEmailDomain",
               "Content-Type"            => 'text/plain; charset="utf-8"',
              ],<<END ,[join("\n",@msg)]),'',undef,1);
@@ -628,6 +652,35 @@ END
     $data->{subject} = $subject;
     $data->{msgid} = $header{'message-id'};
     writebug($ref, $data);
+    # Deal with usertags
+    if (exists $pheader{usertags}) {
+        my $user = $replyto;
+        $user = $pheader{user} if exists $pheader{user};
+        $user =~ s/,.*//;
+        $user =~ s/^.*<(.*)>.*$/$1/;
+        $user =~ s/[(].*[)]//;
+        $user =~ s/^\s*(\S+)\s+.*$/$1/;
+        if ($user ne '' and Debbugs::User::is_valid_user($user)) {
+             $pheader{usertags} =~ s/(?:^\s+|\s+$)//g;
+             my %user_tags;
+             read_usertags(\%user_tags,$user);
+             for my $tag (split /[,\s]+/, $pheader{usertags}) {
+                  if ($tag =~ /^[a-zA-Z0-9.+\@-]+/) {
+                       my %bugs_with_tag; 
+                       @bugs_with_tag{@{$user_tags{$tag}}} = (1) x @{$user_tags{$tag}};
+                       $bugs_with_tag{$ref} = 1;
+                       $user_tags{$tag} = [keys %bugs_with_tag];
+                  }
+             }
+             write_usertags(\%user_tags,$user);
+        }
+        else {
+             $brokenness .=<<END;
+Your message tried to set a usertag, but didn't have a valid
+user set ('$user' isn't valid)
+END
+        }
+    }
     &overwrite("db-h/$hash/$ref.report",
                join("\n",@msg)."\n");
 }
@@ -716,13 +769,13 @@ Resent-Sender: $gMaintainerEmail
 X-$gProject-PR-Message: report $ref
 X-$gProject-PR-Package: $data->{package}
 X-$gProject-PR-Keywords: $data->{keywords}
-$fwd
+${source_pr_header}$fwd
 END
-} elsif ($codeletter eq 'B') {
+} elsif ($codeletter eq 'B') { # Sent to submit
     &htmllog($newref ? "Report" : "Information", "forwarded",
              join(', ',"$gSubmitList\@$gListDomain",@resentccs),
              "<code>$gBug#$ref</code>".
-             (length($data->{package})? "; Package <code>".&sani($data->{package})."</code>" : '').
+             (length($data->{package})? "; Package <code>".html_escape($data->{package})."</code>" : '').
              ".");
     &sendmessage(<<END,["$gSubmitList\@$gListDomain",@resentccs],[@bccs]);
 Subject: $gBug#$ref: $newsubject
@@ -735,9 +788,9 @@ Resent-Sender: $gMaintainerEmail
 X-$gProject-PR-Message: report $ref
 X-$gProject-PR-Package: $data->{package}
 X-$gProject-PR-Keywords: $data->{keywords}
-$fwd
+${source_pr_header}$fwd
 END
-} elsif (@resentccs or @bccs) {
+} elsif (@resentccs or @bccs) { # Quiet or Maintainer
     # D and F done far earlier; B just done - so this must be M or Q
     # We preserve whichever it was in the Reply-To (possibly adding
     # the $gBug#).
@@ -745,13 +798,13 @@ END
         &htmllog($newref ? "Report" : "Information", "forwarded",
                  $resentccval,
                  "<code>$gBug#$ref</code>".
-                 (length($data->{package}) ? "; Package <code>".&sani($data->{package})."</code>" : '').
+                 (length($data->{package}) ? "; Package <code>".html_escape($data->{package})."</code>" : '').
                  ".");
     } else {
         &htmllog($newref ? "Report" : "Information", "stored",
                  "",
                  "<code>$gBug#$ref</code>".
-                 (length($data->{package}) ? "; Package <code>".&sani($data->{package})."</code>" : '').
+                 (length($data->{package}) ? "; Package <code>".html_escape($data->{package})."</code>" : '').
                  ".");
     }
     &sendmessage(<<END,[@resentccs],[@bccs]);
@@ -765,14 +818,14 @@ Resent-Sender: $gMaintainerEmail
 X-$gProject-PR-Message: report $ref
 X-$gProject-PR-Package: $data->{package}
 X-$gProject-PR-Keywords: $data->{keywords}
-$fwd
+${source_pr_header}$fwd
 END
 }
 
-$htmlbreak= length($brokenness) ? "<p>\n".&sani($brokenness)."\n<p>\n" : '';
+$htmlbreak= length($brokenness) ? "<p>\n".html_escape($brokenness)."\n<p>\n" : '';
 $htmlbreak =~ s/\n\n/\n<P>\n\n/g;
 if (length($resentccval)) {
-    $htmlbreak = "  Copy sent to <code>".&sani($resentccval)."</code>.".
+    $htmlbreak = "  Copy sent to <code>".html_escape($resentccval)."</code>.".
         $htmlbreak;
 }
 unless (exists $header{'x-debbugs-no-ack'}) {
@@ -781,20 +834,23 @@ unless (exists $header{'x-debbugs-no-ack'}) {
                  ($veryquiet ?
                   "New $gBug report received and filed, but not forwarded." :
                   "New $gBug report received and forwarded."). $htmlbreak);
-        &sendmessage($veryquiet ? <<END : $codeletter eq 'M' ? <<END : <<END,'');
-From: $gMaintainerEmail ($gProject $gBug Tracking System)
-To: $replyto
-Subject: $gBug#$ref: Acknowledgement of QUIET report
-         ($subject)
-Message-ID: <handler.$ref.$nn.ackquiet\@$gEmailDomain>
-In-Reply-To: $header{'message-id'}
-References: $header{'message-id'}
-Precedence: bulk
-X-$gProject-PR-Message: ack-quiet $ref
-X-$gProject-PR-Package: $data->{package}
-X-$gProject-PR-Keywords: $data->{keywords}
-Reply-To: $ref-quiet\@$gEmailDomain
-
+       if ($veryquiet) {
+            &sendmessage(create_mime_message(
+                      ["X-Loop"      => "$gMaintainerEmail",
+                       From          => "$gMaintainerEmail ($gProject $gBug Tracking System)",
+                       To            => $replyto,
+                        Subject       => "$gBug#$ref: Acknowledgement of QUIET report ($subject)",
+                        "Message-ID"  => "<handler.$ref.$nn.ackquiet\@$gEmailDomain>",
+                        "In-Reply-To" => $header{'message-id'},
+                        References    => $header{'message-id'},
+                        Precedence    => 'bulk',
+                       "X-$gProject-PR-Message"  => "ack-quiet $ref",
+                       "X-$gProject-PR-Package"  => $data->{package},
+                       "X-$gProject-PR-Keywords" => $data->{keywords},
+                       # Only have a X-$gProject-PR-Source when we know the source package
+                       length($source_package)?("X-$gProject-PR-Source" => $source_package):(),
+                       "Reply-To"                => "$ref-quiet\@$gEmailDomain",
+                      ],<<END,[join("\n", @msg)]), '',undef,1);
 Thank you for the problem report you have sent regarding $gProject.
 This is an automatically generated reply, to let you know your message
 has been received.  It has not been forwarded to the package maintainers
@@ -806,25 +862,34 @@ If you wish to submit further information on your problem, please send it
 to $ref-$baddressroot\@$gEmailDomain (and *not*
 to $baddress\@$gEmailDomain).
 
+If you have filed this report in error and wish to close it, please
+send mail to $ref-done\@$gEmailDomain with an explanation
+why the bug report should be closed.
+
 Please do not reply to the address at the top of this message,
 unless you wish to report a problem with the $gBug-tracking system.
 $brokenness
 $gMaintainer
 (administrator, $gProject $gBugs database)
 END
-From: $gMaintainerEmail ($gProject $gBug Tracking System)
-To: $replyto
-Subject: $gBug#$ref: Acknowledgement of maintainer-only report
-         ($subject)
-Message-ID: <handler.$ref.$nn.ackmaint\@$gEmailDomain>
-In-Reply-To: $header{'message-id'}
-References: $header{'message-id'}
-Precedence: bulk
-X-$gProject-PR-Message: ack-maintonly $ref
-X-$gProject-PR-Package: $data->{package}
-X-$gProject-PR-Keywords: $data->{keywords}
-Reply-To: $ref-maintonly\@$gEmailDomain
-
+       }
+       elsif ($codeletter eq 'M') { # Maintonly
+            &sendmessage(create_mime_message(
+                      ["X-Loop"      => "$gMaintainerEmail",
+                       From          => "$gMaintainerEmail ($gProject $gBug Tracking System)",
+                       To            => $replyto,
+                        Subject       => "$gBug#$ref: Acknowledgement of maintainer-only report ($subject)",
+                        "Message-ID"  => "<handler.$ref.$nn.ackmaint\@$gEmailDomain>",
+                        "In-Reply-To" => $header{'message-id'},
+                        References    => $header{'message-id'},
+                        Precedence    => 'bulk',
+                       "X-$gProject-PR-Message" => "ack-maintonly $ref",
+                       "X-$gProject-PR-Package"  => $data->{package},
+                       "X-$gProject-PR-Keywords" => $data->{keywords},
+                       # Only have a X-$gProject-PR-Source when we know the source package
+                       length($source_package)?("X-$gProject-PR-Source" => $source_package):(),
+                       "Reply-To"               => "$ref-maintonly\@$gEmailDomain",
+                      ],<<END,[]), '',undef,1);
 Thank you for the problem report you have sent regarding $gProject.
 This is an automatically generated reply, to let you know your message has
 been received.  It is being forwarded to the package maintainers (but not
@@ -835,24 +900,34 @@ If you wish to submit further information on your problem, please send
 it to $ref-$baddressroot\@$gEmailDomain (and *not*
 to $baddress\@$gEmailDomain).
 
+If you have filed this report in error and wish to close it, please
+send mail to $ref-done\@$gEmailDomain with an explanation
+why the bug report should be closed.
+
 Please do not reply to the address at the top of this message,
 unless you wish to report a problem with the $gBug-tracking system.
 $brokenness
 $gMaintainer
 (administrator, $gProject $gBugs database)
 END
-From: $gMaintainerEmail ($gProject $gBug Tracking System)
-To: $replyto
-Subject: $gBug#$ref: Acknowledgement ($subject)
-Message-ID: <handler.$ref.$nn.ack\@$gEmailDomain>
-In-Reply-To: $header{'message-id'}
-References: $header{'message-id'}
-Precedence: bulk
-X-$gProject-PR-Message: ack $ref
-X-$gProject-PR-Package: $data->{package}
-X-$gProject-PR-Keywords: $data->{keywords}
-Reply-To: $ref\@$gEmailDomain
-
+                  }
+       else {
+            &sendmessage(create_mime_message(
+                      ["X-Loop"      => "$gMaintainerEmail",
+                       From          => "$gMaintainerEmail ($gProject $gBug Tracking System)",
+                       To            => $replyto,
+                        Subject       => "$gBug#$ref: Acknowledgement ($subject)",
+                        "Message-ID"  => "<handler.$ref.$nn.ack\@$gEmailDomain>",
+                        "In-Reply-To" => $header{'message-id'},
+                        References    => $header{'message-id'},
+                        Precedence    => 'bulk',
+                       "X-$gProject-PR-Message"  => "ack $ref",
+                       "X-$gProject-PR-Package"  => $data->{package},
+                       "X-$gProject-PR-Keywords" => $data->{keywords},
+                       # Only have a X-$gProject-PR-Source when we know the source package
+                       length($source_package)?("X-$gProject-PR-Source" => $source_package):(),
+                       "Reply-To"                => "$ref\@$gEmailDomain",
+                      ],<<END,[]), '',undef,1);
 Thank you for the problem report you have sent regarding $gProject.
 This is an automatically generated reply, to let you know your message has
 been received.  It is being forwarded to the package maintainers and other
@@ -862,42 +937,47 @@ If you wish to submit further information on your problem, please send
 it to $ref\@$gEmailDomain (and *not* to
 $baddress\@$gEmailDomain).
 
+If you have filed this report in error and wish to close it, please
+send mail to $ref-done\@$gEmailDomain with an explanation
+why the bug report should be closed.
+
 Please do not reply to the address at the top of this message,
 unless you wish to report a problem with the $gBug-tracking system.
 $brokenness
 $gMaintainer
 (administrator, $gProject $gBugs database)
 END
+                  }
     } elsif ($codeletter ne 'U' and
-             $header{'precedence'} !~ /\b(?:bulk|junk|list)\b/ and
-            # Workaround for gcc mail loops; bugzilla should do Precedence:
-            # instead. Deliberately not in CVS. - cjwatson
-            not exists $header{'x-bugzilla-reason'}) {
+             $header{'precedence'} !~ /\b(?:bulk|junk|list)\b/) {
         &htmllog("Acknowledgement","sent",$replyto,
                  ($veryquiet ? "Extra info received and filed, but not forwarded." :
                   $codeletter eq 'M' ? "Extra info received and forwarded to maintainer." :
                   "Extra info received and forwarded to list."). $htmlbreak);
-        &sendmessage($veryquiet ? <<END : $codeletter eq 'M' ? <<END : <<END,'');
-From: $gMaintainerEmail ($gProject $gBug Tracking System)
-To: $replyto
-Subject: $gBug#$ref: Info received and FILED only
-         (was $subject)
-Message-ID: <handler.$ref.$nn.ackinfoquiet\@$gEmailDomain>
-In-Reply-To: $header{'message-id'}
-References: $header{'message-id'}
-Precedence: bulk
-X-$gProject-PR-Message: ack-info-quiet $ref
-X-$gProject-PR-Package: $data->{package}
-X-$gProject-PR-Keywords: $data->{keywords}
-Reply-To: $ref-quiet\@$gEmailDomain
-
+       if ($veryquiet) {
+            &sendmessage(create_mime_message(
+                      ["X-Loop"      => "$gMaintainerEmail",
+                       From          => "$gMaintainerEmail ($gProject $gBug Tracking System)",
+                       To            => $replyto,
+                        Subject       => "$gBug#$ref: Info received and FILED only (was $subject)",
+                        "Message-ID"  => "<handler.$ref.$nn.ackinfoquiet\@$gEmailDomain>",
+                        "In-Reply-To" => $header{'message-id'},
+                        References    => $header{'message-id'},
+                        Precedence    => 'bulk',
+                       "X-$gProject-PR-Message" => "ack-info-quiet $ref",
+                       "X-$gProject-PR-Package"  => $data->{package},
+                       "X-$gProject-PR-Keywords" => $data->{keywords},
+                       # Only have a X-$gProject-PR-Source when we know the source package
+                       length($source_package)?("X-$gProject-PR-Source" => $source_package):(),
+                       "Reply-To"               => "$ref-maintonly\@$gEmailDomain",
+                      ],<<END,[]), '',undef,1);
 Thank you for the additional information you have supplied regarding
 this problem report.  It has NOT been forwarded to the package
 maintainers, but will accompany the original report in the $gBug
 tracking system.  Please ensure that you yourself have sent a copy of
 the additional information to any relevant developers or mailing lists.
 $resentccexplain
-If you wish to continue to submit further information on your problem,
+If you wish to continue to submit further information on this problem,
 please send it to $ref-$baddressroot\@$gEmailDomain, as before.
 
 Please do not reply to the address at the top of this message,
@@ -906,24 +986,27 @@ $brokenness
 $gMaintainer
 (administrator, $gProject $gBugs database)
 END
-From: $gMaintainerEmail ($gProject $gBug Tracking System)
-To: $replyto
-Subject: $gBug#$ref: Info received for maintainer only
-         (was $subject)
-Message-ID: <handler.$ref.$nn.ackinfomaint\@$gEmailDomain>
-In-Reply-To: $header{'message-id'}
-References: $header{'message-id'}
-Precedence: bulk
-X-$gProject-PR-Message: ack-info-maintonly $ref
-X-$gProject-PR-Package: $data->{package}
-X-$gProject-PR-Keywords: $data->{keywords}
-Reply-To: $ref-maintonly\@$gEmailDomain
-
+                }
+       elsif ($codeletter eq 'M') {
+            &sendmessage(create_mime_message(
+                      ["X-Loop"      => "$gMaintainerEmail",
+                       From          => "$gMaintainerEmail ($gProject $gBug Tracking System)",
+                       To            => $replyto,
+                        Subject       => "$gBug#$ref: Info received for maintainer only (was $subject)",
+                        "Message-ID"  => "<handler.$ref.$nn.ackinfomaint\@$gEmailDomain>",
+                        "In-Reply-To" => $header{'message-id'},
+                        References    => "$header{'message-id'} $data->{msgid}",
+                        Precedence    => 'bulk',
+                       "X-$gProject-PR-Message" => "ack-info-maintonly $ref",
+                       "X-$gProject-PR-Package"  => $data->{package},
+                       "X-$gProject-PR-Keywords" => $data->{keywords},
+                       "Reply-To"               => "$ref-maintonly\@$gEmailDomain",
+                      ],<<END,[]), '',undef,1);
 Thank you for the additional information you have supplied regarding
 this problem report.  It has been forwarded to the package maintainer(s)
 (but not to other interested parties) to accompany the original report.
 $resentccexplain
-If you wish to continue to submit further information on your problem,
+If you wish to continue to submit further information on this problem,
 please send it to $ref-$baddressroot\@$gEmailDomain, as before.
 
 Please do not reply to the address at the top of this message,
@@ -932,22 +1015,29 @@ $brokenness
 $gMaintainer
 (administrator, $gProject $gBugs database)
 END
-From: $gMaintainerEmail ($gProject $gBug Tracking System)
-To: $replyto
-Subject: $gBug#$ref: Info received (was $subject)
-Message-ID: <handler.$ref.$nn.ackinfo\@$gEmailDomain>
-In-Reply-To: $header{'message-id'}
-References: $header{'message-id'}
-Precedence: bulk
-X-$gProject-PR-Message: ack-info $ref
-X-$gProject-PR-Package: $data->{package}
-X-$gProject-PR-Keywords: $data->{keywords}
-
+                  }
+       else {
+            &sendmessage(create_mime_message(
+                      ["X-Loop"      => "$gMaintainerEmail",
+                       From          => "$gMaintainerEmail ($gProject $gBug Tracking System)",
+                       To            => $replyto,
+                        Subject       => "$gBug#$ref: Info received ($subject)",
+                        "Message-ID"  => "<handler.$ref.$nn.ackinfo\@$gEmailDomain>",
+                        "In-Reply-To" => $header{'message-id'},
+                        References    => "$header{'message-id'} $data->{msgid}",
+                        Precedence    => 'bulk',
+                       "X-$gProject-PR-Message"  => "ack-info $ref",
+                       "X-$gProject-PR-Package"  => $data->{package},
+                       "X-$gProject-PR-Keywords" => $data->{keywords},
+                       # Only have a X-$gProject-PR-Source when we know the source package
+                       length($source_package)?("X-$gProject-PR-Source" => $source_package):(),
+                       "Reply-To"                => "$ref\@$gEmailDomain",
+                      ],<<END,[]), '',undef,1);
 Thank you for the additional information you have supplied regarding
 this problem report.  It has been forwarded to the package maintainer(s)
 and to other interested parties to accompany the original report.
 $resentccexplain
-If you wish to continue to submit further information on your problem,
+If you wish to continue to submit further information on this problem,
 please send it to $ref\@$gEmailDomain, as before.
 
 Please do not reply to the address at the top of this message,
@@ -956,10 +1046,9 @@ $brokenness
 $gMaintainer
 (administrator, $gProject $gBugs database)
 END
-# Reply-To: in previous ack disabled by doogie due to mail loops.
-# Are these still a concern?
-# Reply-To: $ref\@$gEmailDomain
-    }
+
+                  }
+   }
 }
 
 &appendlog;
@@ -994,8 +1083,6 @@ sub finish {
 
 &quit("wot no exit");
 
-sub chldhandle { $chldexit = 'yes'; }
-
 sub htmllog {
     local ($whatobj,$whatverb,$where,$desc) = @_;
     my $hash = get_hashname($ref);
@@ -1003,7 +1090,7 @@ sub htmllog {
     print(AP
           "\6\n".
           "<strong>$whatobj $whatverb</strong>".
-          ($where eq '' ? "" : " to <code>".&sani($where)."</code>").
+          ($where eq '' ? "" : " to <code>".html_escape($where)."</code>").
           ":<br>\n". $desc.
           "\n\3\n") || &quit("writing db-h/$hash/$ref.log (lh): $!");
     close(AP) || &quit("closing db-h/$hash/$ref.log (lh): $!");
@@ -1081,6 +1168,7 @@ sub sendmessage {
                      recipients     => $recips);
 }
 
+my $maintainerschecked = 0;
 sub checkmaintainers {
     return if $maintainerschecked++;
     return if !length($data->{package});