date=$_date;
$this->subject=$_subject;
$this->from=$_from;
$this->children=array();
$this->desc=$_desc;
$this->isread=$_read;
$this->descunread=$_descunread;
}
}
/** Class spool
* builds and updates spool
*/
class spool {
# var $date;
/** spool */
var $overview;
/** group name */
var $group;
/** array msgid => msgnum */
var $ids;
/** constructor
* @param $_nntp RESOURCE NNTP socket filehandle
* @param $_group STRING group name
* @param $_display INTEGER 1 => all posts, 2 => only threads with new posts
* @param $_since INTEGER time stamp (used for read/unread)
*/
function spool(&$_nntp,$_group,$_display=0,$_since=""){
global $news;
$groupinfo = $_nntp->group($_group);
if (!$groupinfo) {
$this = false;
return false;
}
$spoolfile=realpath("./spool/spool-$_group.dat");
if (file_exists($spoolfile)) {
$f = fopen($spoolfile,"r");
$this = unserialize(fread($f,filesize($spoolfile)));
fclose($f);
$keys = array_values($this->ids);
rsort($keys);
$first = max($groupinfo[2]-$news['maxspool'],$groupinfo[1]);
$last = $groupinfo[2];
// remove expired messages
$msgids=array_flip($this->ids);
for ($id=min(array_keys($this->overview)); $id<$first; $id++) {
$this->delid[$id];
}
$this->ids=array_flip($msgids);
$first=max(array_keys($this->overview))+1;
} else {
$first = max($groupinfo[2]-$news['maxspool'],$groupinfo[1]);
$last = $groupinfo[2];
$this->group = $_group;
}
if (($first<=$groupinfo[2]) && ($groupinfo[0]!=0)) {
$dates = array_map("strtotime",
$_nntp->xhdr("Date","$first-$last"));
$msgids=$_nntp->xhdr("Message-ID","$first-$last");
$subjects = array_map("headerdecode",$_nntp->xhdr("Subject",
"$first-$last"));
$froms = array_map("headerdecode",$_nntp->xhdr("From",
"$first-$last"));
$refs = $_nntp->xhdr("References","$first-$last");
# $this->date=$nntp->date;
if (isset($this->ids)) {
$this->ids=array_merge($this->ids,array_flip($msgids));
} else {
$this->ids=array_flip($msgids);
}
foreach ($msgids as $id=>$msgid) {
$msg = new spoolhead($dates[$id],$subjects[$id],$froms[$id],
(isset($this->overview[$id]->desc)?
$this->overview[$id]->desc+1:1));
$refs[$id]=str_replace("><","> <",$refs[$id]);
$msgrefs=preg_split("/( |\t)/",strtr($refs[$id],$this->ids));
$parents=preg_grep("/^\d+$/",$msgrefs);
$msg->parent=array_pop($parents);
$p = $msg->parent;
while ($p) {
if (isset($this->overview[$p])) {
$this->overview[$p]->desc++;
if (isset($this->overview[$p]->parent)) {
$p = $this->overview[$p]->parent;
} else {
$p = false;
}
} else {
$this->overview[$p] = new spoolhead($dates[$p],$subjects[$p],$froms[$p],1);
$p = false;
}
}
if ($msg->parent!="")
$this->overview[$msg->parent]->children[]=$id;
$this->overview[$id] = $msg;
}
uasort($this->overview,"spoolcompare");
$f = fopen("spool/spool-$_group.dat","w");
fputs($f,serialize($this));
fclose($f);
}
if ($_since != "") {
$newpostsids = $_nntp->newnews($_since,$_group);
if (sizeof($newpostsids)) {
$newpostsids = array_intersect($newpostsids,
array_keys($this->ids));
if ($newpostsids && !is_null($newpostsids)) {
foreach ($newpostsids as $mid) {
$this->overview[$this->ids[$mid]]->isread=false;
$this->overview[$this->ids[$mid]]->descunread=1;
$parentmid = $this->overview[$this->ids[$mid]]->parent;
while (!is_null($parentmid)) {
$this->overview[$parentmid]->descunread++;
$parentmid = $this->overview[$parentmid]->parent;
}
}
}
}
if (sizeof($newpostsids)>0) {
$flipids = array_flip($this->ids);
switch ($_display) {
case 1:
foreach ($this->overview as $i=>$p) {
if (isset($this->overview[$i]) &&
!isset($this->overview[$i]->parent) &&
($this->overview[$i]->descunread==0)) {
$this->killdesc($i);
}
}
break;
case 2:
foreach ($this->overview as $i=>$p) {
if ($p->isread) {
unset($this->overview[$i]);
unset($flipids[$i]);
}
}
$this->ids=array_flip($flipids);
break;
}
}
}
return true;
}
/** kill post and childrens
* @param $_id MSGNUM of post
*/
function killdesc($_id) {
if (sizeof($this->overview[$_id]->children)) {
foreach ($this->overview[$_id]->children as $c) {
$this->killdesc($c);
}
}
unset($this->overview[$_id]);
# $flipid=array_flip($this->ids);
# unset($flipid[$id]);
# $this->ids=array_flip($flipid);
}
/** delete a post from overview
* @param $_id MSGNUM of post
*/
function delid($_id) {
if (isset($this->overview[$_id])) {
if (sizeof($this->overview[$_id]->parent)) {
$this->overview[$this->overview[$_id]->parent]->children =
array_diff($this->overview[$this->overview[$_id]->parent]->children,
array($_id));
if (sizeof($this->overview[$_id]->children)) {
$this->overview[$this->overview[$_id]->parent]->children =
array_merge($this->overview[$this->overview[$_id]->parent]->children,
$this->overview[$_id]->children);
foreach ($this->overview[$_id]->children as $c) {
$this->overview[$c]->parent = $this->overview[$_id]->parent;
}
}
$p = $this->overview[$_id]->parent;
while ($p) {
$this->overview[$p]->desc--;
$p = $this->overview[$p]->parent;
}
} elseif (sizeof($this->overview[$_id]->children)) {
foreach ($this->overview[$_id]->children as $c) {
$this->overview[$c]->parent = null;
}
}
unset($this->overview[$_id]);
$ids = array_flip($this->ids);
unset($ids[$_id]);
$this->ids = array_flip($ids);
$f = fopen("spool/spool-{$this->group}.dat","w");
fputs($f,serialize($this));
fclose($f);
}
}
/** displays children tree of a post
* @param $_id INTEGER MSGNUM of post
* @param $_index INTEGER linear number of post in the tree
* @param $_first INTEGER linear number of first post displayed
* @param $_last INTEGER linear number of last post displayed
* @param $_ref STRING MSGNUM of current post
* @param $_pfx_node STRING prefix used for current node
* @param $_pfx_end STRING prefix used for children of current node
* @param $_head BOOLEAN true if first post in thread
*/
function disp_desc($_id,$_index="",$_first=0,$_last=0,$_ref="",
$_pfx_node="", $_pfx_end="",$_head=true) {
global $css;
$debug = false;
$spfx_f = '';
$spfx_n = '
';
$spfx_T = '
';
$spfx_L = '
';
$spfx_s = '
';
$spfx_e = '
';
$spfx_I = '
';
if ($_index == "") $_index = $this->getndx($_id);
if (!sizeof($this->overview[$_id]->children) && ($_index<=$_last)
&& ($_index>=$_first)) {
echo '