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