Should fix "unread state" issues.
[banana.git] / banana / mbox.inc.php
CommitLineData
7027794f 1<?php
2/********************************************************************************
3* banana/protocoleinterface.inc.php : interface for box access
4* ------------------------
5*
6* This file is part of the banana distribution
7* Copyright: See COPYING files that comes with this distribution
8********************************************************************************/
9
10require_once dirname(__FILE__) . '/banana.inc.php';
11require_once dirname(__FILE__) . '/protocoleinterface.inc.php';
12require_once dirname(__FILE__) . '/message.inc.php';
13
14class BananaMBox implements BananaProtocoleInterface
15{
19fc7e1d 16 private $debug = false;
17
7027794f 18 private $_lasterrno = 0;
19 private $_lasterror = null;
19fc7e1d 20
0e25d15d 21 public function __construct()
7027794f 22 {
19fc7e1d 23 $this->debug = Banana::$debug_mbox;
7027794f 24 }
19fc7e1d 25
7027794f 26 public function isValid()
27 {
c28d3016 28 return true;
29 //!Banana::$group || $this->file;
7027794f 30 }
31
598a1c53 32 /** Indicate last error n°
7027794f 33 */
34 public function lastErrNo()
35 {
36 return $this->_lasterrno;;
37 }
38
39 /** Indicate last error text
40 */
41 public function lastError()
42 {
43 return $this->_lasterror;
44 }
45
46 /** Return the description of the current box
47 */
48 public function getDescription()
49 {
50 return null;
51 }
52
53 /** Return the list of the boxes
54 * @param mode Kind of boxes to list
55 * @param since date of last check (for new boxes and new messages)
56 * @param withstats Indicated whether msgnum and unread must be set in the result
57 * @return Array(boxname => array(desc => boxdescripton, msgnum => number of message, unread =>number of unread messages)
58 */
59 public function getBoxList($mode = Banana::BOXES_ALL, $since = 0, $withstats = false)
60 {
0e25d15d 61 return array(Banana::$group => array('desc' => '', 'msgnum' => 0, 'unread' => 0));
7027794f 62 }
63
19fc7e1d 64 private function &getRawMessage($id)
7027794f 65 {
7d3f4749 66 $message = null;
7a5823f9 67 if (!is_numeric($id)) {
19fc7e1d 68 if (!Banana::$spool) {
7d3f4749 69 return $message;
7027794f 70 }
71 $id = Banana::$spool->ids[$id];
72 }
19fc7e1d 73 $options = array ('-m ' . $id);
74 if (Banana::$spool->overview) {
75 if (Banana::$spool->overview[$id]) {
76 $options[] = '-p ' . $id . ':' . Banana::$spool->overview[$id]->storage['offset'];
77 } else {
78 $key = max(array_keys(Banana::$spool->overview));
79 if ($key < $id) {
80 $options[] = '-p ' . $key . ':' . Banana::$spool->overview[$key]->storage['offset'];
81 }
82 }
7027794f 83 }
19fc7e1d 84 return $this->callHelper('-b', $options);
85 }
86
87 /** Return a message
88 * @param id Id of the emssage (can be either an Message-id or a message index)
89 * @return A BananaMessage or null if the given id can't be retreived
90 */
91 public function &getMessage($id)
92 {
93 $messages =& $this->getRawMessage($id);
94 if ($messages) {
95 $messages = new BananaMessage($messages);
96 }
97 return $messages;
7027794f 98 }
99
7a5823f9 100 /** Return the sources of the given message
101 */
102 public function getMessageSource($id)
19fc7e1d 103 {
104 $message =& $this->getRawMessage($id);
105 if ($message) {
106 $message = implode("\n", $message);
c28d3016 107 }
19fc7e1d 108 return $message;
7a5823f9 109 }
110
111 /** Compute the number of messages of the box
112 */
7027794f 113 private function getCount()
114 {
19fc7e1d 115 $options = array();
116 if (Banana::$spool->overview) {
117 $key = max(array_keys(Banana::$spool->overview));
118 $options[] = '-p ' . $key . ':' . Banana::$spool->overview[$key]->storage['offset'];
119 }
120 $val =& $this->callHelper('-c', $options);
121 if (!$val) {
122 return 0;
123 }
124 return intval(trim($val[0]));
7027794f 125 }
126
127 /** Return the indexes of the messages presents in the Box
128 * @return Array(number of messages, MSGNUM of the first message, MSGNUM of the last message)
129 */
130 public function getIndexes()
131 {
19fc7e1d 132 $count = $this->getCount();
133 return array($count, 0, $count - 1);
7027794f 134 }
135
136 /** Return the message headers (in BananaMessage) for messages from firstid to lastid
137 * @return Array(id => array(headername => headervalue))
138 */
139 public function &getMessageHeaders($firstid, $lastid, array $msg_headers = array())
140 {
19fc7e1d 141 $headers = null;
142 $options = array();
143 $options[] = "-m $firstid:$lastid";
144 if (Banana::$spool->overview) {
145 if (isset(Banana::$spool->overview[$firstid])) {
146 $options[] = '-p ' . $firstid . ':' . Banana::$spool->overview[$firstid]->storage['offset'];
147 } else {
148 $key = max(array_keys(Banana::$spool->overview));
149 if ($key < $firstid) {
150 $options[] = '-p ' . $key . ':' . Banana::$spool->overview[$key]->storage['offset'];
151 }
152 }
153 }
154 $lines =& $this->callHelper('-d', $options, $msg_headers);
155 if (!$lines) {
c28d3016 156 return $headers;
157 }
19fc7e1d 158 $headers = array();
159 while ($lines) {
160 $id = array_shift($lines);
161 if ($id === '') {
162 continue;
163 }
164 $offset = array_shift($lines);
165 if ($offset === '') {
166 continue;
167 }
168 $id = intval($id);
169 $headers[$id] = array('beginning' => intval($offset));
170 while (true) {
171 $hname = array_shift($lines);
172 if ($hname === '') {
173 break;
174 }
175 $hval = array_shift($lines);
176 if ($hval === '') {
177 break;
7027794f 178 }
19fc7e1d 179 if ($hname == 'date') {
180 $headers[$id][$hname] = @strtotime($hval);
7027794f 181 } else {
19fc7e1d 182 $headers[$id][$hname] = $hval;
7027794f 183 }
184 }
19fc7e1d 185 if (!isset($headers[$id]['date'])) {
186 print_r($id);
187 print_r($offset);
188 print_r($headers[$id]);
189 }
7027794f 190 }
19fc7e1d 191 array_walk_recursive($headers, array('BananaMimePart', 'decodeHeader'));
7027794f 192 return $headers;
193 }
194
195 /** Add storage data in spool overview
196 */
197 public function updateSpool(array &$messages)
198 {
199 foreach ($messages as $id=>&$data) {
200 if (isset(Banana::$spool->overview[$id])) {
201 Banana::$spool->overview[$id]->storage['offset'] = $data['beginning'];
7027794f 202 }
203 }
204 }
205
206 /** Return the indexes of the new messages since the give date
207 * @return Array(MSGNUM of new messages)
208 */
209 public function getNewIndexes($since)
210 {
703b83c3 211 $this->open();
c28d3016 212 if (is_null($this->file)) {
213 return array();
214 }
7027794f 215 if (is_null($this->new_messages)) {
216 $this->getCount();
217 }
218 return range($this->count - $this->new_messages, $this->count - 1);
219 }
220
221 /** Return wether or not the protocole can be used to add new messages
222 */
223 public function canSend()
224 {
225 return true;
226 }
227
228 /** Return false because we can't cancel a mail
229 */
230 public function canCancel()
231 {
232 return false;
233 }
234
235 /** Return the list of requested headers
236 * @return Array('header1', 'header2', ...) with the key 'dest' for the destination header
237 * and 'reply' for the reply header, eg:
238 * * for a mail: Array('From', 'Subject', 'dest' => 'To', 'Cc', 'Bcc', 'reply' => 'Reply-To')
239 * * for a post: Array('From', 'Subject', 'dest' => 'Newsgroups', 'reply' => 'Followup-To')
240 */
241 public function requestedHeaders()
242 {
243 return Array('From', 'Subject', 'dest' => 'To', 'Cc', 'Bcc', 'reply' => 'Reply-To');
244 }
245
246 /** Send a message
247 * @return true if it was successfull
248 */
249 public function send(BananaMessage &$message)
250 {
e1debf92 251 $headers = $message->getHeaders();
252 $to = $headers['To'];
253 $subject = $headers['Subject'];
254 unset($headers['To']);
255 unset($headers['Subject']);
256 $hdrs = '';
257 foreach ($headers as $key=>$value) {
258 if (!empty($value)) {
259 $hdrs .= "$key: $value\r\n";
260 }
261 }
262 $body = $message->get(false);
263 return mail($to, $subject, $body, $hdrs);
7027794f 264 }
265
266 /** Cancel a message
267 * @return true if it was successfull
268 */
269 public function cancel(BananaMessage &$message)
270 {
271 return false;
272 }
273
274 /** Return the protocole name
275 */
276 public function name()
277 {
278 return 'MBOX';
279 }
280
e9360b11 281 /** Return the spool filename
282 */
283 public function filename()
284 {
285 @list($mail, $domain) = explode('@', Banana::$group);
286 $file = "";
287 if (isset($domain)) {
288 $file = $domain . '_';
289 }
290 return $file . $mail;
291 }
292
7027794f 293#######
294# Filesystem functions
295#######
296
c28d3016 297 protected function getFileName()
7027794f 298 {
c28d3016 299 if (is_null(Banana::$group)) {
7027794f 300 return null;
301 }
c28d3016 302 @list($mail, $domain) = explode('@', Banana::$group);
e9360b11 303 return Banana::$mbox_path . '/' . $mail;
7027794f 304 }
305
306#######
307# MBox parser
308#######
309
19fc7e1d 310 private function &callHelper($action, array $options = array(), array $headers = array())
7027794f 311 {
19fc7e1d 312 $action .= ' -f ' . $this->getFileName();
313 $cmd = Banana::$mbox_helper . " $action " . implode(' ', $options) . ' ' . implode(' ', $headers);
314 if ($this->debug) {
315 echo $cmd . '<br />';
316 $start = microtime(true);
7027794f 317 }
19fc7e1d 318 exec($cmd, $out, $return);
319 if ($this->debug) {
320 echo '&nbsp;&nbsp;Execution : ' . (microtime(true) - $start) . 's<br />';
321 echo "&nbsp;&nbsp;Retour : $return<br />";
322 echo '&nbsp;&nbsp;Sortie : ' . count($out) . ' ligne(s)<br />';
7027794f 323 }
19fc7e1d 324 if ($return != 0) {
325 $this->_lasterrorno = 1;
326 $this->_lasterrorcode = "Helper failed";
327 $out = null;
7027794f 328 }
19fc7e1d 329 return $out;
7027794f 330 }
331}
332
598a1c53 333// vim:set et sw=4 sts=4 ts=4 enc=utf-8:
7027794f 334?>