$VERSION
=
'3.010'
;
sub
new(@)
{
my
(
$class
,
%args
) =
@_
;
(
bless
{},
$class
)->init(\
%args
);
}
sub
init($)
{
my
(
$self
,
$args
) =
@_
;
if
(
my
$message
=
$args
->{message})
{
push
@{
$self
->{MBTN_messages}},
$message
;
$self
->{MBTN_msgid} =
$args
->{msgid} ||
$message
->messageId;
}
elsif
(
my
$msgid
=
$args
->{msgid})
{
$self
->{MBTN_msgid} =
$msgid
;
}
else
{ croak
"Need to specify message or message-id"
;
}
$self
->{MBTN_dummy_type} =
$args
->{dummy_type};
$self
;
}
sub
message()
{
my
$self
=
shift
;
unless
(
$self
->{MBTN_messages})
{
return
()
if
wantarray
;
my
$dummy
=
$self
->{MBTN_dummy_type}->new
(
messageId
=>
$self
->{MBTN_msgid}
);
push
@{
$self
->{MBTN_messages}},
$dummy
;
return
$dummy
;
}
my
@messages
= @{
$self
->{MBTN_messages}};
return
@messages
if
wantarray
;
return
$messages
[0]
if
@messages
==1;
foreach
(
@messages
)
{
return
$_
unless
$_
->isDeleted;
}
$messages
[0];
}
sub
addMessage($)
{
my
(
$self
,
$message
) =
@_
;
return
$self
->{MBTN_messages} = [
$message
]
if
$self
->isDummy;
push
@{
$self
->{MBTN_messages}},
$message
;
$message
;
}
sub
isDummy()
{
my
$self
=
shift
;
!
defined
$self
->{MBTN_messages} ||
$self
->{MBTN_messages}[0]->isDummy;
}
sub
messageId() {
shift
->{MBTN_msgid} }
sub
expand(;$)
{
my
$self
=
shift
;
return
$self
->message->label(
'folded'
) || 0
unless
@_
;
my
$fold
= not
shift
;
$_
->label(
folded
=>
$fold
)
foreach
$self
->message;
$fold
;
}
sub
folded(;$)
{
@_
== 1 ?
shift
->expand :
shift
->expand(not
shift
) }
sub
repliedTo()
{
my
$self
=
shift
;
return
wantarray
? (
$self
->{MBTN_parent},
$self
->{MBTN_quality})
:
$self
->{MBTN_parent};
}
sub
follows($$)
{
my
(
$self
,
$thread
,
$how
) =
@_
;
my
$quality
=
$self
->{MBTN_quality};
my
$msgid
=
$self
->messageId;
for
(
my
$walker
=
$thread
;
defined
$walker
;
$walker
=
$walker
->repliedTo)
{
return
undef
if
$walker
->messageId eq
$msgid
;
}
my
$threadid
=
$thread
->messageId;
foreach
(
$self
->followUps)
{
return
undef
if
$_
->messageId eq
$threadid
;
}
if
(
$how
eq
'REPLY'
|| !
defined
$quality
)
{
$self
->{MBTN_parent} =
$thread
;
$self
->{MBTN_quality} =
$how
;
return
$self
;
}
return
$self
if
$quality
eq
'REPLY'
;
if
(
$how
eq
'REFERENCE'
|| (
$how
eq
'GUESS'
&&
$quality
ne
'REFERENCE'
))
{
$self
->{MBTN_parent} =
$thread
;
$self
->{MBTN_quality} =
$how
;
}
$self
;
}
sub
followedBy(@)
{
my
$self
=
shift
;
$self
->{MBTN_followUps}{
$_
->messageId} =
$_
foreach
@_
;
$self
;
}
sub
followUps()
{
my
$self
=
shift
;
$self
->{MBTN_followUps} ?
values
%{
$self
->{MBTN_followUps}} : ();
}
sub
sortedFollowUps()
{
my
$self
=
shift
;
my
$prepare
=
shift
||
sub
{
shift
->startTimeEstimate||0};
my
$compare
=
shift
||
sub
{(
shift
) <=> (
shift
)};
my
%value
=
map
{ (
$prepare
->(
$_
) =>
$_
) }
$self
->followUps;
map
{
$value
{
$_
} }
sort
{
$compare
->(
$a
,
$b
)}
keys
%value
;
}
sub
threadToString(;$$$)
{
my
$self
=
shift
;
my
$code
=
shift
||
sub
{
shift
->head->
study
(
'subject'
)};
my
(
$first
,
$other
) = (
shift
||
''
,
shift
||
''
);
my
$message
=
$self
->message;
my
@follows
=
$self
->sortedFollowUps;
my
@out
;
if
(
$self
->folded)
{
my
$text
=
$code
->(
$message
) ||
''
;
chomp
$text
;
return
" $first ["
.
$self
->nrMessages .
"] $text\n"
;
}
elsif
(
$message
->isDummy)
{
$first
.=
$first
?
'-*-'
:
' *-'
;
return
(
shift
@follows
)->threadToString(
$code
,
$first
,
"$other "
)
if
@follows
==1;
push
@out
, (
shift
@follows
)->threadToString(
$code
,
$first
,
"$other | "
)
while
@follows
> 1;
}
else
{
my
$text
=
$code
->(
$message
) ||
''
;
chomp
$text
;
my
$size
=
$message
->shortSize;
@out
=
"$size$first $text\n"
;
push
@out
, (
shift
@follows
)
->threadToString(
$code
,
"$other |-"
,
"$other | "
)
while
@follows
> 1;
}
push
@out
, (
shift
@follows
)->threadToString(
$code
,
"$other `-"
,
"$other "
)
if
@follows
;
join
''
,
@out
;
}
sub
startTimeEstimate()
{
my
$self
=
shift
;
return
$self
->message->timestamp
unless
$self
->isDummy;
my
$earliest
;
foreach
(
$self
->followUps)
{
my
$stamp
=
$_
->startTimeEstimate;
$earliest
=
$stamp
if
!
defined
$earliest
|| (
defined
$stamp
&&
$stamp
<
$earliest
);
}
$earliest
;
}
sub
endTimeEstimate()
{
my
$self
=
shift
;
my
$latest
;
$self
->recurse
(
sub
{
my
$node
=
shift
;
unless
(
$node
->isDummy)
{
my
$stamp
=
$node
->message->timestamp;
$latest
=
$stamp
if
!
$latest
||
$stamp
>
$latest
;
}
}
);
$latest
;
}
sub
recurse($)
{
my
(
$self
,
$code
) =
@_
;
$code
->(
$self
) or
return
$self
;
$_
->recurse(
$code
) or
last
foreach
$self
->followUps;
$self
;
}
sub
totalSize()
{
my
$self
=
shift
;
my
$total
= 0;
$self
->recurse
(
sub
{
my
@msgs
=
shift
->messages;
$total
+=
$msgs
[0]->size
if
@msgs
;
1;}
);
$total
;
}
sub
numberOfMessages()
{
my
$self
=
shift
;
my
$total
= 0;
$self
->recurse(
sub
{++
$total
unless
shift
->isDummy; 1} );
$total
;
}
sub
nrMessages() {
shift
->numberOfMessages}
sub
threadMessages()
{
my
$self
=
shift
;
my
@messages
;
$self
->recurse
(
sub
{
my
$node
=
shift
;
push
@messages
,
$node
->message
unless
$node
->isDummy;
1;
}
);
@messages
;
}
sub
ids()
{
my
$self
=
shift
;
my
@ids
;
$self
->recurse(
sub
{
push
@ids
,
shift
->messageId} );
@ids
;
}
1;