X-Git-Url: http://git.polytechnique.org/?a=blobdiff_plain;f=banana%2Fmbox.inc.php;h=52b9e7aeead4496268c7721528d3d409bfa05de7;hb=b10e281321dcc27740f64a6a384e295d5c8d3394;hp=c36bb5c492167172c6bd955ff04fe1df281a7f0c;hpb=7027794fb616f65d8910305c9fed9037a751b875;p=banana.git diff --git a/banana/mbox.inc.php b/banana/mbox.inc.php index c36bb5c..52b9e7a 100644 --- a/banana/mbox.inc.php +++ b/banana/mbox.inc.php @@ -13,58 +13,23 @@ require_once dirname(__FILE__) . '/message.inc.php'; class BananaMBox implements BananaProtocoleInterface { - private $boxname; - - private $file = null; - private $filesize = null; - private $current_id = null; - private $at_beginning = false; - private $file_cache = null; - + private $debug = false; + private $_lasterrno = 0; private $_lasterror = null; - - private $count = null; - private $new_messages = null; - private $messages = null; - - /** Build a protocole handler plugged on the given box - */ - public function __construct($box = null) + + public function __construct() { - $this->boxname = $box; - $filename = $this->getFileName($box); - if (is_null($filename)) { - return; - } - $this->filesize = filesize($filename); - $this->file = @fopen($filename, 'r'); - if (!$this->file) { - $this->_lasterrno = 1; - $this->_lasterror = _b_('Can\'t open file'); - $this->file = null; - } - $this->current_id = 0; - $this->at_beginning = true; + $this->debug = Banana::$debug_mbox; } - - /** Close the file - */ - public function __destruct() - { - if ($this->file) { - fclose($this->file); - } - } - - /** Indicate if the Protocole handler has been succesfully built - */ + public function isValid() { - return is_null($this->boxname) || !is_null($this->file); + return true; + //!Banana::$group || $this->file; } - /** Indicate last error n° + /** Indicate last error n° */ public function lastErrNo() { @@ -93,41 +58,70 @@ class BananaMBox implements BananaProtocoleInterface */ public function getBoxList($mode = Banana::BOXES_ALL, $since = 0, $withstats = false) { - return array($this->boxname => array('desc' => '', 'msgnum' => 0, 'unread' => 0)); + return array(Banana::$group => array('desc' => '', 'msgnum' => 0, 'unread' => 0)); + } + + private function &getRawMessage($id) + { + $message = null; + if (!is_numeric($id)) { + if (!Banana::$spool) { + return $message; + } + $id = Banana::$spool->ids[$id]; + } + $options = array ('-m ' . $id); + if (Banana::$spool->overview) { + if (Banana::$spool->overview[$id]) { + $options[] = '-p ' . $id . ':' . Banana::$spool->overview[$id]->storage['offset']; + } else { + $key = max(array_keys(Banana::$spool->overview)); + if ($key < $id) { + $options[] = '-p ' . $key . ':' . Banana::$spool->overview[$key]->storage['offset']; + } + } + } + return $this->callHelper('-b', $options); } /** Return a message * @param id Id of the emssage (can be either an Message-id or a message index) - * @param msg_headers Headers to process - * @param is_msgid If is set, $id is en Message-Id * @return A BananaMessage or null if the given id can't be retreived */ - public function getMessage($id, array $msg_headers = array(), $is_msgid = false) + public function &getMessage($id) { - if ($is_msgid || !is_numeric($id)) { - if (is_null(Banana::$spool)) { - return null; - } - $id = Banana::$spool->ids[$id]; - } - $message = $this->readMessages(array($id)); - if (empty($message)) { - return null; + $messages =& $this->getRawMessage($id); + if ($messages) { + $messages = new BananaMessage($messages); } - $msg = new BananaMessage($message[$id]['message']); - return $msg; + return $messages; } + /** Return the sources of the given message + */ + public function getMessageSource($id) + { + $message =& $this->getRawMessage($id); + if ($message) { + $message = implode("\n", $message); + } + return $message; + } + + /** Compute the number of messages of the box + */ private function getCount() { - $this->count = count(Banana::$spool->overview); - $max = @max(array_keys(Banana::$spool->overview)); - if ($max && Banana::$spool->overview[$max]->storage['next'] == $this->filesize) { - $this->new_messages = 0; - } else { - $this->new_messages = $this->countMessages($this->count); - $this->count += $this->new_messages; - } + $options = array(); + if (Banana::$spool->overview) { + $key = max(array_keys(Banana::$spool->overview)); + $options[] = '-p ' . $key . ':' . Banana::$spool->overview[$key]->storage['offset']; + } + $val =& $this->callHelper('-c', $options); + if (!$val) { + return 0; + } + return intval(trim($val[0])); } /** Return the indexes of the messages presents in the Box @@ -135,10 +129,8 @@ class BananaMBox implements BananaProtocoleInterface */ public function getIndexes() { - if (is_null($this->count)) { - $this->getCount(); - } - return array($this->count, 0, $this->count - 1); + $count = $this->getCount(); + return array($count, 0, $count - 1); } /** Return the message headers (in BananaMessage) for messages from firstid to lastid @@ -146,24 +138,57 @@ class BananaMBox implements BananaProtocoleInterface */ public function &getMessageHeaders($firstid, $lastid, array $msg_headers = array()) { - $msg_headers = array_map('strtolower', $msg_headers); - $messages =& $this->readMessages(range($firstid, $lastid), true); - $msg_headers = array_map('strtolower', $msg_headers); - $headers = array(); - foreach ($msg_headers as $header) { - foreach ($messages as $id=>&$message) { - if (!isset($headers[$id])) { - $headers[$id] = array('beginning' => $message['beginning'], 'end' => $message['end']); + $headers = null; + $options = array(); + $options[] = "-m $firstid:$lastid"; + if (Banana::$spool->overview) { + if (isset(Banana::$spool->overview[$firstid])) { + $options[] = '-p ' . $firstid . ':' . Banana::$spool->overview[$firstid]->storage['offset']; + } else { + $key = max(array_keys(Banana::$spool->overview)); + if ($key < $firstid) { + $options[] = '-p ' . $key . ':' . Banana::$spool->overview[$key]->storage['offset']; + } + } + } + $lines =& $this->callHelper('-d', $options, $msg_headers); + if (!$lines) { + return $headers; + } + $headers = array(); + while ($lines) { + $id = array_shift($lines); + if ($id === '') { + continue; + } + $offset = array_shift($lines); + if ($offset === '') { + continue; + } + $id = intval($id); + $headers[$id] = array('beginning' => intval($offset)); + while (true) { + $hname = array_shift($lines); + if ($hname === '') { + break; + } + $hval = array_shift($lines); + if ($hval === '') { + break; } - if ($header == 'date') { - $headers[$id][$header] = strtotime($message['message'][$header]); + if ($hname == 'date') { + $headers[$id][$hname] = @strtotime($hval); } else { - $headers[$id][$header] = $message['message'][$header]; + $headers[$id][$hname] = $hval; } } + if (!isset($headers[$id]['date'])) { + print_r($id); + print_r($offset); + print_r($headers[$id]); + } } - unset($this->messages); - unset($messages); + array_walk_recursive($headers, array('BananaMimePart', 'decodeHeader')); return $headers; } @@ -174,7 +199,6 @@ class BananaMBox implements BananaProtocoleInterface foreach ($messages as $id=>&$data) { if (isset(Banana::$spool->overview[$id])) { Banana::$spool->overview[$id]->storage['offset'] = $data['beginning']; - Banana::$spool->overview[$id]->storage['next'] = $data['end']; } } } @@ -184,6 +208,10 @@ class BananaMBox implements BananaProtocoleInterface */ public function getNewIndexes($since) { + $this->open(); + if (is_null($this->file)) { + return array(); + } if (is_null($this->new_messages)) { $this->getCount(); } @@ -220,7 +248,19 @@ class BananaMBox implements BananaProtocoleInterface */ public function send(BananaMessage &$message) { - return true; + $headers = $message->getHeaders(); + $to = $headers['To']; + $subject = $headers['Subject']; + unset($headers['To']); + unset($headers['Subject']); + $hdrs = ''; + foreach ($headers as $key=>$value) { + if (!empty($value)) { + $hdrs .= "$key: $value\r\n"; + } + } + $body = $message->get(false); + return mail($to, $subject, $body, $hdrs); } /** Cancel a message @@ -238,194 +278,57 @@ class BananaMBox implements BananaProtocoleInterface return 'MBOX'; } + /** Return the spool filename + */ + public function filename() + { + @list($mail, $domain) = explode('@', Banana::$group); + $file = ""; + if (isset($domain)) { + $file = $domain . '_'; + } + return $file . $mail; + } + ####### # Filesystem functions ####### - protected function getFileName($box) + protected function getFileName() { - if (is_null($box)) { + if (is_null(Banana::$group)) { return null; } - @list($mail, $domain) = explode('@', $box); - if ($mail == 'staff') { - return '/home/x2003bruneau/staff.polytechnique.org_innovation.mbox'; - } else { - return '/var/mail/' . $mail; - } + @list($mail, $domain) = explode('@', Banana::$group); + return Banana::$mbox_path . '/' . $mail; } ####### # MBox parser ####### - /** Go to the given message - */ - private function goTo($id) + private function &callHelper($action, array $options = array(), array $headers = array()) { - if ($this->current_id == $id && $this->at_beginning) { - return true; + $action .= ' -f ' . $this->getFileName(); + $cmd = Banana::$mbox_helper . " $action " . implode(' ', $options) . ' ' . implode(' ', $headers); + if ($this->debug) { + echo $cmd . '
'; + $start = microtime(true); } - if ($id == 0) { - fseek($this->file, 0); - $this->current_id = 0; - $this->at_beginning = true; - return true; - } elseif (isset(Banana::$spool->overview[$id]) || isset($this->messages[$id])) { - if (isset(Banana::$spool->overview[$id])) { - $pos = Banana::$spool->overview[$id]->storage['offset']; - } else { - $pos = $this->messages[$id]['beginning']; - } - if (fseek($this->file, $pos) == 0) { - $this->current_id = $id; - $this->at_beginning = true; - return true; - } else { - $this->current_id = null; - $this->_lasterrno = 2; - $this->_lasterror = _b_('Can\'t find message ') . $id; - return false; - } - } else { - $max = @max(array_keys(Banana::$spool->overview)); - if (is_null($max)) { - $max = 0; - } - if ($id <= $max && $max != 0) { - $this->current_id = null; - $this->_lasterrno = 3; - $this->_lasterror = _b_('Invalid message index ') . $id; - return false; - } - if (!$this->goTo($max)) { - return false; - } - if (feof($this->file)) { - $this->current_id = null; - $this->_lasterrno = 4; - $this->_lasterror = _b_('Requested index does not exists or file has been truncated'); - return false; - } - while ($this->readCurrentMessage(true) && $this->current_id < $id); - if ($this->current_id == $id) { - return true; - } - $this->current_id = null; - $this->_lasterrno = 5; - $this->_lasterror = _b_('Requested index does not exists or file has been truncated'); - return false; + exec($cmd, $out, $return); + if ($this->debug) { + echo '  Execution : ' . (microtime(true) - $start) . 's
'; + echo "  Retour : $return
"; + echo '  Sortie : ' . count($out) . ' ligne(s)
'; } - } - - private function countMessages($from = 0) - { - $this->messages =& $this->readMessages(array($from), true, true); - return count($this->messages); - } - - /** Read the current message (identified by current_id) - * @param needFrom_ BOOLEAN is true if the first line *must* be a From_ line - * @param alignNext BOOLEAN is true if the buffer must be aligned at the beginning of the next From_ line - * @return message sources (without storage data) - */ - private function &readCurrentMessage($stripBody = false, $needFrom_ = true, $alignNext = true) - { - $file_cache =& $this->file_cache; - if ($file_cache && $file_cache != ftell($this->file)) { - $file_cache = null; - } - $msg = array(); - $canFrom_ = false; - $inBody = false; - while(!feof($this->file)) { - // Process file cache - if ($file_cache) { // this is a From_ line - $needFrom_ = false; - $this->at_beginning = false; - $file_cache = null; - continue; - } - - // Read a line - $line = rtrim(fgets($this->file), "\r\n"); - - // Process From_ line - if ($needFrom_ || !$msg || $canFrom_) { - if (substr($line, 0, 5) == 'From ') { // this is a From_ line - if ($needFrom_) { - $needFrom = false; - } elseif (!$msg) { - continue; - } else { - $this->current_id++; // we are finally in the next message - if ($alignNext) { // align the file pointer at the beginning of the new message - $this->at_beginning = true; - $file_cache = ftell($this->file); - } - break; - } - } elseif ($needFrom_) { - return $msg; - } - } - - // Process non-From_ lines - if (substr($line, 0, 6) == '>From ') { // remove inline From_ quotation - $line = substr($line, 1); - } - if (!$stripBody || !$inBody) { - $msg[] = $line; // add the line to the message source - } - $canFrom_ = empty($line); // check if next line can be a From_ line - if ($canFrom_ && !$inBody && $stripBody) { - $inBody = true; - } - $this->at_beginning = false; - } - if (!feof($this->file) && !$canFrom_) { - $msg = array(); - } - return $msg; - } - - /** Read message with the given ids - * @param ids ARRAY of ids to look for - * @param strip BOOLEAN if true, only headers are retrieved - * @param from BOOLEAN if true, process all messages from max(ids) to the end of the mbox - * @return Array(Array('message' => message sources (or parsed message headers if $strip is true), - * 'beginning' => offset of message beginning, - * 'end' => offset of message end)) - */ - private function &readMessages(array $ids, $strip = false, $from = false) - { - if (!is_null($this->messages)) { - return $this->messages; - } - sort($ids); - $messages = array(); - while ((count($ids) || $from) && !feof($this->file)) { - if (count($ids)) { - $id = array_shift($ids); - } else { - $id++; - } - if ($id != $this->current_id || !$this->at_beginning) { - if (!$this->goTo($id)) { - continue; - } - } - $beginning = ftell($this->file); - $message =& $this->readCurrentMessage($strip, false); - if ($strip) { - $message =& BananaMimePart::parseHeaders($message); - } - $end = ftell($this->file); - $messages[$id] = array('message' => $message, 'beginning' => $beginning, 'end' => $end); + if ($return != 0) { + $this->_lasterrorno = 1; + $this->_lasterrorcode = "Helper failed"; + $out = null; } - return $messages; + return $out; } } -// vim:set et sw=4 sts=4 ts=4: +// vim:set et sw=4 sts=4 ts=4 enc=utf-8: ?>