X-Git-Url: http://git.polytechnique.org/?a=blobdiff_plain;f=banana%2Fspool.inc.php;h=172e4aa16bf4e66a54e378fe4d9b1082f950bb0b;hb=cfb7fe5d9f451e667b12440409ad6cbec6a2be43;hp=c7a7daeb85471109d0434be7befed00cf7f9c297;hpb=fb6428c855e1be6fed8326d1ddecbf7a4eab3f60;p=banana.git
diff --git a/banana/spool.inc.php b/banana/spool.inc.php
index c7a7dae..172e4aa 100644
--- a/banana/spool.inc.php
+++ b/banana/spool.inc.php
@@ -7,20 +7,9 @@
* Copyright: See COPYING files that comes with this distribution
********************************************************************************/
-if(!function_exists('file_put_contents')) {
- function file_put_contents($filename, $data)
- {
- $fp = fopen($filename, 'w');
- if(!$fp) {
- trigger_error('file_put_contents cannot write in file '.$filename, E_USER_ERROR);
- return;
- }
- fputs($fp, $data);
- fclose($fp);
- }
-}
+require_once dirname(__FILE__) . '/banana.inc.php';
-function spoolCompare($a,$b) { return ($b->date>=$a->date); }
+define('BANANA_SPOOL_VERSION', '0.3');
/** Class spoolhead
* class used in thread overviews
@@ -28,23 +17,26 @@ function spoolCompare($a,$b) { return ($b->date>=$a->date); }
class BananaSpoolHead
{
/** date (timestamp) */
- var $date;
+ public $date;
/** subject */
- var $subject;
+ public $subject;
/** author */
- var $from;
+ public $from;
/** reference of parent */
- var $parent;
+ public $parent = null;
/** paren is direct */
- var $parent_direct;
+ public $parent_direct;
/** array of children */
- var $children = Array();
+ public $children = Array();
/** true if post is read */
- var $isread;
+ public $isread;
/** number of posts deeper in this branch of tree */
- var $desc;
+ public $desc;
/** same as desc, but counts only unread posts */
- var $descunread;
+ public $descunread;
+
+ /** storage data */
+ public $storage = array();
/** constructor
* @param $_date INTEGER timestamp of post
@@ -54,102 +46,96 @@ class BananaSpoolHead
* @param $_read BOOLEAN true if read
* @param $_descunread INTEGER descunread value (0 for a new post)
*/
-
- function BananaSpoolHead($_date, $_subject, $_from, $_desc=1, $_read=true, $_descunread=0)
+ public function __construct(array &$message)
{
- $this->date = $_date;
- $this->subject = $_subject;
- $this->from = $_from;
- $this->desc = $_desc;
- $this->isread = $_read;
- $this->descunread = $_descunread;
+ $this->date = $message['date'];
+ $this->subject = $message['subject'];
+ $this->from = $message['from'];
+ $this->desc = 1;
+ $this->isread = true;
+ $this->descunread = 0;
}
}
-/** Class spool
- * builds and updates spool
- */
-
-define("BANANA_SPOOL_VERSION", '0.2');
class BananaSpool
{
- var $version;
- /** spool */
- var $overview;
+ private $version;
+ private $mode;
+
/** group name */
- var $group;
+ public $group;
+ /** spool */
+ public $overview;
/** array msgid => msgnum */
- var $ids;
+ public $ids;
/** thread starts */
- var $roots;
- /** test validity */
- var $valid = true;
+ public $roots;
+
/** constructor
* @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 BananaSpool($_group, $_display=0, $_since="")
+ protected function __construct($group)
{
- global $banana;
- $this->group = $_group;
- $groupinfo = $banana->nntp->group($_group);
- if (!$groupinfo) {
- $this->valid = false;
- return null;
- }
-
- $this->_readFromFile();
+ $this->version = BANANA_SPOOL_VERSION;
+ $this->mode = Banana::SPOOL_ALL;
+ $this->group = $group;
+ }
- $do_save = false;
- $first = $banana->maxspool ? max($groupinfo[2] - $banana->maxspool, $groupinfo[1]) : $groupinfo[1];
- $last = $groupinfo[2];
-
- if ($this->version == BANANA_SPOOL_VERSION && is_array($this->overview)) {
- $mids = array_keys($this->overview);
- foreach ($mids as $id) {
- if (($first <= $last && ($id < $first || $id > $last))
- || ($first > $last && $id < $first && $id > $last))
- {
- $this->delid($id, false);
- $do_save = true;
- }
- }
- if (!empty($this->overview)) {
- $first = max(array_keys($this->overview))+1;
- }
+ public static function getSpool($group, $since = 0, $clean = false)
+ {
+ if (!is_null(Banana::$spool) && Banana::$spool->group == $group) {
+ $spool =& Banana::$spool;
} else {
- unset($this->overview, $this->ids);
- $this->version = BANANA_SPOOL_VERSION;
+ $spool = BananaSpool::readFromFile($group);
+ }
+ if (is_null($spool)) {
+ $spool = new BananaSpool($group);
}
-
- if ($first<=$last && $groupinfo[0]) {
- $do_save = true;
- $this->_updateSpool("$first-$last");
+ Banana::$spool =& $spool;
+ $spool->build();
+ if ($clean) {
+ $spool->markAllAsRead();
}
+ $spool->updateUnread($since);
+ return $spool;
+ }
- if ($do_save) { $this->_saveToFile(); }
-
- $this->_updateUnread($_since, $_display);
+ private static function spoolFilename($group)
+ {
+ $file = dirname(dirname(__FILE__));
+ $file .= '/spool/' . Banana::$protocole->name() . '/';
+ if (!is_dir($file)) {
+ mkdir($file);
+ }
+ return $file . Banana::$protocole->filename();
}
- function _readFromFile()
+ private static function readFromFile($group)
{
- $file = $this->_spoolfile();
- if (file_exists($file)) {
- $temp = unserialize(file_get_contents($file));
- foreach (get_object_vars($temp) as $key=>$val) {
- $this->$key = $val;
- }
+ $file = BananaSpool::spoolFilename($group);
+ if (!file_exists($file)) {
+ return null;
+ }
+ $spool = unserialize(file_get_contents($file));
+ if ($spool->version != BANANA_SPOOL_VERSION || $spool->mode != Banana::SPOOL_ALL) {
+ return null;
}
+ return $spool;
+ }
+
+ private function compare($a, $b)
+ {
+ return ($b->date >= $a->date);
}
- function _saveToFile()
+ private function saveToFile()
{
- $file = $this->_spoolfile();
- uasort($this->overview, "spoolcompare");
+ $file = BananaSpool::spoolFilename($this->group);
+ uasort($this->overview, array($this, 'compare'));
$this->roots = Array();
foreach($this->overview as $id=>$msg) {
@@ -158,98 +144,185 @@ class BananaSpool
}
}
- file_put_contents($file, serialize($this));
+ if ($this->mode == Banana::SPOOL_ALL) {
+ file_put_contents($file, serialize($this));
+ }
}
- function _spoolfile()
+ private function build()
{
- global $banana;
- $url = parse_url($banana->host);
- $file = $url['host'].'_'.$url['port'].'_'.$this->group;
- return dirname(dirname(__FILE__)).'/spool/'.$file;
+ $threshold = 0;
+
+ // Compute the range of indexes
+ list($msgnum, $first, $last) = Banana::$protocole->getIndexes();
+ if ($last < $first) {
+ $threshold = $firt + $msgnum - $last;
+ $threshold = (int)(log($threshold)/log(2));
+ $threshold = (2 ^ ($threshold + 1)) - 1;
+ }
+ if (Banana::$spool_max && Banana::$spool_max < $msgnum) {
+ $first = $last - Banana::$spool_max;
+ if ($first < 0) {
+ $first += $threshold;
+ }
+ }
+ $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)) {
+ $mids = array_keys($this->overview);
+ foreach ($mids as $id) {
+ if (($first <= $last && ($id < $first || $id > $last))
+ || ($first > $last && $id < $first && $id > $last)) {
+ $this->delid($id, false);
+ $do_save = true;
+ }
+ }
+ if (!empty($this->overview)) {
+ $first = max(array_keys($this->overview))+1;
+ }
+ }
+ return $do_save;
}
- function _updateSpool($arg)
+ private function update(&$first, &$last, $msgnum)
{
- global $banana;
- $dates = array_map('strtotime', $banana->nntp->xhdr('Date', $arg));
- $subjects = array_map('headerdecode', $banana->nntp->xhdr('Subject', $arg));
- $froms = array_map('headerdecode', $banana->nntp->xhdr('From', $arg));
- $msgids = $banana->nntp->xhdr('Message-ID', $arg);
- $refs = $banana->nntp->xhdr('References', $arg);
-
- if (is_array($this->ids)) {
- $this->ids = array_merge($this->ids, array_flip($msgids));
- } else {
- $this->ids = array_flip($msgids);
+ if ($first > $last || !$msgnum) {
+ return false;
}
- foreach ($msgids as $id=>$msgid) {
- $msg = new BananaSpoolHead($dates[$id], $subjects[$id], $froms[$id]);
- $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);
- $msg->parent_direct = preg_match('/^\d+$/', array_pop($msgrefs));
+ $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 (isset($this->overview[$id])) {
- $msg->desc = $this->overview[$id]->desc;
- $msg->children = $this->overview[$id]->children;
+ if (!is_array($this->overview)) {
+ $this->overview = array();
+ }
+ foreach ($messages as $id=>&$message) {
+ if (!isset($this->overview[$id])) {
+ $this->overview[$id] = new BananaSpoolHead($message);
}
- $this->overview[$id] = $msg;
+ $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 ($p = $msg->parent) {
+ if (!is_null($p = $msg->parent)) {
if (empty($this->overview[$p])) {
- $this->overview[$p] = new BananaSpoolHead($dates[$p], $subjects[$p], $froms[$p], 1);
+ $this->overview[$p] = new BananaSpoolHead($messages[$p]);
}
$this->overview[$p]->children[] = $id;
- while ($p) {
+ while (!is_null($p)) {
$this->overview[$p]->desc += $msg->desc;
- $p = $this->overview[$p]->parent;
+ if ($p != $this->overview[$p]->parent) {
+ $p = $this->overview[$p]->parent;
+ } else {
+ $p = null;
+ }
}
}
}
+ Banana::$protocole->updateSpool($messages);
+ return true;
}
- function _updateUnread($since, $mode)
+ private function updateUnread($since)
{
- global $banana;
- if (empty($since)) { return; }
-
- if (is_array($newpostsids = $banana->nntp->newnews($since, $this->group))) {
- if (!is_array($this->ids)) { $this->ids = array(); }
- $newpostsids = array_intersect($newpostsids, array_keys($this->ids));
- foreach ($newpostsids as $mid) {
- $this->overview[$this->ids[$mid]]->isread = false;
- $this->overview[$this->ids[$mid]]->descunread = 1;
- $parentmid = $this->ids[$mid];
- while (isset($parentmid)) {
- $this->overview[$parentmid]->descunread ++;
- $parentmid = $this->overview[$parentmid]->parent;
+ if (empty($since)) {
+ return;
+ }
+
+ $newpostsids = Banana::$protocole->getNewIndexes($since);
+
+ if (empty($newpostsids)) {
+ 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;
+ while (isset($id)) {
+ $this->overview[$id]->descunread ++;
+ $id = $this->overview[$id]->parent;
}
}
+ }
+ }
- if (count($newpostsids)) {
- switch ($mode) {
- case 1:
- foreach ($this->roots as $k=>$i) {
- if ($this->overview[$i]->descunread==0) {
- $this->killdesc($i);
- unset($this->roots[$k]);
- }
- }
- break;
+ public function setMode($mode)
+ {
+ $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]);
}
}
+ break;
+ }
+ }
+
+ /** 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;
+ while (isset($id)) {
+ $this->overview[$id]->descunread--;
+ $id = $this->overview[$id]->parent;
+ }
+ }
+ }
+
+ /** Mark all unread messages as read
+ */
+ public function markAllAsRead(array &$array = null)
+ {
+ if (is_null($array)) {
+ $array =& $this->roots;
+ }
+ if (!is_array($this->roots)) {
+ return;
+ }
+ foreach ($array as $id) {
+ if (!$this->overview[$id]->isread) {
+ $this->markAsRead($id);
+ }
+ if ($this->overview[$id]->descunread) {
+ $this->markAllAsRead($this->overview[$id]->children);
+ }
}
}
/** kill post and childrens
* @param $_id MSGNUM of post
*/
-
- function killdesc($_id)
+ private function killdesc($_id)
{
if (sizeof($this->overview[$_id]->children)) {
foreach ($this->overview[$_id]->children as $c) {
@@ -265,8 +338,7 @@ class BananaSpool
/** delete a post from overview
* @param $_id MSGNUM of post
*/
-
- function delid($_id, $write=true)
+ public function delid($_id, $write = true)
{
if (isset($this->overview[$_id])) {
if (sizeof($this->overview[$_id]->parent)) {
@@ -292,14 +364,38 @@ class BananaSpool
}
unset($this->overview[$_id]);
$msgid = array_search($_id, $this->ids);
- if ($msgid) {
+ if ($msgid !== false) {
unset($this->ids[$msgid]);
}
+ $msgid = array_search($_id, $this->roots);
+ if ($msgid !== false) {
+ unset($this->roots[$msgid]);
+ }
- if ($write) { $this->_saveToFile(); }
+ if ($write) {
+ $this->markAllAsRead();
+ $this->saveToFile();
+ }
}
}
+ private function formatDate($stamp)
+ {
+ $today = intval(time() / (24*3600));
+ $dday = intval($stamp / (24*3600));
+
+ if ($today == $dday) {
+ $format = "%H:%M";
+ } elseif ($today == 1 + $dday) {
+ $format = _b_('hier')." %H:%M";
+ } elseif ($today < 7 + $dday) {
+ $format = '%a %H:%M';
+ } else {
+ $format = '%a %e %b';
+ }
+ return utf8_encode(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
@@ -309,68 +405,79 @@ class BananaSpool
* @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
*/
-
- function _to_html($_id, $_index, $_first=0, $_last=0, $_ref="", $_pfx_node="", $_pfx_end="", $_head=true)
+ private function _to_html($_id, $_index, $_first=0, $_last=0, $_ref="", $_pfx_node="", $_pfx_end="", $_head=true)
{
- $spfx_f = '';
- $spfx_n = '
';
- $spfx_Tnd = '
';
- $spfx_Lnd = '
';
- $spfx_snd = '
';
- $spfx_T = '
';
- $spfx_L = '
';
- $spfx_s = '
';
- $spfx_e = '
';
- $spfx_I = '
';
-
- if ($_index + $this->overview[$_id]->desc < $_first || $_index > $_last) {
- return;
+ 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));
}
- $res = '';
-
- if ($_index>=$_first) {
- $hc = empty($this->overview[$_id]->children);
+ $overview =& $this->overview[$_id];
+ if ($_index + $overview->desc < $_first || $_index > $_last) {
+ return '';
+ }
- $res .= '
'._b_('Date').' | '; - $res .= ''._b_('Sujet').' | '; - $res .= ''._b_('Auteur').' |
---|---|---|
'._b_('Aucun message dans ce forum').' |