Year of the post
[banana.git] / banana / spool.inc.php
index 3d4eee6..19cc647 100644 (file)
@@ -9,7 +9,7 @@
 
 require_once dirname(__FILE__) . '/banana.inc.php';
 
-define('BANANA_SPOOL_VERSION', '0.3');
+define('BANANA_SPOOL_VERSION', '0.5');
 
 /** Class spoolhead
  *  class used in thread overviews
@@ -71,7 +71,10 @@ class BananaSpool
     public $ids;
     /** thread starts */
     public $roots;
+    /** protocole specific data */
+    public $storage = array();
 
+    private $unreadnb = 0;
 
     /** constructor
      * @param $_group STRING group name
@@ -85,12 +88,12 @@ class BananaSpool
         $this->group      = $group;
     }
 
-    public static function getSpool($group, $since = 0, $clean = false)
+    public static function &getSpool($group, $since = 0, $clean = false)
     {
         if (!is_null(Banana::$spool) && Banana::$spool->group == $group) {
             $spool =& Banana::$spool;
         } else {
-            $spool = BananaSpool::readFromFile($group);
+            $spool =& BananaSpool::readFromFile($group);
         }        
         if (is_null($spool)) {
             $spool = new BananaSpool($group);
@@ -113,35 +116,38 @@ class BananaSpool
         return $file . Banana::$protocole->filename();
     }
 
-    private static function readFromFile($group)
+    private static function &readFromFile($group)
     {
+        $spool = null;
         $file = BananaSpool::spoolFilename($group);
         if (!file_exists($file)) {
-            return null;
+            return $spool;
         }
         $spool =  unserialize(file_get_contents($file));
         if ($spool->version != BANANA_SPOOL_VERSION || $spool->mode != Banana::SPOOL_ALL) {
-            return null;
+            $spool = null;
+            return $spool;
         }
+        $spool->markAllAsRead();
         return $spool;
     }
 
     private function compare($a, $b)
     {
-        return ($b->date >= $a->date);
+        return ($this->overview[$b]->date >= $this->overview[$a]->date);
     }
 
     private function saveToFile()
     {
         $file = BananaSpool::spoolFilename($this->group);
-        uasort($this->overview, array($this, 'compare'));
 
         $this->roots = Array();
-        foreach($this->overview as $id=>$msg) {
+        foreach($this->overview as $id=>&$msg) {
             if (is_null($msg->parent)) {
                 $this->roots[] = $id;
             }
         }
+        usort($this->roots, array($this, 'compare'));
 
         if ($this->mode == Banana::SPOOL_ALL) {
             file_put_contents($file, serialize($this));
@@ -155,7 +161,7 @@ class BananaSpool
         // Compute the range of indexes
         list($msgnum, $first, $last) = Banana::$protocole->getIndexes();
         if ($last < $first) {
-            $threshold = $firt + $msgnum - $last;
+            $threshold = $first + $msgnum - $last;
             $threshold = (int)(log($threshold)/log(2));
             $threshold = (2 ^ ($threshold + 1)) - 1;
         }
@@ -241,7 +247,7 @@ class BananaSpool
         return true;
     }
 
-    private function updateUnread($since)
+    public function updateUnread($since)
     {
         if (empty($since)) {
             return;
@@ -260,9 +266,10 @@ class BananaSpool
         foreach ($newpostsids as $mid) {
             $id = $this->ids[$mid];
             if ($this->overview[$id]->isread) {
-                $this->overview[$id]->isread     = false;
+                $this->overview[$id]->isread = false;
+                $this->unreadnb++;
                 while (isset($id)) {
-                    $this->overview[$id]->descunread ++;
+                    $this->overview[$id]->descunread++;
                     $id = $this->overview[$id]->parent;
                 }
             }
@@ -291,6 +298,7 @@ class BananaSpool
     {
         if (!$this->overview[$id]->isread) {
             $this->overview[$id]->isread = true;
+            $this->unreadnb--;
             while (isset($id)) {
                 $this->overview[$id]->descunread--;
                 $id = $this->overview[$id]->parent;
@@ -302,15 +310,20 @@ class BananaSpool
      */
     public function markAllAsRead(array &$array = null)
     {
-        if (is_null($array)) {
-            $array =& $this->roots;
+        if (!$this->unreadnb) {
+            return;
         }
-        if (!is_array($this->roots)) {
+        if (is_null($array) && is_array($this->roots)) {
+            $array =& $this->roots;
+        } elseif (is_null($array)) {
             return;
         }
         foreach ($array as $id) {
             if (!$this->overview[$id]->isread) {
                 $this->markAsRead($id);
+                if (!$this->unreadnb) {
+                    return;
+                }
             }
             if ($this->overview[$id]->descunread) {
                 $this->markAllAsRead($this->overview[$id]->children);
@@ -340,27 +353,31 @@ class BananaSpool
     public function delid($_id, $write = true)
     {
         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;
+            $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;
                     }
                 }
-                $p = $this->overview[$_id]->parent;
-                while ($p) {
+                while (isset($p)) {
                     $this->overview[$p]->desc--;
                     $p = $this->overview[$p]->parent;
                 }
-            } elseif (sizeof($this->overview[$_id]->children)) {
-                foreach ($this->overview[$_id]->children as $c) {
+            } elseif ($overview->children) {
+                foreach ($overview->children as $c) {
                     $this->overview[$c]->parent = null;
                 }
             }
+            unset($overview);
             unset($this->overview[$_id]);
             $msgid = array_search($_id, $this->ids);
             if ($msgid !== false) {
@@ -372,7 +389,6 @@ class BananaSpool
             }
             
             if ($write) {
-                $this->markAllAsRead();
                 $this->saveToFile();
             }
         }
@@ -389,8 +405,10 @@ 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);
     }
@@ -407,7 +425,7 @@ class BananaSpool
      *
      * 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)
+    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)) {
@@ -432,16 +450,16 @@ class BananaSpool
         if ($_index >= $_first) {
             $hc = empty($overview->children);
 
-            $res .= '<tr class="' . ($_index%2 ? 'pair' : 'impair') . ($overview->isread ? '' : ' new') . "\">\n";
+            $res .= '<tr id="'.$_pfx_id.$_id.'" class="' . ($_index%2 ? 'pair' : 'impair') . ($overview->isread ? '' : ' new') . "\">\n";
             $res .= '<td class="date">' . $this->formatDate($overview->date) . " </td>\n";
             $res .= '<td class="subj' . ($_index == $_ref ? ' cur' : '') . '"><div class="tree">'
                 . $_pfx_node .($hc ? ($_head ? $spfx_f : ($overview->parent_direct ? $spfx_s : $spfx_snd)) : $spfx_n)
                 . '</div>';
-            $subject = $overview->subject;
+            $popup = $subject = $overview->subject;
             if (function_exists('hook_formatDisplayHeader')) {
                 list($subject, $link) = hook_formatDisplayHeader('subject', $subject, true);
             } else {
-                $subject = banana_catchFormats(banana_htmlentities(stripslashes($subject)));
+                $subject = banana_catchFormats(banana_entities(stripslashes($subject)));
                 $link = null;
             }
             if (empty($subject)) {
@@ -449,7 +467,7 @@ class BananaSpool
             }
             if ($_index != $_ref) {
                 $subject = Banana::$page->makeLink(Array('group' => $this->group, 'artid' => $_id,
-                                                    'text'  => $subject, 'popup' => $subject));
+                                                    'text'  => $subject, 'popup' => $popup));
             }
             $res .= '&nbsp;' . $subject . $link;
             $res .= "</td>\n<td class='from'>" . BananaMessage::formatFrom($overview->from) . "</td>\n</tr>";
@@ -470,11 +488,11 @@ class BananaSpool
                 if (sizeof($children)) {
                     $res .= $this->_to_html($child, $_index, $_first, $_last, $_ref,
                             $_pfx_end . ($overview->parent_direct ? $spfx_T : $spfx_Tnd),
-                            $_pfx_end . $spfx_I, false);
+                            $_pfx_end . $spfx_I, false,$_id.'_');
                 } else {
                     $res .= $this->_to_html($child, $_index, $_first, $_last, $_ref,
                             $_pfx_end . ($overview->parent_direct ? $spfx_L : $spfx_Lnd),
-                            $_pfx_end . $spfx_e, false);
+                            $_pfx_end . $spfx_e, false,$_id.'_');
                 }
             }
             $_index += $overview->desc;
@@ -490,7 +508,8 @@ class BananaSpool
      */
     public function toHtml($first = 0, $overview = false)
     {
-        $res = '';
+        $res = Banana::$page->makeJs('jquery');
+        $res .= Banana::$page->makeJs('spool_toggle');
 
         if (!$overview) {
             $_first = $first;
@@ -559,6 +578,32 @@ class BananaSpool
         return $id_cur;
     }
 
+    /** Return the last post id with the given subject
+     * @param subject
+     */
+    public function getPostId($subject)
+    {
+        $subject = trim($subject);
+        $id = max(array_keys($this->overview));
+        while (isset($this->overview[$id])) {
+            $test = $this->overview[$id]->subject;
+            if (function_exists('hook_formatDisplayHeader')) {
+                $val = hook_formatDisplayHeader('subject', $test, true);
+                if (is_array($val)) {
+                    $test = banana_html_entity_decode($val[0]);
+                } else {
+                    $test = banana_html_entity_decode($val);
+                }
+            }
+            $test = trim($test);
+            if ($test == $subject) {
+                return $id;
+            }
+            $id--;
+        }
+        return -1;
+    }
+
     /** Returns previous thread root index
      * @param id INTEGER message number
      */
@@ -663,6 +708,10 @@ class BananaSpool
      */
     public function nextUnread($id = null)
     {
+        if (!$this->unreadnb) {
+            return null;
+        }
+
         if (!is_null($id)) {
             // Look in message children
             foreach ($this->overview[$id]->children as $child) {