Improvements and bugfixes
[banana.git] / banana / feed.inc.php
1 <?php
2 /********************************************************************************
3 * banana/feed.inc.php : Feed Builder
4 * ------------------------
5 *
6 * This file is part of the banana distribution
7 * Copyright: See COPYING files that comes with this distribution
8 ********************************************************************************/
9
10 require_once dirname(__FILE__) . '/banana.inc.php';
11
12 define('BANANA_FEED_VERSION', '0.1');
13
14 class BananaFeed
15 {
16 /** Structure version
17 */
18 private $version;
19
20 /** Feed name
21 */
22 public $group;
23
24 /** Feed description
25 */
26 public $description;
27
28 /** A 'ordered by id' spool of the last messages
29 * Each Message is an array with :
30 * array('author' => author, 'date' => date (UNIX TS), 'title' => subject, 'body' => html body,
31 * 'link' => link, 'reply' => reply)
32 */
33 public $messages = array();
34
35 /** Last update time
36 */
37 public $lastupdate = 0;
38
39 /** Create an empty feed
40 */
41 private function __construct()
42 {
43 $this->version = BANANA_FEED_VERSION;
44 $this->group = Banana::$group;
45 $this->description = trim(Banana::$protocole->getDescription());
46 }
47
48 /** Update the feed, using current settings of Banana
49 * Calling this function suppose that Banana::$spool is the spool of the current box
50 */
51 public function update()
52 {
53 if (!Banana::$spool || Banana::$spool->group != $this->group) {
54 return false;
55 }
56 if (!Banana::$spool->ids) {
57 $spool_indexes = array();
58 } else {
59 $spool_indexes = Banana::$spool->ids;
60 sort($spool_indexes, SORT_NUMERIC);
61 $spool_indexes = array_slice($spool_indexes, -Banana::$feed_size, Banana::$feed_size);
62 }
63 $feed_indexes = array_keys($this->messages);
64 $old = array_diff($feed_indexes, $spool_indexes);
65 foreach ($old as $key) {
66 unset($this->messages[$key]);
67 }
68 $new = array_diff($spool_indexes, $feed_indexes);
69 foreach ($new as $key) {
70 $message =& Banana::$protocole->getMessage($key);
71 $array = array();
72 $array['author'] = $message->getAuthorName();
73 $array['date'] = $message->getHeaderValue('Date');
74 $array['title'] = $message->getHeaderValue('Subject');
75 $array['body'] = $message->toHtml();
76 $array['link'] = Banana::$page->makeUrl(array('group' => $this->group, 'artid' => $key));
77 if (Banana::$protocole->canSend()) {
78 $array['reply'] = Banana::$page->makeUrl(array('group' => $this->group, 'artid' => $key, 'action' => 'new'));
79 }
80 $this->messages[$key] = $array;
81 }
82 uasort($this->messages, Array('BananaFeed', 'compare'));
83 $this->lastupdate = time();
84 $this->writeToFile();
85 }
86
87 /** Get the spool corresponding with the current settings of Banana
88 */
89 static public function &getFeed()
90 {
91 $feed =& BananaFeed::readFromFile();
92 if (!$feed) {
93 $feed = new BananaFeed();
94 }
95 if (Banana::$feed_updateOnDemand) {
96 $feed->update();
97 }
98 return $feed;
99 }
100
101 /** Return the cache file name
102 */
103 static private function filename()
104 {
105 $file = Banana::$spool_root . '/' . Banana::$protocole->name() . '/';
106 if (!is_dir($file)) {
107 mkdir($file);
108 }
109 return $file . Banana::$protocole->filename() . '_feed';
110 }
111
112 /** Read a feed from a cache file
113 */
114 static private function &readFromFile()
115 {
116 $feed = null;
117 $file = BananaFeed::filename();
118 if (!file_exists($file)) {
119 return $feed;
120 }
121 $feed = unserialize(file_get_contents($file));
122 if ($feed->version != BANANA_FEED_VERSION) {
123 $feed = null;
124 }
125 return $feed;
126 }
127
128 /** Write a feed to a cache file
129 */
130 private function writeToFile()
131 {
132 $file = BananaFeed::filename();
133 file_put_contents($file, serialize($this));
134 }
135
136 /** Merge to feeds into a new one
137 */
138 static public function &merge(&$feed1, &$feed2, $name, $description = null)
139 {
140 if (!$feed1) {
141 $feed = null;
142 $feed1 =& $feed2;
143 $feed2 =& $feed;
144 }
145 if ($feed1->group == $name) {
146 $master =& $feed1;
147 $slave =& $feed2;
148 } else if ($feed2 && $feed2->group == $name) {
149 $master =& $feed2;
150 $slave =& $feed1;
151 } else {
152 $master = new BananaFeed();
153 $master->group = $name;
154 $master->description = $description;
155 foreach ($feed1->messages as $key=>$message) {
156 $message['title'] = '[' . $feed1->group . '] ' . $message['title'];
157 $master->messages[$feed1->group . '-' . $key] = $message;
158 }
159 $slave =& $feed2;
160 }
161 if (!$slave) {
162 return $master;
163 }
164 $messages = array();
165 $m1 = end($master->messages);
166 $m2 = end($slave->messages);
167 for ($i = 0 ; $i < 2 * Banana::$feed_size && ($m1 || $m2) ; $i++) {
168 if ($m2 && (!$m1 || $m1['date'] < $m2['date'])) {
169 $m2['title'] = '[' . $feed2->group . '] ' . $m2['title'];
170 $messages[$slave->group . '-' . key($slave->messages)] = $m2;
171 $m2 = prev($slave->messages);
172 } else {
173 $messages[key($master->messages)] = $m1;
174 $m1 = prev($master->messages);
175 }
176 }
177 uasort($messages, array('BananaFeed', 'compare'));
178 $master->messages =& $messages;
179 $master->lastupdate = time();
180 return $master;
181 }
182
183 static function compare($a, $b)
184 {
185 if ($a['date'] == $b['date']) {
186 return 0;
187 }
188 return $a['date'] < $b['date'] ? -1 : 1;
189 }
190
191 /** Generate the feed xml
192 */
193 public function toXML()
194 {
195 Banana::$page->assign_by_ref('feed', $this);
196 return Banana::$page->feed();
197 }
198 }
199
200 // vim:set et sw=4 sts=4 ts=4 enc=utf-8:
201 ?>