X-Git-Url: http://git.polytechnique.org/?a=blobdiff_plain;f=banana%2Fspool.inc.php;h=ace19f7277dde077404d0aba500faba7a184384c;hb=ade32c5593c555591eb5cf859ea64b8ef7fdaaf8;hp=7a483391bd136ebdfec415bd65db8f64d5853bf6;hpb=dc5f77ad837f38a80e02699b97a4d7947f2f7f70;p=banana.git diff --git a/banana/spool.inc.php b/banana/spool.inc.php index 7a48339..ace19f7 100644 --- a/banana/spool.inc.php +++ b/banana/spool.inc.php @@ -8,24 +8,28 @@ ********************************************************************************/ require_once dirname(__FILE__) . '/banana.inc.php'; +require_once dirname(__FILE__) . '/tree.inc.php'; -define('BANANA_SPOOL_VERSION', '0.5'); +define('BANANA_SPOOL_VERSION', '0.5.14'); /** Class spoolhead * class used in thread overviews */ class BananaSpoolHead { + public $id; + public $msgid; + /** date (timestamp) */ public $date; /** subject */ public $subject; /** author */ public $from; + public $name; + public $color; /** reference of parent */ public $parent = null; - /** paren is direct */ - public $parent_direct; /** array of children */ public $children = Array(); /** true if post is read */ @@ -34,6 +38,8 @@ class BananaSpoolHead public $desc; /** same as desc, but counts only unread posts */ public $descunread; + /** last time the number of children has been updated */ + public $time = 0; /** storage data */ public $storage = array(); @@ -46,14 +52,22 @@ class BananaSpoolHead * @param $_read BOOLEAN true if read * @param $_descunread INTEGER descunread value (0 for a new post) */ - public function __construct(array &$message) + public function __construct($id, array &$message) { + list($name, $from) = BananaMessage::extractMail($message['from']); + $this->id = $id; + $this->msgid = @$message['message-id']; $this->date = $message['date']; - $this->subject = $message['subject']; + $this->subject = @$message['subject']; $this->from = $message['from']; + $this->color = sprintf('#%06x', abs(crc32($from) % 0xffffff)); $this->desc = 1; $this->isread = true; $this->descunread = 0; + $this->name = $name; + if ($name === $from) { + $this->name = 'Anonymous'; + } } } @@ -66,11 +80,12 @@ class BananaSpool /** group name */ public $group; /** spool */ - public $overview; + public $overview = array(); /** array msgid => msgnum */ - public $ids; + public $ids = array(); /** thread starts */ - public $roots; + public $roots = array(); + /** protocole specific data */ public $storage = array(); @@ -94,7 +109,7 @@ class BananaSpool $spool =& Banana::$spool; } else { $spool =& BananaSpool::readFromFile($group); - } + } if (is_null($spool)) { $spool = new BananaSpool($group); } @@ -107,19 +122,27 @@ class BananaSpool return $spool; } - private static function spoolFilename($group) + public static function getPath($file = null) { - $file = Banana::$spool_root . '/' . Banana::$protocole->name() . '/'; - if (!is_dir($file)) { - mkdir($file); + $path = Banana::$spool_root . '/' . Banana::$protocole->name() . '/' . Banana::$protocole->filename(); + if (!is_dir($path)) { + if (file_exists($path)) { + @unlink($path); + } + mkdir($path, 0777, true); } - return $file . Banana::$protocole->filename(); + return $path . '/' . $file; + } + + private static function spoolFilename() + { + return BananaSpool::getPath('spool'); } private static function &readFromFile($group) { $spool = null; - $file = BananaSpool::spoolFilename($group); + $file = BananaSpool::spoolFilename(); if (!file_exists($file)) { return $spool; } @@ -134,24 +157,24 @@ class BananaSpool private function compare($a, $b) { - return ($b->date >= $a->date); + return ($b->date - $a->date); } private function saveToFile() { - $file = BananaSpool::spoolFilename($this->group); - uasort($this->overview, array($this, 'compare')); + $file = BananaSpool::spoolFilename(); $this->roots = Array(); - foreach($this->overview as $id=>$msg) { + foreach($this->overview as &$msg) { if (is_null($msg->parent)) { - $this->roots[] = $id; + $this->roots[] =& $msg; } } + usort($this->roots, array($this, 'compare')); if ($this->mode == Banana::SPOOL_ALL) { file_put_contents($file, serialize($this)); - } + } } private function build() @@ -173,16 +196,16 @@ class BananaSpool } $clean = $this->clean($first, $last, $msgnum); $update = $this->update($first, $last, $msgnum); - + if ($clean || $update) { $this->saveToFile(); } } - + private function clean(&$first, &$last, $msgnum) { $do_save = false; - if (is_array($this->overview)) { + if (!empty($this->overview)) { $mids = array_keys($this->overview); foreach ($mids as $id) { if (($first <= $last && ($id < $first || $id > $last)) @@ -200,46 +223,45 @@ class BananaSpool private function update(&$first, &$last, $msgnum) { - if ($first > $last || !$msgnum) { + if ($first > $last || !$msgnum) { return false; } $messages =& Banana::$protocole->getMessageHeaders($first, $last, array('Date', 'Subject', 'From', 'Message-ID', 'References', 'In-Reply-To')); - if (!is_array($this->ids)) { - $this->ids = array(); - } - foreach ($messages as $id=>&$message) { - $this->ids[$message['message-id']] = $id; - } - - if (!is_array($this->overview)) { - $this->overview = array(); - } + // Build all the new Spool Heads + $time = time(); foreach ($messages as $id=>&$message) { if (!isset($this->overview[$id])) { - $this->overview[$id] = new BananaSpoolHead($message); + $this->overview[$id] = new BananaSpoolHead($id, $message); + $head =& $this->overview[$id]; + $this->ids[$head->msgid] =& $head; + $head->time = $time; } - $msg =& $this->overview[$id]; - $msgrefs = BananaMessage::formatReferences($message); - $parents = preg_grep('/^\d+$/', $msgrefs); - $msg->parent = array_pop($parents); - $msg->parent_direct = preg_match('/^\d+$/', array_pop($msgrefs)); - - if (!is_null($p = $msg->parent)) { - if (empty($this->overview[$p])) { - $this->overview[$p] = new BananaSpoolHead($messages[$p]); - } - $this->overview[$p]->children[] = $id; + } - while (!is_null($p)) { - $this->overview[$p]->desc += $msg->desc; - if ($p != $this->overview[$p]->parent) { - $p = $this->overview[$p]->parent; + // Build tree + $null = null; + foreach ($messages as $id=>&$message) { + $msg =& $this->overview[$id]; + $parents =& $this->getReferences($message); + while (!empty($parents) && ($msg->parent === $msg || is_null($msg->parent))) { + @$msg->parent =& array_pop($parents); + } + + if (!is_null($msg->parent)) { + $parent =& $msg->parent; + $parent->children[] =& $msg; + while (!is_null($parent)) { + $parent->desc += $msg->desc; + $parent->time = $time; + $prev =& $parent; + if ($parent !== $parent->parent) { + $parent =& $parent->parent; } else { - $p = null; - } + $parent =& $null; + } } } } @@ -259,19 +281,32 @@ class BananaSpool return; } - if (!is_array($this->ids)) { - $this->ids = array(); - } $newpostsids = array_intersect($newpostsids, array_keys($this->ids)); foreach ($newpostsids as $mid) { - $id = $this->ids[$mid]; - if ($this->overview[$id]->isread) { - $this->overview[$id]->isread = false; - $this->unreadnb++; - while (isset($id)) { - $this->overview[$id]->descunread++; - $id = $this->overview[$id]->parent; + $overview =& $this->ids[$mid]; + if ($overview->isread) { + $overview->isread = false; + while (!is_null($overview)) { + $overview->descunread++; + $overview =& $overview->parent; + } + } + } + $this->unreadnb += count($newpostsids); + + if (function_exists('hook_listReadMessages')) { + $msgs = hook_listReadMessages($this->group); + if (!is_array($msgs)) { + return; + } + foreach ($msgs as $msg) { + if (!is_numeric($msg)) { + if (!isset($this->ids[$msg])) { + continue; + } + $msg = $this->ids[$msg]->id; } + $this->markAsRead($msg); } } } @@ -281,27 +316,56 @@ class BananaSpool $this->mode = $mode; switch ($mode) { case Banana::SPOOL_UNREAD: - foreach ($this->roots as $k=>$i) { - if ($this->overview[$i]->descunread == 0) { - $this->killdesc($i); - unset($this->roots[$k]); + $num = max(array_keys($this->overview)); + if ($this->overview[$num]->isread) { + break; + } + foreach ($this->roots as &$root) { + if ($root->descunread == 0) { + $this->killdesc($root->id); } } break; } } + /** Fetch list of references + */ + public function &getReferences(array &$refs) + { + $references = array(); + if (isset($refs['references'])) { + $text = preg_split('/\s/', str_replace('><', '> <', $refs['references'])); + foreach ($text as $id=>&$value) { + if (isset($this->ids[$value])) { + $references[] =& $this->ids[$value]; + } + } + } elseif (isset($refs['in-reply-to']) && isset($this->ids[$refs['in-reply-to']])) { + $references[] =& $this->ids[$refs['in-reply-to']]; + } + return $references; + } + + /** Get the tree associated to a given id + */ + public function &getTree($id) + { + return BananaTree::build($id)->show(); + } + /** Mark the given id as read * @param id MSGNUM of post */ public function markAsRead($id) { - if (!$this->overview[$id]->isread) { - $this->overview[$id]->isread = true; + $overview =& $this->overview[$id]; + if (!$overview->isread) { + $overview->isread = true; $this->unreadnb--; - while (isset($id)) { - $this->overview[$id]->descunread--; - $id = $this->overview[$id]->parent; + while (!is_null($overview)) { + $overview->descunread--; + $overview =& $overview->parent; } } } @@ -313,20 +377,20 @@ class BananaSpool if (!$this->unreadnb) { return; } - if (is_null($array) && is_array($this->roots)) { + if (is_null($array) && !empty($this->roots)) { $array =& $this->roots; } elseif (is_null($array)) { return; } - foreach ($array as $id) { - if (!$this->overview[$id]->isread) { - $this->markAsRead($id); + foreach ($array as &$msg) { + if (!$msg->isread) { + $this->markAsRead($msg->id); if (!$this->unreadnb) { return; } } - if ($this->overview[$id]->descunread) { - $this->markAllAsRead($this->overview[$id]->children); + if ($msg->descunread) { + $this->markAllAsRead($msg->children); } } } @@ -336,15 +400,22 @@ class BananaSpool */ private function killdesc($_id) { - if (sizeof($this->overview[$_id]->children)) { - foreach ($this->overview[$_id]->children as $c) { - $this->killdesc($c); + $overview =& $this->overview[$_id]; + $children =& $overview->children; + if (sizeof($children)) { + foreach ($children as &$c) { + $this->killdesc($c->id); } } unset($this->overview[$_id]); - if (($msgid = array_search($_id, $this->ids)) !== false) { - unset($this->ids[$msgid]); + foreach ($this->roots as $k=>&$root) { + if ($root === $overview) { + unset($this->roots[$k]); + break; + } } + unset($this->ids[$overview->msgid]); + $overview = null; } /** delete a post from overview @@ -352,50 +423,61 @@ class BananaSpool */ public function delid($_id, $write = true) { - if (isset($this->overview[$_id])) { - $overview =& $this->overview[$_id]; - if (!$overview->isread) { - $this->markAsRead($_id); - } - if ($overview->parent) { - $p = $overview->parent; - $parent =& $this->overview[$p]; - $parent->children = array_diff($parent->children, array($_id)); - if (sizeof($overview->children)) { - $parent->children = array_merge($parent->children, $overview->children); - foreach ($overview->children as $c) { - $this->overview[$c]->parent = $p; - $this->overview[$c]->parent_direct = false; - } - } - while (isset($p)) { - $this->overview[$p]->desc--; - $p = $this->overview[$p]->parent; - } - } elseif ($overview->children) { - foreach ($overview->children as $c) { - $this->overview[$c]->parent = null; + if (!isset($this->overview[$_id])) { + return; + } + + $overview =& $this->overview[$_id]; + // Be sure it is not counted as unread + if (!$overview->isread) { + $this->markAsRead($_id); + } + + $parent =& $overview->parent; + + // Remove from the message tree + if (!is_null($parent)) { + $time = time(); + foreach ($parent->children as $key=>&$child) { + if ($child === $overview) { + unset($parent->children[$key]); + break; } } - unset($overview); - unset($this->overview[$_id]); - $msgid = array_search($_id, $this->ids); - if ($msgid !== false) { - unset($this->ids[$msgid]); + if (sizeof($overview->children)) { + foreach ($overview->children as &$child) { + $parent->children[] =& $child; + $child->time = $time; + $child->parent =& $parent; + } } - $msgid = array_search($_id, $this->roots); - if ($msgid !== false) { - unset($this->roots[$msgid]); + while (!is_null($parent)) { + $parent->desc--; + $parent->time = $time; + $parent =& $parent->parent; } - - if ($write) { - $this->saveToFile(); + } + + // Remove all refenrences and assign null to the object + unset($this->ids[$overview->msgid]); + unset($this->overview[$_id]); + BananaTree::kill($_id); + foreach ($this->roots as $k=>&$root) { + if ($root === $overview) { + unset($this->roots[$k]); + break; } } + $overview = null; + + if ($write) { + $this->saveToFile(); + } } - private function formatDate($stamp) + public function formatDate(BananaSpoolHead $head) { + $stamp = $head->date; $today = intval(time() / (24*3600)); $dday = intval($stamp / (24*3600)); @@ -405,175 +487,67 @@ class BananaSpool $format = _b_('hier')." %H:%M"; } elseif ($today < 7 + $dday) { $format = '%a %H:%M'; - } else { + } elseif ($today < 90 + $dday) { $format = '%a %e %b'; + } else { + $format = '%a %e %b %Y'; } return strftime($format, $stamp); } - /** 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 - * - * If you want to analyse subject, you can define the function hook_formatDisplayHeader - */ - private function _to_html($_id, $_index, $_first=0, $_last=0, $_ref="", $_pfx_node="", $_pfx_end="", $_head=true, $_pfx_id="") - { - static $spfx_f, $spfx_n, $spfx_Tnd, $spfx_Lnd, $spfx_snd, $spfx_T, $spfx_L, $spfx_s, $spfx_e, $spfx_I; - if (!isset($spfx_f)) { - $spfx_f = Banana::$page->makeImg(Array('img' => 'k1', 'alt' => 'o', 'height' => 21, 'width' => 9)); - $spfx_n = Banana::$page->makeImg(Array('img' => 'k2', 'alt' => '*', 'height' => 21, 'width' => 9)); - $spfx_Tnd = Banana::$page->makeImg(Array('img' => 'T-direct', 'alt' => '+', 'height' => 21, 'width' => 12)); - $spfx_Lnd = Banana::$page->makeImg(Array('img' => 'L-direct', 'alt' => '`', 'height' => 21, 'width' => 12)); - $spfx_snd = Banana::$page->makeImg(Array('img' => 's-direct', 'alt' => '-', 'height' => 21, 'width' => 5)); - $spfx_T = Banana::$page->makeImg(Array('img' => 'T', 'alt' => '+', 'height' => 21, 'width' => 12)); - $spfx_L = Banana::$page->makeImg(Array('img' => 'L', 'alt' => '`', 'height' => 21, 'width' => 12)); - $spfx_s = Banana::$page->makeImg(Array('img' => 's', 'alt' => '-', 'height' => 21, 'width' => 5)); - $spfx_e = Banana::$page->makeImg(Array('img' => 'e', 'alt' => ' ', 'height' => 21, 'width' => 12)); - $spfx_I = Banana::$page->makeImg(Array('img' => 'I', 'alt' => '|', 'height' => 21, 'width' => 12)); + public function formatSubject(BananaSpoolHead $head) + { + $subject = $popup = $head->subject; + $popup = $subject; + if (function_exists('hook_formatDisplayHeader')) { + list($subject, $link) = hook_formatDisplayHeader('subject', $subject, true); + } else { + $subject = banana_catchFormats(banana_entities(stripslashes($subject))); + $link = null; } - - $overview =& $this->overview[$_id]; - if ($_index + $overview->desc < $_first || $_index > $_last) { - return ''; + if (empty($subject)) { + $subject = _b_('(pas de sujet)'); } - - $res = ''; - if ($_index >= $_first) { - $hc = empty($overview->children); - - $res .= '