X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=scripts%2Fservice;h=eb10acd031a8d15755de92fba2492a899b144937;hb=443472028485f30c0ba63d0680df6e62d29cb5aa;hp=30b411e78bbf13bc1c659ae9f20f83ab0d8ceda6;hpb=0f00ae1b1ddca847996ffe92b96a284145bbe444;p=debbugs.git diff --git a/scripts/service b/scripts/service index 30b411e..eb10acd 100755 --- a/scripts/service +++ b/scripts/service @@ -33,6 +33,10 @@ use Debbugs::Control qw(:all); use Debbugs::Log qw(:misc); use Debbugs::Text qw(:templates); +use Scalar::Util qw(looks_like_number); + +use List::Util qw(first); + use Mail::RFC822::Address; chdir($config{spool_dir}) or @@ -84,6 +88,7 @@ for (@headerlines) { } } $header{'message-id'} ||= ''; +$header{subject} ||= ''; grep(s/\s+$//,@bodylines); @@ -107,14 +112,35 @@ if ( defined($header{'reply-to'}) && $header{'reply-to'} ne "" ) { # This is an error counter which should be incremented every time there is an error. my $errors = 0; -my $controlrequestaddr= ($control ? 'control' : 'request').$config{email_domain}; +my $controlrequestaddr= ($control ? 'control' : 'request').'@'.$config{email_domain}; my $transcript_scalar = ''; my $transcript = IO::Scalar->new(\$transcript_scalar) or die "Unable to create new IO::Scalar"; print {$transcript} "Processing commands for $controlrequestaddr:\n\n"; -# debug level + my $dl = 0; +my %affected_packages; +my %recipients; +# this is the hashref which is passed to all control calls +my %limit = (); + + +my @common_control_options = + (transcript => $transcript, + requester => $header{from}, + request_addr => $controlrequestaddr, + request_msgid => $header{'message-id'}, + request_subject => $header{subject}, + request_nn => $nn, + request_replyto => $replyto, + message => \@log, + affected_bugs => \%bug_affected, + affected_packages => \%affected_packages, + recipients => \%recipients, + limit => \%limit, + ); + my $state= 'idle'; my $lowstate= 'idle'; my $mergelowstate= 'idle'; @@ -155,10 +181,6 @@ our $mismatch; our $action; -# recipients of mail -my %recipients; -# affected_packages -my %affected_packages; my $ok = 0; my $unknowns = 0; my $procline=0; @@ -175,16 +197,22 @@ for ($procline=0; $procline<=$#bodylines; $procline++) { last; } $_= $bodylines[$procline]; s/\s+$//; + # Remove BOM markers from UTF-8 strings + # Fixes #488554 + s/\xef\xbb\xbf//g; next unless m/\S/; print {$transcript} "> $_\n"; next if m/^\s*\#/; $action= ''; - if (m/^stop\s*$/i || m/^quit\s*$/i || m/^--\s*$/ || m/^thank(?:s|\s*you)?\s*$/i || m/^kthxbye\s*$/i) { + if (m/^(?:stop|quit|--|thank(?:s|\s*you)?|kthxbye)\.*\s*$/i) { print {$transcript} "Stopping processing here.\n\n"; last; } elsif (m/^debug\s+(\d+)$/i && $1 >= 0 && $1 <= 1000) { $dl= $1+0; - print {$transcript} "Debug level $dl.\n\n"; + if ($dl > 0 and not grep /debug/,@common_control_options) { + push @common_control_options,(debug => $transcript); + } + print {$transcript} "Debug level $dl.\n\n"; } elsif (m/^(send|get)\s+\#?(\d{2,})$/i) { $ref= $2+0; &sendlynxdoc("bugreport.cgi?bug=$ref","logs for $gBug#$ref"); @@ -277,7 +305,7 @@ END } elsif (m/^usercategory\s+(\S+)(\s+\[hidden\])?\s*$/i) { $ok++; my $catname = $1; - my $hidden = ($2 ne ""); + my $hidden = (defined $2 and $2 ne ""); my $prefix = ""; my @cats; @@ -337,8 +365,11 @@ END push @ords, "$ord DEF"; $catsec--; } - @ords = sort { my ($a1, $a2, $b1, $b2) = split / /, "$a $b"; - $a1 <=> $b1 || $a2 <=> $b2; } @ords; + @ords = sort { + my ($a1, $a2, $b1, $b2) = split / /, "$a $b"; + ((looks_like_number($a1) and looks_like_number($a2))?$a1 <=> $b1:$a1 cmp $b1) || + ((looks_like_number($a2) and looks_like_number($b2))?$a2 <=> $b2:$a2 cmp $b2); + } @ords; $cats[-1]->{"ord"} = [map { m/^.* (\S+)/; $1 eq "DEF" ? $catsec + 1 : $1 } @ords]; } elsif ($o eq "*") { $catsec = 0; @@ -387,12 +418,14 @@ END Debbugs::User::read_usertags(\%ut, $user); my @oldtags = (); my @newtags = (); my @badtags = (); my %chtags; - for my $t (split /[,\s]+/, $tags) { - if ($t =~ m/^[a-zA-Z0-9.+\@-]+$/) { - $chtags{$t} = 1; - } else { - push @badtags, $t; - } + if (defined $tags and length $tags) { + for my $t (split /[,\s]+/, $tags) { + if ($t =~ m/^[a-zA-Z0-9.+\@-]+$/) { + $chtags{$t} = 1; + } else { + push @badtags, $t; + } + } } if (@badtags) { print {$transcript} "Ignoring illegal tag/s: ".join(', ', @badtags).".\nPlease use only alphanumerics, at, dot, plus and dash.\n"; @@ -433,751 +466,425 @@ END } #### "developer only" ones start here } elsif (m/^close\s+\#?(-?\d+)(?:\s+(\d.*))?$/i) { - $ok++; - $ref= $1; - $bug_affected{$ref}=1; - my $version= $2; - if (&setbug) { - print {$transcript} "'close' is deprecated; see http://$gWebDomain/Developer$gHTMLSuffix#closing.\n"; - if (length($data->{done}) and not defined($version)) { - print {$transcript} "$gBug is already closed, cannot re-close.\n\n"; - &nochangebug; - } else { - $action= "$gBug " . - (defined($version) ? - "marked as fixed in version $version" : - "closed") . - ", send any further explanations to $data->{originator}"; - do { - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - actions_taken => {done => 1}, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - $data->{done}= $replyto; - my @keywords= split ' ', $data->{keywords}; - my $extramessage = ''; - if (grep $_ eq 'pending', @keywords) { - $extramessage= "Removed pending tag.\n"; - $data->{keywords}= join ' ', grep $_ ne 'pending', - @keywords; - } - addfixedversions($data, $data->{package}, $version, 'binary'); - - my $message= <{originator} -Subject: $gBug#$ref acknowledged by developer - ($header{'subject'}) -References: $header{'message-id'} $data->{msgid} -In-Reply-To: $data->{msgid} -Message-ID: -Reply-To: $ref\@$gEmailDomain -X-$gProject-PR-Message: they-closed-control $ref - -This is an automatic notification regarding your $gBug report -#$ref: $data->{subject}, -which was filed against the $data->{package} package. - -It has been marked as closed by one of the developers, namely -$replyto. - -You should be hearing from them with a substantive response shortly, -in case you haven't already. If not, please contact them directly. - -$gMaintainer -(administrator, $gProject $gBugs database) - -END - &sendmailmessage($message,$data->{originator}); - } while (&getnextbug); - } - } - } elsif (m/^reassign\s+\#?(-?\d+)\s+(\S+)(?:\s+(\d.*))?$/i) { $ok++; $ref= $1; - my $newpackage= $2; - $bug_affected{$ref}=1; + $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; + if (defined $2) { + eval { + set_fixed(@common_control_options, + bug => $ref, + fixed => $2, + add => 1, + ); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to add fixed version '$2' to $ref: ".cleanup_eval_fail($@,$debug)."\n"; + } + } + eval { + set_done(@common_control_options, + done => 1, + bug => $ref, + reopen => 0, + notify_submitter => 1, + clear_fixed => 0, + ); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to mark $ref as done: ".cleanup_eval_fail($@,$debug)."\n"; + } + } elsif (m/^reassign\s+\#?(-?\d+)\s+ # bug and command + (?:(?:((?:src:|source:)?$config{package_name_re}) # new package + (?:\s+((?:$config{package_name_re}\/)? + $config{package_version_re}))?)| # optional version + ((?:src:|source:)?$config{package_name_re} # multiple package form + (?:\s*\,\s*(?:src:|source:)?$config{package_name_re})+)) + \s*$/xi) { + $ok++; + $ref= $1; + my @new_packages; + if (not defined $2) { + push @new_packages, split /\s*\,\s*/,$4; + } + else { + push @new_packages, $2; + } + @new_packages = map {y/A-Z/a-z/; s/^(?:src|source):/src:/; $_;} @new_packages; + $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; my $version= $3; - $newpackage =~ y/A-Z/a-z/; - if (&setbug) { - if (length($data->{package})) { - $action= "$gBug reassigned from package \`$data->{package}'". - " to \`$newpackage'."; - } else { - $action= "$gBug assigned to package \`$newpackage'."; - } - do { - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - $data->{package}= $newpackage; - $data->{found_versions}= []; - $data->{fixed_versions}= []; - # TODO: what if $newpackage is a source package? - addfoundversions($data, $data->{package}, $version, 'binary'); - add_recipients(data => $data, - recipients => \%recipients, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - } while (&getnextbug); - } - } elsif (m/^reopen\s+\#?(-?\d+)$/i ? ($noriginator='', 1) : - m/^reopen\s+\#?(-?\d+)\s+\=$/i ? ($noriginator='', 1) : - m/^reopen\s+\#?(-?\d+)\s+\!$/i ? ($noriginator=$replyto, 1) : - m/^reopen\s+\#?(-?\d+)\s+(\S.*\S)$/i ? ($noriginator=$2, 1) : 0) { + eval { + set_package(@common_control_options, + bug => $ref, + package => \@new_packages, + ); + # if there is a version passed, we make an internal call + # to set_found + if (defined($version) && length $version) { + set_found(@common_control_options, + bug => $ref, + found => $version, + ); + } + }; + if ($@) { + $errors++; + print {$transcript} "Failed to clear fixed versions and reopen on $ref: ".cleanup_eval_fail($@,$debug)."\n"; + } + } elsif (m/^reopen\s+\#?(-?\d+)(?:\s+([\=\!]|(?:\S.*\S)))?$/i) { $ok++; $ref= $1; - $bug_affected{$ref}=1; - if (&setbug) { - if (@{$data->{fixed_versions}}) { - print {$transcript} "'reopen' may be inappropriate when a bug has been closed with a version;\nyou may need to use 'found' to remove fixed versions.\n"; - } - if (!length($data->{done})) { - print {$transcript} "$gBug is already open, cannot reopen.\n\n"; - &nochangebug; - } else { - $action= - $noriginator eq '' ? "$gBug reopened, originator not changed." : - "$gBug reopened, originator set to $noriginator."; - do { - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - $data->{originator}= $noriginator eq '' ? $data->{originator} : $noriginator; - $data->{fixed_versions}= []; - $data->{done}= ''; - } while (&getnextbug); - } - } - } elsif (m{^found\s+\#?(-?\d+) + $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; + my $new_submitter = $2; + if (defined $new_submitter) { + if ($new_submitter eq '=') { + undef $new_submitter; + } + elsif ($new_submitter eq '!') { + $new_submitter = $replyto; + } + } + eval { + set_done(@common_control_options, + bug => $ref, + reopen => 1, + submitter => $new_submitter, + ); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to reopen $ref: ".cleanup_eval_fail($@,$debug)."\n"; + } + } elsif (m{^(?:(?i)found)\s+\#?(-?\d+) (?:\s+((?:$config{package_name_re}\/)? - $config{package_version_re}))?$}ix) { + $config{package_version_re} + # allow for multiple packages + (?:\s*,\s*(?:$config{package_name_re}\/)? + $config{package_version_re})*) + )?$}x) { $ok++; $ref= $1; - my $version= $2; - if (&setbug) { - if (!length($data->{done}) and not defined($version)) { - print {$transcript} "$gBug is already open, cannot reopen.\n\n"; + $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; + my @versions; + if (defined $2) { + @versions = split /\s*,\s*/,$2; + eval { + set_found(@common_control_options, + bug => $ref, + found => \@versions, + add => 1, + ); + }; + if ($@) { $errors++; - &nochangebug; - } else { - $action= - defined($version) ? - "$gBug marked as found in version $version." : - "$gBug reopened."; - do { - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - # The 'done' field gets a bit weird with version - # tracking, because a bug may be closed by multiple - # people in different branches. Until we have something - # more flexible, we set it every time a bug is fixed, - # and clear it when a bug is found in a version greater - # than any version in which the bug is fixed or when - # a bug is found and there is no fixed version - if (defined $version) { - my ($version_only) = $version =~ m{([^/]+)$}; - addfoundversions($data, $data->{package}, $version, 'binary'); - my @fixed_order = sort {Debbugs::Versions::Dpkg::vercmp($a,$b);} - map {s{.+/}{}; $_;} @{$data->{fixed_versions}}; - if (not @fixed_order or (Debbugs::Versions::Dpkg::vercmp($version_only,$fixed_order[-1]) >= 0)) { - $action = "$gBug marked as found in version $version and reopened." - if length $data->{done}; - $data->{done} = ''; - } - } else { - # Versionless found; assume old-style "not fixed at - # all". - $data->{fixed_versions} = []; - $data->{done} = ''; - } - } while (&getnextbug); - } - } - } elsif (m[^notfound\s+\#?(-?\d+)\s+ - ((?:$config{package_name_re}\/)? - \S+)\s*$]ix) { + print {$transcript} "Failed to add found on $ref: ".cleanup_eval_fail($@,$debug)."\n"; + } + } + else { + eval { + set_fixed(@common_control_options, + bug => $ref, + fixed => [], + reopen => 1, + ); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to clear fixed versions and reopen on $ref: ".cleanup_eval_fail($@,$debug)."\n"; + } + } + } + elsif (m{^(?:(?i)notfound)\s+\#?(-?\d+) + \s+((?:$config{package_name_re}\/)? + $config{package_version_re} + # allow for multiple packages + (?:\s*,\s*(?:$config{package_name_re}\/)? + $config{package_version_re})* + )$}x) { $ok++; $ref= $1; - my $version= $2; - if (&setbug) { - $action= "$gBug no longer marked as found in version $version."; - if (length($data->{done})) { - $extramessage= "(By the way, this $gBug is currently marked as done.)\n"; - } - do { - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - removefoundversions($data, $data->{package}, $version, 'binary'); - } while (&getnextbug); - } - } - elsif (m[^fixed\s+\#?(-?\d+)\s+ - ((?:$config{package_name_re}\/)? - $config{package_version_re})\s*$]ix) { + $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; + my @versions; + @versions = split /\s*,\s*/,$2; + eval { + set_found(@common_control_options, + bug => $ref, + found => \@versions, + remove => 1, + ); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to remove found on $ref: ".cleanup_eval_fail($@,$debug)."\n"; + } + } + elsif (m{^(?:(?i)fixed)\s+\#?(-?\d+) + \s+((?:$config{package_name_re}\/)? + $config{package_version_re} + # allow for multiple packages + (?:\s*,\s*(?:$config{package_name_re}\/)? + $config{package_version_re})*) + \s*$}x) { $ok++; $ref= $1; - my $version= $2; - if (&setbug) { - $action= - defined($version) ? - "$gBug marked as fixed in version $version." : - "$gBug reopened."; - do { - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - addfixedversions($data, $data->{package}, $version, 'binary'); - } while (&getnextbug); + $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; + my @versions; + @versions = split /\s*,\s*/,$2; + eval { + set_fixed(@common_control_options, + bug => $ref, + fixed => \@versions, + add => 1, + ); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to add fixed on $ref: ".cleanup_eval_fail($@,$debug)."\n"; } - } - elsif (m[^notfixed\s+\#?(-?\d+)\s+ - ((?:$config{package_name_re}\/)? - \S+)\s*$]ix) { + } + elsif (m{^(?:(?i)notfixed)\s+\#?(-?\d+) + \s+((?:$config{package_name_re}\/)? + $config{package_version_re} + # allow for multiple packages + (?:\s*,\s*(?:$config{package_name_re}\/)? + $config{package_version_re})*) + \s*$}x) { $ok++; $ref= $1; - my $version= $2; - if (&setbug) { - $action= - defined($version) ? - "$gBug no longer marked as fixed in version $version." : - "$gBug reopened."; - do { - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - removefixedversions($data, $data->{package}, $version, 'binary'); - } while (&getnextbug); + $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; + my @versions; + @versions = split /\s*,\s*/,$2; + eval { + set_fixed(@common_control_options, + bug => $ref, + fixed => \@versions, + remove => 1, + ); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to remove fixed on $ref: ".cleanup_eval_fail($@,$debug)."\n"; } - } - elsif (m/^submitter\s+\#?(-?\d+)\s+\!$/i ? ($newsubmitter=$replyto, 1) : - m/^submitter\s+\#?(-?\d+)\s+(\S.*\S)$/i ? ($newsubmitter=$2, 1) : 0) { + } + elsif (m/^submitter\s+\#?(-?\d+)\s+(\!|\S.*\S)$/i) { $ok++; $ref= $1; - $bug_affected{$ref}=1; - if ($ref =~ m/^-\d+$/ && defined $clonebugs{$ref}) { - $ref = $clonebugs{$ref}; - } - if (not Mail::RFC822::Address::valid($newsubmitter)) { - transcript("$newsubmitter is not a valid e-mail address; not changing submitter\n"); + $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; + my $newsubmitter = $2 eq '!' ? $replyto : $2; + if (not Mail::RFC822::Address::valid($newsubmitter)) { + print {$transcript} "$newsubmitter is not a valid e-mail address; not changing submitter\n"; $errors++; } - elsif (&getbug) { - if (&checkpkglimit) { - &foundbug; - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - $oldsubmitter= $data->{originator}; - $data->{originator}= $newsubmitter; - $action= "Changed $gBug submitter from $oldsubmitter to $newsubmitter."; - &savebug; - print {$transcript} "$action\n"; - if (length($data->{done})) { - print {$transcript} "(By the way, that $gBug is currently marked as done.)\n"; - } - print {$transcript} "\n"; - $message= <{msgid} -In-Reply-To: $data->{msgid} -Message-ID: -Reply-To: $ref\@$gEmailDomain -X-$gProject-PR-Message: submitter-changed $ref - -The submitter address recorded for your $gBug report -#$ref: $data->{subject} -has been changed. - -The old submitter address for this report was -$oldsubmitter. -The new submitter address is -$newsubmitter. - -This change was made by -$replyto. -If it was incorrect, please contact them directly. - -$gMaintainer -(administrator, $gProject $gBugs database) - -END - &sendmailmessage($message,$oldsubmitter); - } else { - &cancelbug; - } - } else { - ¬foundbug; + else { + eval { + set_submitter(@common_control_options, + bug => $ref, + submitter => $newsubmitter, + ); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to set submitter on $ref: ".cleanup_eval_fail($@,$debug)."\n"; + } } } elsif (m/^forwarded\s+\#?(-?\d+)\s+(\S.*\S)$/i) { $ok++; $ref= $1; - my $whereto= $2; - $bug_affected{$ref}=1; - if (&setbug) { - if (length($data->{forwarded})) { - $action= "Forwarded-to-address changed from $data->{forwarded} to $whereto."; - } else { - $action= "Noted your statement that $gBug has been forwarded to $whereto."; - } - if (length($data->{done})) { - $extramessage= "(By the way, this $gBug is currently marked as done.)\n"; - } - do { - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - actions_taken => {forwarded => 1}, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - $data->{forwarded}= $whereto; - } while (&getnextbug); - } + my $forward_to= $2; + $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; + eval { + set_forwarded(@common_control_options, + bug => $ref, + forwarded => $forward_to, + ); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to set the forwarded-to-address of $ref: ".cleanup_eval_fail($@,$debug)."\n"; + } } elsif (m/^notforwarded\s+\#?(-?\d+)$/i) { $ok++; $ref= $1; - $bug_affected{$ref}=1; - if (&setbug) { - if (!length($data->{forwarded})) { - print {$transcript} "$gBug is not marked as having been forwarded.\n\n"; - &nochangebug; - } else { - $action= "Removed annotation that $gBug had been forwarded to $data->{forwarded}."; - do { - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients. - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - $data->{forwarded}= ''; - } while (&getnextbug); - } - } - } elsif (m/^severity\s+\#?(-?\d+)\s+([-0-9a-z]+)$/i || - m/^priority\s+\#?(-?\d+)\s+([-0-9a-z]+)$/i) { + $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; + eval { + set_forwarded(@common_control_options, + bug => $ref, + forwarded => undef, + ); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to clear the forwarded-to-address of $ref: ".cleanup_eval_fail($@,$debug)."\n"; + } + } elsif (m/^(?:severity|priority)\s+\#?(-?\d+)\s+([-0-9a-z]+)$/i) { $ok++; $ref= $1; - $bug_affected{$ref}=1; + $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; my $newseverity= $2; - if (!grep($_ eq $newseverity, @gSeverityList, "$gDefaultSeverity")) { - print {$transcript} "Severity level \`$newseverity' is not known.\n". - "Recognized are: $gShowSeverities.\n\n"; - $errors++; - } elsif (exists $gObsoleteSeverities{$newseverity}) { + if (exists $gObsoleteSeverities{$newseverity}) { print {$transcript} "Severity level \`$newseverity' is obsolete. " . "Use $gObsoleteSeverities{$newseverity} instead.\n\n"; $errors++; - } elsif (&setbug) { - my $printseverity= $data->{severity}; - $printseverity= "$gDefaultSeverity" if $printseverity eq ''; - $action= "Severity set to \`$newseverity' from \`$printseverity'"; - do { - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - if (defined $gStrongList and isstrongseverity($newseverity)) { - addbcc("$gStrongList\@$gListDomain"); - } - $data->{severity}= $newseverity; - } while (&getnextbug); - } - } elsif (m/^tags?\s+\#?(-?\d+)\s+(([=+-])\s*)?(\S.*)?$/i) { + } elsif (not defined first {$_ eq $newseverity} + (@gSeverityList, "$gDefaultSeverity")) { + print {$transcript} "Severity level \`$newseverity' is not known.\n". + "Recognized are: $gShowSeverities.\n\n"; + $errors++; + } else { + eval { + set_severity(@common_control_options, + bug => $ref, + severity => $newseverity, + ); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to set severity of $config{bug} $ref to $newseverity: ".cleanup_eval_fail($@,$debug)."\n"; + } + } + } elsif (m/^tags?\s+\#?(-?\d+)\s+(\S.*)$/i) { $ok++; $ref = $1; - my $addsubcode = $3; - my $tags = $4; - $bug_affected{$ref}=1; - my $addsub = "add"; - if (defined $addsubcode) { - $addsub = "sub" if ($addsubcode eq "-"); - $addsub = "add" if ($addsubcode eq "+"); - $addsub = "set" if ($addsubcode eq "="); - } - my @okaytags = (); - my @badtags = (); - foreach my $t (split /[\s,]+/, $tags) { - if (!grep($_ eq $t, @gTags)) { - push @badtags, $t; - } else { - push @okaytags, $t; + $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; + my $tags = $2; + my @tags = map {m/^([+=-])(.+)/ ? ($1,$2):($_)} split /[\s,]+/, $tags; + # this is an array of hashrefs which contain two elements, the + # first of which is the array of tags, the second is the + # option to pass to set_tag (we use a hashref here to make it + # more obvious what is happening) + my @tag_operations; + my @badtags; + for my $tag (@tags) { + if ($tag =~ /^[=+-]$/) { + if ($tag eq '=') { + @tag_operations = {tags => [], + option => [], + }; + } + elsif ($tag eq '-') { + push @tag_operations, + {tags => [], + option => [remove => 1], + }; + } + elsif ($tag eq '+') { + push @tag_operations, + {tags => [], + option => [add => 1], + }; + } + next; + } + if (not defined first {$_ eq $tag} @{$config{tags}}) { + push @badtags, $tag; + next; } + if (not @tag_operations) { + @tag_operations = {tags => [], + option => [add => 1], + }; + } + push @{$tag_operations[-1]{tags}},$tag; } if (@badtags) { print {$transcript} "Unknown tag/s: ".join(', ', @badtags).".\n". "Recognized are: ".join(' ', @gTags).".\n\n"; $errors++; } - if (&setbug) { - if ($data->{keywords} eq '') { - print {$transcript} "There were no tags set.\n"; - } else { - print {$transcript} "Tags were: $data->{keywords}\n"; - } - if ($addsub eq "set") { - $action= "Tags set to: " . join(", ", @okaytags); - } elsif ($addsub eq "add") { - $action= "Tags added: " . join(", ", @okaytags); - } elsif ($addsub eq "sub") { - $action= "Tags removed: " . join(", ", @okaytags); + eval { + for my $operation (@tag_operations) { + set_tag(@common_control_options, + bug => $ref, + tag => [@{$operation->{tags}}], + warn_on_bad_tags => 0, # don't warn on bad tags, + # 'cause we do that above + @{$operation->{option}}, + ); } - do { - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - $data->{keywords} = '' if ($addsub eq "set"); - # Allow removing obsolete tags. - if ($addsub eq "sub") { - foreach my $t (@badtags) { - $data->{keywords} = join ' ', grep $_ ne $t, - split ' ', $data->{keywords}; - } - } - # Now process all other additions and subtractions. - foreach my $t (@okaytags) { - $data->{keywords} = join ' ', grep $_ ne $t, - split ' ', $data->{keywords}; - $data->{keywords} = "$t $data->{keywords}" unless($addsub eq "sub"); - } - $data->{keywords} =~ s/\s*$//; - } while (&getnextbug); + }; + if ($@) { + # we intentionally have two errors here if there is a bad + # tag and the above fails for some reason + $errors++; + print {$transcript} "Failed to alter tags of $config{bug} $ref: ".cleanup_eval_fail($@,$debug)."\n"; } - } elsif (m/^(un)?block\s+\#?(-?\d+)\s+(by|with)\s+(\S.*)?$/i) { + } elsif (m/^(un)?block\s+\#?(-?\d+)\s+(?:by|with)\s+(\S.*)?$/i) { $ok++; - my $bugnum = $2; my $blockers = $4; - my $addsub = "add"; - $addsub = "sub" if ($1 eq "un"); - if ($bugnum =~ m/^-\d+$/ && defined $clonebugs{$bugnum}) { - $bugnum = $clonebugs{$bugnum}; - } - - my @okayblockers; - my @badblockers; - foreach my $b (split /[\s,]+/, $blockers) { - $b=~s/^\#//; - if ($b=~/[0-9]+/) { - $ref=$b; - if ($ref =~ m/^-\d+$/ && defined $clonebugs{$ref}) { - $ref = $clonebugs{$ref}; - } - if (&getbug) { - &foundbug; - push @okayblockers, $ref; - - # add to the list all bugs that are merged with $b, - # because all of their data must be kept in sync - my @thisbugmergelist= split(/ /,$data->{mergedwith}); - &cancelbug; - - foreach $ref (@thisbugmergelist) { - if (&getbug) { - push @okayblockers, $ref; - &cancelbug; - } - } - } - else { - ¬foundbug; - push @badblockers, $ref; - } - } - else { - push @badblockers, $b; - } - } - if (@badblockers) { - print {$transcript} "Unknown blocking bug/s: ".join(', ', @badblockers).".\n"; + $ref= $2; + my $add_remove = defined $1 && $1 eq 'un'; + my @blockers = map {exists $clonebugs{$_}?$clonebugs{$_}:$_} split /[\s,]+/, $3; + $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; + eval { + set_blocks(@common_control_options, + bug => $ref, + block => \@blockers, + $add_remove ? (remove => 1):(add => 1), + ); + }; + if ($@) { $errors++; - } - - $ref=$bugnum; - if (&setbug) { - if ($data->{blockedby} eq '') { - print {$transcript} "Was not blocked by any bugs.\n"; - } else { - print {$transcript} "Was blocked by: $data->{blockedby}\n"; - } - if ($addsub eq "set") { - $action= "Blocking bugs of $bugnum set to: " . join(", ", @okayblockers); - } elsif ($addsub eq "add") { - $action= "Blocking bugs of $bugnum added: " . join(", ", @okayblockers); - } elsif ($addsub eq "sub") { - $action= "Blocking bugs of $bugnum removed: " . join(", ", @okayblockers); - } - my %removedblocks; - my %addedblocks; - do { - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - my @oldblockerlist = split ' ', $data->{blockedby}; - $data->{blockedby} = '' if ($addsub eq "set"); - foreach my $b (@okayblockers) { - $data->{blockedby} = manipset($data->{blockedby}, $b, - ($addsub ne "sub")); - } - - foreach my $b (@oldblockerlist) { - if (! grep { $_ eq $b } split ' ', $data->{blockedby}) { - push @{$removedblocks{$b}}, $ref; - } - } - foreach my $b (split ' ', $data->{blockedby}) { - if (! grep { $_ eq $b } @oldblockerlist) { - push @{$addedblocks{$b}}, $ref; - } - } - } while (&getnextbug); - - # Now that the blockedby data is updated, change blocks data - # to match the changes. - foreach $ref (keys %addedblocks) { - if (&getbug) { - foreach my $b (@{$addedblocks{$ref}}) { - $data->{blocks} = manipset($data->{blocks}, $b, 1); - } - &savebug; - } - } - foreach $ref (keys %removedblocks) { - if (&getbug) { - foreach my $b (@{$removedblocks{$ref}}) { - $data->{blocks} = manipset($data->{blocks}, $b, 0); - } - &savebug; - } - } + print {$transcript} "Failed to set blocking bugs of $ref: ".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m/^retitle\s+\#?(-?\d+)\s+(\S.*\S)\s*$/i) { $ok++; $ref= $1; my $newtitle= $2; - $bug_affected{$ref}=1; - if ($ref =~ m/^-\d+$/ && defined $clonebugs{$ref}) { - $ref = $clonebugs{$ref}; + $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; + eval { + set_title(@common_control_options, + bug => $ref, + title => $newtitle, + ); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to set the title of $ref: ".cleanup_eval_fail($@,$debug)."\n"; } - if (&getbug) { - if (&checkpkglimit) { - &foundbug; - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - my $oldtitle = $data->{subject}; - $data->{subject}= $newtitle; - $action= "Changed $gBug title to `$newtitle' from `$oldtitle'."; - &savebug; - print {$transcript} "$action\n"; - if (length($data->{done})) { - print {$transcript} "(By the way, that $gBug is currently marked as done.)\n"; - } - print {$transcript} "\n"; - } else { - &cancelbug; - } - } else { - ¬foundbug; - } } elsif (m/^unmerge\s+\#?(-?\d+)$/i) { $ok++; $ref= $1; - $bug_affected{$ref} = 1; - if (&setbug) { - if (!length($data->{mergedwith})) { - print {$transcript} "$gBug is not marked as being merged with any others.\n\n"; - &nochangebug; - } else { - $mergelowstate eq 'locked' || die "$mergelowstate ?"; - $action= "Disconnected #$ref from all other report(s)."; - my @newmergelist= split(/ /,$data->{mergedwith}); - my $discref= $ref; - @bug_affected{@newmergelist} = 1 x @newmergelist; - do { - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - $data->{mergedwith}= ($ref == $discref) ? '' - : join(' ',grep($_ ne $ref,@newmergelist)); - } while (&getnextbug); - } + $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; + eval { + set_merged(@common_control_options, + bug => $ref, + ); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to unmerge $ref: $@".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m/^merge\s+#?(-?\d+(\s+#?-?\d+)+)\s*$/i) { $ok++; - my @tomerge= sort { $a <=> $b } split(/\s+#?/,$1); - my @newmergelist= (); - my %tags = (); - my %found = (); - my %fixed = (); - &getmerge; - while (defined($ref= shift(@tomerge))) { - print {$transcript} "D| checking merge $ref\n" if $dl; - $ref+= 0; - if ($ref =~ m/^-\d+$/ && defined $clonebugs{$ref}) { - $ref = $clonebugs{$ref}; - } - next if grep($_ == $ref,@newmergelist); - if (!&getbug) { ¬foundbug; @newmergelist=(); last } - if (!&checkpkglimit) { &cancelbug; @newmergelist=(); last; } - &foundbug; - print {$transcript} "D| adding $ref ($data->{mergedwith})\n" if $dl; - $mismatch= ''; - &checkmatch('package','m_package',$data->{package},@newmergelist); - &checkmatch('forwarded addr','m_forwarded',$data->{forwarded},@newmergelist); - $data->{severity} = '$gDefaultSeverity' if $data->{severity} eq ''; - &checkmatch('severity','m_severity',$data->{severity},@newmergelist); - &checkmatch('blocks','m_blocks',$data->{blocks},@newmergelist); - &checkmatch('blocked-by','m_blockedby',$data->{blockedby},@newmergelist); - &checkmatch('done mark','m_done',length($data->{done}) ? 'done' : 'open',@newmergelist); - &checkmatch('owner','m_owner',$data->{owner},@newmergelist); - &checkmatch('summary','m_summary',$data->{summary},@newmergelist); - &checkmatch('affects','m_affects',$data->{affects},@newmergelist); - foreach my $t (split /\s+/, $data->{keywords}) { $tags{$t} = 1; } - foreach my $f (@{$data->{found_versions}}) { $found{$f} = 1; } - foreach my $f (@{$data->{fixed_versions}}) { $fixed{$f} = 1; } - if (length($mismatch)) { - print {$transcript} "Mismatch - only $gBugs in same state can be merged:\n". - $mismatch."\n"; - $errors++; - &cancelbug; @newmergelist=(); last; - } - push(@newmergelist,$ref); - push(@tomerge,split(/ /,$data->{mergedwith})); - &cancelbug; - } - if (@newmergelist) { - @newmergelist= sort { $a <=> $b } @newmergelist; - $action= "Merged @newmergelist."; - delete @fixed{keys %found}; - for $ref (@newmergelist) { - &getbug || die "huh ? $gBug $ref disappeared during merge"; - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - @bug_affected{@newmergelist} = 1 x @newmergelist; - $data->{mergedwith}= join(' ',grep($_ != $ref,@newmergelist)); - $data->{keywords}= join(' ', keys %tags); - $data->{found_versions}= [sort keys %found]; - $data->{fixed_versions}= [sort keys %fixed]; - &savebug; - } - print {$transcript} "$action\n\n"; + my @tomerge; + ($ref,@tomerge) = map {exists $clonebugs{$_}?$clonebugs{$_}:$_} + split(/\s+#?/,$1); + eval { + set_merged(@common_control_options, + bug => $ref, + merge_with => \@tomerge, + ); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to merge $ref: $@".cleanup_eval_fail($@,$debug)."\n"; } - &endmerge; } elsif (m/^forcemerge\s+\#?(-?\d+(?:\s+\#?-?\d+)+)\s*$/i) { $ok++; - my @temp = split /\s+\#?/,$1; - my $master_bug = shift @temp; - my $master_bug_data; - my @tomerge = sort { $a <=> $b } @temp; - unshift @tomerge,$master_bug; - print {$transcript} "D| force merging ".join(',',@tomerge)."\n" if $dl; - my @newmergelist= (); - my %tags = (); - my %found = (); - my %fixed = (); - # Here we try to do the right thing. - # First, if the bugs are in the same package, we merge all of the found, fixed, and tags. - # If not, we discard the found and fixed. - # Everything else we set to the values of the first bug. - &getmerge; - while (defined($ref= shift(@tomerge))) { - print {$transcript} "D| checking merge $ref\n" if $dl; - $ref+= 0; - if ($ref =~ m/^-\d+$/ && defined $clonebugs{$ref}) { - $ref = $clonebugs{$ref}; - } - next if grep($_ == $ref,@newmergelist); - if (!&getbug) { ¬foundbug; @newmergelist=(); last } - if (!&checkpkglimit) { &cancelbug; @newmergelist=(); last; } - &foundbug; - print {$transcript} "D| adding $ref ($data->{mergedwith})\n" if $dl; - $master_bug_data = $data if not defined $master_bug_data; - if ($data->{package} ne $master_bug_data->{package}) { - print {$transcript} "Mismatch - only $gBugs in the same package can be forcibly merged:\n". - "$gBug $ref is not in the same package as $master_bug\n"; - $errors++; - &cancelbug; @newmergelist=(); last; - } - for my $t (split /\s+/,$data->{keywords}) { - $tags{$t} = 1; - } - @found{@{$data->{found_versions}}} = (1) x @{$data->{found_versions}}; - @fixed{@{$data->{fixed_versions}}} = (1) x @{$data->{fixed_versions}}; - push(@newmergelist,$ref); - push(@tomerge,split(/ /,$data->{mergedwith})); - &cancelbug; - } - if (@newmergelist) { - @newmergelist= sort { $a <=> $b } @newmergelist; - $action= "Forcibly Merged @newmergelist."; - delete @fixed{keys %found}; - for $ref (@newmergelist) { - &getbug || die "huh ? $gBug $ref disappeared during merge"; - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - @bug_affected{@newmergelist} = 1 x @newmergelist; - $data->{mergedwith}= join(' ',grep($_ != $ref,@newmergelist)); - $data->{keywords}= join(' ', keys %tags); - $data->{found_versions}= [sort keys %found]; - $data->{fixed_versions}= [sort keys %fixed]; - my @field_list = qw(forwarded package severity blocks blockedby owner done affects summary); - @{$data}{@field_list} = @{$master_bug_data}{@field_list}; - &savebug; - } - print {$transcript} "$action\n\n"; + my @tomerge; + ($ref,@tomerge) = map {exists $clonebugs{$_}?$clonebugs{$_}:$_} + split(/\s+#?/,$1); + eval { + set_merged(@common_control_options, + bug => $ref, + merge_with => \@tomerge, + force => 1, + masterbug => 1, + ); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to forcibly merge $ref: ".cleanup_eval_fail($@,$debug)."\n"; } - &endmerge; } elsif (m/^clone\s+#?(\d+)\s+((-\d+\s+)*-\d+)\s*$/i) { $ok++; @@ -1186,73 +893,65 @@ END my $newbugsneeded = scalar(@newclonedids); $ref = $origref; + if (exists $clonebugs{$ref}) { + $ref = $clonebugs{$ref}; + } $bug_affected{$ref} = 1; - if (&setbug) { - $affected_packages{$data->{package}} = 1; - if (length($data->{mergedwith})) { - print {$transcript} "$gBug is marked as being merged with others. Use an existing clone.\n\n"; - $errors++; - &nochangebug; - } else { - &filelock("nextnumber.lock"); - open(N,"nextnumber") || die "nextnumber: read: $!"; - my $v=; $v =~ s/\n$// || die "nextnumber bad format"; - my $firstref= $v+0; $v += $newbugsneeded; - open(NN,">nextnumber"); print NN "$v\n"; close(NN); - &unfilelock; - - my $lastref = $firstref + $newbugsneeded - 1; - - if ($newbugsneeded == 1) { - $action= "$gBug $origref cloned as bug $firstref."; - } else { - $action= "$gBug $origref cloned as bugs $firstref-$lastref."; - } - - my $blocks = $data->{blocks}; - my $blockedby = $data->{blockedby}; - - &getnextbug; - my $ohash = get_hashname($origref); - my $clone = $firstref; - @bug_affected{@newclonedids} = 1 x @newclonedids; - for my $newclonedid (@newclonedids) { - $clonebugs{$newclonedid} = $clone; - - my $hash = get_hashname($clone); - copy("db-h/$ohash/$origref.log", "db-h/$hash/$clone.log"); - copy("db-h/$ohash/$origref.status", "db-h/$hash/$clone.status"); - copy("db-h/$ohash/$origref.summary", "db-h/$hash/$clone.summary"); - copy("db-h/$ohash/$origref.report", "db-h/$hash/$clone.report"); - &bughook('new', $clone, $data); - - # Update blocking info of bugs blocked by or blocking the - # cloned bug. - foreach $ref (split ' ', $blocks) { - &getbug; - $data->{blockedby} = manipset($data->{blockedby}, $clone, 1); - &savebug; - } - foreach $ref (split ' ', $blockedby) { - &getbug; - $data->{blocks} = manipset($data->{blocks}, $clone, 1); - &savebug; - } - - $clone++; - } - } + eval { + my %new_clones; + clone_bug(@common_control_options, + bug => $ref, + new_bugs => \@newclonedids, + new_clones => \%new_clones, + ); + %clonebugs = (%clonebugs, + %new_clones); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to clone $ref: ".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m/^package\:?\s+(\S.*\S)?\s*$/i) { $ok++; my @pkgs = split /\s+/, $1; if (scalar(@pkgs) > 0) { %limit_pkgs = map { ($_, 1) } @pkgs; - print {$transcript} "Ignoring bugs not assigned to: " . - join(" ", keys(%limit_pkgs)) . "\n\n"; + $limit{package} = [@pkgs]; + print {$transcript} "Limiting to bugs with field 'package' containing at least one of ".join(', ',map {qq('$_')} @pkgs)."\n"; + print {$transcript} "Limit currently set to"; + for my $limit_field (keys %limit) { + print {$transcript} " '$limit_field':".join(', ',map {qq('$_')} @{$limit{$limit_field}})."\n"; + } + print {$transcript} "\n"; } else { - %limit_pkgs = (); - print {$transcript} "Not ignoring any bugs.\n\n"; + %limit_pkgs = (); + $limit{package} = []; + print {$transcript} "Limit cleared.\n\n"; + } + } elsif (m/^limit\:?\s+(\S.*\S)\s*$/) { + $ok++; + my ($field,@options) = split /\s+/, $1; + $field = lc($field); + if ($field =~ /^(?:clear|unset|blank)$/) { + %limit = (); + print {$transcript} "Limit cleared.\n\n"; + } + elsif (exists $Debbugs::Status::fields{$field} or $field eq 'source') { + # %limit can actually contain regexes, but because they're + # not evaluated in Safe, DO NOT allow them through without + # fixing this. + $limit{$field} = [@options]; + print {$transcript} "Limiting to bugs with field '$field' containing at least one of ".join(', ',map {qq('$_')} @options)."\n"; + print {$transcript} "Limit currently set to"; + for my $limit_field (keys %limit) { + print {$transcript} " '$limit_field':".join(', ',map {qq('$_')} @{$limit{$limit_field}})."\n"; + } + print {$transcript} "\n"; + } + else { + print {$transcript} "Limit key $field not understood. Stopping processing here.\n\n"; + $errors++; + last; } } elsif (m/^affects?\s+\#?(-?\d+)(?:\s+((?:[=+-])?)\s*(\S.*)?)?\s*$/i) { $ok++; @@ -1260,23 +959,17 @@ END my $add_remove = $2 || ''; my $packages = $3 || ''; $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; - $bug_affected{$ref} = 1; eval { - affects(bug => $ref, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - requester => $header{from}, - request_addr => $controlrequestaddr, - message => \@log, - recipients => \%recipients, - packages => [splitpackages($3)], + affects(@common_control_options, + bug => $ref, + package => [splitpackages($3)], ($add_remove eq '+'?(add => 1):()), ($add_remove eq '-'?(remove => 1):()), ); }; if ($@) { $errors++; - print {$transcript} "Failed to give $ref a summary: $@"; + print {$transcript} "Failed to mark $ref as affecting package(s): ".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m/^summary\s+\#?(-?\d+)\s*(\d+|)\s*$/i) { @@ -1284,21 +977,15 @@ END $ref = $1; my $summary_msg = length($2)?$2:undef; $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; - $bug_affected{$ref} = 1; eval { - summary(bug => $ref, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - requester => $header{from}, - request_addr => $controlrequestaddr, - message => \@log, - recipients => \%recipients, + summary(@common_control_options, + bug => $ref, summary => $summary_msg, ); }; if ($@) { $errors++; - print {$transcript} "Failed to give $ref a summary: $@"; + print {$transcript} "Failed to give $ref a summary: ".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m/^owner\s+\#?(-?\d+)\s+((?:\S.*\S)|\!)\s*$/i) { @@ -1309,55 +996,37 @@ END if ($newowner eq '!') { $newowner = $replyto; } - $bug_affected{$ref} = 1; eval { - owner(bug => $ref, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - requester => $header{from}, - request_addr => $controlrequestaddr, - message => \@log, - recipients => \%recipients, + owner(@common_control_options, + bug => $ref, owner => $newowner, ); }; if ($@) { $errors++; - print {$transcript} "Failed to mark $ref as having an owner: $@"; + print {$transcript} "Failed to mark $ref as having an owner: ".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m/^noowner\s+\#?(-?\d+)\s*$/i) { $ok++; $ref = $1; $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; - $bug_affected{$ref} = 1; eval { - owner(bug => $ref, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - requester => $header{from}, - request_addr => $controlrequestaddr, - message => \@log, - recipients => \%recipients, + owner(@common_control_options, + bug => $ref, owner => undef, ); }; if ($@) { $errors++; - print {$transcript} "Failed to mark $ref as not having an owner: $@"; + print {$transcript} "Failed to mark $ref as not having an owner: ".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m/^unarchive\s+#?(\d+)$/i) { $ok++; $ref = $1; $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; - $bug_affected{$ref} = 1; eval { - bug_unarchive(bug => $ref, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - affected_bugs => \%bug_affected, - requester => $header{from}, - request_addr => $controlrequestaddr, - message => \@log, + bug_unarchive(@common_control_options, + bug => $ref, recipients => \%recipients, ); }; @@ -1368,18 +1037,11 @@ END $ok++; $ref = $1; $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; - $bug_affected{$ref} = 1; eval { - bug_archive(bug => $ref, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), + bug_archive(@common_control_options, + bug => $ref, ignore_time => 1, archive_unarchived => 0, - affected_bugs => \%bug_affected, - requester => $header{from}, - request_addr => $controlrequestaddr, - message => \@log, - recipients => \%recipients, ); }; if ($@) { @@ -1439,13 +1101,12 @@ References: $header{'message-id'} Message-ID: Precedence: bulk ${packagepr}X-$gProject-PR-Message: transcript - -${transcript_scalar}Please contact me if you need assistance. - -$gMaintainer -(administrator, $gProject $gBugs database) END +$reply .= fill_template('mail/message_body', + {body => "${transcript_scalar}Please contact me if you need assistance."}, + ); + my $repliedshow= join(', ',$replyto, determine_recipients(recipients => \%recipients, cc => 1, @@ -1492,12 +1153,15 @@ sub fill_template{ my $variables = {config => \%config, defined($ref)?(ref => $ref):(), defined($data)?(data => $data):(), + refs => [map {exists $clonebugs{$_}?$clonebugs{$_}:$_} keys %bug_affected], %{$extra_var}, }; my $hole_var = {'&bugurl' => sub{"$_[0]: ". 'http://'.$config{cgi_domain}.'/'. - Debbugs::CGI::bug_url($_[0]); + Debbugs::CGI::bug_links(bug=>$_[0], + links_only => 1, + ); } }; return fill_in_template(template => $template, @@ -1526,9 +1190,12 @@ sub message_body_template{ } sub sendhelp { - &sendtxthelpraw("bug-log-mailserver.txt","instructions for request\@$gEmailDomain"); - &sendtxthelpraw("bug-maint-mailcontrol.txt","instructions for control\@$gEmailDomain") - if $control; + if ($control) { + &sendtxthelpraw("bug-maint-mailcontrol.txt","instructions for control\@$gEmailDomain") + } + else { + &sendtxthelpraw("bug-log-mailserver.txt","instructions for request\@$gEmailDomain"); + } } #sub unimplemented { @@ -1787,6 +1454,11 @@ our $doc; sub sendtxthelpraw { my ($relpath,$description) = @_; $doc=''; + if (not -e "$gDocDir/$relpath") { + print {$transcript} "Unfortunatly, the help text doesn't exist, so it wasn't sent.\n"; + warn "Help text $gDocDir/$relpath not found"; + return; + } open(D,"$gDocDir/$relpath") || die "open doc file $relpath: $!"; while() { $doc.=$_; } close(D);