]> git.donarmstrong.com Git - debbugs.git/commitdiff
Merge branch 'master' into database
authorDon Armstrong <don@donarmstrong.com>
Fri, 22 Mar 2013 22:42:14 +0000 (15:42 -0700)
committerDon Armstrong <don@donarmstrong.com>
Fri, 22 Mar 2013 22:42:14 +0000 (15:42 -0700)
20 files changed:
Debbugs/CGI/Bugreport.pm
Debbugs/Common.pm
Debbugs/Config.pm
Debbugs/Recipients.pm
Debbugs/SOAP.pm
Debbugs/Status.pm
Debbugs/UTF8.pm
bin/debbugs-rebuild-index.db [new file with mode: 0755]
cgi/bugreport.cgi
debian/changelog
debian/control
debian/rules
debian/source/format [new file with mode: 0644]
examples/debian/postpa/21bugclosers
html/bugs.css
scripts/spamscan-sa
t/01_pod.t
t/13_utf8_mail.t
t/15_rebuild_indexdb.t [new file with mode: 0644]
templates/en_US/cgi/bugreport.tmpl

index 29602c58c39f1088bc17208e49ab28c1561ac152..d9a8744ec246a8fad827b4a15790b92b2137668f 100644 (file)
@@ -40,7 +40,7 @@ use Debbugs::Common qw(globify_scalar english_join);
 use Debbugs::UTF8;
 use Debbugs::Config qw(:config);
 use POSIX qw(strftime);
-use Encode qw(decode_utf8);
+use Encode qw(decode_utf8 encode_utf8);
 
 BEGIN{
      ($VERSION) = q$Revision: 494 $ =~ /^Revision:\s+([^\s+])/;
@@ -113,10 +113,13 @@ sub display_entity {
                                         trim_headers => {type => BOOLEAN,
                                                          default => 1,
                                                         },
+                                         avatars => {type => BOOLEAN,
+                                                     default => 1,
+                                                    },
                                        }
                             );
 
-    $param{output} = globify_scalar($param{output});
+    my $output = globify_scalar($param{output});
     my $entity = $param{entity};
     my $ref = $param{bug_num};
     my $top = $param{outer};
@@ -135,25 +138,26 @@ sub display_entity {
        not $param{terse} and
        not exists $param{att}) {
         my $header = $entity->head;
-        print {$param{output}} "<div class=\"headers\">\n";
+        print {$output} "<div class=\"headers\">\n";
         if ($param{trim_headers}) {
              my @headers;
              foreach (qw(From To Cc Subject Date)) {
                   my $head_field = $head->get($_);
                   next unless defined $head_field and $head_field ne '';
-                   if ($_ eq 'From') {
+                   chomp $head_field;
+                   if ($_ eq 'From' and $param{avatars}) {
                        my $libravatar_url = __libravatar_url(decode_rfc1522($head_field));
                        if (defined $libravatar_url and length $libravatar_url) {
-                           push @headers,q(<img src=").$libravatar_url.q(">);
+                           push @headers,q(<img src=").$libravatar_url.qq(" alt="">\n);
                        }
                    }
-                  push @headers, qq(<p><span class="header">$_:</span> ) . html_escape(decode_rfc1522($head_field))."</p>";
+                  push @headers, qq(<div class="header"><span class="headerfield">$_:</span> ) . html_escape(decode_rfc1522($head_field))."</div>\n";
              }
-             print {$param{output}} join(qq(), @headers);
+             print {$output} join(qq(), @headers);
         } else {
-             print {$param{output}} "<pre>".html_escape(decode_rfc1522($entity->head->stringify))."</pre>\n";
+             print {$output} "<pre>".html_escape(decode_rfc1522($entity->head->stringify))."</pre>\n";
         }
-        print {$param{output}} "</div>\n";
+        print {$output} "</div>\n";
     }
 
     if (not (($param{outer} and $type =~ m{^text(?:/plain)?(?:;|$)})
@@ -168,32 +172,31 @@ sub display_entity {
            my $body = $entity->stringify_body;
            # this attachment has its own content type, so we must not
            # try to convert it to UTF-8 or do anything funky.
-           my @layers = PerlIO::get_layers($param{output});
-           binmode($param{output},':raw');
-           print {$param{output}} "Content-Type: $type";
+           binmode($output,':raw');
+           print {$output} "Content-Type: $type";
            my ($charset) = $head->get('Content-Type:') =~ m/charset\s*=\s*\"?([\w-]+)\"?/i;
-           print {$param{output}} qq(; charset="$charset") if defined $charset;
-           print {$param{output}} "\n";
+           print {$output} qq(; charset="$charset") if defined $charset;
+           print {$output} "\n";
            if ($filename ne '') {
                my $qf = $filename;
                $qf =~ s/"/\\"/g;
                $qf =~ s[.*/][];
-               print {$param{output}} qq{Content-Disposition: inline; filename="$qf"\n};
+               print {$output} qq{Content-Disposition: inline; filename="$qf"\n};
            }
-           print {$param{output}} "\n";
+           print {$output} "\n";
            my $decoder = MIME::Decoder->new($head->mime_encoding);
-           $decoder->decode(IO::Scalar->new(\$body), $param{output});
-           if (grep {/utf8/} @layers) {
-               binmode($param{output},':utf8');
-           }
-           return;
+           $decoder->decode(IO::Scalar->new(\$body), $output);
+            # we don't reset the layers here, because it makes no
+            # sense to add anything to the output handle after this
+            # point.
+           return(1);
        }
        elsif (not exists $param{att}) {
             my @dlargs = (msg=>$xmessage, att=>$#$attachments);
             push @dlargs, (filename=>$filename) if $filename ne '';
             my $printname = $filename;
             $printname = 'Message part ' . ($#$attachments + 1) if $filename eq '';
-            print {$param{output}} '<pre class="mime">[<a href="' .
+            print {$output} '<pre class="mime">[<a href="' .
                  html_escape(bug_links(bug => $ref,
                                        links_only => 1,
                                        options => {@dlargs})
@@ -202,31 +205,36 @@ sub display_entity {
        }
     }
 
-    return if not $param{outer} and $disposition eq 'attachment' and not exists $param{att};
-    return unless ($type =~ m[^text/?] and
-                  $type !~ m[^text/(?:html|enriched)(?:;|$)]) or
-                 $type =~ m[^application/pgp(?:;|$)] or
-                 $entity->parts;
+    return if not $param{outer} and $disposition eq 'attachment' and not exists $param{att};
+    return 0 unless (($type =~ m[^text/?] and
+                      $type !~ m[^text/(?:html|enriched)(?:;|$)]) or
+                     $type =~ m[^application/pgp(?:;|$)] or
+                     $entity->parts);
 
     if ($entity->is_multipart) {
        my @parts = $entity->parts;
        foreach my $part (@parts) {
-           display_entity(entity => $part,
-                          bug_num => $ref,
-                          outer => 0,
-                          msg_num => $xmessage,
-                          output => $param{output},
-                          attachments => $attachments,
-                          terse => $param{terse},
-                          exists $param{msg}?(msg=>$param{msg}):(),
-                          exists $param{att}?(att=>$param{att}):(),
-                         );
-           # print {$param{output}} "\n";
+           my $raw_output =
+                display_entity(entity => $part,
+                               bug_num => $ref,
+                               outer => 0,
+                               msg_num => $xmessage,
+                               output => $output,
+                               attachments => $attachments,
+                               terse => $param{terse},
+                               exists $param{msg}?(msg=>$param{msg}):(),
+                               exists $param{att}?(att=>$param{att}):(),
+                               exists $param{avatars}?(avatars=>$param{avatars}):(),
+                              );
+            if ($raw_output) {
+                return $raw_output;
+            }
+           # print {$output} "\n";
        }
     } elsif ($entity->parts) {
        # We must be dealing with a nested message.
         if (not exists $param{att}) {
-             print {$param{output}} "<blockquote>\n";
+             print {$output} "<blockquote>\n";
         }
        my @parts = $entity->parts;
        foreach my $part (@parts) {
@@ -234,16 +242,17 @@ sub display_entity {
                           bug_num => $ref,
                           outer => 1,
                           msg_num => $xmessage,
-                          output => $param{output},
+                          output => $output,
                           attachments => $attachments,
                           terse => $param{terse},
                           exists $param{msg}?(msg=>$param{msg}):(),
                           exists $param{att}?(att=>$param{att}):(),
+                           exists $param{avatars}?(avatars=>$param{avatars}):(),
                          );
-           # print {$param{output}} "\n";
+           # print {$output} "\n";
        }
         if (not exists $param{att}) {
-             print {$param{output}} "</blockquote>\n";
+             print {$output} "</blockquote>\n";
         }
     } elsif (not $param{terse}) {
         my $content_type = $entity->head->get('Content-Type:') || "text/html";
@@ -277,9 +286,10 @@ sub display_entity {
                       {$1<a href="http://$config{cve_tracker}$2">$2</a>$3}gxm;
         }
         if (not exists $param{att}) {
-             print {$param{output}} qq(<pre class="message">$body</pre>\n);
+             print {$output} qq(<pre class="message">$body</pre>\n);
         }
     }
+    return 0;
 }
 
 
@@ -299,9 +309,8 @@ appropriate.
 sub handle_email_message{
      my ($email,%param) = @_;
 
-     # output needs to have the is_utf8 flag on to avoid double
-     # encoding
-     my $output = decode_utf8('');
+     my $output;
+     my $output_fh = globify_scalar(\$output);
      my $parser = MIME::Parser->new();
      # Because we are using memory, not tempfiles, there's no need to
      # clean up here like in Debbugs::MIME
@@ -309,19 +318,20 @@ sub handle_email_message{
      $parser->output_to_core(1);
      my $entity = $parser->parse_data( $email);
      my @attachments = ();
-     display_entity(entity  => $entity,
-                   bug_num => $param{ref},
-                   outer   => 1,
-                   msg_num => $param{msg_num},
-                   output => \$output,
-                   attachments => \@attachments,
-                   terse       => $param{terse},
-                   exists $param{msg}?(msg=>$param{msg}):(),
-                   exists $param{att}?(att=>$param{att}):(),
-                   exists $param{trim_headers}?(trim_headers=>$param{trim_headers}):(),
-                  );
-     return $output;
-
+     my $raw_output =
+         display_entity(entity  => $entity,
+                        bug_num => $param{ref},
+                        outer   => 1,
+                        msg_num => $param{msg_num},
+                        output => $output_fh,
+                        attachments => \@attachments,
+                        terse       => $param{terse},
+                        exists $param{msg}?(msg=>$param{msg}):(),
+                        exists $param{att}?(att=>$param{att}):(),
+                        exists $param{trim_headers}?(trim_headers=>$param{trim_headers}):(),
+                        exists $param{avatars}?(avatars=>$param{avatars}):(),
+                       );
+     return $raw_output?$output:decode_utf8($output);
 }
 
 =head2 handle_record
@@ -335,7 +345,7 @@ should be output to the browser.
 =cut
 
 sub handle_record{
-     my ($record,$bug_number,$msg_number,$seen_msg_ids) = @_;
+     my ($record,$bug_number,$msg_number,$seen_msg_ids,%param) = @_;
 
      # output needs to have the is_utf8 flag on to avoid double
      # encoding
@@ -398,6 +408,7 @@ sub handle_record{
          $output .= handle_email_message($record->{text},
                                          ref     => $bug_number,
                                          msg_num => $msg_number,
+                                          %param,
                                         );
      }
      elsif (/autocheck/) {
@@ -425,6 +436,7 @@ sub handle_record{
          $output .= handle_email_message($record->{text},
                                          ref     => $bug_number,
                                          msg_num => $msg_number,
+                                          %param,
                                         );
      }
      else {
index 4595433a04b01d363f7d1978dc3e22b46db5245f..cf53b07e0e35344c35823496315585cd958df8ca 100644 (file)
@@ -75,6 +75,7 @@ use Storable qw(dclone);
 use Params::Validate qw(validate_with :types);
 
 use Fcntl qw(:DEFAULT :flock);
+use Encode qw(is_utf8 decode_utf8);
 
 our $DEBUG_FH = \*STDERR if not defined $DEBUG_FH;
 
@@ -816,6 +817,10 @@ Will carp if given a scalar which isn't a scalarref or a glob (or
 globref), and return /dev/null. May return undef if IO::Scalar or
 IO::File fails. (Check $!)
 
+The scalar will fill with octets, not perl's internal encoding, so you
+must use decode_utf8() after on the scalar, and encode_utf8() on it
+before. This appears to be a bug in the underlying modules.
+
 =cut
 
 sub globify_scalar {
@@ -825,7 +830,11 @@ sub globify_scalar {
          if (defined ref($scalar)) {
               if (ref($scalar) eq 'SCALAR' and
                   not UNIVERSAL::isa($scalar,'GLOB')) {
-                   open $handle, '>:scalar', $scalar;
+                   if (is_utf8(${$scalar})) {
+                       ${$scalar} = decode_utf8(${$scalar});
+                       carp(q(\$scalar must not be in perl's internal encoding));
+                   }
+                   open $handle, '>:scalar:utf8', $scalar;
                    return $handle;
               }
               else {
index 3a6e7cf366290b4e2f9e83ce8294488f2f38ce73..cb30eda342c09a0704e9edfc5e1d762a5d7c12c8 100644 (file)
@@ -78,10 +78,11 @@ BEGIN {
                                ],
                     text     => [qw($gBadEmailPrefix $gHTMLTail $gHTMLExpireNote),
                                 ],
+                     cgi => [qw($gLibravatarUri $gLibravatarUriOptions)],
                     config   => [qw(%config)],
                    );
      @EXPORT_OK = ();
-     Exporter::export_ok_tags(qw(globals text config));
+     Exporter::export_ok_tags(keys %EXPORT_TAGS);
      $EXPORT_TAGS{all} = [@EXPORT_OK];
      $ENV{HOME} = '' if not defined $ENV{HOME};
 }
@@ -368,7 +369,7 @@ set_default(\%config,'bug_subscription_domain',$config{list_domain});
 
 =over
 
-=item libravatar_uri
+=item libravatar_uri $gLibravatarUri
 
 URI to a libravatar configuration. If empty or undefined, libravatar
 support will be disabled. Defaults to
@@ -379,7 +380,7 @@ and falls back to gravatar if necessary.
 
 set_default(\%config,'libravatar_uri',"http://cdn.libravatar.org/avatar/");
 
-=item libravatar_uri_options
+=item libravatar_uri_options $gLibravatarUriOptions
 
 Options to append to the md5_hex of the e-mail. This sets the default
 avatar used when an avatar isn't available. Currently defaults to
@@ -1088,7 +1089,7 @@ sub read_config{
          die "Error in configuration file: $@" if $@;
          # Now what we do is check out the contents of %EXPORT_TAGS to see exactly which variables
          # we want to glob in from the configuration file
-         for my $variable (@{$EXPORT_TAGS{globals}}) {
+         for my $variable (map {$_ =~ /^(?:config|all)$/ ? () : @{$EXPORT_TAGS{$_}}} keys %EXPORT_TAGS) {
               my ($hash_name,$glob_name,$glob_type) = __convert_name($variable);
               my $var_glob = $cpt->varglob($glob_name);
               my $value; #= $cpt->reval("return $variable");
index 47c648541044c8cf3f3a4ee2b7923ba2f37225ac..ae739e973647ef74d2641dfe60b61dacf666093d 100644 (file)
@@ -245,7 +245,7 @@ Using the recipient hashref, determines the set of recipients.
 If you specify one of C<bcc>, C<cc>, or C<to>, you will receive only a
 LIST of recipients which the main should be Bcc'ed, Cc'ed, or To'ed
 respectively. By default, a LIST with keys bcc, cc, and to is returned
-with ARRAYREF values correponding to the users to whom a message
+with ARRAYREF values corresponding to the users to whom a message
 should be sent.
 
 =over
index c1fc85f9b84fb5465bbab56ab916b4b445f1073b..f87581e60c07af74150cacce8a633be362afb79d 100644 (file)
@@ -343,7 +343,7 @@ architectures are at which versions.
 
 =back
 
-This function correponds to L<Debbugs::Packages::get_versions>
+This function corresponds to L<Debbugs::Packages::get_versions>
 
 =cut
 
index c66ab416805c37bdf9f5e3ed28ce4e292e28ba5a..f44f9fc4fbefdbb7114c95a7565e206c4cff568c 100644 (file)
@@ -70,6 +70,7 @@ BEGIN{
                                  qw(removefoundversions removefixedversions)
                                 ],
                     hook     => [qw(bughook bughook_archive)],
+                     indexdb  => [qw(generate_index_db_line)],
                     fields   => [qw(%fields)],
                    );
      @EXPORT_OK = ();
@@ -207,6 +208,7 @@ sub read_bug{
         $log = $status;
         $log =~ s/\.summary$/.log/;
         ($location) = $status =~ m/(db-h|db|archive)/;
+         ($param{bug}) = $status =~ m/(\d+)\.summary$/;
     }
     if ($param{lock}) {
        filelock("$config{spool_dir}/lock/$param{bug}",exists $param{locks}?$param{locks}:());
@@ -655,7 +657,7 @@ sub makestatus {
 
 Writes the bug status and summary files out.
 
-Skips writting out a status file if minversion is 2
+Skips writing out a status file if minversion is 2
 
 Does not call bughook if disablebughook is true.
 
@@ -773,7 +775,7 @@ exactly are removed. Otherwise, all versions matching the version
 number are removed.
 
 Currently $package and $isbinary are entirely ignored, but accepted
-for backwards compatibilty.
+for backwards compatibility.
 
 =cut
 
@@ -1599,6 +1601,39 @@ sub isstrongseverity {
     return grep { $_ eq $severity } @{$config{strong_severities}};
 }
 
+=head1 indexdb
+
+=head2 generate_index_db_line
+
+       my $data = read_bug(bug => $bug,
+                           location => $initialdir);
+        # generate_index_db_line hasn't been written yet at all.
+        my $line = generate_index_db_line($data);
+
+Returns a line for a bug suitable to be written out to index.db.
+
+=cut
+
+sub generate_index_db_line {
+    my ($data,$bug) = @_;
+
+    # just in case someone has given us a split out data
+    $data = join_status_fields($data);
+
+    my $whendone = "open";
+    my $severity = $config{default_severity};
+    (my $pkglist = $data->{package}) =~ s/[,\s]+/,/g;
+    $pkglist =~ s/^,+//;
+    $pkglist =~ s/,+$//;
+    $whendone = "forwarded" if defined $data->{forwarded} and length $data->{forwarded};
+    $whendone = "done" if defined $data->{done} and length $data->{done};
+    $severity = $data->{severity} if length $data->{severity};
+    return sprintf "%s %d %d %s [%s] %s %s\n",
+        $pkglist, $data->{bug_num}//$bug, $data->{date}, $whendone,
+            $data->{originator}, $severity, $data->{keywords};
+}
+
+
 
 =head1 PRIVATE FUNCTIONS
 
@@ -1615,6 +1650,7 @@ sub update_realtime {
        my $idx_new = IO::File->new($file.'.new','w')
             or die "Couldn't open ${file}.new: $!";
 
+        binmode($idx_old,':raw:utf8');
         binmode($idx_new,':raw:encoding(UTF-8)');
        my $min_bug = min(keys %bugs);
        my $line;
@@ -1680,19 +1716,7 @@ sub bughook {
             my $data = $bugs_temp{$bug};
             appendfile("$config{spool_dir}/debbugs.trace","$type $bug\n",makestatus($data, 1));
 
-            my $whendone = "open";
-            my $severity = $config{default_severity};
-            (my $pkglist = $data->{package}) =~ s/[,\s]+/,/g;
-            $pkglist =~ s/^,+//;
-            $pkglist =~ s/,+$//;
-            $whendone = "forwarded" if defined $data->{forwarded} and length $data->{forwarded};
-            $whendone = "done" if defined $data->{done} and length $data->{done};
-            $severity = $data->{severity} if length $data->{severity};
-
-            my $k = sprintf "%s %d %d %s [%s] %s %s\n",
-                 $pkglist, $bug, $data->{date}, $whendone,
-                      $data->{originator}, $severity, $data->{keywords};
-            $bugs{$bug} = $k;
+            $bugs{$bug} = generate_index_db_line($data,$bug);
        }
        update_realtime("$config{spool_dir}/index.db.realtime", %bugs);
 
index 74a40427412fe402bc81bb4b9cb631e6985995f6..c90cedf48109f0c6301b1e87ebdc964e28d1a170 100644 (file)
@@ -146,12 +146,13 @@ sub decode_utf8_safely{
 our %iconv_converters;
 
 sub convert_to_utf8 {
-    my ($data,$charset) = @_;
+    my ($data,$charset,$internal_call) = @_;
+    $internal_call //= 0;
     if (is_utf8($data)) {
         cluck("utf8 flag is set when calling convert_to_utf8");
         return $data;
     }
-    $charset = uc($charset);
+    $charset = uc($charset//'UTF-8');
     if ($charset eq 'RAW') {
         croak("Charset must not be raw when calling convert_to_utf8");
     }
@@ -161,6 +162,7 @@ sub convert_to_utf8 {
                 die "Unable to create converter for '$charset'";
         };
         if ($@) {
+            return undef if $internal_call;
             warn $@;
             # We weren't able to create the converter, so use Encode
             # instead
@@ -168,6 +170,7 @@ sub convert_to_utf8 {
         }
     }
     if (not defined $iconv_converters{$charset}) {
+        return undef if $internal_call;
         warn "The converter for $charset wasn't created properly somehow!";
         return __fallback_convert_to_utf8($data,$charset);
     }
@@ -178,7 +181,17 @@ sub convert_to_utf8 {
     if (not defined $retval or
         $retval < 0
        ) {
-        warn "failed to convert to utf8";
+        # try iso8559-1 first
+        if (not $internal_call) {
+            my $call_back_data = convert_to_utf8($data,'ISO8859-1',1);
+            # if there's an Ã (0xC3), it's probably something
+            # horrible, and we shouldn't try to convert it.
+            if (defined $call_back_data and $call_back_data !~ /\x{C3}/) {
+                warn "failed to convert to utf8 (charset: $charset, data: $data), but succeeded with ISO8859-1: ".encode_utf8($call_back_data);
+                return $call_back_data;
+            }
+        }
+        warn "failed to convert to utf8 (charset: $charset, data: $data)";
         # Fallback to encode, which will probably also fail.
         return __fallback_convert_to_utf8($data,$charset);
     }
@@ -199,7 +212,7 @@ sub __fallback_convert_to_utf8 {
      $charset //= 'utf8';
      my $result;
      eval {
-        $result = decode($charset,$data);
+        $result = decode($charset,$data,0);
      };
      if ($@) {
          warn "Unable to decode charset; '$charset' and '$data': $@";
diff --git a/bin/debbugs-rebuild-index.db b/bin/debbugs-rebuild-index.db
new file mode 100755 (executable)
index 0000000..c44bc32
--- /dev/null
@@ -0,0 +1,157 @@
+#! /usr/bin/perl
+# debbugs-rebuild-index.db is part of debbugs, and is released
+# under the terms of the GPL version 2, or any later version, at your
+# option. See the file README and COPYING for more information.
+# Copyright 2012 by Don Armstrong <don@donarmstrong.com>.
+
+
+use warnings;
+use strict;
+
+use Getopt::Long qw(:config no_ignore_case);
+use Pod::Usage;
+
+=head1 NAME
+
+debbugs-rebuild-index.db -- rebuild Debbug's index.db
+
+=head1 SYNOPSIS
+
+debbugs-rebuild-index.db [options]
+
+ Options:
+  --spool-dir debbugs spool directory
+  --debug, -d debugging level (Default 0)
+  --help, -h display this help
+  --man, -m display manual
+
+=head1 OPTIONS
+
+=over
+
+=item B<--spool-dir>
+
+Debbugs spool directory; defaults to the value configured in the
+debbugs configuration file.
+
+=item B<--debug, -d>
+
+Debug verbosity.
+
+=item B<--help, -h>
+
+Display brief useage information.
+
+=item B<--man, -m>
+
+Display this manual.
+
+=back
+
+=head1 EXAMPLES
+
+Rebuild the index.db for db-h.
+
+ debbugs-rebuild-index.db;
+
+Rebuild the index.db for archive
+
+ debbugs-rebuild-index.db archive;
+
+
+=cut
+
+
+use vars qw($DEBUG);
+
+use Debbugs::Common qw(checkpid lockpid get_hashname getparsedaddrs getbugcomponent make_list);
+use Debbugs::Config qw(:config);
+use Debbugs::Status qw(read_bug split_status_fields generate_index_db_line);
+
+my %options = (debug           => 0,
+              help            => 0,
+              man             => 0,
+              verbose         => 0,
+              quiet           => 0,
+              quick           => 0,
+              service         => 'debbugs',
+             );
+
+
+GetOptions(\%options,
+          'quick|q',
+          'service|s',
+          'sysconfdir|c',
+          'spool_dir|spool-dir=s',
+          'debug|d+','help|h|?','man|m');
+
+pod2usage() if $options{help};
+pod2usage({verbose=>2}) if $options{man};
+
+$DEBUG = $options{debug};
+
+my @USAGE_ERRORS;
+$options{verbose} = $options{verbose} - $options{quiet};
+
+pod2usage(join("\n",@USAGE_ERRORS)) if @USAGE_ERRORS;
+
+if (exists $options{spool_dir} and defined $options{spool_dir}) {
+    $config{spool_dir} = $options{spool_dir};
+}
+chdir($config{spool_dir}) or die "chdir $config{spool_dir} failed: $!";
+
+my $verbose = $options{debug};
+
+my $initialdir = "db-h";
+
+if (defined $ARGV[0] and $ARGV[0] eq "archive") {
+    $initialdir = "archive";
+}
+
+if (not lockpid($config{spool_dir}.'/lock/debbugs-rebuild-index.db')) {
+     print STDERR "Another debbugs-rebuild-index.db is running; stopping\n";
+     exit 1;
+}
+
+my $fh_type = $initialdir;
+# if initaldir is db-h, the file is db.
+$fh_type = 'db' if $initialdir eq 'db-h';
+
+my $file = "index.${fh_type}.realtime";
+my $idx_rebuild = IO::File->new($file.'.rebuild','w')
+    or die "Couldn't open ${file}.rebuild: $!";
+
+
+my @dirs = ($initialdir);
+my $cnt = 0;
+my %bugs;
+while (my $dir = shift @dirs) {
+    printf "Doing dir %s ...\n", $dir if $verbose;
+
+    opendir(DIR, "$dir/.") or die "opendir $dir: $!";
+    my @subdirs = readdir(DIR);
+    closedir(DIR);
+
+    my @list = map { m/^(\d+)\.summary$/?($1):() } @subdirs;
+    push @dirs, map { m/^(\d+)$/ && -d "$dir/$1"?("$dir/$1"):() } @subdirs;
+
+    for my $bug (@list) {
+       print "Up to $cnt bugs...\n" if (++$cnt % 100 == 0 && $verbose);
+       my $stat = stat(getbugcomponent($bug,'summary',$initialdir));
+       if (not defined $stat) {
+           print STDERR "Unable to stat $bug $!\n";
+           next;
+       }
+       my $data = read_bug(bug => $bug,
+                           location => $initialdir);
+        my $line = generate_index_db_line($data);
+        $bugs{$bug} = $line;
+    }
+}
+binmode($idx_rebuild,':raw:encoding(UTF-8)');
+print {$idx_rebuild} $bugs{$_} foreach sort {$a <=> $b} keys %bugs;
+close($idx_rebuild);
+rename("$file.rebuild", $file);
+
+
+__END__
index 70f42292644f437e1284a6ba0aee2eeb5aabb635..3899a9defe715f2486770d1285cafe01fd17cb4b 100755 (executable)
@@ -43,7 +43,7 @@ my %param = cgi_parameters(query => $q,
                           single => [qw(bug msg att boring terse),
                                      qw(reverse mbox mime trim),
                                      qw(mboxstat mboxmaint archive),
-                                     qw(repeatmerged)
+                                     qw(repeatmerged avatars),
                                     ],
                           default => {# msg       => '',
                                       boring    => 'no',
@@ -55,6 +55,7 @@ my %param = cgi_parameters(query => $q,
                                       mboxmaint => 'no',
                                       archive   => 'no',
                                       repeatmerged => 'yes',
+                                       avatars   => 'yes',
                                      },
                          );
 # This is craptacular.
@@ -70,6 +71,7 @@ my $terse = $param{'terse'} eq 'yes';
 my $reverse = $param{'reverse'} eq 'yes';
 my $mbox = $param{'mbox'} eq 'yes';
 my $mime = $param{'mime'} eq 'yes';
+my $avatars = $param{avatars} eq 'yes';
 
 my %bugusertags;
 my %ut;
@@ -265,7 +267,11 @@ else {
               next;
          }
          $skip_next = 1 if $record->{type} eq 'html' and not $boring;
-         push @log, handle_record($record,$ref,$msg_num,\%seen_msg_ids);
+         push @log, handle_record($record,$ref,$msg_num,
+                                   \%seen_msg_ids,
+                                   trim_headers => $trim_headers,
+                                   avatars => $avatars,
+                                  );
      }
 }
 
index 14a0d66a3676296aabf245a153cbe094226dceb8..e2ab47d747421578d94d64abdbfd0d9fdfaa441f 100644 (file)
@@ -17,6 +17,7 @@ debbugs (2.4.2~exp2) UNRELEASED; urgency=low
   * Fix failure to forcibly merge/merge when found/fixed is not qualified
     (closes: #670456). Thanks to Jonathan Nieder and Bernhard Schmidt.
   * Add libravatar support.
+  * Fix double encoding of attachments (closes: #703300)
 
   [Thanks to Arnout Engelen: ]
   * Add Homepage (closes: #670555).
@@ -52,9 +53,25 @@ debbugs (2.4.2~exp2) UNRELEASED; urgency=low
     a site admin aware of its existence (closes: #688345).
   * Make sure that mails to gSubscriptionDomain and gBugSubscriptionDomain
     are only sent out if the variables in config are defined and
-    have a lenght < 0 (closes: #688344).
+    have a length < 0 (closes: #688344).
   * Use locale independent date format for mail processing and service mail
     generation (closes: #688745).
+  * Fix spelling error in /debian/changelog.
+  * Fix lintian issue: description-synopsis-starts-with-article.
+  * Fix lintian issues: debian-rules-missing-recommended-target build-arch,
+    debian-rules-missing-recommended-target build-indep.
+  * Switch to debian/source/format: 3.0 (native).
+  * Fix lintian issue: debbugs source: duplicate-in-relation-field in
+    libdebbugs-perl depends: libtext-template-perl, libtext-template-perl.
+  * Fix lintian issues: debbugs source:
+    debian-rules-makemaker-prefix-is-deprecated line 44,
+    debian-rules-makemaker-prefix-is-deprecated line 56.
+  * Fix lintian issues: libdebbugs-perl: spelling-error-in-manpage for:
+    + usr/share/man/man3/Debbugs::Recipients.3pm.gz
+    + usr/share/man/man3/Debbugs::SOAP.3pm.gz
+    + usr/share/man/man3/Debbugs::Status.3pm.gz
+  * Raise Standards to 3.9.4 (after fixing several lintian issues).
+  * Pass param bug=<NNN> to bugreport.html call in bugreport.cgi.
 
  -- Don Armstrong <don@debian.org>  Wed, 25 Aug 2010 01:57:38 -0700
 
index f0f5d614f8f3f17605f0b88f1647ec2b001506eb..d8f19b53d4545ee1c484d67bbff6743194f8b109 100644 (file)
@@ -3,7 +3,7 @@ Section: misc
 Priority: extra
 Maintainer: Debbugs developers <debian-debbugs@lists.debian.org>
 Uploaders: Colin Watson <cjwatson@debian.org>, Don Armstrong <don@debian.org>
-Standards-Version: 3.8.2
+Standards-Version: 3.9.4
 Vcs-Browser: http://bugs.debian.org/debbugs-source/mainline
 Vcs-Git: http://bugs.debian.org/debbugs-source/debbugs.git
 Build-Depends: debhelper (>= 5)
@@ -25,7 +25,7 @@ Depends:
  libdebbugs-perl,
 Recommends: debbugs-web
 Suggests: spamassassin (>= 3.0), libcgi-alert-perl
-Description: The bug tracking system based on the active Debian BTS
+Description: bug tracking system based on the active Debian BTS
  Debian has a bug tracking system which files details of bugs reported by
  users and developers. Each bug is given a number, and is kept on file until
  it is marked as having been dealt with. The system is mainly controlled by
@@ -44,7 +44,6 @@ Depends:
  libio-stringy-perl, libmldbm-perl, liburi-perl, libsoap-lite-perl,
  libcgi-simple-perl, libparams-validate-perl, libtext-template-perl,
  libsafe-hole-perl, libmail-rfc822-address-perl, liblist-moreutils-perl,
- libtext-template-perl
 Section: perl
 Description: modules used by the active Debian BTS
  Debian has a bug tracking system which files details of bugs reported by
@@ -77,7 +76,7 @@ Depends:
  ${misc:Depends},
  libdebbugs-perl, debbugs-web, libconfig-simple-perl,
  libuser-perl, rsync, libhttp-server-simple-perl, libnet-server-perl
-Description: run and maintains a local mirror of the Debian BTS
+Description: Run and maintains a local mirror of the Debian BTS
  Debian has a bug tracking system which files details of bugs reported
  by users and developers. Each bug is given a number, and is kept on
  file until it is marked as having been dealt with. The system is
index c3483791a6757eec503f2920237f60f45e4c0eb3..7bdd341f7ab2e7ce59ca12837a2c5e56aedfa278 100755 (executable)
@@ -10,7 +10,13 @@ DEST_DIR := $(CURDIR)/debian/tmp
 PERL ?= /usr/bin/perl
 
 
-build: build-stamp
+build: build-arch build-indep
+
+build-arch:
+# nothing to do, as there aren't any architecture-dependent packages
+
+build-indep: build-stamp
+
 build-stamp:
 # Call the test suite
        $(PERL) Makefile.PL INSTALLDIRS=vendor
@@ -35,7 +41,7 @@ install-stamp: build
        dh_clean -k
        dh_installdirs
        $(MAKE) install_mostfiles DESTDIR=$(DEST_DIR)
-       $(MAKE) -f Makefile.perl install PREFIX=$(DEST_DIR)/usr
+       $(MAKE) -f Makefile.perl install DESTDIR=$(DEST_DIR)
        touch $@
 
 binary-arch:
@@ -47,7 +53,7 @@ binary-indep: build install
        dh_clean -k
        dh_installdirs
        $(MAKE) install_mostfiles DESTDIR=$(DEST_DIR)
-       $(MAKE) -f Makefile.perl install PREFIX=$(DEST_DIR)/usr
+       $(MAKE) -f Makefile.perl install DESTDIR=$(DEST_DIR)
        dh_install --sourcedir=debian/tmp --fail-missing
        dh_installdocs
        dh_installchangelogs
diff --git a/debian/source/format b/debian/source/format
new file mode 100644 (file)
index 0000000..9f67427
--- /dev/null
@@ -0,0 +1 @@
+3.0 (native)
\ No newline at end of file
index 382b779de61ae51d3ab130eae54745134e463b39..dfcc44a30bbd8999c60cbe44bd2f8a5464853320 100755 (executable)
@@ -39,6 +39,7 @@ my %bugclosers = count_bugs(function => sub {
 
 open BUGCLOSERS, '> /org/bugs.debian.org/www/stats/bugclosers.txt.new'
     or die "can't open bugclosers.txt.new: $!";
+binmode(BUGCLOSERS,':raw:encoding(UTF-8)');
 for my $closer (sort { $bugclosers{$a} <=> $bugclosers{$b} } keys %bugclosers) {
     printf BUGCLOSERS "%4d %s\n", $bugclosers{$closer}, $closer
        or die "can't write to bugclosers.txt.new: $!";
index c251cea97376a7845f37646819bf34361a9d422e..9019b9d8a32d3f21cf1ffdb8970d5bf25bc3e908 100644 (file)
@@ -99,7 +99,7 @@ a.submitter:hover, a.submitter:visited:hover {
 
 pre.message {
     font-family: monospace;
-    padding-top: 0;
+    padding-top: 8px;
     margin-top: 0;
     border-top: 0;
 }
@@ -133,6 +133,15 @@ div.headers {
     overflow: auto;
  }
 
+div.header {
+    font-family: sans-serif;
+    font-size: 95%;
+    color: #3c3c3c;
+    padding: 0px;
+    line-height: 120%;
+    margin: 0px;
+}
+
 div.headers p {
     font-family: sans-serif;
     font-size: 95%;
@@ -146,7 +155,7 @@ div.headers img {
     float: right;
 }
 
-span.header { 
+span.headerfield { 
   font-weight: bold
  };
 
index 29a1fb6ff141a9ff9f2879a565cec5d941a5c6ce..3f6c26f490a650d8c7f6747febb9ef850194f2ce 100755 (executable)
@@ -24,7 +24,8 @@ sub header_or_empty ($$) {
     my $value = $mail->get_header($hdr);
     if (defined $value) {
        chomp $value;
-       $value =~ tr/\n/\\n/;
+        # replace newlines with '\n'
+       $value =~ s/\n/\\n/g;
        return $value;
     }
     return '';
index 8fb590fcd65d1f2b6e8503820a354860cf62530b..2f1d2dfb8371d8736fa759c0573f003f2583c562 100644 (file)
@@ -2,4 +2,6 @@
 use Test::More;
 eval "use Test::Pod 1.00";
 plan skip_all => "Test::Pod 1.00 required for testing POD" if $@;
-all_pod_files_ok(all_pod_files('.'));
+all_pod_files_ok(grep {$_ !~ /[~#]$/} all_pod_files((-e 'blib'?'blib':(qw(Debbugs Mail))),
+                                                     (qw(bin cgi scripts))
+                                                    ));
index d5397dc9a5e492d5c77e12d37c86cff05d43b508..be6b6c654f7a657b3d1fa9468c1cc6b7e30a442c 100644 (file)
@@ -1,7 +1,7 @@
 # -*- mode: cperl;-*-
 # $Id: 05_mail.t,v 1.1 2005/08/17 21:46:17 don Exp $
 
-use Test::More tests => 12;
+use Test::More tests => 13;
 
 use warnings;
 use strict;
@@ -24,7 +24,7 @@ use File::Basename qw(dirname basename);
 use lib qw(t/lib);
 use DebbugsTest qw(:all);
 use Data::Dumper;
-use Encode qw(decode encode decode_utf8);
+use Encode qw(decode encode decode_utf8 encode_utf8);
 
 # HTTP::Server:::Simple defines a SIG{CHLD} handler that breaks system; undef it here.
 $SIG{CHLD} = sub {};
@@ -53,7 +53,7 @@ END{
 
 send_message(to=>'submit@bugs.something',
             headers => [To   => 'submit@bugs.something',
-                        From => 'fff@bugs.something',
+                        From => 'föoff@bugs.something',
                         Subject => 'Submiting a bug',
                        ],
             body => <<EOF,attachments => [{Type=>"text/plain",Charset=>"utf-8",Data=><<EOF2}]) or fail('Unable to send message');
@@ -133,4 +133,5 @@ ok($status->{subject} eq 'ütff8 title encoding test','bug 1 retitled');
 ok($status->{severity} eq 'wishlist','bug 1 wishlisted');
 ok(system('sh','-c','[ $(egrep "retitle.*encoding test" '.$spool_dir.'/db-h/01/1.log|grep -v "=C3=BCt=EF=AC=808"|wc -l) -eq 0 ]') == 0,
    'Control messages escaped properly');
-
+ok(system('sh','-c',encode_utf8('grep -q "föoff@bugs.something" '.$spool_dir.'/index.db'))==0,
+   'index.db not double escaped');
diff --git a/t/15_rebuild_indexdb.t b/t/15_rebuild_indexdb.t
new file mode 100644 (file)
index 0000000..a3036ec
--- /dev/null
@@ -0,0 +1,128 @@
+# -*- mode: cperl;-*-
+
+use Test::More tests => 9;
+
+use warnings;
+use strict;
+
+use utf8;
+
+# Here, we're going to shoot messages through a set of things that can
+# happen.
+
+# First, we're going to send mesages to receive.
+# To do so, we'll first send a message to submit,
+# then send messages to the newly created bugnumber.
+
+use IO::File;
+use File::Temp qw(tempdir);
+use Cwd qw(getcwd);
+use Debbugs::MIME qw(create_mime_message);
+use File::Basename qw(dirname basename);
+# The test functions are placed here to make things easier
+use lib qw(t/lib);
+use DebbugsTest qw(:all);
+use Data::Dumper;
+use Encode qw(decode encode decode_utf8 encode_utf8);
+
+# HTTP::Server:::Simple defines a SIG{CHLD} handler that breaks system; undef it here.
+$SIG{CHLD} = sub {};
+my %config;
+eval {
+     %config = create_debbugs_configuration(debug => exists $ENV{DEBUG}?$ENV{DEBUG}:0);
+};
+if ($@) {
+     BAIL_OUT($@);
+}
+
+my $sendmail_dir = $config{sendmail_dir};
+my $spool_dir = $config{spool_dir};
+my $config_dir = $config{config_dir};
+
+END{
+     if ($ENV{DEBUG}) {
+         diag("spool_dir:   $spool_dir\n");
+         diag("config_dir:   $config_dir\n");
+         diag("sendmail_dir: $sendmail_dir\n");
+     }
+}
+
+# We're going to use create mime message to create these messages, and
+# then just send them to receive.
+
+send_message(to=>'submit@bugs.something',
+            headers => [To   => 'submit@bugs.something',
+                        From => 'föoff@bugs.something',
+                        Subject => 'Submiting a bug',
+                       ],
+            body => <<EOF,attachments => [{Type=>"text/plain",Charset=>"utf-8",Data=><<EOF2}]) or fail('Unable to send message');
+Package: foo
+Severity: normal
+
+This is a silly bug
+EOF
+This is the silly bug's test ütff8 attachment.
+EOF2
+
+
+
+# now we check to see that we have a bug, and nextnumber has been incremented
+ok(-e "$spool_dir/db-h/01/1.log",'log file created');
+ok(-e "$spool_dir/db-h/01/1.summary",'sumary file created');
+ok(-e "$spool_dir/db-h/01/1.status",'status file created');
+ok(-e "$spool_dir/db-h/01/1.report",'report file created');
+ok(system('sh','-c','[ $(grep "attachment." '.$spool_dir.'/db-h/01/1.log|grep -v "ütff8"|wc -l) -eq 0 ]') == 0,
+   'Everything attachment is escaped properly');
+
+# next, we check to see that (at least) the proper messages have been
+# sent out. 1) ack to submitter 2) mail to maintainer
+
+# This keeps track of the previous size of the sendmail directory
+my $SD_SIZE = 0;
+$SD_SIZE =
+    num_messages_sent($SD_SIZE,2,
+                     $sendmail_dir,
+                     'submit messages appear to have been sent out properly',
+                    );
+
+
+# now send a message to the bug
+
+send_message(to => '1@bugs.something',
+            headers => [To   => '1@bugs.something',
+                        From => 'föoff@bugs.something',
+                        Subject => 'Sending a message to a bug',
+                       ],
+            body => <<EOF) or fail('sending message to 1@bugs.someting failed');
+Package: foo
+Severity: normal
+
+This is a silly bug
+EOF
+
+$SD_SIZE =
+    num_messages_sent($SD_SIZE,2,
+                     $sendmail_dir,
+                     '1@bugs.something messages appear to have been sent out properly');
+
+# just check to see that control doesn't explode
+send_message(to => 'control@bugs.something',
+            headers => [To   => 'control@bugs.something',
+                        From => 'föoff@bugs.something',
+                        Subject => 'Munging a bug',
+                       ],
+            body => <<EOF) or fail 'message to control@bugs.something failed';
+severity 1 wishlist
+retitle 1 ütff8 title encoding test
+thanks
+EOF
+
+$SD_SIZE =
+   num_messages_sent($SD_SIZE,1,
+                    $sendmail_dir,
+                    'control@bugs.something messages appear to have been sent out properly');
+# now we need to check to make sure the control message was processed without errors
+# now we need to check to make sure that the control message actually did anything
+# This is an eval because $ENV{DEBBUGS_CONFIG_FILE} isn't set at BEGIN{} time
+eval "use Debbugs::Status qw(read_bug writebug);";
+ok(system('bin/debbugs-rebuild-index.db')==0,'debbugs-rebuild-index seems to work');
index 070005abdd1e40517e1449e4269ff029054c993b..66a1ca2dd0f132b4b57ff83af1dfe07049e9891e 100644 (file)
@@ -43,7 +43,7 @@ function toggle_infmessages()
 }
 {$log}
 <hr>
-<p class="msgreceived">Send a report that <a href="http://{$config{cgi_domain}}/bugspam.cgi">this bug log contains spam</a>.</p>
+<p class="msgreceived">Send a report that <a href="http://{$config{cgi_domain}}/bugspam.cgi?bug={$bug_num}">this bug log contains spam</a>.</p>
 <hr>
 {include(q(html/html_tail))}
 </body>