2 # $Id: db2html.in,v 1.6 2000/10/07 17:27:13 joy Exp $
3 # usage: db2html [-diff] [-stampfile=<stampfile>] [-lastrun=<days>] <wwwbase>
5 #load the necessary libraries/configuration
6 require('/etc/debbugs/config');
7 require('/etc/debbugs/text');
8 require('/usr/lib/debbugs/errorlib');
9 $ENV{'PATH'} = '/usr/lib/debbugs:'.$ENV{'PATH'};
11 #set current working directory
12 chdir("$gSpoolDir") || die "chdir spool: $!\n";
16 $stampfile = 'stamp.html';
17 $tail_html = $gHTMLTail;
18 $expirynote_html = $gHTMLExpireNote;
19 $shorthead = ' Ref * Package Keywords/Subject Submitter';
23 %displayshowpendings = ('pending','outstanding',
25 'forwarded','forwarded to upstream software authors');
27 #set timestamp for html files
28 chop($dtime=`date -u '+%H:%M:%S GMT %a %d %h'`); $? and die $?;
29 $tail_html =~ s/SUBSTITUTE_DTIME/$dtime/;
31 #check for commandline switches
32 while (@ARGV && $ARGV[0] =~ m/^-/)
33 { if ($ARGV[0] eq '-diff') { $diff=1; }
34 elsif ($ARGV[0] =~ m/^-lastrun\=([0-9.]+)$/) { $lastrun= $1; undef $stampfile; }
35 elsif ($ARGV[0] =~ m/^-full$/) { undef $lastrun; undef $stampfile; }
36 elsif ($ARGV[0] =~ m/^-stampfile\=(\S+)$/) { $stampfile= $1; }
37 else { &quit("bad usage"); }
41 #check for remaing argument, only one...
43 $wwwbase= shift(@ARGV);
46 defined($startdate= time) || &quit("failed to get time: $!");
50 #if stamp file was given,
51 if (defined($stampfile))
52 { if (open(X,"< $stampfile"))
55 printf "progress last run %.7f days\n",$lastrun;
56 } else { print "progress stamp file $stampfile: $! - full\n"; }
59 #only process file if greater than last run...
60 if (defined($lastrun) && -M "db" > $lastrun)
62 s/SUBSTITUTE_DTIME/$dtime/o;
63 s/\<\!\-\-updateupdate\-\-\>.*\<\!\-\-\/updateupdate\-\-\>/check/;
64 &file('ix/zstamp.html','non',$_."</body></html>\n");
66 # print "db2html: no changes since last run\n";
70 #parse maintainer file
71 open(MM,"$gMaintainerFile") || &quit("open $gMaintainerFile: $!");
73 { m/^(\S+)\s+(\S.*\S)\s*$/ || &quit("$gMaintainerFile: \`$_'");
80 #load all database files
81 opendir(D,'db') || &quit("opendir db: $!");
82 @files= sort { $a <=> $b } readdir(D);
85 for $pending (qw(pending done forwarded))
86 { for $severity (@showseverities)
87 { eval "\$index${pending}${severity}= \$iiindex${pending}${severity}= ''; 1;"
88 or &quit("reset \$index${pending}${severity}: $@");
93 { next unless $f =~ m/^(-?\d+)\.log$/;
95 #((print STDERR "$ref\n"),
98 # unless $ref =~ m/^-/ || $ref =~ m/^124/;
99 &filelock("lock/$ref");
100 $preserveonly= defined($lastrun) && -M "db/$ref.log" > $lastrun;
101 if ($ref =~ m/^-\d$/)
102 { $week= $ref eq '-1' ? 'this week' :
103 $ref eq '-2' ? 'last week' :
104 $ref eq '-3' ? 'two weeks ago' :
105 ($ref-1)." weeks ago";
106 $linkto= "ju/unmatched$ref";
107 $short= "junk, $week";
109 "This includes messages sent to <code>done\@$gEmailDomain</code>\n".
110 "which did not have a $gBug reference number in the Subject line\n".
111 "or which contained an\n".
112 "unknown or out of date $gBug report number (these cause a warning\n".
113 "to be sent to the sender) and details about the messages\n".
114 "sent to <code>request@$gEmailDomain</code> (all of which".
115 "produce replies).\n";
116 $indexlink= "Messages not matched to a specific $gBug report - $week";
122 $tpackfile= "pnone.html";
123 $indexpart= 'unmatched';
125 { open(S,"db/$ref.status") || &quit("open db/$ref.status: $!");
126 chomp($s_originator= <S>);
128 chomp($s_subject= <S>);
129 chomp($s_msgid= <S>);
130 chomp($s_package= <S>);
131 chomp($s_keywords= <S>);
133 chomp($s_forwarded= <S>);
134 chomp($s_mergedwith= <S>);
135 chomp($s_severity= <S>);
136 $_= $s_package; y/A-Z/a-z/; $_= $` if m/[^-+._a-z0-9()]/;
138 if ($s_severity eq '' || $s_severity eq 'normal')
140 $addseverity= $gDefaultSeverity;
141 } elsif (grep($s_severity eq $_, @strongseverities))
142 { $showseverity= "<strong>Severity: $s_severity</strong>;\n";
143 $addseverity= $s_severity;
145 { $showseverity= "Severity: <em>$s_severity</em>;\n";
146 $addseverity= $s_severity;
148 $days= int(($startdate - $s_date)/86400); close(S);
149 $indexlink= "#$ref: ".&sani($s_subject);
151 $packfile= length($tpack) ? "pa/l$tpack.html" : "pa/none.html";
152 $indexentry .= "Package: <A href=\"../$packfile\"><strong>".
153 &sani($s_package)."</strong></A>;\n"
154 if length($s_package);
155 $indexentry .= $showseverity;
156 $indexentry .= "Reported by: ".&sani($s_originator);
157 $indexentry .= ";\nKeywords: ".&sani($s_keywords)
158 if length($s_keywords);
159 $linkto= $ref; $linkto =~ s,^..,$&/$&,;
160 @merged= split(/ /,$s_mergedwith);
162 { $mseparator= ";\nmerged with ";
164 { $mfile= $m; $mfile =~ s,^..,$&/$&,;
165 $indexentry .= $mseparator."<A href=\"../$mfile.html\">#$m</A>";
169 $daysold=$submitted='';
171 { $indexentry .= ";\n<strong>Done:</strong> ".&sani($s_done);
172 $indexpart= "done$addseverity";
173 } elsif (length($s_forwarded))
174 { $indexentry .= ";\n<strong>Forwarded</strong> to ".&sani($s_forwarded);
175 $indexpart= "forwarded$addseverity";
177 { $cmonths= int($days/30);
178 if ($cmonths != $amonths)
179 { $msg= $cmonths == 0 ? "Submitted in the last month" :
180 $cmonths == 1 ? "Over one month old" :
181 $cmonths == 2 ? "Over two months old - attention is required" :
182 "OVER $cmonths MONTHS OLD - ATTENTION IS REQUIRED";
183 $shortindex .= "</pre><h2>$msg:</h2><pre>\n$shorthead\n";
186 $pad= 6-length(sprintf("%d",$f));
188 ($pad>0 ? ' 'x$pad : '').
189 sprintf("<A href=\"../%s.html\">%d</A>",$linkto,$ref).
190 &sani(sprintf(" %-1.1s %-10.10s %-35.35s %-.25s\n",
193 (length($s_keywords) ? $s_keywords.'/' : '').
194 $s_subject, $s_originator));
195 $shortindex.= $thissient;
196 $sient{"$ref $s_package"}= $thissient;
198 { $font= $days <= 30 ? '' :
201 $efont= length($font) ? "</$font>" : '';
202 $font= length($font) ? "<$font>" : '';
203 $daysold= "; $font$days days old$efont";
205 if ($preserveonly) { $submitted= 'THIS IS A BUG IN THE BUG PROCESSOR'; }
207 { $submitted= `TZ=GMT LANG=C \\
208 date -d '1 Jan 1970 00:00:00 + $s_date seconds' \\
209 '+ %a, %d %b %Y %T %Z'`;
212 $submitted =~ s/\n$//; $submitted =~ s/, 0/, /g;
213 $submitted= "; dated $submitted";
214 $indexpart= "pending$addseverity";
217 $short= $ref; $short =~ s/^\d+/#$&/;
218 $tmaint= defined($maintainer{$tpack}) ? $maintainer{$tpack} : '(unknown)';
219 $qpackage= &sani($_);
220 $descriptivehead= $indexentry.$submitted.";\nMaintainer for $qpackage is\n".
221 '<A href="../ma/l'.&maintencoded($tmaint).'.html">'.&sani($tmaint).'</A>.';
222 $indexentry .= $daysold;
226 $indexadd .= "<!--iid $iiref-->" if defined($iiref);
227 $indexadd .= "<li><A href=\"../$linkto.html\">".$indexlink."</A>";
228 $indexadd .= "<br>\n".$indexentry if length($indexentry);
229 $indexadd .= "<!--/iid-->" if defined($iiref);
231 $estr= "\$index$indexpart = \$indexadd.\$index$indexpart; 1;";
232 eval($estr) || &quit("eval add to \$index$indexpart ($estr) failed: $@");
233 #print STDERR ">$estr|$indexadd<\n";
234 $indexadd= "<!--ii $iiref-->\n" if defined($iiref);
235 eval("\$iiindex$indexpart = \$indexadd.\$iiindex$indexpart; 1;") ||
236 &quit("eval add to \$iiindex$indexpart failed: $@");
237 if (defined($tmaint))
238 { $countpermaint{$tmaint} += length($s_done) ? 0 : length($s_forwarded) ? 0 : 1;
239 eval("\$permaint${indexpart}{\$tmaint} .= \$indexadd; 1;") ||
240 &quit("eval add to \$permaint${indexpart}{\$tmaint} failed: $@");
243 { $countperpack{$tpack} += length($s_done) ? 0 : length($s_forwarded) ? 0 : 1;
244 eval("\$perpack${indexpart}{\$tpack} .= \$indexadd; 1;") ||
245 &quit("eval add to \$perpack${indexpart}{\$tpack} failed: $@");
247 if ($preserveonly) { &preserve("$linkto.html"); &preserve("$linkto-b.html"); &unfilelock; next; }
248 open(L,"db/$ref.log") || &quit("open db/$ref.log: $!");
250 $boring=''; $xmessage= 0;
251 $normstate= 'kill-init';
255 $normstate eq 'kill-init' || $normstate eq 'kill-end' ||
256 &quit("$ref ^G in state $normstate");
257 $normstate= 'incoming-recv';
259 $normstate eq 'kill-init' || $normstate eq 'kill-end' ||
260 &quit("$ref ^A in state $normstate");
261 $normstate= 'autocheck';
263 $normstate eq 'kill-init' || $normstate eq 'kill-end' ||
264 &quit("$ref ^B in state $normstate");
265 $normstate= 'recips';
267 $normstate eq 'go' || $normstate eq 'go-nox' || $normstate eq 'html' ||
268 &quit("$ref ^C in state $normstate");
269 $this .= "</pre>\n" if $normstate eq 'go' || $normstate eq 'go-nox';
270 if ($normstate eq 'html') {
272 $this .= " <em><A href=\"../$linkto-b.html#m$xmessage\">Full text</A>".
275 if ($suppressnext && $normstate ne 'html') {
276 $ntis= $this; $ntis =~ s:\<pre\>:</A><pre>:i;
277 $boring .= "<hr><A name=\"m$xmessage\">\n$ntis\n";
279 $log = $this. "<hr>\n". $log;
281 $suppressnext= $normstate eq 'html';
282 $normstate= 'kill-end';
284 $normstate eq 'kill-body' || &quit("^E in state $normstate");
288 $normstate eq 'kill-init' || $normstate eq 'kill-end' ||
289 &quit("$ref ^F in state $normstate");
290 $normstate= 'html'; $this= '';
291 } elsif ($normstate eq 'incoming-recv') {
292 $pl= $_; $pl =~ s/\n+$//;
293 m/^Received: \(at (\S+)\) by (\S+)\;/ ||
294 &quit("bad line \`$pl' in state incoming-recv");
295 $this = "<h2>Message received at ".&sani("$1\@$2").":</h2><br>\n".
299 } elsif ($normstate eq 'html') {
301 } elsif ($normstate eq 'go') {
303 } elsif ($normstate eq 'go-nox') {
306 } elsif ($normstate eq 'recips') {
308 $this = "<h2>Message sent:</h2><br>\n";
311 $this = "<h2>Message sent to ".&sani($_).":</h2><br>\n";
313 $normstate= 'kill-body';
314 } elsif ($normstate eq 'autocheck') {
315 next if !m/^X-Debian-Bugs(-\w+)?: This is an autoforward from (\S+)/;
316 $normstate= 'autowait';
317 $this = "<h2>Message received at $2:</h2><br>\n";
318 } elsif ($normstate eq 'autowait') {
320 $normstate= 'go-nox';
323 &quit("$ref state $normstate line \`$_'");
326 &quit("$ref state $normstate at end") unless $normstate eq 'kill-end';
328 if (length($boring)) {
329 &file("$linkto-b.html",'non',
330 "<html><head><title>$gProject $gBug report logs - ".
331 "$short, boring messages</title>\n".
332 "<link rev=\"made\" href=\"mailto:$gMaintainerEmail)\">\n".
333 "</head>$gHTMLStart<h1>$gProject $gBugreport logs -".
334 "\n <A href=\"../$linkto.html\">$short</A>,".
335 " boring messages</h1>\n$boring\n<hr>\n".
336 $tail_html."</body></html>\n");
338 &file("$linkto.html",'non',
339 "<html><head><title>$gProject $gBug report logs - ".
341 "<link rev=\"made\" href=\"mailto:$gMaintainerEmail\">\n".
342 "</head>$gHTMLStart<h1>$gProject $gBug report logs - $short<br>\n".
343 &sani($s_subject)."</h1>".
344 "$descriptivehead\n".
347 $tail_html."</body></html>\n");
353 s/([^<>()]+) \(([^()<>]+)\)/$2 \<$1\>/;
357 $email= s/ *\<[^<>()]+\>$//g ? $& : '';
358 $_= "$1 $_" if s/ (\S+)$//;
364 return $maintencoded{$_[0]} if defined($maintencoded{$_[0]});
366 local ($todo,$encoded)= ($input);
367 while ($todo =~ m/\W/) {
368 $encoded.=$`.sprintf("-%02x_",unpack("C",$&));
372 $encoded =~ s/-2e_/\./g;
373 $encoded =~ s/^([^,]+)-20_-3c_(.*)-40_(.*)-3e_/$1,$2,$3,/;
374 $encoded =~ s/^(.*)-40_(.*)-20_-28_([^,]+)-29_$/,$1,$2,$3/;
375 $encoded =~ s/-20_/_/g;
376 $encoded =~ s/-([^_]+)_-/-$1/g;
377 $maintencoded{$input}= $encoded;
380 for $tmaint (keys %countpermaint) {
382 $after=$before=$sort2d=$sort2s=$sort1d=$sort1s='';
383 $after= "$&$after" if s/\s*\<[^<>()]+\>\s*$//;
384 $after= "$&$after" if s/\s*\)\s*$//;
385 $after= "$&$after" if s/\s*,.*$//;
386 $before.= $& if s/^.*\(\s*//;
387 $sort2d= $& if s/\S+$//;
389 while (s/^([^()<>]+)\. */$1 /) { };
390 s/\s+$//; y/A-Za-z/a-zA-Z/; $sort1s= $_;
391 $sort2s= $sort2d; $sort2s =~ y/A-Za-z/a-zA-Z/;
392 $maintsort{$tmaint}= $sort2s.' '.$sort1s.' '.$before.$sort1d.$sort2d.$after;
393 $maintdisplay{$tmaint}=
394 &sani($before).'<strong>'.&sani($sort1d.$sort2d).'</strong>'.&sani($after);
399 return $displayshowseverities{$sv}.' - '.$displayshowpendings{$pt};
402 sub makeindex ($$$) {
403 my ($varprefix,$varsuffix,$tkey) = @_;
404 my ($pending,$severity,$anydone,$text);
407 for $pending (qw(pending forwarded done)) {
408 for $severity (@showseverities) {
409 $estr= "\$value= \\${varprefix}${pending}${severity}${varsuffix}; 1;";
412 or &quit("eval get \$${varprefix}${pending}${severity} failed: $@");
413 #print STDERR ">$$value<\n";
414 next unless length($$value);
415 $text.= "<hr>\n<h2>".&heading($pending,$severity).":</h2>\n".
416 "(List of <A href=\"../si/$pending$severity.html\">all".
417 " such $gBugs</A> is available.)\n<ul>\n".
420 $anydone=1 if $pending eq 'done';
423 $text.= $expirynote_html if $anydone;
427 &file("ix/full.html",'def',
429 makeindex('$index',"",'').
431 $tail_html."</body><html>\n");
433 &file("ju/junk.html",'non',
435 "<hr>\n<h2>Junk (messages without a specific $gBug report number):</h2>\n".
436 "(\`this week' is everything since last Wednesday.)\n<ul>\n".
439 $tail_html."</body><html>\n");
441 $nobugs_html= "No reports are currently in this state.";
442 $who_html= $gProject;
443 $owner_addr= $gMaintainerEmail;
444 $otherindex_html= "For other kinds of index or for other information about
445 $gProject and the $gBug system, see the <A HREF\"../../\">$gBug system top-level
446 contents WWW page</A>.
450 for $pending (qw(pending forwarded done)) {
451 for $severity (@showseverities) {
452 eval "\$value= \\\$iiindex${pending}${severity}; 1;"
453 or &quit("eval get \$iiindex${pendingtype}${severity} failed: $@");
454 $value= \$nobugs_html if !length($$value);
455 $headstring= &heading($pending,$severity);
456 &file("si/$pending$severity.html",'ref',
457 "<html><head><title>$who_html $gBug reports: $headstring</title>\n".
458 "<link rev=\"made\" href=\"mailto:".&sani($owner_addr)."\">\n".
459 "</head>$gHTMLStart<h1>$who_html $gBug reports: $headstring</h1>\n".
461 ($pending eq 'done' ? "<P>\n$expirynote_html" : '').
465 $tail_html."</body></html>\n");
469 sub individualindexes ($\@&\%&&$$$$$&&) {
470 my ($filename,$keysref,$getfilenameref,$countref,$getdisplayref,
471 $getsimpledisplayref,$what,$caveat,$whatplural,$abbrev,$ihead,
472 $getxinforef,$getxindexref) = @_;
473 my ($itext,$i,$tkey,$sani,$count,$tfilename,$refto,$backnext,$xitext,$bugbugs);
475 for ($i=0; $i<=$#$keysref; $i++) {
476 $tkey= $$keysref[$i];
477 $tfilename= &$getfilenameref($tkey);
478 $sani= &$getsimpledisplayref($tkey);
479 $count= $$countref{$tkey};
480 $count= $count >= 1 ? "$count" : "no";
481 $bugbugs= $count == 1 ? "$gBug" : "$gBugs";
482 $xitext= &$getxindexref($tkey);
483 $xitext= length($xitext) ? "$count $bugbugs; $xitext"
484 : "$count outstanding $bugbugs";
485 $itext .= "<li><A href=\"../$tfilename\">".&$getdisplayref($tkey)."</A>"."\n".
489 $refto= $$keysref[$i-1];
490 $xitext= &$getxindexref($refto);
491 $xitext= " ($xitext)" if length($xitext);
492 $backnext .= "<br>\nPrevious $what in list, <A href=\"../".
493 &$getfilenameref($refto)."\">".&$getdisplayref($refto)."</A>".
497 $refto= $$keysref[$i+1];
498 $xitext= &$getxindexref($refto);
499 $xitext= " ($xitext)" if length($xitext);
500 $backnext .= "<br>\nNext $what in list, <A href=\"../".
501 &$getfilenameref($refto)."\">".&$getdisplayref($refto)."</A>".
504 &file($tfilename,'ref',
505 "<html><head><title>$gProject $gBug reports: $what $sani</title>\n".
506 "<link rev=\"made\" href=\"mailto:$gMaintainerEmail\">\n".
507 "</head>$gHTMLStart<h1>$gProject $gBug reports: $what $sani</h1>\n".
508 &$getxinforef($tkey).
510 "See the <A href=\"../$filename\">listing of $whatplural</A>.\n".
512 &makeindex("\$per${abbrev}","{\$tkey}",$tkey).
514 $tail_html."</body></html>\n");
516 &file($filename,'non',
521 $tail_html."</body></html>\n");
524 @maintainers= sort { $maintsort{$a} cmp $maintsort{$b}; } keys %countpermaint;
525 individualindexes('ix/maintainers.html',
527 sub { 'ma/l'.&maintencoded($_[0]).'.html'; },
529 sub { $maintdisplay{$_[0]}; },
530 sub { &sani($_[0]); },
532 "Note that there may be other reports filed under different
533 variations on the maintainer\'s name and email address.<P>",
540 @packages= sort keys %countperpack;
541 individualindexes('ix/packages.html',
543 sub { length($_[0]) ? "pa/l$_[0].html" : 'pa/none.html'; },
545 sub { length($_[0]) ? $_[0] : 'not specified'; },
546 sub { &sani(length($_[0]) ? $_[0] : 'not specified'); },
548 "Note that with multi-binary packages there may be other
549 reports filed under the different binary package names.<P>",
554 return unless defined($maintainer{$_[0]});
555 $tmaint= $maintainer{$_[0]};
556 return "Maintainer for $_[0] is <A href=\"../ma/l".
557 &maintencoded($tmaint).
558 ".html\">".&sani($tmaint)."</A>.\n<p>\n";
561 return unless defined($maintainer{$_[0]});
562 $tmaint= $maintainer{$_[0]};
563 return "<A href=\"../ma/l".
564 &maintencoded($tmaint).
565 ".html\">".&sani($tmaint)."</A>";
568 &file('ix/summary.html','non',
573 $tail_html."</body></html>\n");
576 for $k (map {$_->[0] }
577 sort { $a->[2] cmp $b->[2] || $a->[1] <=> $b->[1] }
578 map { [$_, split(' ',$_,2)] } keys %sient)
579 { $bypackageindex.= $sient{$k}; }
580 &file('ix/psummary.html','non',
582 "<hr><pre>\n$shorthead\n".
585 $tail_html."</body></html>\n");
587 open(P,"$gPseudoDescFile") ||
588 &quit("$gPseudoDescFile: $!");
589 $ppd=''; while(<P>) { s/\s*\n$//; $ppd.= &sani($_)."\n"; } close(P);
590 &file('ix/pseudopackages.html','non',
594 $tail_html."</body></html>\n");
596 $_= $gHTMLStamp; s/SUBSTITUTE_DTIME/$dtime/o;
598 &file('ix/zstamp.html','non',$_."</body></html>\n");
600 sub notimestamp ($) {
602 s/\<\!\-\-timestamp\-\-\>\n.*\n\<\!\-\-\/timestamp\-\-\>\n//;
607 local ($name,$ii,$file)= @_;
609 $cmppath= "$wwwbase/$name".($ii eq 'ref' ? '.ref' : '');
610 if (open(ORIG,"$cmppath")) {
611 undef $/; $orig= <ORIG>; $/= "\n";
613 if (¬imestamp($orig) eq ¬imestamp($file)) {
614 print "preserve $name\n";
617 defined($c= open(P,"-|")) or &quit("pipe/fork for diff: $!");
619 open(Q,"|diff -e $cmppath -") or die "pipe/fork II for diff: $!\n";
620 print Q $file or die "write orig to diff: $!\n";
621 close(Q); $?==0 || $?==256 or die "diff gave $?\n";
624 undef $/; $difftxt= <P>; $/= "\n";
625 close(P); $?==0 || $?==256 or die "diff fork gave $?\n";
627 print "preserve $name\n";
630 $v= (split(/\n/,$difftxt));
631 print "diff $v $ii $name\n${difftxt}thatdiff $name\n"
632 or &quit("stdout (diff): $!");
636 $v= (split(/\n/,$file));
637 print "file $v $ii $name\n${file}thatfile $name\n" or &quit("stdout: $!");
641 print "preserve $_[0]\n";
646 while ($u= $cleanups[$#cleanups]) { &$u; }