#!/usr/bin/perl -wT package debbugs; use strict; use POSIX qw(strftime nice); require './common.pl'; use Debbugs::Config qw(:globals :text); use Debbugs::User; use Debbugs::CGI qw(version_url); use Debbugs::Common qw(getparsedaddrs :date); use Debbugs::Bugs qw(get_bugs); use vars qw($gPackagePages $gWebDomain %gSeverityDisplay @gSeverityList); if (defined $ENV{REQUEST_METHOD} and $ENV{REQUEST_METHOD} eq 'HEAD') { print "Content-Type: text/html; charset=utf-8\n\n"; exit 0; } nice(5); my $userAgent = detect_user_agent(); my %param = readparse(); my $repeatmerged = ($param{'repeatmerged'} || "yes") eq "yes"; my $archive = ($param{'archive'} || "no") eq "yes"; my $include = $param{'&include'} || $param{'include'} || ""; my $exclude = $param{'&exclude'} || $param{'exclude'} || ""; my $users = $param{'users'} || ""; my $ordering = $param{'ordering'}; my $raw_sort = ($param{'raw'} || "no") eq "yes"; my $old_view = ($param{'oldview'} || "no") eq "yes"; unless (defined $ordering) { $ordering = "normal"; $ordering = "oldview" if $old_view; $ordering = "raw" if $raw_sort; } my $bug_rev = ($param{'bug-rev'} || "no") eq "yes"; my $pend_rev = ($param{'pend-rev'} || "no") eq "yes"; my $sev_rev = ($param{'sev-rev'} || "no") eq "yes"; my $pend_exc = $param{'&pend-exc'} || $param{'pend-exc'} || ""; my $pend_inc = $param{'&pend-inc'} || $param{'pend-inc'} || ""; my $sev_exc = $param{'&sev-exc'} || $param{'sev-exc'} || ""; my $sev_inc = $param{'&sev-inc'} || $param{'sev-inc'} || ""; my $maxdays = ($param{'maxdays'} || -1); my $mindays = ($param{'mindays'} || 0); my $version = $param{'version'} || undef; my $dist = $param{'dist'} || undef; my $arch = $param{'arch'} || undef; my $show_list_header = ($param{'show_list_header'} || $userAgent->{'show_list_header'} || "yes" ) eq "yes"; my $show_list_footer = ($param{'show_list_footer'} || $userAgent->{'show_list_footer'} || "yes" ) eq "yes"; { if (defined $param{'vt'}) { my $vt = $param{'vt'}; if ($vt eq "none") { $dist = undef; $arch = undef; $version = undef; } if ($vt eq "bysuite") { $version = undef; $arch = undef if ($arch eq "any"); } if ($vt eq "bypkg" || $vt eq "bysrc") { $dist = undef; $arch = undef; } } if (defined $param{'includesubj'}) { my $is = $param{'includesubj'}; $include .= "," . join(",", map { "subj:$_" } (split /[\s,]+/, $is)); } if (defined $param{'excludesubj'}) { my $es = $param{'excludesubj'}; $exclude .= "," . join(",", map { "subj:$_" } (split /[\s,]+/, $es)); } } my %hidden = map { $_, 1 } qw(status severity classification); my %cats = ( "status" => [ { "nam" => "Status", "pri" => [map { "pending=$_" } qw(pending forwarded pending-fixed fixed done absent)], "ttl" => ["Outstanding","Forwarded","Pending Upload", "Fixed in NMU","Resolved","From other Branch"], "def" => "Unknown Pending Status", "ord" => [0,1,2,3,4,5,6], } ], "severity" => [ { "nam" => "Severity", "pri" => [map { "severity=$_" } @gSeverityList], "ttl" => [map { $gSeverityDisplay{$_} } @gSeverityList], "def" => "Unknown Severity", "ord" => [0..@gSeverityList], } ], "classification" => [ { "nam" => "Classification", "pri" => [qw(pending=pending+tag=wontfix pending=pending+tag=moreinfo pending=pending+tag=patch pending=pending+tag=confirmed pending=pending)], "ttl" => ["Will Not Fix","More information needed", "Patch Available","Confirmed"], "def" => "Unclassified", "ord" => [2,3,4,1,0,5], } ], "oldview" => [ qw(status severity) ], "normal" => [ qw(status severity classification) ], ); my ($pkg, $src, $maint, $maintenc, $submitter, $severity, $status, $tag, $usertag, $owner, ); my %which = ( 'pkg' => \$pkg, 'src' => \$src, 'maint' => \$maint, 'maintenc' => \$maintenc, 'submitter' => \$submitter, 'severity' => \$severity, 'tag' => \$tag, 'usertag' => \$usertag, 'owner' => \$owner, ); my @allowedEmpty = ( 'maint' ); my $found; foreach ( keys %which ) { $status = $param{'status'} || 'open' if /^severity$/; if (($found = $param{$_})) { ${ $which{$_} } = $found; last; } } if (!$found && !$archive) { foreach ( @allowedEmpty ) { if (exists($param{$_})) { ${ $which{$_} } = ''; $found = 1; last; } } } if (!$found) { my $which; if (($which = $param{'which'})) { if (grep( /^\Q$which\E$/, @allowedEmpty)) { ${ $which{$which} } = $param{'data'}; $found = 1; } elsif (($found = $param{'data'})) { ${ $which{$which} } = $found if (exists($which{$which})); } } } quitcgi("You have to choose something to select by") if (!$found); my %bugusertags; my %ut; for my $user (split /[\s*,]+/, $users) { next unless length($user) >= 4; add_user($user); } if (defined $usertag) { my %select_ut = (); my ($u, $t) = split /:/, $usertag, 2; Debbugs::User::read_usertags(\%select_ut, $u); unless (defined $t && $t ne "") { $t = join(",", keys(%select_ut)); } add_user($u); $tag = $t; } my $Archived = $archive ? " Archived" : ""; my $this = ""; my %indexentry; my %strings = (); my $dtime = strftime "%a, %e %b %Y %T UTC", gmtime; my $tail_html = $debbugs::gHTMLTail; $tail_html = $debbugs::gHTMLTail; $tail_html =~ s/SUBSTITUTE_DTIME/$dtime/; set_option("repeatmerged", $repeatmerged); set_option("archive", $archive); set_option("include", $include); set_option("exclude", $exclude); set_option("pend-exc", $pend_exc); set_option("pend-inc", $pend_inc); set_option("sev-exc", $sev_exc); set_option("sev-inc", $sev_inc); set_option("maxdays", $maxdays); set_option("mindays", $mindays); set_option("version", $version); set_option("dist", $dist); set_option("arch", $arch); set_option("use-bug-idx", defined($param{'use-bug-idx'}) ? $param{'use-bug-idx'} : 0); set_option("show_list_header", $show_list_header); set_option("show_list_footer", $show_list_footer); our %seen_users; sub add_user { my $ut = \%ut; my $u = shift; return if $seen_users{$u}; $seen_users{$u} = 1; my $user = Debbugs::User::get_user($u); my %vis = map { $_, 1 } @{$user->{"visible_cats"}}; for my $c (keys %{$user->{"categories"}}) { $cats{$c} = $user->{"categories"}->{$c}; $hidden{$c} = 1 unless defined $vis{$c}; } for my $t (keys %{$user->{"tags"}}) { $ut->{$t} = [] unless defined $ut->{$t}; push @{$ut->{$t}}, @{$user->{"tags"}->{$t}}; } %bugusertags = (); for my $t (keys %{$ut}) { for my $b (@{$ut->{$t}}) { $bugusertags{$b} = [] unless defined $bugusertags{$b}; push @{$bugusertags{$b}}, $t; } } set_option("bugusertags", \%bugusertags); } my $pseudodesc = getpseudodesc(); if (defined $pseudodesc and defined $pkg and exists $pseudodesc->{$pkg}) { undef $dist; set_option('dist',$dist) } my $title; my @bugs; if (defined $pkg) { $title = "package $pkg"; add_user("$pkg\@packages.debian.org"); # figure out the source package my $pkgsrc = getpkgsrc(); add_user($pkgsrc->{$pkg}.'@packages.debian.org') if defined $pkgsrc->{$pkg}; if (defined $version) { $title .= " (version $version)"; } elsif (defined $dist) { $title .= " in $dist"; my $verdesc = getversiondesc($pkg); $title .= " ($verdesc)" if defined $verdesc; } my @pkgs = split /,/, $pkg; @bugs = get_bugs(package=>\@pkgs, archive=>$archive ); } elsif (defined $src) { add_user("$src\@packages.debian.org"); $title = "source $src"; set_option('arch', 'source'); if (defined $version) { $title .= " (version $version)"; } elsif (defined $dist) { $title .= " in $dist"; my $verdesc = getversiondesc($src); $title .= " ($verdesc)" if defined $verdesc; } @bugs = get_bugs(src=>[split /,/, $src], archive=>$archive ); } elsif (defined $maint) { add_user($maint); $title = "maintainer $maint"; $title .= " in $dist" if defined $dist; if ($maint eq "") { my %maintainers = %{getmaintainers()}; @bugs = @{getbugs(sub {my %d=@_; foreach my $try (splitpackages($d{"pkg"})) { return 1 if !getparsedaddrs($maintainers{$try}); } return 0; })}; } else { @bugs = get_bugs(maint=>[map {lc ($_)} split /,/,$maint], archive=>$archive ); } } elsif (defined $maintenc) { my %maintainers = %{getmaintainers()}; $title = "encoded maintainer $maintenc"; $title .= " in $dist" if defined $dist; @bugs = @{getbugs(sub {my %d=@_; foreach my $try (splitpackages($d{"pkg"})) { my @me = getparsedaddrs($maintainers{$try}); return 1 if grep { maintencoded($_->address) eq $maintenc } @me; } return 0; })}; } elsif (defined $submitter) { add_user($submitter); $title = "submitter $submitter"; $title .= " in $dist" if defined $dist; my @submitters = map {lc ($_)} split /,/, $submitter; @bugs = get_bugs(submitter => \@submitters, archive=>$archive ); } elsif (defined($severity) && defined($status)) { $title = "$status $severity bugs"; $title .= " in $dist" if defined $dist; my @severities = split /,/, $severity; my @statuses = split /,/, $status; @bugs = @{getbugs(sub {my %d=@_; return (grep($d{"severity"} eq $_, @severities)) && (grep($d{"status"} eq $_, @statuses)); })}; } elsif (defined($severity)) { $title = "$severity bugs"; $title .= " in $dist" if defined $dist; my @severities = split /,/, $severity; @bugs = @{getbugs(sub {my %d=@_; return (grep($d{"severity"} eq $_, @severities)); }, 'severity', @severities)}; } elsif (defined($tag)) { $title = "bugs tagged $tag"; $title .= " in $dist" if defined $dist; my @tags = split /,/, $tag; my %bugs = (); for my $t (@tags) { for my $b (@{$ut{$t}}) { $bugs{$b} = 1; } } @bugs = @{getbugs(sub {my %d = @_; return 1 if $bugs{$d{"bug"}}; my %tags = map { $_ => 1 } split ' ', $d{"tags"}; return grep(exists $tags{$_}, @tags); })}; } elsif (defined $owner) { $title = "bugs owned by $owner"; $title .= " in $dist" if defined $dist; my @owners = map {lc ($_)} split /,/, $owner; my %bugs = (); @bugs = get_bugs(owner=>\@owners, archive=>$archive ); } $title = htmlsanit($title); my @names; my @prior; my @title; my @order; determine_ordering(); # strip out duplicate bugs my %bugs; @bugs{@bugs} = @bugs; @bugs = keys %bugs; my $result = pkg_htmlizebugs(\@bugs); print "Content-Type: text/html; charset=utf-8\n\n"; print "\n"; print "\n" . "$title -- $gProject$Archived $gBug report logs\n" . qq() . "\n" . '' . "\n"; print "

" . "$gProject$Archived $gBug report logs: $title" . "

\n"; my $showresult = 1; if (defined $pkg || defined $src) { my $showpkg = htmlsanit((defined $pkg) ? $pkg : "source package $src"); my %maintainers = %{getmaintainers()}; my $maint = $pkg ? $maintainers{$pkg} : $maintainers{$src} ? $maintainers{$src} : undef; if (defined $maint) { print '

'; print htmlmaintlinks(sub { $_[0] == 1 ? "Maintainer for $showpkg is " : "Maintainers for $showpkg are " }, $maint); print ".

\n"; } else { print "

No maintainer for $showpkg. Please do not report new bugs against this package.

\n"; } if (defined $maint or @bugs) { my %pkgsrc = %{getpkgsrc()}; my $srcforpkg; if (defined $pkg) { $srcforpkg = $pkgsrc{$pkg}; defined $srcforpkg or $srcforpkg = $pkg; } my @pkgs = getsrcpkgs($pkg ? $srcforpkg : $src); undef $srcforpkg unless @pkgs; @pkgs = grep( !/^\Q$pkg\E$/, @pkgs ) if ( $pkg ); if ( @pkgs ) { @pkgs = sort @pkgs; if ($pkg) { print "

You may want to refer to the following packages that are part of the same source:\n"; } else { print "

You may want to refer to the following individual bug pages:\n"; } push @pkgs, $src if ( $src && !grep(/^\Q$src\E$/, @pkgs) ); print join( ", ", map( "$_", @pkgs ) ); print ".\n"; } my @references; my $pseudodesc = getpseudodesc(); if ($pkg and defined($pseudodesc) and exists($pseudodesc->{$pkg})) { push @references, "to the list of other pseudo-packages"; } else { if ($pkg and defined $gPackagePages) { push @references, sprintf "to the %s package page", urlsanit("http://${debbugs::gPackagePages}/$pkg"), htmlsanit("$pkg"); } if (defined $gSubscriptionDomain) { my $ptslink = $pkg ? $srcforpkg : $src; push @references, "to the Package Tracking System"; } # Only output this if the source listing is non-trivial. if ($pkg and $srcforpkg and (@pkgs or $pkg ne $srcforpkg)) { push @references, sprintf "to the source package %s's bug page", srcurl($srcforpkg), htmlsanit($srcforpkg); } } if (@references) { $references[$#references] = "or $references[$#references]" if @references > 1; print "

You might like to refer ", join(", ", @references), ".

\n"; } if (defined $maint || defined $maintenc) { print "

If you find a bug not listed here, please\n"; printf "report it.

\n", urlsanit("http://${debbugs::gWebDomain}/Reporting${debbugs::gHTMLSuffix}"); } } else { print "

There is no record of the " . (defined($pkg) ? htmlsanit($pkg) . " package" : htmlsanit($src) . " source package") . ", and no bugs have been filed against it.

"; $showresult = 0; } } elsif (defined $maint || defined $maintenc) { print "

Note that maintainers may use different Maintainer fields for\n"; print "different packages, so there may be other reports filed under\n"; print "different addresses.\n"; } elsif (defined $submitter) { print "

Note that people may use different email accounts for\n"; print "different bugs, so there may be other reports filed under\n"; print "different addresses.\n"; } set_option("archive", !$archive); printf "

See the %s reports

", urlsanit(pkg_url(( map { $_ eq 'archive'?():($_,$param{$_}) } keys %param ), ('archive',($archive?"no":"yes")) ) ), ($archive ? "active" : "archived"); set_option("archive", $archive); print $result if $showresult; print pkg_javascript() . "\n"; print "

Options

\n"; print "
\n"; printf "
\n", myurl(); print "\n"; my ($checked_any, $checked_sui, $checked_ver) = ("", "", ""); if (defined $dist) { $checked_sui = "CHECKED"; } elsif (defined $version) { $checked_ver = "CHECKED"; } else { $checked_any = "CHECKED"; } print "\n"; print " \n"; print ""; print " \n"; if (defined $pkg) { my $v = htmlsanit($version) || ""; my $pkgsane = htmlsanit($pkg); print ""; print " \n"; } elsif (defined $src) { my $v = htmlsanit($version) || ""; my $srcsane = htmlsanit($src); print ""; print " \n"; } print "\n"; my $includetags = htmlsanit(join(" ", grep { !m/^subj:/i } map {split /[\s,]+/} ref($include)?@{$include}:$include)); my $excludetags = htmlsanit(join(" ", grep { !m/^subj:/i } map {split /[\s,]+/} ref($exclude)?@{$exclude}:$exclude)); my $includesubj = htmlsanit(join(" ", map { s/^subj://i; $_ } grep { m/^subj:/i } map {split /[\s,]+/} ref($include)?@{$include}:$include)); my $excludesubj = htmlsanit(join(" ", map { s/^subj://i; $_ } grep { m/^subj:/i } map {split /[\s,]+/} ref($exclude)?@{$exclude}:$exclude)); my $vismindays = ($mindays == 0 ? "" : $mindays); my $vismaxdays = ($maxdays == -1 ? "" : $maxdays); my $sel_rmy = ($repeatmerged ? " selected" : ""); my $sel_rmn = ($repeatmerged ? "" : " selected"); my $sel_ordraw = ($ordering eq "raw" ? " selected" : ""); my $sel_ordold = ($ordering eq "oldview" ? " selected" : ""); my $sel_ordnor = ($ordering eq "normal" ? " selected" : ""); my $chk_bugrev = ($bug_rev ? " checked" : ""); my $chk_pendrev = ($pend_rev ? " checked" : ""); my $chk_sevrev = ($sev_rev ? " checked" : ""); print <\n"; printf "\n", pkg_htmlselectyesno("pend-rev", "outstanding bugs first", "done bugs first", $pend_rev); printf "\n", pkg_htmlselectyesno("sev-rev", "highest severity first", "lowest severity first", $sev_rev); printf "\n", pkg_htmlselectyesno("bug-rev", "oldest bugs first", "newest bugs first", $bug_rev); print < EOF print "
Show bugs applicable toanything
" . pkg_htmlselectsuite(1,2,1) . " for " . pkg_htmlselectarch(1,2,2) . "
$pkgsane version
$srcsane version
 
Only include bugs tagged with or that have in their subject
Exclude bugs tagged with or that have in their subject
Only show bugs older than days, and younger than days
 
Merged bugs should be
Categorise bugs by
Order bugs by%s
%s
%s
 
with new settings
\n"; print "
\n"; print "

$tail_html"; print "\n"; sub pkg_htmlindexentrystatus { my $s = shift; my %status = %{$s}; my $result = ""; my $showseverity; if ($status{severity} eq 'normal') { $showseverity = ''; } elsif (isstrongseverity($status{severity})) { $showseverity = "Severity: $status{severity};\n"; } else { $showseverity = "Severity: $status{severity};\n"; } $result .= pkg_htmlpackagelinks($status{"package"}, 1); my $showversions = ''; if (@{$status{found_versions}}) { my @found = @{$status{found_versions}}; $showversions .= join ', ', map {s{/}{ }; htmlsanit($_)} @found; } if (@{$status{fixed_versions}}) { $showversions .= '; ' if length $showversions; $showversions .= 'fixed: '; my @fixed = @{$status{fixed_versions}}; $showversions .= join ', ', map {s{/}{ }; htmlsanit($_)} @fixed; } $result .= ' ($showversions)} if length $showversions; $result .= ";\n"; $result .= $showseverity; $result .= pkg_htmladdresslinks("Reported by: ", \&submitterurl, $status{originator}); $result .= ";\nOwned by: " . htmlsanit($status{owner}) if length $status{owner}; $result .= ";\nTags: " . htmlsanit(join(", ", sort(split(/\s+/, $status{tags})))) . "" if (length($status{tags})); $result .= buglinklist(";\nMerged with ", ", ", split(/ /,$status{mergedwith})); $result .= buglinklist(";\nBlocked by ", ", ", split(/ /,$status{blockedby})); $result .= buglinklist(";\nBlocks ", ", ", split(/ /,$status{blocks})); if (length($status{done})) { $result .= "
Done: " . htmlsanit($status{done}); my $days = bug_archiveable(bug => $status{id}, status => \%status, days_until => 1, ); if ($days >= 0 and defined $status->{location} and $status->{location} ne 'archive') { $result .= ";\nWill be archived" . ( $days == 0 ? " today" : $days == 1 ? " in $days day" : " in $days days" ) . ""; } } unless (length($status{done})) { if (length($status{forwarded})) { $result .= ";\nForwarded to " . join(', ', map {maybelink($_)} split /[,\s]+/,$status{forwarded} ); } # Check the age of the logfile my ($days_last,$eng_last) = secs_to_english(time - $status{log_modified}); my ($days,$eng) = secs_to_english(time - $status{date}); if ($days >= 7) { my $font = ""; my $efont = ""; $font = "em" if ($days > 30); $font = "strong" if ($days > 60); $efont = "" if ($font); $font = "<$font>" if ($font); $result .= ";\n ${font}$eng old$efont"; } if ($days_last > 7) { my $font = ""; my $efont = ""; $font = "em" if ($days_last > 30); $font = "strong" if ($days_last > 60); $efont = "" if ($font); $font = "<$font>" if ($font); $result .= ";\n ${font}Modified $eng_last ago$efont"; } } $result .= "."; return $result; } sub pkg_htmlizebugs { $b = $_[0]; my @bugs = @$b; my @status = (); my %count; my $header = ''; my $footer = "

Summary

\n"; my @dummy = ($gRemoveAge); #, @gSeverityList, @gSeverityDisplay); #, $gHTMLExpireNote); if (@bugs == 0) { return "

No reports found!

\n"; } if ( $bug_rev ) { @bugs = sort {$b<=>$a} @bugs; } else { @bugs = sort {$a<=>$b} @bugs; } my %seenmerged; my %common = ( 'show_list_header' => 1, 'show_list_footer' => 1, ); my %section = (); foreach my $bug (@bugs) { my %status = %{getbugstatus($bug)}; next unless %status; next if bugfilter($bug, %status); my $html = sprintf "
  • #%d: %s\n
    ", bugurl($bug), $bug, htmlsanit($status{subject}); $html .= pkg_htmlindexentrystatus(\%status) . "\n"; my $key = ""; for my $i (0..$#prior) { my $v = get_bug_order_index($prior[$i], \%status); $count{"g_${i}_${v}"}++; $key .= "_$v"; } $section{$key} .= $html; $count{"_$key"}++; push @status, [ $bug, \%status, $html ]; } my $result = ""; if ($ordering eq "raw") { $result .= "\n"; } else { $header .= "\n"; $footer .= "\n"; } $result = $header . $result if ( $common{show_list_header} ); $result .= $footer if ( $common{show_list_footer} ); return $result; } sub pkg_htmlpackagelinks { my $pkgs = shift; return unless defined $pkgs and $pkgs ne ''; my $strong = shift; my @pkglist = splitpackages($pkgs); $strong = 0; my $openstrong = $strong ? '' : ''; my $closestrong = $strong ? '' : ''; return 'Package' . (@pkglist > 1 ? 's' : '') . ': ' . join(', ', map { '' . $openstrong . htmlsanit($_) . $closestrong . '' } @pkglist ); } sub pkg_htmladdresslinks { htmlize_addresslinks(@_,'submitter'); } sub pkg_javascript { return < EOF } sub pkg_htmlselectyesno { my ($name, $n, $y, $default) = @_; return sprintf('', $name, ($default ? "" : " selected"), $n, ($default ? " selected" : ""), $y); } sub pkg_htmlselectsuite { my $id = sprintf "b_%d_%d_%d", $_[0], $_[1], $_[2]; my @suites = ("stable", "testing", "unstable", "experimental"); my %suiteaka = ("stable", "etch", "testing", "lenny", "unstable", "sid"); my $defaultsuite = "unstable"; my $result = sprintf ''; return $result; } sub pkg_htmlselectarch { my $id = sprintf "b_%d_%d_%d", $_[0], $_[1], $_[2]; my @arches = qw(alpha amd64 arm hppa i386 ia64 m68k mips mipsel powerpc s390 sparc); my $result = sprintf ''; return $result; } sub myurl { return urlsanit(pkg_url(map {exists $param{$_}?($_,$param{$_}):()} qw(archive repeatmerged mindays maxdays), qw(version dist arch pkg src tag maint submitter) ) ); } sub make_order_list { my $vfull = shift; my @x = (); if ($vfull =~ m/^([^:]+):(.*)$/) { my $v = $1; for my $vv (split /,/, $2) { push @x, "$v=$vv"; } } else { for my $v (split /,/, $vfull) { next unless $v =~ m/.=./; push @x, $v; } } push @x, ""; # catch all return @x; } sub get_bug_order_index { my $order = shift; my $status = shift; my $pos = -1; my %tags = (); %tags = map { $_, 1 } split / /, $status->{"tags"} if defined $status->{"tags"}; for my $el (@${order}) { $pos++; my $match = 1; for my $item (split /[+]/, $el) { my ($f, $v) = split /=/, $item, 2; next unless (defined $f and defined $v); my $isokay = 0; $isokay = 1 if (defined $status->{$f} and $v eq $status->{$f}); $isokay = 1 if ($f eq "tag" && defined $tags{$v}); unless ($isokay) { $match = 0; last; } } if ($match) { return $pos; last; } } return $pos + 1; } sub buglinklist { my ($prefix, $infix, @els) = @_; return '' if not @els; return $prefix . bug_linklist($infix,'submitter',@els); } # sets: my @names; my @prior; my @title; my @order; sub determine_ordering { $cats{status}[0]{ord} = [ reverse @{$cats{status}[0]{ord}} ] if ($pend_rev); $cats{severity}[0]{ord} = [ reverse @{$cats{severity}[0]{ord}} ] if ($sev_rev); my $i; if (defined $param{"pri0"}) { my @c = (); $i = 0; while (defined $param{"pri$i"}) { my $h = {}; my $pri = $param{"pri$i"}; if ($pri =~ m/^([^:]*):(.*)$/) { $h->{"nam"} = $1; # overridden later if necesary $h->{"pri"} = [ map { "$1=$_" } (split /,/, $2) ]; } else { $h->{"pri"} = [ split /,/, $pri ]; } $h->{"nam"} = $param{"nam$i"} if (defined $param{"nam$i"}); $h->{"ord"} = [ split /\s*,\s*/, $param{"ord$i"} ] if (defined $param{"ord$i"}); $h->{"ttl"} = [ split /\s*,\s*/, $param{"ttl$i"} ] if (defined $param{"ttl$i"}); push @c, $h; $i++; } $cats{"_"} = [@c]; $ordering = "_"; } $ordering = "normal" unless defined $cats{$ordering}; sub get_ordering { my @res; my $cats = shift; my $o = shift; for my $c (@{$cats->{$o}}) { if (ref($c) eq "HASH") { push @res, $c; } else { push @res, get_ordering($cats, $c); } } return @res; } my @cats = get_ordering(\%cats, $ordering); sub toenglish { my $expr = shift; $expr =~ s/[+]/ and /g; $expr =~ s/[a-z]+=//g; return $expr; } $i = 0; for my $c (@cats) { $i++; push @prior, $c->{"pri"}; push @names, ($c->{"nam"} || "Bug attribute #" . $i); if (defined $c->{"ord"}) { push @order, $c->{"ord"}; } else { push @order, [ 0..$#{$prior[-1]} ]; } my @t = @{ $c->{"ttl"} } if defined $c->{ttl}; if (@t < $#{$prior[-1]}) { push @t, map { toenglish($prior[-1][$_]) } @t..($#{$prior[-1]}); } push @t, $c->{"def"} || ""; push @title, [@t]; } }