#!/usr/bin/perl -w
my
$VERSION
=
"1.02"
;
my
$host
=
"localhost"
;
my
$perlbug
=
"~perlbug/PerlBug"
;
Getopt::Long::Configure
qw(nopermute bundling bundling_override)
;
use
lib
qw(/home/perlbug/Perlbug)
;
$ENV
{MYSQLDB} =
"perlbug"
;
if
(
$Tk::VERSION
>= 800.013) {
Tk::CmdLine->LoadResources ();
Tk::CmdLine->SetArguments ();
}
my
$opt_m
= 0;
my
$opt_x
= 0;
GetOptions (
"x"
=> \
&$opt_x
,
"m"
=> \
&$opt_m
,
) or usage ();
my
@sel
=
qw(ticketid admin
status category severity osname
fixed version
subject author body
note
)
;
my
%sel
;
my
%pat
;
my
%subs
;
my
%ticket
=
map
{
$_
=>
""
}
qw(ticketid status subject sourceaddr destaddr
severity category fixed version os osname
messageid follows author msgheader msgbody msgcount
noteid noteauthor noteheader notebody)
;
my
@ticket
;
my
$top
;
my
%head
;
$pat
{ticketid} =
shift
(
@ARGV
) ||
undef
;
InitTU ();
SetList ();
MainLoop;
sub
usage
{
print
STDERR
"usage: perlbug-db ...\n"
;
exit
0;
}
sub
to_background
{
my
$pid
=
fork
;
if
(
$pid
< 0) {
print
STDERR
"Unable to run in the background, cannot fork: $!\n"
;
exit
$?;
}
$pid
and
exit
0;
}
sub
pat_reset ($)
{
my
$mask
=
$_
[-1];
if
(
length
(
$mask
) > 2 and
exists
$pat
{
$mask
}) {
$pat
{
$mask
} =
""
;
$pat
{prv}{
$mask
} =
"?"
;
}
else
{
$mask
=
qr/^$mask/
;
"t"
=~
$mask
and
$pat
{ticketid} =
""
,
$pat
{prv}{ticketid} =
"?"
;
"a"
=~
$mask
and
$pat
{admin} =
""
,
$pat
{prv}{admin} =
"?"
;
"s"
=~
$mask
and
$pat
{status} =
""
,
$pat
{prv}{status} =
"?"
;
"c"
=~
$mask
and
$pat
{category} =
""
,
$pat
{prv}{category} =
"?"
;
"y"
=~
$mask
and
$pat
{severity} =
""
,
$pat
{prv}{severity} =
"?"
;
"o"
=~
$mask
and
$pat
{osname} =
""
,
$pat
{prv}{osname} =
"?"
;
"f"
=~
$mask
and
$pat
{fixed} =
""
,
$pat
{prv}{fixed} =
"?"
;
"v"
=~
$mask
and
$pat
{version} =
""
,
$pat
{prv}{version} =
"?"
;
"u"
=~
$mask
and
$pat
{author} =
""
,
$pat
{prv}{author} =
"?"
;
"j"
=~
$mask
and
$pat
{subject} =
""
,
$pat
{prv}{subject} =
"?"
;
"b"
=~
$mask
and
$pat
{body} =
""
,
$pat
{prv}{body} =
"?"
;
"n"
=~
$mask
and
$pat
{note} =
""
,
$pat
{prv}{note} =
"?"
;
}
$pat
{prv}{admin} =
"refresh"
;
DoOneEvent ();
}
sub
GetData ($)
{
my
$init
=
shift
;
if
(
$init
) {
pat_reset (
"."
);
}
$init
and
print
STDERR
"Getting data ."
;
{
my
$sth
= prepex (
"select type, flag from tm_flags"
);
my
(
$type
,
$flag
);
$sth
->bind_columns (\
$type
, \
$flag
);
while
(
$sth
->fetch) {
push
@{
$sel
{
$type
}},
$flag
;
}
$sth
->finish;
}
{
my
$sth
= prepex (
"select userid, name from tm_users"
);
my
(
$userid
,
$name
);
$sth
->bind_columns (\
$userid
, \
$name
);
while
(
$sth
->fetch) {
$sel
{admin}{
$userid
} =
$name
;
}
$sth
->finish;
}
foreach
my
$sel
(
qw(ticketid fixed version osname)
) {
my
$sth
= prepex (
"select $sel from tm_tickets"
);
my
$f
;
my
%f
= ();
$sth
->bind_columns (\
$f
);
while
(
$sth
->fetch) {
defined
$f
or
next
;
$f
{
$f
} = 1;
}
$sth
->finish;
@{
$sel
{
$sel
}} =
sort
keys
%f
;
}
$init
and
print
STDERR
"\n"
;
}
sub
Tk::bindDefKeys ($$)
{
my
$w
=
shift
;
$w
->
bind
(
"<Delete>"
=>
"Backspace"
);
$w
->
bind
(
"<Enter>"
=> [ \
&SetRealList
]);
$w
->
bind
(
"<Control-Key-w>"
=> [ \
&pat_reset
,
shift
]);
$w
->
bind
(
"<Alt-Key-r>"
=> [ \
&pat_reset
,
"."
]);
$w
;
}
sub
InitTU
{
select
((
select
(STDERR), $| = 1)[0]);
select
((
select
(STDOUT), $| = 1)[0]);
GetData (1);
$ticket
{sql_list} = prepex (
"select ticketid, status, subject, sourceaddr, destaddr,"
,
" severity, category, fixed, version, os, osname"
,
"from tm_tickets"
);
$ticket
{sql_list}->bind_columns (
\
@ticket
{
qw(ticketid status subject sourceaddr destaddr
severity category fixed version os osname)
});
$ticket
{sql_list}->finish;
$ticket
{sql_ticket} = prepex (
"select ticketid, status, subject, sourceaddr, destaddr,"
,
" severity, category, fixed, version, os, osname"
,
"from tm_tickets"
,
"where ticketid = ?"
);
$ticket
{sql_ticket}->bind_columns (
\
@ticket
{
qw(ticketid status subject sourceaddr destaddr
severity category fixed version os osname)
});
$ticket
{sql_ticket}->finish;
$ticket
{sql_msg} = prepex (
"select messageid, follows, author, msgheader, msgbody"
,
"from tm_messages"
,
"where ticketid = ?"
);
$ticket
{sql_msg}->bind_columns (
\
@ticket
{
qw(messageid follows author msgheader msgbody)
});
$ticket
{sql_msg}->finish;
$ticket
{sql_notes} = prepex (
"select noteid, author, msgheader, msgbody"
,
"from tm_notes"
,
"where ticketid = ?"
);
$ticket
{sql_notes}->bind_columns (
\
@ticket
{
qw(noteid noteauthor noteheader notebody)
});
$ticket
{sql_notes}->finish;
to_background ();
$top
= MainWindow->new (
-name
=>
"perlbug"
,
-cursor
=>
"top_left_arrow"
);
$top
->title (
"Perl5 Bug database"
);
my
$ico
= Tk::Toplevel->new (
$top
,
-borderwidth
=> 0,
-class
=>
'Icon'
);
$top
->iconwindow (
$ico
);
$top
->iconname (
"perlbug"
);
$subs
{SelBugs} =
sub
{ SetList (); };
my
$bln
=
$top
->Balloon (
-foreground
=>
"Blue4"
,
-background
=>
"LightYellow2"
);
my
%f
= (
search
=>
$top
->Frame (
-relief
=>
"flat"
)->
pack
(
-side
=>
"top"
,
-expand
=> 0,
-fill
=>
"x"
),
list
=>
$top
->Frame (
-relief
=>
"sunken"
)->
pack
(
-side
=>
"left"
,
-expand
=> 0,
-fill
=>
"y"
),
message
=>
$top
->Frame (
-relief
=>
"sunken"
)->
pack
(
-side
=>
"left"
,
-expand
=> 1,
-fill
=>
"both"
),
);
my
$NIndex
=
undef
;
my
$NCurrent
=
sub
{
$NIndex
||
$ticket
{list}->
index
(
"current"
);
};
my
$f
=
$f
{search}->Frame (
-relief
=>
"flat"
)->
pack
(
qw(-side top -expand 0 fill x)
);
foreach
my
$sel
(
qw(status category severity osname version fixed)
) {
my
$b
=
$f
->BrowseEntry (
-relief
=>
"sunken"
,
-width
=> 15,
-borderwidth
=> 1,
-highlightthickness
=> 1,
-listwidth
=> 50,
-variable
=> \
$pat
{
$sel
},
-browsecmd
=>
$subs
{SelBugs})->
pack
(
-anchor
=>
"w"
,
-side
=>
"left"
)->bindDefKeys (
substr
(
$sel
, 0, 1));
$bln
->attach (
$b
,
-msg
=>
"Browse to select $sel"
);
$b
->insert (
"end"
,
undef
);
foreach
my
$s
(
sort
@{
$sel
{
$sel
}}) {
$b
->insert (
"end"
,
$s
);
}
}
$f
=
$f
{search}->Frame (
-relief
=>
"flat"
)->
pack
(
qw(-side left -expand 0 fill x)
);
my
$e
=
$f
->Frame (
-relief
=>
"flat"
)->
pack
(
qw(-side top expand 0 -fill x)
);
foreach
my
$sel
(
qw(ticketid admin)
) {
my
$b
=
$e
->BrowseEntry (
-relief
=>
"sunken"
,
-width
=> 15,
-borderwidth
=> 1,
-highlightthickness
=> 1,
-listwidth
=> 50,
-variable
=> \
$pat
{
$sel
},
-browsecmd
=>
$subs
{SelBugs})->
pack
(
-anchor
=>
"w"
,
-side
=>
"left"
)->bindDefKeys (
$sel
);
$bln
->attach (
$b
,
-msg
=>
"Browse to select $sel"
);
$b
->insert (
"end"
,
undef
);
my
@v
=
$sel
eq
"admin"
?
keys
%{
$sel
{
$sel
}} : @{
$sel
{
$sel
}};
foreach
my
$s
(
sort
@v
) {
$b
->insert (
"end"
,
$s
);
}
}
$f
->Button (
-text
=>
"reset"
,
-command
=>
sub
{ pat_reset (
"."
); SetRealList (); },
)->
pack
(
qw(-side left -expand 1 -fill both)
);
$f
->Button (
-text
=>
"quit"
,
-command
=> \
&exit
,
)->
pack
(
qw(-side left -expand 1 -fill both)
);
$f
=
$f
{search}->Frame (
-relief
=>
"flat"
)->
pack
(
qw(-side right -expand 0 fill x)
);
foreach
my
$sel
(
qw(subject note message)
) {
my
$e
=
$f
->Frame (
-relief
=>
"flat"
)->
pack
(
qw(-side top expand 0 -fill x)
);
$e
->Label (
-text
=>
ucfirst
$sel
,
-foreground
=>
"Green4"
,
-anchor
=>
"c"
,
-width
=> 8,
-relief
=>
"flat"
)->
pack
(
-side
=>
"left"
);
my
$b
=
$e
->Entry (
-relief
=>
"sunken"
,
-width
=> 60,
-borderwidth
=> 1,
-highlightthickness
=> 1,
-textvariable
=> \
$pat
{
$sel
})->
pack
(
-anchor
=>
"w"
,
-side
=>
"left"
)->bindDefKeys (
$sel
);
$bln
->attach (
$b
,
-msg
=>
"Enter selection criterium for $sel"
);
}
$f
=
$f
{message}->Frame (
-relief
=>
"sunken"
)->
pack
(
qw(-side top -expand 0 -fill x)
);
foreach
my
$s
(
qw(status category severity osname version fixed admin)
) {
my
$l
=
$f
->Label (
-textvariable
=> \
$ticket
{
$s
},
-foreground
=>
"Green4"
,
-anchor
=>
"c"
,
-width
=> 12,
-relief
=>
"ridge"
)->
pack
(
-side
=>
"left"
);
$bln
->attach (
$l
,
-msg
=>
"This is the $s of the ticket"
);
$head
{
$s
} =
$l
;
}
my
$l
=
$f
->Label (
-textvariable
=> \
$ticket
{msgcount},
-foreground
=>
"Red4"
,
-anchor
=>
"e"
,
-width
=> 6,
-relief
=>
"flat"
)->
pack
(
-side
=>
"left"
);
$bln
->attach (
$l
,
-msg
=>
"This is the message count of the ticket"
);
$head
{msgcount} =
$l
;
$f
=
$f
{message}->Frame (
-relief
=>
"sunken"
)->
pack
(
qw(-side top -expand 0 -fill x)
);
$l
=
$f
->Label (
-textvariable
=> \
$ticket
{ticketid},
-foreground
=>
"Red4"
,
-anchor
=>
"c"
,
-width
=> 12,
-relief
=>
"flat"
)->
pack
(
-side
=>
"left"
);
$bln
->attach (
$l
,
-msg
=>
"This is the ID of the ticket"
);
$head
{ticketid} =
$l
;
$l
=
$f
->Label (
-textvariable
=> \
$ticket
{subject},
-foreground
=>
"Blue4"
,
-anchor
=>
"w"
,
-width
=> 8,
-relief
=>
"sunken"
)->
pack
(
-expand
=> 1,
-fill
=>
"x"
,
-side
=>
"left"
);
$bln
->attach (
$l
,
-msg
=>
"This is the subject of the ticket"
);
$head
{subject} =
$l
;
$l
=
$f
->Label (
-textvariable
=> \
$ticket
{author},
-foreground
=>
"Blue4"
,
-anchor
=>
"w"
,
-width
=> 15,
-relief
=>
"sunken"
)->
pack
(
-expand
=> 0,
-fill
=>
"x"
,
-side
=>
"left"
);
$bln
->attach (
$l
,
-msg
=>
"This is the author of the ticket"
);
$head
{author} =
$l
;
my
$nb
=
$f
{message}->NoteBook ()->
pack
(
qw(-side top -expand 1 -fill both)
);
foreach
my
$page
(0 .. 24) {
$ticket
{message}[
$page
] = [
$nb
,
$nb
->add (
$page
,
-label
=>
sprintf
(
"%2d"
,
$page
),
-state
=>
"disabled"
,
-anchor
=>
"nw"
)->Scrolled (
"ROText"
,
-scrollbars
=>
"osoe"
,
-wrap
=>
"none"
,
-borderwidth
=> 1,
-highlightthickness
=> 0,
-width
=> 70,
-height
=> 25)->
pack
(
-expand
=> 1,
-fill
=>
"both"
,
-side
=>
"top"
) ];
}
$ticket
{note} =
$f
{message}->Scrolled (
"ROText"
,
-scrollbars
=>
"osoe"
,
-wrap
=>
"none"
,
-borderwidth
=> 1,
-highlightthickness
=> 0,
-width
=> 70,
-height
=> 5)->
pack
(
-expand
=> 1,
-fill
=>
"both"
,
-side
=>
"top"
);
$f
=
$f
{list};
my
$lastActive
=
""
;
my
$NMotion
=
sub
{
my
$e
=
$ticket
{list}->XEvent;
my
(
$x
,
$y
) = (
$e
->x,
$e
->y);
my
$newLine
=
$ticket
{list}->
index
(
"\@$x,$y linestart"
);
if
(
$newLine
ne
$lastActive
) {
$ticket
{list}->tagRemove (
"active"
,
"1.0"
,
"end"
);
$lastActive
=
$newLine
;
$ticket
{list}->tagAdd (
"active"
,
$lastActive
,
"$lastActive lineend"
);
my
$ticketid
=
$ticket
[
int
(
$lastActive
) - 1];
$ticket
{sql_ticket}->execute (
$ticketid
);
$ticket
{sql_ticket}->fetch;
$ticket
{sql_msg}->execute (
$ticketid
);
foreach
my
$page
(0 .. 24) {
$ticket
{message}[
$page
][0]->pageconfigure (
$page
,
-state
=>
"disabled"
);
$ticket
{message}[
$page
][1]->
delete
(
"0.0"
,
"end"
);
}
my
$page
= 0;
while
(
$ticket
{sql_msg}->fetch) {
$ticket
{message}[
$page
][0]->pageconfigure (
$page
,
-state
=>
"normal"
);
$ticket
{message}[
$page
++][1]->insert (
"end"
,
$ticket
{msgbody});
}
$ticket
{msgcount} =
$page
;
while
(
my
(
$k
,
$w
) =
each
%head
) {
$w
->configure (
-text
=>
$ticket
{
$k
});
$w
->update;
}
$ticket
{note}->
delete
(
"0.0"
,
"end"
);
$ticket
{sql_notes}->execute (
$ticketid
);
while
(
$ticket
{sql_notes}->fetch) {
$ticket
{note}->insert (
"end"
,
sprintf
"%5d %-20.20s %s\n"
,
@ticket
{
qw(noteid noteauthor notebody)
});
}
}
};
my
$NLock
=
sub
{
$ticket
{list}->tagBind (
"all"
,
"<Motion>"
=>
sub
{});
$NIndex
=
$ticket
{list}->
index
(
"current"
);
};
$subs
{NUnlock} =
sub
{
$ticket
{list}->tagBind (
"all"
,
"<Motion>"
=>
$NMotion
);
$NIndex
=
undef
;
};
$ticket
{list} =
$f
->Scrolled (
"ROText"
,
-scrollbars
=>
"osoe"
,
-wrap
=>
"none"
,
-borderwidth
=> 1,
-highlightthickness
=> 0,
-width
=> 13,
-height
=> 25)->
pack
(
-fill
=>
"both"
,
-expand
=> 1,
-side
=>
"top"
)->Subwidget (
"scrolled"
);
$ticket
{list}->bindDefKeys (
"-"
);
$ticket
{list}->tagConfigure (
"active"
,
-relief
=>
"raised"
,
-borderwidth
=> 1);
$ticket
{list}->tagBind (
"all"
,
"<Motion>"
=>
$NMotion
,
);
$ticket
{list}->
after
(500,
$subs
{SelBugs});
}
sub
fail ($)
{
my
$id
=
shift
;
my
(
$s
,
$p
) = (
$ticket
{
$id
},
$pat
{regex}{
$id
});
defined
$s
or
$s
=
""
;
defined
$p
or
return
0;
$opt_m
and
return
index
(
uc
$s
,
$p
) < 0;
$s
!~
$p
;
}
sub
SetList
{
if
(
$top
->state eq
"iconic"
) {
$ticket
{list}->
after
(5000,
$subs
{SelBugs});
return
;
}
local
$
" = "
÷";
"@pat{@sel}"
eq
"@{$pat{prv}}{@sel}"
and
return
;
$ticket
{list}->DoWhenIdle (\
&SetRealList
);
}
sub
SetRealList
{
$top
->Busy;
@{
$pat
{prv}}{
@sel
} =
@pat
{
@sel
};
my
@tickets
= ();
foreach
my
$sel
(
@sel
) {
my
$p
=
$pat
{
$sel
};
if
(
$opt_m
) {
$pat
{regex}{
$sel
} =
uc
$p
;
next
;
}
do
{
eval
{
''
=~ m/
$p
/};
}
while
($@ and
chop
$p
);
$pat
{regex}{
$sel
} =
qr/$p/
i;
}
$ticket
{sql_list}->execute;
while
(
$ticket
{sql_list}->fetch) {
fail (
"ticketid"
) and
next
;
fail (
"admin"
) and
next
;
fail (
"status"
) and
next
;
fail (
"category"
) and
next
;
fail (
"severity"
) and
next
;
fail (
"osname"
) and
next
;
fail (
"fixed"
) and
next
;
fail (
"version"
) and
next
;
fail (
"subject"
) and
next
;
push
@tickets
,
$ticket
{ticketid};
}
$ticket
{list}->
delete
(
"1.0"
,
"end"
);
@ticket
=
reverse
sort
@tickets
;
foreach
my
$tid
(
@ticket
) {
my
@tags
= (
"all"
);
$ticket
{list}->insert (
"end"
,
"$tid\n"
, \
@tags
);
}
$top
->Unbusy;
$ticket
{list}->
after
(500,
$subs
{SelBugs});
}