From 8ec8da0491ad89604700b3e29a227966f6d84ba1 Mon Sep 17 00:00:00 2001 From: Perl Tidy Date: Wed, 5 Dec 2018 15:38:52 -0500 Subject: no bug - reformat all the code using the new perltidy rules --- email_in.pl | 582 +++++++++++++++++++++++++++++++----------------------------- 1 file changed, 300 insertions(+), 282 deletions(-) (limited to 'email_in.pl') diff --git a/email_in.pl b/email_in.pl index d2d57ed59..382e60660 100755 --- a/email_in.pl +++ b/email_in.pl @@ -16,10 +16,11 @@ use lib qw(. lib local/lib/perl5); # run from this one so that it can find its modules. use Cwd qw(abs_path); use File::Basename qw(dirname); + BEGIN { - # Untaint the abs_path. - my ($a) = abs_path($0) =~ /^(.*)$/; - chdir dirname($a); + # Untaint the abs_path. + my ($a) = abs_path($0) =~ /^(.*)$/; + chdir dirname($a); } use Data::Dumper; @@ -60,213 +61,221 @@ our ($input_email, %switch); #################### sub parse_mail { - my ($mail_text) = @_; - debug_print('Parsing Email'); - $input_email = Email::MIME->new($mail_text); - - my %fields = %{ $switch{'default'} || {} }; - Bugzilla::Hook::process('email_in_before_parse', { mail => $input_email, - fields => \%fields }); - - my $summary = $input_email->header('Subject'); - if ($summary =~ /\[\S+ (\d+)\](.*)/i) { - $fields{'bug_id'} = $1; - $summary = trim($2); + my ($mail_text) = @_; + debug_print('Parsing Email'); + $input_email = Email::MIME->new($mail_text); + + my %fields = %{$switch{'default'} || {}}; + Bugzilla::Hook::process('email_in_before_parse', + {mail => $input_email, fields => \%fields}); + + my $summary = $input_email->header('Subject'); + if ($summary =~ /\[\S+ (\d+)\](.*)/i) { + $fields{'bug_id'} = $1; + $summary = trim($2); + } + + # Ignore automatic replies. + # XXX - Improve the way to detect such subjects in different languages. + my $auto_submitted = $input_email->header('Auto-Submitted') || ''; + if ($summary =~ /out of( the)? office/i || $auto_submitted eq 'auto-replied') { + debug_print("Automatic reply detected: $summary"); + exit; + } + + my ($body, $attachments) = get_body_and_attachments($input_email); + if (@$attachments) { + $fields{'attachments'} = $attachments; + } + + debug_print("Body:\n" . $body, 3); + + $body = remove_leading_blank_lines($body); + my @body_lines = split(/\r?\n/s, $body); + + # If there are fields specified. + if ($body =~ /^\s*@/s) { + my $current_field; + while (my $line = shift @body_lines) { + + # If the sig is starting, we want to keep this in the + # @body_lines so that we don't keep the sig as part of the + # comment down below. + if ($line eq SIGNATURE_DELIMITER) { + unshift(@body_lines, $line); + last; + } + + # Otherwise, we stop parsing fields on the first blank line. + $line = trim($line); + last if !$line; + if ($line =~ /^\@(\w+)\s*(?:=|\s|$)\s*(.*)\s*/) { + $current_field = lc($1); + $fields{$current_field} = $2; + } + else { + $fields{$current_field} .= " $line"; + } } + } - # Ignore automatic replies. - # XXX - Improve the way to detect such subjects in different languages. - my $auto_submitted = $input_email->header('Auto-Submitted') || ''; - if ($summary =~ /out of( the)? office/i || $auto_submitted eq 'auto-replied') { - debug_print("Automatic reply detected: $summary"); - exit; - } + %fields = %{Bugzilla::Bug::map_fields(\%fields)}; - my ($body, $attachments) = get_body_and_attachments($input_email); - if (@$attachments) { - $fields{'attachments'} = $attachments; - } + my ($reporter) = Email::Address->parse($input_email->header('From')); + $fields{'reporter'} = $reporter->address; - debug_print("Body:\n" . $body, 3); - - $body = remove_leading_blank_lines($body); - my @body_lines = split(/\r?\n/s, $body); - - # If there are fields specified. - if ($body =~ /^\s*@/s) { - my $current_field; - while (my $line = shift @body_lines) { - # If the sig is starting, we want to keep this in the - # @body_lines so that we don't keep the sig as part of the - # comment down below. - if ($line eq SIGNATURE_DELIMITER) { - unshift(@body_lines, $line); - last; - } - # Otherwise, we stop parsing fields on the first blank line. - $line = trim($line); - last if !$line; - if ($line =~ /^\@(\w+)\s*(?:=|\s|$)\s*(.*)\s*/) { - $current_field = lc($1); - $fields{$current_field} = $2; - } - else { - $fields{$current_field} .= " $line"; - } - } - } + # The summary line only affects us if we're doing a post_bug. + # We have to check it down here because there might have been + # a bug_id specified in the body of the email. + if (!$fields{'bug_id'} && !$fields{'short_desc'}) { + $fields{'short_desc'} = $summary; + } - %fields = %{ Bugzilla::Bug::map_fields(\%fields) }; + my $comment = ''; - my ($reporter) = Email::Address->parse($input_email->header('From')); - $fields{'reporter'} = $reporter->address; + # Get the description, except the signature. + foreach my $line (@body_lines) { + last if $line eq SIGNATURE_DELIMITER; + $comment .= "$line\n"; + } + $fields{'comment'} = $comment; - # The summary line only affects us if we're doing a post_bug. - # We have to check it down here because there might have been - # a bug_id specified in the body of the email. - if (!$fields{'bug_id'} && !$fields{'short_desc'}) { - $fields{'short_desc'} = $summary; - } + my %override = %{$switch{'override'} || {}}; + foreach my $key (keys %override) { + $fields{$key} = $override{$key}; + } - my $comment = ''; - # Get the description, except the signature. - foreach my $line (@body_lines) { - last if $line eq SIGNATURE_DELIMITER; - $comment .= "$line\n"; - } - $fields{'comment'} = $comment; - - my %override = %{ $switch{'override'} || {} }; - foreach my $key (keys %override) { - $fields{$key} = $override{$key}; - } + debug_print("Parsed Fields:\n" . Dumper(\%fields), 2); - debug_print("Parsed Fields:\n" . Dumper(\%fields), 2); - - return \%fields; + return \%fields; } sub check_email_fields { - my ($fields) = @_; - - my ($retval, $non_conclusive_fields) = - Bugzilla::User::match_field({ - 'assigned_to' => { 'type' => 'single' }, - 'qa_contact' => { 'type' => 'single' }, - 'cc' => { 'type' => 'multi' }, - 'newcc' => { 'type' => 'multi' } - }, $fields, MATCH_SKIP_CONFIRM); - - if ($retval != USER_MATCH_SUCCESS) { - ThrowUserError('user_match_too_many', {fields => $non_conclusive_fields}); - } + my ($fields) = @_; + + my ($retval, $non_conclusive_fields) = Bugzilla::User::match_field( + { + 'assigned_to' => {'type' => 'single'}, + 'qa_contact' => {'type' => 'single'}, + 'cc' => {'type' => 'multi'}, + 'newcc' => {'type' => 'multi'} + }, + $fields, + MATCH_SKIP_CONFIRM + ); + + if ($retval != USER_MATCH_SUCCESS) { + ThrowUserError('user_match_too_many', {fields => $non_conclusive_fields}); + } } sub post_bug { - my ($fields) = @_; - debug_print('Posting a new bug...'); + my ($fields) = @_; + debug_print('Posting a new bug...'); - my $user = Bugzilla->user; + my $user = Bugzilla->user; - check_email_fields($fields); + check_email_fields($fields); - my $bug = Bugzilla::Bug->create($fields); - debug_print("Created bug " . $bug->id); - return ($bug, $bug->comments->[0]); + my $bug = Bugzilla::Bug->create($fields); + debug_print("Created bug " . $bug->id); + return ($bug, $bug->comments->[0]); } sub process_bug { - my ($fields_in) = @_; - my %fields = %$fields_in; - - my $bug_id = $fields{'bug_id'}; - $fields{'id'} = $bug_id; - delete $fields{'bug_id'}; - - debug_print("Updating Bug $fields{id}..."); - - my $bug = Bugzilla::Bug->check($bug_id); - - if ($fields{'bug_status'}) { - $fields{'knob'} = $fields{'bug_status'}; - } - # If no status is given, then we only want to change the resolution. - elsif ($fields{'resolution'}) { - $fields{'knob'} = 'change_resolution'; - $fields{'resolution_knob_change_resolution'} = $fields{'resolution'}; - } - if ($fields{'dup_id'}) { - $fields{'knob'} = 'duplicate'; - } - - # Move @cc to @newcc as @cc is used by process_bug.cgi to remove - # users from the CC list when @removecc is set. - $fields{'newcc'} = delete $fields{'cc'} if $fields{'cc'}; - - # Make it possible to remove CCs. - if ($fields{'removecc'}) { - $fields{'cc'} = [split(',', $fields{'removecc'})]; - $fields{'removecc'} = 1; - } - - check_email_fields(\%fields); - - my $cgi = Bugzilla->cgi; - foreach my $field (keys %fields) { - $cgi->param(-name => $field, -value => $fields{$field}); - } - $cgi->param('longdesclength', scalar @{ $bug->comments }); - $cgi->param('token', issue_hash_token([$bug->id, $bug->delta_ts])); - - require 'process_bug.cgi'; - debug_print("Bug processed."); - - my $added_comment; - if (trim($fields{'comment'})) { - # The "old" bug object doesn't contain the comment we just added. - $added_comment = Bugzilla::Bug->check($bug_id)->comments->[-1]; - } - return ($bug, $added_comment); + my ($fields_in) = @_; + my %fields = %$fields_in; + + my $bug_id = $fields{'bug_id'}; + $fields{'id'} = $bug_id; + delete $fields{'bug_id'}; + + debug_print("Updating Bug $fields{id}..."); + + my $bug = Bugzilla::Bug->check($bug_id); + + if ($fields{'bug_status'}) { + $fields{'knob'} = $fields{'bug_status'}; + } + + # If no status is given, then we only want to change the resolution. + elsif ($fields{'resolution'}) { + $fields{'knob'} = 'change_resolution'; + $fields{'resolution_knob_change_resolution'} = $fields{'resolution'}; + } + if ($fields{'dup_id'}) { + $fields{'knob'} = 'duplicate'; + } + + # Move @cc to @newcc as @cc is used by process_bug.cgi to remove + # users from the CC list when @removecc is set. + $fields{'newcc'} = delete $fields{'cc'} if $fields{'cc'}; + + # Make it possible to remove CCs. + if ($fields{'removecc'}) { + $fields{'cc'} = [split(',', $fields{'removecc'})]; + $fields{'removecc'} = 1; + } + + check_email_fields(\%fields); + + my $cgi = Bugzilla->cgi; + foreach my $field (keys %fields) { + $cgi->param(-name => $field, -value => $fields{$field}); + } + $cgi->param('longdesclength', scalar @{$bug->comments}); + $cgi->param('token', issue_hash_token([$bug->id, $bug->delta_ts])); + + require 'process_bug.cgi'; + debug_print("Bug processed."); + + my $added_comment; + if (trim($fields{'comment'})) { + + # The "old" bug object doesn't contain the comment we just added. + $added_comment = Bugzilla::Bug->check($bug_id)->comments->[-1]; + } + return ($bug, $added_comment); } sub handle_attachments { - my ($bug, $attachments, $comment) = @_; - return if !$attachments; - debug_print("Handling attachments..."); - my $dbh = Bugzilla->dbh; - $dbh->bz_start_transaction(); - my ($update_comment, $update_bug); - foreach my $attachment (@$attachments) { - my $data = delete $attachment->{payload}; - debug_print("Inserting Attachment: " . Dumper($attachment), 2); - $attachment->{content_type} ||= 'application/octet-stream'; - my $obj = Bugzilla::Attachment->create({ - bug => $bug, - description => $attachment->{filename}, - filename => $attachment->{filename}, - mimetype => $attachment->{content_type}, - data => $data, - }); - # If we added a comment, and our comment does not already have a type, - # and this is our first attachment, then we make the comment an - # "attachment created" comment. - if ($comment and !$comment->type and !$update_comment) { - $comment->set_all({ type => CMT_ATTACHMENT_CREATED, - extra_data => $obj->id }); - $update_comment = 1; - } - else { - $bug->add_comment('', { type => CMT_ATTACHMENT_CREATED, - extra_data => $obj->id }); - $update_bug = 1; - } + my ($bug, $attachments, $comment) = @_; + return if !$attachments; + debug_print("Handling attachments..."); + my $dbh = Bugzilla->dbh; + $dbh->bz_start_transaction(); + my ($update_comment, $update_bug); + foreach my $attachment (@$attachments) { + my $data = delete $attachment->{payload}; + debug_print("Inserting Attachment: " . Dumper($attachment), 2); + $attachment->{content_type} ||= 'application/octet-stream'; + my $obj = Bugzilla::Attachment->create({ + bug => $bug, + description => $attachment->{filename}, + filename => $attachment->{filename}, + mimetype => $attachment->{content_type}, + data => $data, + }); + + # If we added a comment, and our comment does not already have a type, + # and this is our first attachment, then we make the comment an + # "attachment created" comment. + if ($comment and !$comment->type and !$update_comment) { + $comment->set_all({type => CMT_ATTACHMENT_CREATED, extra_data => $obj->id}); + $update_comment = 1; } - # We only update the comments and bugs at the end of the transaction, - # because doing so modifies bugs_fulltext, which is a non-transactional - # table. - $bug->update() if $update_bug; - $comment->update() if $update_comment; - $dbh->bz_commit_transaction(); + else { + $bug->add_comment('', {type => CMT_ATTACHMENT_CREATED, extra_data => $obj->id}); + $update_bug = 1; + } + } + + # We only update the comments and bugs at the end of the transaction, + # because doing so modifies bugs_fulltext, which is a non-transactional + # table. + $bug->update() if $update_bug; + $comment->update() if $update_comment; + $dbh->bz_commit_transaction(); } ###################### @@ -274,116 +283,124 @@ sub handle_attachments { ###################### sub debug_print { - my ($str, $level) = @_; - $level ||= 1; - print STDERR "$str\n" if $level <= $switch{'verbose'}; + my ($str, $level) = @_; + $level ||= 1; + print STDERR "$str\n" if $level <= $switch{'verbose'}; } sub get_body_and_attachments { - my ($email) = @_; + my ($email) = @_; + + my $ct = $email->content_type || 'text/plain'; + debug_print("Splitting Body and Attachments [Type: $ct]..."); + + my $body; + my $attachments = []; + if ($ct =~ /^multipart\/(alternative|signed)/i) { + $body = get_text_alternative($email); + } + else { + my $stripper + = new Email::MIME::Attachment::Stripper($email, force_filename => 1); + my $message = $stripper->message; + $body = get_text_alternative($message); + $attachments = [$stripper->attachments]; + } + + return ($body, $attachments); +} - my $ct = $email->content_type || 'text/plain'; - debug_print("Splitting Body and Attachments [Type: $ct]..."); +sub get_text_alternative { + my ($email) = @_; - my $body; - my $attachments = []; - if ($ct =~ /^multipart\/(alternative|signed)/i) { - $body = get_text_alternative($email); + my @parts = $email->parts; + my $body; + foreach my $part (@parts) { + my $ct = $part->content_type || 'text/plain'; + my $charset = 'iso-8859-1'; + + # The charset may be quoted. + if ($ct =~ /charset="?([^;"]+)/) { + $charset = $1; } - else { - my $stripper = new Email::MIME::Attachment::Stripper( - $email, force_filename => 1); - my $message = $stripper->message; - $body = get_text_alternative($message); - $attachments = [$stripper->attachments]; + debug_print("Part Content-Type: $ct", 2); + debug_print("Part Character Encoding: $charset", 2); + if (!$ct || $ct =~ /^text\/plain/i) { + $body = $part->body; + if (Bugzilla->params->{'utf8'} && !utf8::is_utf8($body)) { + $body = Encode::decode($charset, $body); + } + last; } + } - return ($body, $attachments); -} - -sub get_text_alternative { - my ($email) = @_; - - my @parts = $email->parts; - my $body; - foreach my $part (@parts) { - my $ct = $part->content_type || 'text/plain'; - my $charset = 'iso-8859-1'; - # The charset may be quoted. - if ($ct =~ /charset="?([^;"]+)/) { - $charset= $1; - } - debug_print("Part Content-Type: $ct", 2); - debug_print("Part Character Encoding: $charset", 2); - if (!$ct || $ct =~ /^text\/plain/i) { - $body = $part->body; - if (Bugzilla->params->{'utf8'} && !utf8::is_utf8($body)) { - $body = Encode::decode($charset, $body); - } - last; - } - } + if (!defined $body) { - if (!defined $body) { - # Note that this only happens if the email does not contain any - # text/plain parts. If the email has an empty text/plain part, - # you're fine, and this message does NOT get thrown. - ThrowUserError('email_no_text_plain'); - } + # Note that this only happens if the email does not contain any + # text/plain parts. If the email has an empty text/plain part, + # you're fine, and this message does NOT get thrown. + ThrowUserError('email_no_text_plain'); + } - return $body; + return $body; } sub remove_leading_blank_lines { - my ($text) = @_; - $text =~ s/^(\s*\n)+//s; - return $text; + my ($text) = @_; + $text =~ s/^(\s*\n)+//s; + return $text; } sub html_strip { - my ($var) = @_; - # Trivial HTML tag remover (this is just for error messages, really.) - $var =~ s/<[^>]*>//g; - # And this basically reverses the Template-Toolkit html filter. - $var =~ s/\&/\&/g; - $var =~ s/\<//g; - $var =~ s/\"/\"/g; - $var =~ s/@/@/g; - # Also remove undesired newlines and consecutive spaces. - $var =~ s/[\n\s]+/ /gms; - return $var; + my ($var) = @_; + + # Trivial HTML tag remover (this is just for error messages, really.) + $var =~ s/<[^>]*>//g; + + # And this basically reverses the Template-Toolkit html filter. + $var =~ s/\&/\&/g; + $var =~ s/\<//g; + $var =~ s/\"/\"/g; + $var =~ s/@/@/g; + + # Also remove undesired newlines and consecutive spaces. + $var =~ s/[\n\s]+/ /gms; + return $var; } sub die_handler { - my ($msg) = @_; - - # In Template-Toolkit, [% RETURN %] is implemented as a call to "die". - # But of course, we really don't want to actually *die* just because - # the user-error or code-error template ended. So we don't really die. - return if blessed($msg) && $msg->isa('Template::Exception') - && $msg->type eq 'return'; - - # If this is inside an eval, then we should just act like...we're - # in an eval (instead of printing the error and exiting). - die(@_) if $^S; - - # We can't depend on the MTA to send an error message, so we have - # to generate one properly. - if ($input_email) { - $msg =~ s/at .+ line.*$//ms; - $msg =~ s/^Compilation failed in require.+$//ms; - $msg = html_strip($msg); - my $from = Bugzilla->params->{'mailfrom'}; - my $reply = reply(to => $input_email, from => $from, top_post => 1, - body => "$msg\n"); - MessageToMTA($reply->as_string); - } - print STDERR "$msg\n"; - # We exit with a successful value, because we don't want the MTA - # to *also* send a failure notice. - exit; + my ($msg) = @_; + + # In Template-Toolkit, [% RETURN %] is implemented as a call to "die". + # But of course, we really don't want to actually *die* just because + # the user-error or code-error template ended. So we don't really die. + return + if blessed($msg) + && $msg->isa('Template::Exception') + && $msg->type eq 'return'; + + # If this is inside an eval, then we should just act like...we're + # in an eval (instead of printing the error and exiting). + die(@_) if $^S; + + # We can't depend on the MTA to send an error message, so we have + # to generate one properly. + if ($input_email) { + $msg =~ s/at .+ line.*$//ms; + $msg =~ s/^Compilation failed in require.+$//ms; + $msg = html_strip($msg); + my $from = Bugzilla->params->{'mailfrom'}; + my $reply + = reply(to => $input_email, from => $from, top_post => 1, body => "$msg\n"); + MessageToMTA($reply->as_string); + } + print STDERR "$msg\n"; + + # We exit with a successful value, because we don't want the MTA + # to *also* send a failure notice. + exit; } ############### @@ -400,18 +417,19 @@ pod2usage({-verbose => 0, -exitval => 1}) if $switch{'help'}; Bugzilla->usage_mode(USAGE_MODE_EMAIL); -my @mail_lines = ; -my $mail_text = join("", @mail_lines); +my @mail_lines = ; +my $mail_text = join("", @mail_lines); my $mail_fields = parse_mail($mail_text); -Bugzilla::Hook::process('email_in_after_parse', { fields => $mail_fields }); +Bugzilla::Hook::process('email_in_after_parse', {fields => $mail_fields}); my $attachments = delete $mail_fields->{'attachments'}; my $username = $mail_fields->{'reporter'}; + # If emailsuffix is in use, we have to remove it from the email address. if (my $suffix = Bugzilla->params->{'emailsuffix'}) { - $username =~ s/\Q$suffix\E$//i; + $username =~ s/\Q$suffix\E$//i; } my $user = Bugzilla::User->check($username); @@ -419,10 +437,10 @@ Bugzilla->set_user($user); my ($bug, $comment); if ($mail_fields->{'bug_id'}) { - ($bug, $comment) = process_bug($mail_fields); + ($bug, $comment) = process_bug($mail_fields); } else { - ($bug, $comment) = post_bug($mail_fields); + ($bug, $comment) = post_bug($mail_fields); } handle_attachments($bug, $attachments, $comment); @@ -434,7 +452,7 @@ handle_attachments($bug, $attachments, $comment); # to wait for $bug->update() to be fully used in email_in.pl first. So # currently, process_bug.cgi does the mail sending for bugs, and this does # any mail sending for attachments after the first one. -Bugzilla::BugMail::Send($bug->id, { changer => Bugzilla->user }); +Bugzilla::BugMail::Send($bug->id, {changer => Bugzilla->user}); debug_print("Sent bugmail"); -- cgit v1.2.3-24-g4f1b