]> git.donarmstrong.com Git - debbugs.git/commitdiff
add submitter changed email template
authorDon Armstrong <don@donarmstrong.com>
Thu, 19 Mar 2009 16:31:35 +0000 (09:31 -0700)
committerDon Armstrong <don@donarmstrong.com>
Thu, 19 Mar 2009 16:31:35 +0000 (09:31 -0700)
Debbugs/Control.pm
scripts/service
templates/en_US/mail/submitter_changed.tmpl [new file with mode: 0644]

index 4b400d13ca66216f577a564ad5b19af0b04de03d..358842cd023e5003d66bd8a53c0b45a630b07b70 100644 (file)
@@ -49,6 +49,10 @@ following options:
 
 =item request_addr -- Address to which the request was sent
 
+=item request_nn -- Name of queue file which caused this request
+
+=item request_msgid -- Message id of message which caused this request
+
 =item location -- Optional location; currently ignored but may be
 supported in the future for updating archived bugs upon archival
 
@@ -117,6 +121,7 @@ use Mail::RFC822::Address qw();
 use POSIX qw(strftime);
 
 use Storable qw(dclone nfreeze);
+use List::Util qw(first);
 
 use Carp;
 
@@ -143,6 +148,15 @@ my %common_options = (debug       => {type => SCALARREF|HANDLE,
                      show_bug_info => {type => BOOLEAN,
                                        default => 1,
                                       },
+                     request_subject => {type => SCALAR,
+                                         default => 'Unknown Subject',
+                                        },
+                     request_msgid    => {type => SCALAR,
+                                          default => '',
+                                         },
+                     request_nn       => {type => SCALAR,
+                                          optional => 1,
+                                         },
                     );
 
 
@@ -196,39 +210,394 @@ my %append_action_options =
 #
 # =cut
 #
-## sub set_foo {
-##     my %param = validate_with(params => \@_,
-##                           spec   => {bug => {type   => SCALAR,
-##                                              regex  => qr/^\d+$/,
-##                                             },
-##                                      # specific options here
-##                                      %common_options,
-##                                      %append_action_options,
-##                                     },
-##                          );
-##     my %info =
-##     __begin_control(%param,
-##                     command  => 'foo'
-##                    );
-##     my ($new_locks,$debug,$transcript) =
-##     @info{qw(new_locks debug transcript)};
-##     my @data = @{$info{data}};
-##     my @bugs = @{$info{bugs}};
-## 
-##     for my $data (@data) {
-##     append_action_to_log(bug => $data->{bug_num},
-##                          get_lock => 0,
-##                          __return_append_to_log_options(
-##                                                         %param,
-##                                                         action => $action,
-##                                                        ),
-##                         )
-##         if not exists $param{append_log} or $param{append_log};
-##     writebug($data->{bug_num},$data);
-##     print {$transcript} "$action\n";
-##     }
-##     __end_control(\%info);
-## }
+# sub set_foo {
+#     my %param = validate_with(params => \@_,
+#                            spec   => {bug => {type   => SCALAR,
+#                                               regex  => qr/^\d+$/,
+#                                              },
+#                                       # specific options here
+#                                       %common_options,
+#                                       %append_action_options,
+#                                      },
+#                           );
+#     my %info =
+#      __begin_control(%param,
+#                      command  => 'foo'
+#                     );
+#     my ($debug,$transcript) =
+#      @info{qw(debug transcript)};
+#     my @data = @{$info{data}};
+#     my @bugs = @{$info{bugs}};
+#
+#     my $action = '';
+#     for my $data (@data) {
+#      append_action_to_log(bug => $data->{bug_num},
+#                           get_lock => 0,
+#                           __return_append_to_log_options(
+#                                                          %param,
+#                                                          action => $action,
+#                                                         ),
+#                          )
+#          if not exists $param{append_log} or $param{append_log};
+#      writebug($data->{bug_num},$data);
+#      print {$transcript} "$action\n";
+#     }
+#     __end_control(\%info);
+# }
+
+=head2 set_tag
+
+     eval {
+           set_tag(bug          => $ref,
+                   transcript   => $transcript,
+                   ($dl > 0 ? (debug => $transcript):()),
+                   requester    => $header{from},
+                   request_addr => $controlrequestaddr,
+                   message      => \@log,
+                    affected_packages => \%affected_packages,
+                   recipients   => \%recipients,
+                   tag          => [],
+                    add          => 1,
+                   );
+       };
+       if ($@) {
+           $errors++;
+           print {$transcript} "Failed to set tag on $ref: $@";
+       }
+
+
+Sets, adds, or removes the specified tags on a bug
+
+=over
+
+=item tag -- scalar or arrayref of tags to set, add or remove
+
+=item add -- if true, add tags
+
+=item remove -- if true, remove tags
+
+=item warn_on_bad_tags -- if true (the default) warn if bad tags are
+passed.
+
+=back
+
+=cut
+
+sub set_tag {
+    my %param = validate_with(params => \@_,
+                             spec   => {bug => {type   => SCALAR,
+                                                regex  => qr/^\d+$/,
+                                               },
+                                        # specific options here
+                                        tag    => {type => SCALAR|ARRAYREF,
+                                                   default => [],
+                                                  },
+                                        add      => {type => BOOLEAN,
+                                                     default => 0,
+                                                    },
+                                        remove   => {type => BOOLEAN,
+                                                     default => 0,
+                                                    },
+                                        warn_on_bad_tags => {type => BOOLEAN,
+                                                             default => 1,
+                                                            },
+                                        %common_options,
+                                        %append_action_options,
+                                       },
+                            );
+    if ($param{add} and $param{remove}) {
+       croak "It's nonsensical to add and remove the same tags";
+    }
+
+    my %info =
+       __begin_control(%param,
+                       command  => 'tag'
+                      );
+    my ($debug,$transcript) =
+       @info{qw(debug transcript)};
+    my @data = @{$info{data}};
+    my @bugs = @{$info{bugs}};
+    my @tags = make_list($param{tag});
+    if (not @tags and ($param{remove} or $param{add})) {
+       if ($param{remove}) {
+           print {$transcript} "Requested to remove no tags; doing nothing.\n";
+       }
+       else {
+           print {$transcript} "Requested to add no tags; doing nothing.\n";
+       }
+       __end_control(%info);
+       return;
+    }
+    # first things first, make the versions fully qualified source
+    # versions
+    for my $data (@data) {
+       # 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
+       my $action = 'Did not alter tags';
+       my %tag_added = ();
+       my %tag_removed = ();
+       my %fixed_removed = ();
+       my @old_tags = split /\,\s*/, $data->{tags};
+       my %tags;
+       @tags{@old_tags} = (1) x @old_tags;
+       my $reopened = 0;
+       my $old_data = dclone($data);
+       if (not $param{add} and not $param{remove}) {
+           $tag_removed{$_} = 1 for @old_tags;
+           %tags = ();
+       }
+       my @bad_tags = ();
+       for my $tag (@tags) {
+           if (not $param{remove} and
+               not defined first {$_ eq $tag} @{$config{tags}}) {
+               push @bad_tags, $tag;
+               next;
+           }
+           if ($param{add}) {
+               if (not exists $tags{$tag}) {
+                   $tags{$tag} = 1;
+                   $tag_added{$tag} = 1;
+               }
+           }
+           elsif ($param{remove}) {
+               if (exists $tags{$tag}) {
+                   delete $tags{$tag};
+                   $tag_removed{$tag} = 1;
+               }
+           }
+           else {
+               if (exists $tag_removed{$tag}) {
+                   delete $tag_removed{$tag};
+               }
+               else {
+                   $tag_added{$tag} = 1;
+               }
+               $tags{$tag} = 1;
+           }
+       }
+       if (@bad_tags and $param{warn_on_bad_tags}) {
+           print {$transcript} "Unknown tag(s): ".join(', ',@bad_tags).".\n";
+           print {$transcript} "These tags are recognized: ".join(', ',@{$config{tags}}).".\n";
+       }
+       $data->{tags} = join(', ',keys %tags); # double check this
+
+       my @changed;
+       push @changed, 'added tag(s) '.english_join([keys %tag_added]) if keys %tag_added;
+       push @changed, 'removed tag(s) '.english_join([keys %tag_removed]) if keys %tag_removed;
+       $action = ucfirst(join ('; ',@changed)) if @changed;
+       if (not @changed) {
+           print {$transcript} "Ignoring request to alter tags of bug #$data->{bug_num} to the same tags previously set\n"
+               unless __internal_request();
+           next;
+       }
+       $action .= '.';
+       append_action_to_log(bug => $data->{bug_num},
+                            get_lock => 0,
+                            command  => 'tag',
+                            old_data => $old_data,
+                            new_data => $data,
+                            __return_append_to_log_options(
+                                                           %param,
+                                                           action => $action,
+                                                          ),
+                           )
+           if not exists $param{append_log} or $param{append_log};
+       writebug($data->{bug_num},$data);
+       print {$transcript} "$action\n";
+    }
+    __end_control(%info);
+}
+
+
+
+=head2 set_severity
+
+     eval {
+           set_severity(bug          => $ref,
+                        transcript   => $transcript,
+                        ($dl > 0 ? (debug => $transcript):()),
+                        requester    => $header{from},
+                        request_addr => $controlrequestaddr,
+                        message      => \@log,
+                         affected_packages => \%affected_packages,
+                        recipients   => \%recipients,
+                        severity     => 'normal',
+                        );
+       };
+       if ($@) {
+           $errors++;
+           print {$transcript} "Failed to set the severity of bug $ref: $@";
+       }
+
+Sets the severity of a bug. If severity is not passed, is undefined,
+or has zero length, sets the severity to the defafult severity.
+
+=cut
+
+sub set_severity {
+    my %param = validate_with(params => \@_,
+                             spec   => {bug => {type   => SCALAR,
+                                                regex  => qr/^\d+$/,
+                                               },
+                                        # specific options here
+                                        severity => {type => SCALAR|UNDEF,
+                                                     default => $config{default_severity},
+                                                    },
+                                        %common_options,
+                                        %append_action_options,
+                                       },
+                            );
+    if (not defined $param{severity} or
+       not length $param{severity}
+       ) {
+       $param{severity} = $config{default_severity};
+    }
+
+    # check validity of new severity
+    if (not defined first {$_ eq $param{severity}} (@{$config{severity_list}},$config{default_severity})) {
+       die "Severity '$param{severity}' is not a valid severity level";
+    }
+    my %info =
+       __begin_control(%param,
+                       command  => 'severity'
+                      );
+    my ($debug,$transcript) =
+       @info{qw(debug transcript)};
+    my @data = @{$info{data}};
+    my @bugs = @{$info{bugs}};
+
+    my $action = '';
+    for my $data (@data) {
+       if (not defined $data->{severity}) {
+           $data->{severity} = $param{severity};
+           $action = "Severity set to '$param{severity}'\n";
+       }
+       else {
+           if ($data->{severity} eq '') {
+               $data->{severity} = $config{default_severity};
+           }
+           if ($data->{severity} eq $param{severity}) {
+               print {$transcript} "Ignoring request to change severity of $config{bug} $data->{bug_num} to the same value.\n";
+               next;
+           }
+           $action = "Severity set to '$param{severity}' from '$data->{severity}'\n";
+           $data->{severity} = $param{severity};
+       }
+       append_action_to_log(bug => $data->{bug_num},
+                            get_lock => 0,
+                            __return_append_to_log_options(
+                                                           %param,
+                                                           action => $action,
+                                                          ),
+                           )
+           if not exists $param{append_log} or $param{append_log};
+       writebug($data->{bug_num},$data);
+       print {$transcript} "$action\n";
+    }
+    __end_control(\%info);
+}
+
+
+=head2 reopen
+
+     eval {
+           set_foo(bug          => $ref,
+                   transcript   => $transcript,
+                   ($dl > 0 ? (debug => $transcript):()),
+                   requester    => $header{from},
+                   request_addr => $controlrequestaddr,
+                   message      => \@log,
+                  affected_packages => \%affected_packages,
+                   recipients   => \%recipients,
+                   summary      => undef,
+                 );
+       };
+       if ($@) {
+           $errors++;
+           print {$transcript} "Failed to set foo $ref bar: $@";
+       }
+
+Foo frobinates
+
+=cut
+
+sub reopen {
+    my %param = validate_with(params => \@_,
+                             spec   => {bug => {type   => SCALAR,
+                                                regex  => qr/^\d+$/,
+                                               },
+                                        # specific options here
+                                        submitter => {type => SCALAR|UNDEF,
+                                                      default => undef,
+                                                     },
+                                        %common_options,
+                                        %append_action_options,
+                                       },
+                            );
+
+    $param{submitter} = undef if defined $param{submitter} and
+       not length $param{submitter};
+
+    if (defined $param{submitter} and
+       not Mail::RFC822::Address::valid($param{submitter})) {
+       die "New submitter address $param{submitter} is not a valid e-mail address";
+    }
+
+    my %info =
+       __begin_control(%param,
+                       command  => 'reopen'
+                      );
+    my ($debug,$transcript) =
+       @info{qw(debug transcript)};
+    my @data = @{$info{data}};
+    my @bugs = @{$info{bugs}};
+    my $action ='';
+
+    my $warn_fixed = 1; # avoid warning multiple times if there are
+                        # fixed versions
+    my @change_submitter = ();
+    my @bugs_to_reopen = ();
+    for my $data (@data) {
+       if (not exists $data->{done} or
+           not defined $data->{done} or
+           not length $data->{done}) {
+           print {$transcript} "Bug $data->{bug_num} is not marked as done; doing nothing.\n";
+           __end_control(%info);
+           return;
+       }
+       if (@{$data->{fixed_versions}} and $warn_fixed) {
+           print {$transcript} "'reopen' may be inappropriate when a bug has been closed with a version;\n";
+           print {$transcript} "you may need to use 'found' to remove fixed versions.\n";
+           $warn_fixed = 0;
+       }
+       if (defined $param{submitter} and length $param{submitter}
+           and $data->{originator} ne $param{submitter}) {
+           push @change_submitter,$data->{bug_num};
+       }
+    }
+    __end_control(\%info);
+    my @params_for_subcalls = 
+       map {exists $param{$_}?($_,$param{$_}):()}
+           (keys %common_options,
+            keys %append_action_options,
+           );
+
+    for my $bug (@change_submitter) {
+       set_submitter(bug=>$bug,
+                     submitter => $param{submitter},
+                     @params_for_subcalls,
+                    );
+    }
+    set_fixed(fixed => [],
+             bug => $param{bug},
+             reopen => 1,
+            );
+}
+
 
 =head2 set_submitter
 
@@ -277,13 +646,14 @@ sub set_submitter {
        __begin_control(%param,
                        command  => 'submitter'
                       );
-    my ($new_locks,$debug,$transcript) =
-       @info{qw(new_locks debug transcript)};
+    my ($debug,$transcript) =
+       @info{qw(debug transcript)};
     my @data = @{$info{data}};
     my @bugs = @{$info{bugs}};
     my $action = '';
     # here we only concern ourselves with the first of the merged bugs
     for my $data ($data[0]) {
+       my $notify_old_submitter = 0;
        my $old_data = dclone($data);
        print {$debug} "Going to change bug submitter\n";
        if (((not defined $param{submitter} or not length $param{submitter}) and
@@ -296,6 +666,7 @@ sub set_submitter {
        else {
            if (defined $data->{submitter} and length($data->{submitter})) {
                $action= "Changed $config{bug} submitter to '$param{submitter}' from '$data->{submitter}'";
+               $notify_old_submitter = 1;
            }
            else {
                $action= "Set $config{bug} submitter to '$param{submitter}'.";
@@ -303,7 +674,7 @@ sub set_submitter {
            $data->{submitter} = $param{submitter};
        }
         append_action_to_log(bug => $data->{bug_num},
-                            command => 'set_submitter',
+                            command => 'submitter',
                             new_data => $data,
                             old_data => $old_data,
                             get_lock => 0,
@@ -315,6 +686,33 @@ sub set_submitter {
            if not exists $param{append_log} or $param{append_log};
        writebug($data->{bug_num},$data);
        print {$transcript} "$action\n";
+       # notify old submitter
+       if ($notify_old_submitter and $param{notify_submitter}) {
+           send_mail_message(message =>
+                             create_mime_message(["X-Loop"      => $config{maintainer_email},
+                                                  From          => "$config{maintainer_email} ($config{project} $config{ubug} Tracking System)",
+                                                  To            => $old_data->{submitter},
+                                                  Subject       => "$config{ubug}#$data->{bug_num} submitter addressed changed ($param{request_subject})",
+                                                  "Message-ID"  => "<$data->{bug_num}.$param{request_nn}.ackfwdd\@$config{email_domain}>",
+                                                  "In-Reply-To" => $param{request_msgid},
+                                                  References    => join(' ',grep {defined $_} $param{request_msgid},$data->{msgid}),
+                                                  Precedence    => 'bulk',
+                                                  "X-$gProject-PR-Message"  => "submitter-changed $data->{bug_num}",
+                                                  "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
+                                                  (defined($source_package) and length($source_package))?("X-$gProject-PR-Source" => $source_package):(),
+                                                 ],
+                                                 message_body_template('mail/submitter_changed',
+                                                                       {old_data => $old_data,
+                                                                        data     => $data,
+                                                                        replyto  => exists $param{header}{'reply-to'} ? $param{request_replyto} : $param{requester} || 'Unknown',
+                                                                        config   => \%config,
+                                                                       })
+                                                ),
+                             recipients => $old_data->{submitter},
+                            );
+       }
     }
     __end_control(%info);
 }
@@ -365,8 +763,8 @@ sub set_forwarded {
        __begin_control(%param,
                        command  => 'forwarded'
                       );
-    my ($new_locks,$debug,$transcript) =
-       @info{qw(new_locks debug transcript)};
+    my ($debug,$transcript) =
+       @info{qw(debug transcript)};
     my @data = @{$info{data}};
     my @bugs = @{$info{bugs}};
     my $action = '';
@@ -393,7 +791,7 @@ sub set_forwarded {
            $data->{forwarded} = $param{forwarded};
        }
         append_action_to_log(bug => $data->{bug_num},
-                            command => 'set_forwarded',
+                            command => 'forwarded',
                             new_data => $data,
                             old_data => $old_data,
                             get_lock => 0,
@@ -478,7 +876,7 @@ sub set_title {
            $data->{subject} = $param{title};
        }
         append_action_to_log(bug => $data->{bug_num},
-                            command => 'set_title',
+                            command => 'title',
                             new_data => $data,
                             old_data => $old_data,
                             get_lock => 0,
@@ -551,8 +949,8 @@ sub set_package {
     my %info = __begin_control(%param,
                               command  => 'package',
                              );
-    my ($new_locks,$debug,$transcript) =
-       @info{qw(new_locks debug transcript)};
+    my ($debug,$transcript) =
+       @info{qw(debug transcript)};
     my @data = @{$info{data}};
     my @bugs = @{$info{bugs}};
     # clean up the new package
@@ -585,7 +983,7 @@ sub set_package {
            $data->{package} = $new_package;
        }
         append_action_to_log(bug => $data->{bug_num},
-                            command => 'set_package',
+                            command => 'package',
                             new_data => $data,
                             old_data => $old_data,
                             get_lock => 0,
@@ -676,8 +1074,8 @@ sub set_found {
        __begin_control(%param,
                        command  => 'found'
                       );
-    my ($new_locks,$debug,$transcript) =
-       @info{qw(new_locks debug transcript)};
+    my ($debug,$transcript) =
+       @info{qw(debug transcript)};
     my @data = @{$info{data}};
     my @bugs = @{$info{bugs}};
     my %versions;
@@ -810,7 +1208,7 @@ sub set_found {
        $action .= '.';
        append_action_to_log(bug => $data->{bug_num},
                             get_lock => 0,
-                            command  => 'set_found',
+                            command  => 'found',
                             old_data => $old_data,
                             new_data => $data,
                             __return_append_to_log_options(
@@ -847,14 +1245,14 @@ sub set_found {
        }
 
 
-Sets, adds, or removes the specified found versions of a package
+Sets, adds, or removes the specified fixed versions of a package
 
-If the version list is empty, and the bug is currently not "done",
-causes the done field to be cleared.
+If the fixed versions are empty (or end up being empty after this
+call) or the greatest fixed version is less than the greatest found
+version and the reopen option is true, the bug is reopened.
 
-If any of the versions added to found are greater than any version in
-which the bug is fixed (or when the bug is found and there are no
-fixed versions) the done field is cleared.
+This function is also called by the reopen function, which causes all
+of the fixed versions to be cleared.
 
 =cut
 
@@ -887,8 +1285,8 @@ sub set_fixed {
        __begin_control(%param,
                        command  => 'fixed'
                       );
-    my ($new_locks,$debug,$transcript) =
-       @info{qw(new_locks debug transcript)};
+    my ($debug,$transcript) =
+       @info{qw(debug transcript)};
     my @data = @{$info{data}};
     my @bugs = @{$info{bugs}};
     my %versions;
@@ -1018,7 +1416,7 @@ sub set_fixed {
        }
        $action .= '.';
        append_action_to_log(bug => $data->{bug_num},
-                            command  => 'set_fixed',
+                            command  => 'fixed',
                             new_data => $data,
                             old_data => $old_data,
                             get_lock => 0,
@@ -1093,8 +1491,8 @@ sub affects {
        __begin_control(%param,
                        command  => 'affects'
                       );
-    my ($new_locks,$debug,$transcript) =
-       @info{qw(new_locks debug transcript)};
+    my ($debug,$transcript) =
+       @info{qw(debug transcript)};
     my @data = @{$info{data}};
     my @bugs = @{$info{bugs}};
     my $action = '';
@@ -1227,8 +1625,8 @@ sub summary {
        __begin_control(%param,
                        command  => 'summary'
                       );
-    my ($new_locks,$debug,$transcript) =
-       @info{qw(new_locks debug transcript)};
+    my ($debug,$transcript) =
+       @info{qw(debug transcript)};
     my @data = @{$info{data}};
     my @bugs = @{$info{bugs}};
     # figure out the log that we're going to use
@@ -1380,8 +1778,8 @@ sub owner {
         __begin_control(%param,
                         command  => 'owner',
                        );
-     my ($new_locks,$debug,$transcript) =
-       @info{qw(new_locks debug transcript)};
+     my ($debug,$transcript) =
+       @info{qw(debug transcript)};
      my @data = @{$info{data}};
      my @bugs = @{$info{bugs}};
      my $action = '';
@@ -1491,7 +1889,7 @@ sub bug_archive {
      my %info = __begin_control(%param,
                                command => 'archive',
                                );
-     my ($new_locks,$debug,$transcript) = @info{qw(data debug transcript)};
+     my ($debug,$transcript) = @info{qw(debug transcript)};
      my @data = @{$info{data}};
      my @bugs = @{$info{bugs}};
      my $action = "$config{bug} archived.";
@@ -1596,8 +1994,8 @@ sub bug_unarchive {
      my %info = __begin_control(%param,
                                archived=>1,
                                command=>'unarchive');
-     my ($new_locks,$debug,$transcript) =
-        @info{qw(new_locks debug transcript)};
+     my ($debug,$transcript) =
+        @info{qw(debug transcript)};
      my @data = @{$info{data}};
      my @bugs = @{$info{bugs}};
      my $action = "$config{bug} unarchived.";
@@ -1955,7 +2353,7 @@ sub __return_append_to_log_options{
      my %info = __begin_control(%param,
                                archived=>1,
                                command=>'unarchive');
-     my ($new_locks,$debug,$transcript) = @info{qw(new_locksa debug transcript)};
+     my ($debug,$transcript) = @info{qw(debug transcript)};
      my @data = @{$info{data}};
      my @bugs = @{$info{bugs}};
 
index d0ebe53fbfce9294b95e7b6ab41bbb37e0438f42..231ae83d36d411fde7eb53ea882d09d68ce991dc 100755 (executable)
@@ -35,6 +35,8 @@ 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
@@ -116,8 +118,25 @@ 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;
+
+my @common_control_options =
+    (($dl > 0 (debug => $transcript):()),
+     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_packages => \%affected_packages,
+     recipients        => \%recipients,
+    );
+
 my $state= 'idle';
 my $lowstate= 'idle';
 my $mergelowstate= 'idle';
@@ -528,25 +547,15 @@ END
        $bug_affected{$ref}=1;
         my $version= $3;
        eval {
-           set_package(bug          => $ref,
-                       transcript   => $transcript,
-                       ($dl > 0 ? (debug => $transcript):()),
-                       requester    => $header{from},
-                       request_addr => $controlrequestaddr,
-                       message      => \@log,
-                       recipients   => \%recipients,
+           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(bug          => $ref,
-                         transcript   => $transcript,
-                         ($dl > 0 ? (debug => $transcript):()),
-                         requester    => $header{from},
-                         request_addr => $controlrequestaddr,
-                         message      => \@log,
-                         recipients   => \%recipients,
+               set_found(@common_control_options,
+                         bug          => $ref,
                          version      => $version,
                         );
            }
@@ -555,37 +564,29 @@ END
            $errors++;
            print {$transcript} "Failed to clear fixed versions and reopen on $ref: $@";
        }
-    } 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) {
+    } 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);
-            }
-        }
+       $bug_affected{$ref}=1; 
+       my $new_submitter = $2;
+       if (defined $new_submitter) {
+           if ($new_submitter eq '=') {
+               undef $new_submitter;
+           }
+           elsif ($new_submitter eq '!') {
+               $new_submitter = $replyto;
+           }
+       }
+       eval {
+           reopen(@common_control_options,
+                  bug          => $ref,
+                  submitter    => $new_submitter,
+                 );
+       };
+       if ($@) {
+           $errors++;
+           print {$transcript} "Failed to reopen $ref: $@";
+       }
     } elsif (m{^(?:(?i)found)\s+\#?(-?\d+)
               (?:\s+((?:$config{package_name_re}\/)?
                    $config{package_version_re}
@@ -600,14 +601,8 @@ END
         if (defined $2) {
            @versions = split /\s*,\s*/,$2;
            eval {
-               set_found(bug          => $ref,
-                         transcript   => $transcript,
-                         ($dl > 0 ? (debug => $transcript):()),
-                         requester    => $header{from},
-                         request_addr => $controlrequestaddr,
-                         message      => \@log,
-                         affected_packages => \%affected_packages,
-                         recipients   => \%recipients,
+               set_found(@common_control_options,
+                         bug          => $ref,
                          found        => \@versions,
                          add          => 1,
                         );
@@ -619,14 +614,8 @@ END
        }
        else {
            eval {
-               set_fixed(bug          => $ref,
-                         transcript   => $transcript,
-                         ($dl > 0 ? (debug => $transcript):()),
-                         requester    => $header{from},
-                         request_addr => $controlrequestaddr,
-                         message      => \@log,
-                         affected_packages => \%affected_packages,
-                         recipients   => \%recipients,
+               set_fixed(@common_control_options,
+                         bug          => $ref,
                          fixed        => [],
                          reopen       => 1,
                         );
@@ -650,14 +639,8 @@ END
        my @versions;
         @versions = split /\s*,\s*/,$2;
        eval {
-           set_found(bug          => $ref,
-                     transcript   => $transcript,
-                     ($dl > 0 ? (debug => $transcript):()),
-                     requester    => $header{from},
-                     request_addr => $controlrequestaddr,
-                     message      => \@log,
-                     affected_packages => \%affected_packages,
-                     recipients   => \%recipients,
+           set_found(@common_control_options,
+                     bug          => $ref,
                      found        => \@versions,
                      remove       => 1,
                     );
@@ -680,14 +663,8 @@ END
        my @versions;
         @versions = split /\s*,\s*/,$2;
        eval {
-           set_fixed(bug          => $ref,
-                     transcript   => $transcript,
-                     ($dl > 0 ? (debug => $transcript):()),
-                     requester    => $header{from},
-                     request_addr => $controlrequestaddr,
-                     message      => \@log,
-                     affected_packages => \%affected_packages,
-                     recipients   => \%recipients,
+           set_fixed(@common_control_options,
+                     bug          => $ref,
                      fixed        => \@versions,
                      add          => 1,
                     );
@@ -710,14 +687,8 @@ END
        my @versions;
         @versions = split /\s*,\s*/,$2;
        eval {
-           set_fixed(bug          => $ref,
-                     transcript   => $transcript,
-                     ($dl > 0 ? (debug => $transcript):()),
-                     requester    => $header{from},
-                     request_addr => $controlrequestaddr,
-                     message      => \@log,
-                     affected_packages => \%affected_packages,
-                     recipients   => \%recipients,
+           set_fixed(@common_control_options,
+                     bug          => $ref,
                      fixed        => \@versions,
                      remove       => 1,
                     );
@@ -737,58 +708,17 @@ END
             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= <<END;
-From: $gMaintainerEmail ($gProject $gBug Tracking System)
-To: $oldsubmitter
-Subject: $gBug#$ref submitter address changed
-         ($header{'subject'})
-References: $header{'message-id'} $data->{msgid}
-In-Reply-To: $data->{msgid}
-Message-ID: <handler.$ref.$nn.newsubmitter.$midix\@$gEmailDomain>
-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 {
-            &notfoundbug;
+       else {
+           eval {
+               set_submitter(@common_control_options,
+                             bug       => $ref,
+                             submitter => $newsubmitter,
+                            );
+           };
+           if ($@) {
+               $errors++;
+               print {$transcript} "Failed to set submitter on $ref: $@";
+           }
         }
     } elsif (m/^forwarded\s+\#?(-?\d+)\s+(\S.*\S)$/i) {
         $ok++;
@@ -797,15 +727,9 @@ END
        $ref = $clonebugs{$ref} if exists $clonebugs{$ref};
        $bug_affected{$ref} = 1;
        eval {
-           set_forwarded(bug          => $ref,
-                         transcript   => $transcript,
-                         ($dl > 0 ? (debug => $transcript):()),
-                         requester    => $header{from},
-                         request_addr => $controlrequestaddr,
-                         message      => \@log,
-                          affected_packages => \%affected_packages,
-                         recipients   => \%recipients,
-                         forwarded    => $forward_to,
+           set_forwarded(@common_control_options,
+                         bug          => $ref,
+                         forwarded    => $forward_to,
                           );
        };
        if ($@) {
@@ -818,15 +742,9 @@ END
        $ref = $clonebugs{$ref} if exists $clonebugs{$ref};
        $bug_affected{$ref} = 1;
        eval {
-           set_forwarded(bug          => $ref,
-                         transcript   => $transcript,
-                         ($dl > 0 ? (debug => $transcript):()),
-                         requester    => $header{from},
-                         request_addr => $controlrequestaddr,
-                         message      => \@log,
-                          affected_packages => \%affected_packages,
-                         recipients   => \%recipients,
-                         forwarded    => undef,
+           set_forwarded(@common_control_options,
+                         bug          => $ref,
+                         forwarded    => undef,
                           );
        };
        if ($@) {
@@ -836,52 +754,51 @@ END
     } elsif (m/^(?:severity|priority)\s+\#?(-?\d+)\s+([-0-9a-z]+)$/i) {
         $ok++;
         $ref= $1;
+       $ref = $clonebugs{$ref} if exists $clonebugs{$ref};
        $bug_affected{$ref}=1;
         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 (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: $@";
+           }
+       }
     } elsif (m/^tags?\s+\#?(-?\d+)\s+(([=+-])\s*)?(\S.*)?$/i) {
+       ### TODO: [#505189] Consider altering this to accept tag #nnn + foo - bar - baz
        $ok++;
        $ref = $1;
-       my $addsubcode = $3;
-       my $tags = $4;
+       $ref = $clonebugs{$ref} if exists $clonebugs{$ref};
        $bug_affected{$ref}=1;
-       my $addsub = "add";
+       my $addsubcode = $3;
+       my @add_remove_option = ();
        if (defined $addsubcode) {
-           $addsub = "sub" if ($addsubcode eq "-");
-           $addsub = "add" if ($addsubcode eq "+");
-           $addsub = "set" if ($addsubcode eq "=");
+           if ($addsubcode eq '-') {
+               push @add_remove_option,(remove => 1);
+           }
+           elsif ($addsubcode eq '+') {
+               push @add_remove_option,(add => 1);
+           }
        }
-       my @okaytags = ();
-       my @badtags = ();
-       foreach my $t (split /[\s,]+/, $tags) {
-           if (!grep($_ eq $t, @gTags)) {
+       my $tags = $4;
+       my @tags = /[\s,]+/, $tags;
+       foreach my $tag (@tags) {
+           if (not defined first {$_ eq $tag} @{$config{tags}}) {
                push @badtags, $t;
-           } else {
-               push @okaytags, $t;
            }
        }
        if (@badtags) {
@@ -889,42 +806,20 @@ END
                 "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);
-           }
-           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);
+       eval {
+           set_tags(@common_control_options,
+                    bug => $ref,
+                    tags => [@tags],
+                    warn_on_bad_tags => 0, # don't warn on bad tags,
+                                            # 'cause we do that above
+                    @add_remove_option,
+                   );
+       };
+       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: $@";
        }
     } elsif (m/^(un)?block\s+\#?(-?\d+)\s+(by|with)\s+(\S.*)?$/i) {
        $ok++;
@@ -1298,13 +1193,7 @@ END
        $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,
+            affects(@common_control_options,
                     packages     => [splitpackages($3)],
                     ($add_remove eq '+'?(add => 1):()),
                     ($add_remove eq '-'?(remove => 1):()),
@@ -1322,13 +1211,8 @@ END
        $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,
                   );
        };
@@ -1347,13 +1231,8 @@ END
        }
        $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,
                 );
        };
@@ -1367,13 +1246,8 @@ END
        $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,
                 );
        };
@@ -1387,13 +1261,8 @@ END
         $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,
                           );
         };
@@ -1406,16 +1275,10 @@ END
         $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 ($@) {
diff --git a/templates/en_US/mail/submitter_changed.tmpl b/templates/en_US/mail/submitter_changed.tmpl
new file mode 100644 (file)
index 0000000..1f0a9c0
--- /dev/null
@@ -0,0 +1,12 @@
+The submitter address recorded for your {$config{bug}} report
+#{$data->{bug_num}}: {$data->{subject}}
+has been changed.
+
+The old submitter address for this report was
+{$old_data->{submitter}}.
+The new submitter address is
+{$data->{submitter}}.
+
+This change was made by
+{$replyto}.
+If it was incorrect, please contact them directly.